-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Client's buffer for non-101 response body issue optimization proposition #1005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -172,6 +172,8 @@ var nilDialer = *DefaultDialer | |
| // non-nil *http.Response so that callers can handle redirects, authentication, | ||
| // etcetera. The response body may not contain the entire response and does not | ||
| // need to be closed by the application. | ||
| var maxErrorResponseSize = 4096 | ||
|
|
||
| func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { | ||
| if d == nil { | ||
| d = &nilDialer | ||
|
|
@@ -364,9 +366,13 @@ func (d *Dialer) DialContext(ctx context.Context, urlStr string, requestHeader h | |
| // Before closing the network connection on return from this | ||
| // function, slurp up some of the response to aid application | ||
| // debugging. | ||
| buf := make([]byte, 1024) | ||
| n, _ := io.ReadFull(resp.Body, buf) | ||
| resp.Body = io.NopCloser(bytes.NewReader(buf[:n])) | ||
|
|
||
| limReader := io.LimitReader(resp.Body, int64(maxErrorResponseSize)) | ||
|
||
| buf, err := io.ReadAll(limReader) | ||
| if err != nil && err != io.EOF { | ||
|
||
| buf = []byte{} | ||
| } | ||
| resp.Body = io.NopCloser(bytes.NewReader(buf)) | ||
| return nil, resp, ErrBadHandshake | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -573,8 +573,10 @@ func TestHandshake(t *testing.T) { | |
| } | ||
|
|
||
| func TestRespOnBadHandshake(t *testing.T) { | ||
| // Test Body smaller than maxErrorResponseSize. | ||
| const expectedStatus = http.StatusGone | ||
| const expectedBody = "This is the response body." | ||
| const maxErrorResponseSize = 4096 | ||
|
|
||
| s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| w.WriteHeader(expectedStatus) | ||
|
|
@@ -604,6 +606,76 @@ func TestRespOnBadHandshake(t *testing.T) { | |
| if string(p) != expectedBody { | ||
| t.Errorf("resp.Body=%s, want %s", p, expectedBody) | ||
| } | ||
|
|
||
| // Test Body larger than maxErrorResponseSize. | ||
| t.Run("ErrorResponseSizeLimited", func(t *testing.T) { | ||
| largeBody := make([]byte, maxErrorResponseSize+100) | ||
| for i := range largeBody { | ||
| largeBody[i] = 'a' | ||
| } | ||
|
|
||
| s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| w.WriteHeader(http.StatusInternalServerError) | ||
| w.Write(largeBody) | ||
| })) | ||
| defer s.Close() | ||
|
|
||
| ws, resp, err := cstDialer.Dial(makeWsProto(s.URL), nil) | ||
| if err == nil { | ||
| ws.Close() | ||
| t.Fatalf("Dial: expected error, got nil") | ||
| } | ||
|
|
||
| if resp == nil { | ||
| t.Fatalf("resp=nil, err=%v", err) | ||
| } | ||
|
|
||
| p, err := io.ReadAll(resp.Body) | ||
| if err != nil { | ||
| t.Fatalf("ReadAll(resp.Body) returned error %v", err) | ||
| } | ||
|
|
||
| resp.Body.Close() | ||
|
|
||
| if len(p) > maxErrorResponseSize { | ||
| t.Fatalf("body size=%d, want <= %d", len(p), maxErrorResponseSize) | ||
| } | ||
| }) | ||
|
|
||
| // Test Body exactly maxErrorResponseSize. | ||
| t.Run("ErrorResponseSizeExactLimit", func(t *testing.T) { | ||
| limitedBody := make([]byte, maxErrorResponseSize) | ||
| for i := range limitedBody { | ||
| limitedBody[i] = 'a' | ||
| } | ||
|
|
||
| s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||
| w.WriteHeader(http.StatusBadGateway) | ||
| w.Write(limitedBody) | ||
| })) | ||
| defer s.Close() | ||
|
|
||
| ws, resp, err := cstDialer.Dial(makeWsProto(s.URL), nil) | ||
| if err == nil { | ||
| ws.Close() | ||
| t.Fatalf("Dial: expected error, got nil") | ||
| } | ||
|
|
||
| if resp == nil { | ||
| t.Fatalf("resp=nil, err=%v", err) | ||
| } | ||
|
|
||
| p, err := io.ReadAll(resp.Body) | ||
| if err != nil { | ||
| t.Fatalf("ReadAll(resp.Body) returned error %v", err) | ||
| } | ||
|
|
||
| resp.Body.Close() | ||
|
|
||
| if len(p) != maxErrorResponseSize { | ||
| t.Fatalf("body size=%d, want %d", len(p), maxErrorResponseSize) | ||
| } | ||
| }) | ||
|
||
| } | ||
|
|
||
| type testLogWriter struct { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The location of this variable declaration breaks the documentation (the DialContext documentation is no longer associated with the method). Move the var declaration.
While you are at it, change it to a
const.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup indeed you're right there !