Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions buffer/buffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ func (b *Buffer) ServeHTTP(w http.ResponseWriter, req *http.Request) {

outReq := b.copyRequest(req, body, totalSize)

defer func() {
if err := recover(); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with this recover, you will catch all the panic from other middleware.

if err == http.ErrAbortHandler {
b.log.Error("vulcand/oxy/buffer: failed to read response, err: %v", err)

b.errHandler.ServeHTTP(w, req, err.(error))
return
}

panic(err)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about that.
Why do you not write the error inside the response?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that the Write method of bufferWriter doesn't return an error prevents ErrAbortHandler from being raised.
The idea is to fix the Write method and specifically handles ErrAbortHandler by returning a 500 status code to avoid breaking changes.
For other errors, a panic is raised to ensure that existing panic behaviors remain unchanged.

After giving it some thought, I wonder if there might be impacts I didn't anticipate. Perhaps an approach like this (#247) might be safer.

}
}()

attempt := 1
for {
// We create a special writer that will limit the response size, buffer it to disk if necessary
Expand Down Expand Up @@ -292,14 +305,7 @@ func (b *bufferWriter) Header() http.Header {
}

func (b *bufferWriter) Write(buf []byte) (int, error) {
length, err := b.buffer.Write(buf)
if err != nil {
// Since go1.11 (https://github.com/golang/go/commit/8f38f28222abccc505b9a1992deecfe3e2cb85de)
// if the writer returns an error, the reverse proxy panics
b.log.Error("write: %v", err)
length = len(buf)
}
return length, nil
return b.buffer.Write(buf)
}

// WriteHeader sets rw.Code.
Expand Down
8 changes: 6 additions & 2 deletions buffer/buffer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package buffer

import (
"bufio"
"crypto/rand"
"crypto/tls"
"fmt"
"io"
Expand Down Expand Up @@ -173,8 +174,11 @@ func TestBuffer_requestLimitReached(t *testing.T) {
}

func TestBuffer_responseLimitReached(t *testing.T) {
payload := make([]byte, 40000)
_, _ = rand.Read(payload)

srv := testutils.NewHandler(func(w http.ResponseWriter, _ *http.Request) {
_, _ = w.Write([]byte("hello, this response is too large"))
_, _ = w.Write(payload)
})
t.Cleanup(srv.Close)

Expand All @@ -188,7 +192,7 @@ func TestBuffer_responseLimitReached(t *testing.T) {
})

// stream handler will forward requests to redirect
st, err := New(rdr, MaxResponseBodyBytes(4))
st, err := New(rdr, MaxResponseBodyBytes(10000))
require.NoError(t, err)

proxy := httptest.NewServer(st)
Expand Down
Loading