Skip to content

Commit df8335f

Browse files
A response without a body can't have trailers (#1825)
1 parent 9df444b commit df8335f

File tree

5 files changed

+63
-12
lines changed

5 files changed

+63
-12
lines changed

client.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,9 +1365,7 @@ func (c *HostClient) do(req *Request, resp *Response) (bool, error) {
13651365
defer ReleaseResponse(resp)
13661366
}
13671367

1368-
ok, err := c.doNonNilReqResp(req, resp)
1369-
1370-
return ok, err
1368+
return c.doNonNilReqResp(req, resp)
13711369
}
13721370

13731371
func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error) {

client_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3484,3 +3484,52 @@ func TestDialTimeout(t *testing.T) {
34843484
})
34853485
}
34863486
}
3487+
3488+
func TestClientHeadWithBody(t *testing.T) {
3489+
t.Parallel()
3490+
3491+
ln := fasthttputil.NewInmemoryListener()
3492+
defer ln.Close()
3493+
3494+
go func() {
3495+
c, err := ln.Accept()
3496+
if err != nil {
3497+
t.Error(err)
3498+
}
3499+
c.Write([]byte("HTTP/1.1 200 OK\r\n" + //nolint:errcheck
3500+
"content-type: text/plain\r\n" +
3501+
"transfer-encoding: chunked\r\n\r\n" +
3502+
"24\r\nThis is the data in the first chunk \r\n" +
3503+
"1B\r\nand this is the second one \r\n" +
3504+
"0\r\n\r\n",
3505+
))
3506+
}()
3507+
3508+
c := &Client{
3509+
Dial: func(addr string) (net.Conn, error) {
3510+
return ln.Dial()
3511+
},
3512+
ReadTimeout: time.Millisecond * 10,
3513+
MaxIdemponentCallAttempts: 1,
3514+
}
3515+
3516+
req := AcquireRequest()
3517+
req.SetRequestURI("http://127.0.0.1:7070")
3518+
req.Header.SetMethod(MethodHead)
3519+
3520+
resp := AcquireResponse()
3521+
3522+
err := c.Do(req, resp)
3523+
if err != nil {
3524+
t.Fatal(err)
3525+
}
3526+
3527+
// The second request on the same connection is going to give a timeout as it can't find
3528+
// a proper request in what is left on the connection.
3529+
err = c.Do(req, resp)
3530+
if err == nil {
3531+
t.Error("expected timeout error")
3532+
} else if err != ErrTimeout {
3533+
t.Error(err)
3534+
}
3535+
}

header_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2965,6 +2965,8 @@ func verifyRequestHeader(t *testing.T, h *RequestHeader, expectedContentLength i
29652965
}
29662966

29672967
func verifyResponseTrailer(t *testing.T, h *ResponseHeader, expectedTrailers map[string]string) {
2968+
t.Helper()
2969+
29682970
for k, v := range expectedTrailers {
29692971
got := h.Peek(k)
29702972
if !bytes.Equal(got, []byte(v)) {

http.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1446,7 +1446,8 @@ func (resp *Response) ReadLimitBody(r *bufio.Reader, maxBodySize int) error {
14461446
}
14471447
}
14481448

1449-
if resp.Header.ContentLength() == -1 && !resp.StreamBody {
1449+
// A response without a body can't have trailers.
1450+
if resp.Header.ContentLength() == -1 && !resp.StreamBody && !resp.mustSkipBody() {
14501451
err = resp.Header.ReadTrailer(r)
14511452
if err != nil && err != io.EOF {
14521453
if isConnectionReset(err) {

http_test.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,25 +2021,27 @@ func TestResponseReadWithoutBody(t *testing.T) {
20212021
var resp Response
20222022

20232023
testResponseReadWithoutBody(t, &resp, "HTTP/1.1 304 Not Modified\r\nContent-Type: aa\r\nContent-Length: 1235\r\n\r\n", false,
2024-
304, 1235, "aa", nil)
2024+
304, 1235, "aa")
20252025

2026-
testResponseReadWithoutBody(t, &resp, "HTTP/1.1 204 Foo Bar\r\nContent-Type: aab\r\nTransfer-Encoding: chunked\r\n\r\n0\r\nFoo: bar\r\n\r\n", false,
2027-
204, -1, "aab", map[string]string{"Foo": "bar"})
2026+
testResponseReadWithoutBody(t, &resp, "HTTP/1.1 204 Foo Bar\r\nContent-Type: aab\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\n", false,
2027+
204, -1, "aab")
20282028

20292029
testResponseReadWithoutBody(t, &resp, "HTTP/1.1 123 AAA\r\nContent-Type: xxx\r\nContent-Length: 3434\r\n\r\n", false,
2030-
123, 3434, "xxx", nil)
2030+
123, 3434, "xxx")
20312031

20322032
testResponseReadWithoutBody(t, &resp, "HTTP 200 OK\r\nContent-Type: text/xml\r\nContent-Length: 123\r\n\r\nfoobar\r\n", true,
2033-
200, 123, "text/xml", nil)
2033+
200, 123, "text/xml")
20342034

20352035
// '100 Continue' must be skipped.
20362036
testResponseReadWithoutBody(t, &resp, "HTTP/1.1 100 Continue\r\nFoo-bar: baz\r\n\r\nHTTP/1.1 329 aaa\r\nContent-Type: qwe\r\nContent-Length: 894\r\n\r\n", true,
2037-
329, 894, "qwe", nil)
2037+
329, 894, "qwe")
20382038
}
20392039

20402040
func testResponseReadWithoutBody(t *testing.T, resp *Response, s string, skipBody bool,
2041-
expectedStatusCode, expectedContentLength int, expectedContentType string, expectedTrailer map[string]string,
2041+
expectedStatusCode, expectedContentLength int, expectedContentType string,
20422042
) {
2043+
t.Helper()
2044+
20432045
r := bytes.NewBufferString(s)
20442046
rb := bufio.NewReader(r)
20452047
resp.SkipBody = skipBody
@@ -2051,7 +2053,6 @@ func testResponseReadWithoutBody(t *testing.T, resp *Response, s string, skipBod
20512053
t.Fatalf("Unexpected response body %q. Expected %q. response=%q", resp.Body(), "", s)
20522054
}
20532055
verifyResponseHeader(t, &resp.Header, expectedStatusCode, expectedContentLength, expectedContentType, "")
2054-
verifyResponseTrailer(t, &resp.Header, expectedTrailer)
20552056

20562057
// verify that ordinal response is read after null-body response
20572058
resp.SkipBody = false

0 commit comments

Comments
 (0)