Skip to content

Commit 4f75d41

Browse files
authored
fix(buffer): incorrect short-circuiting in buffer logic (#253)
1 parent cc307fc commit 4f75d41

3 files changed

Lines changed: 59 additions & 4 deletions

File tree

buffer/buffer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ func (b *Buffer) ServeHTTP(w http.ResponseWriter, req *http.Request) {
250250
reader = rdr
251251
}
252252

253-
if body == nil || (b.retryPredicate == nil || attempt > DefaultMaxRetryAttempts) ||
253+
if b.retryPredicate == nil || attempt > DefaultMaxRetryAttempts ||
254254
!b.retryPredicate(&context{r: req, attempt: attempt, responseCode: bw.code}) {
255255
utils.CopyHeaders(w.Header(), bw.Header())
256256
w.WriteHeader(bw.code)

roundrobin/rr_test.go

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
package roundrobin
22

33
import (
4+
"fmt"
45
"net/http"
56
"net/http/httptest"
7+
"sync/atomic"
68
"testing"
79

810
"github.com/stretchr/testify/assert"
911
"github.com/stretchr/testify/require"
12+
"github.com/vulcand/oxy/v2/buffer"
1013
"github.com/vulcand/oxy/v2/forward"
1114
"github.com/vulcand/oxy/v2/testutils"
1215
"github.com/vulcand/oxy/v2/utils"
@@ -201,13 +204,55 @@ func TestRoundRobinRequestRewriteListener(t *testing.T) {
201204
assert.NotNil(t, lb.requestRewriteListener)
202205
}
203206

204-
func seq(t *testing.T, url string, repeat int) []string {
207+
func TestRoundRobinFailWell(t *testing.T) {
208+
req := httptest.NewRequest(http.MethodGet, "/", nil)
209+
210+
rr := httptest.NewRecorder()
211+
212+
var oneCount atomic.Int32
213+
214+
oneServer := testutils.NewResponderWithCount(&oneCount)
215+
216+
t.Cleanup(func() { oneServer.Close() })
217+
218+
var twoCount atomic.Int32
219+
220+
twoServer := testutils.NewResponderWithCount(&twoCount)
221+
222+
// explicit close now
223+
twoServer.Close()
224+
225+
lb, err := New(forward.New(false))
226+
require.NoError(t, err)
227+
228+
require.NoError(t, lb.UpsertServer(testutils.MustParseRequestURI(oneServer.URL)))
229+
require.NoError(t, lb.UpsertServer(testutils.MustParseRequestURI(twoServer.URL)))
230+
231+
buff, err := buffer.New(lb, buffer.Retry(fmt.Sprintf("IsNetworkError() && Attempts() < %d", 2)))
232+
require.NoError(t, err)
233+
234+
okCount := 0
235+
236+
for range 10 {
237+
buff.ServeHTTP(rr, req)
238+
239+
assert.Equal(t, http.StatusOK, rr.Code)
240+
241+
okCount++
242+
}
243+
244+
assert.Equal(t, 10, okCount)
245+
assert.Equal(t, int32(10), oneCount.Load())
246+
assert.Zero(t, twoCount.Load())
247+
}
248+
249+
func seq(t *testing.T, uri string, repeat int) []string {
205250
t.Helper()
206251

207252
var out []string
208253

209254
for range repeat {
210-
_, body, err := testutils.Get(url)
255+
_, body, err := testutils.Get(uri)
211256
require.NoError(t, err)
212257

213258
out = append(out, string(body))

testutils/utils.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"net/http/httptest"
99
"net/url"
1010
"strings"
11+
"sync/atomic"
1112
"testing"
1213

1314
"github.com/vulcand/oxy/v2/internal/holsterv4/clock"
@@ -19,7 +20,7 @@ func NewHandler(handler http.HandlerFunc) *httptest.Server {
1920
return httptest.NewServer(handler)
2021
}
2122

22-
// NewResponder creates a new Server with response.
23+
// NewResponder creates a new Server with a response.
2324
func NewResponder(t *testing.T, response string) *httptest.Server {
2425
t.Helper()
2526

@@ -32,6 +33,15 @@ func NewResponder(t *testing.T, response string) *httptest.Server {
3233
return server
3334
}
3435

36+
// NewResponderWithCount creates a new Server with a call counter.
37+
func NewResponderWithCount(count *atomic.Int32) *httptest.Server {
38+
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
39+
count.Add(1)
40+
41+
_, _ = w.Write([]byte("Ok"))
42+
}))
43+
}
44+
3545
// MustParseRequestURI is the version of url.ParseRequestURI that panics if incorrect, helpful to shorten the tests.
3646
func MustParseRequestURI(uri string) *url.URL {
3747
out, err := url.ParseRequestURI(uri)

0 commit comments

Comments
 (0)