aboutsummaryrefslogtreecommitdiff
path: root/http_test.go
diff options
context:
space:
mode:
authorGravatar ichx <czn16@qq.com> 2021-12-05 21:11:51 +0800
committerGravatar GitHub <noreply@github.com> 2021-12-05 14:11:51 +0100
commitda7ff7a2080953e370e8bd712f5ae8ef8b0cb4e1 (patch)
treed361832c2ab7da262ce69a646377cf3301968cca /http_test.go
parentfix: reset request after reset user values on keep-alive connections (#1162) (diff)
downloadfasthttp-da7ff7a2080953e370e8bd712f5ae8ef8b0cb4e1.tar.gz
fasthttp-da7ff7a2080953e370e8bd712f5ae8ef8b0cb4e1.tar.bz2
fasthttp-da7ff7a2080953e370e8bd712f5ae8ef8b0cb4e1.zip
Add trailer support (#1165)
* Add trailer support * fix issue and add documentation * remove redundant code * add error return for add/set trailer method * fix lint error * fix bad trailer error return issue and update bad content-length error * update errNonNumericChars * update errNonNumericChars * fix issue about error and fix typo
Diffstat (limited to 'http_test.go')
-rw-r--r--http_test.go392
1 files changed, 311 insertions, 81 deletions
diff --git a/http_test.go b/http_test.go
index 8bd050b..978703a 100644
--- a/http_test.go
+++ b/http_test.go
@@ -155,6 +155,122 @@ func testResponseCopyTo(t *testing.T, src *Response) {
}
}
+func TestRequestBodyStreamWithTrailer(t *testing.T) {
+ t.Parallel()
+
+ testRequestBodyStreamWithTrailer(t, nil, false)
+
+ body := createFixedBody(1e5)
+ testRequestBodyStreamWithTrailer(t, body, false)
+ testRequestBodyStreamWithTrailer(t, body, true)
+}
+
+func testRequestBodyStreamWithTrailer(t *testing.T, body []byte, disableNormalizing bool) {
+ expectedTrailer := map[string]string{
+ "foo": "testfoo",
+ "bar": "testbar",
+ }
+
+ var req1 Request
+ req1.Header.disableNormalizing = disableNormalizing
+ req1.SetHost("google.com")
+ req1.SetBodyStream(bytes.NewBuffer(body), -1)
+ for k, v := range expectedTrailer {
+ err := req1.Header.AddTrailer(k)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ req1.Header.Set(k, v)
+ }
+
+ w := &bytes.Buffer{}
+ bw := bufio.NewWriter(w)
+ if err := req1.Write(bw); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if err := bw.Flush(); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ var req2 Request
+ req2.Header.disableNormalizing = disableNormalizing
+ br := bufio.NewReader(w)
+ if err := req2.Read(br); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ reqBody := req2.Body()
+ if !bytes.Equal(reqBody, body) {
+ t.Fatalf("unexpected body: %q. Expecting %q", reqBody, body)
+ }
+
+ for k, v := range expectedTrailer {
+ kBytes := []byte(k)
+ normalizeHeaderKey(kBytes, disableNormalizing)
+ r := req2.Header.Peek(k)
+ if string(r) != v {
+ t.Fatalf("unexpected trailer header %q: %q. Expecting %s", kBytes, r, v)
+ }
+ }
+}
+
+func TestResponseBodyStreamWithTrailer(t *testing.T) {
+ t.Parallel()
+
+ testResponseBodyStreamWithTrailer(t, nil, false)
+
+ body := createFixedBody(1e5)
+ testResponseBodyStreamWithTrailer(t, body, false)
+ testResponseBodyStreamWithTrailer(t, body, true)
+}
+
+func testResponseBodyStreamWithTrailer(t *testing.T, body []byte, disableNormalizing bool) {
+ expectedTrailer := map[string]string{
+ "foo": "testfoo",
+ "bar": "testbar",
+ }
+ var resp1 Response
+ resp1.Header.disableNormalizing = disableNormalizing
+ resp1.SetBodyStream(bytes.NewReader(body), -1)
+ for k, v := range expectedTrailer {
+ err := resp1.Header.AddTrailer(k)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ resp1.Header.Set(k, v)
+ }
+
+ w := &bytes.Buffer{}
+ bw := bufio.NewWriter(w)
+ if err := resp1.Write(bw); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ if err := bw.Flush(); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ var resp2 Response
+ resp2.Header.disableNormalizing = disableNormalizing
+ br := bufio.NewReader(w)
+ if err := resp2.Read(br); err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ respBody := resp2.Body()
+ if !bytes.Equal(respBody, body) {
+ t.Fatalf("unexpected body: %q. Expecting %q", respBody, body)
+ }
+
+ for k, v := range expectedTrailer {
+ kBytes := []byte(k)
+ normalizeHeaderKey(kBytes, disableNormalizing)
+ r := resp2.Header.Peek(k)
+ if string(r) != v {
+ t.Fatalf("unexpected trailer header %q: %q. Expecting %s", kBytes, r, v)
+ }
+ }
+}
+
func TestResponseBodyStreamDeflate(t *testing.T) {
t.Parallel()
@@ -1344,17 +1460,19 @@ func TestResponseReadLimitBody(t *testing.T) {
// response with content-length
testResponseReadLimitBodySuccess(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nContent-Length: 10\r\n\r\n9876543210", 10)
testResponseReadLimitBodySuccess(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nContent-Length: 10\r\n\r\n9876543210", 100)
- testResponseReadLimitBodyError(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nContent-Length: 10\r\n\r\n9876543210", 9)
+ testResponseReadLimitBodyError(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nContent-Length: 10\r\n\r\n9876543210", 9, ErrBodyTooLarge)
// chunked response
testResponseReadLimitBodySuccess(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 9)
+ testResponseReadLimitBodySuccess(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\nFoo: bar\r\n\r\n", 9)
testResponseReadLimitBodySuccess(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 100)
- testResponseReadLimitBodyError(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 2)
+ testResponseReadLimitBodySuccess(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\nfoobar\r\n\r\n", 100)
+ testResponseReadLimitBodyError(t, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\nTransfer-Encoding: chunked\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 2, ErrBodyTooLarge)
// identity response
testResponseReadLimitBodySuccess(t, "HTTP/1.1 400 OK\r\nContent-Type: aa\r\n\r\n123456", 6)
testResponseReadLimitBodySuccess(t, "HTTP/1.1 400 OK\r\nContent-Type: aa\r\n\r\n123456", 106)
- testResponseReadLimitBodyError(t, "HTTP/1.1 400 OK\r\nContent-Type: aa\r\n\r\n123456", 5)
+ testResponseReadLimitBodyError(t, "HTTP/1.1 400 OK\r\nContent-Type: aa\r\n\r\n123456", 5, ErrBodyTooLarge)
}
func TestRequestReadLimitBody(t *testing.T) {
@@ -1363,15 +1481,17 @@ func TestRequestReadLimitBody(t *testing.T) {
// request with content-length
testRequestReadLimitBodySuccess(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 9)
testRequestReadLimitBodySuccess(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 92)
- testRequestReadLimitBodyError(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 5)
+ testRequestReadLimitBodyError(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 5, ErrBodyTooLarge)
// chunked request
testRequestReadLimitBodySuccess(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 9)
+ testRequestReadLimitBodySuccess(t, "POST /a HTTP/1.1\nHost: a.com\nTransfer-Encoding: chunked\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\nFoo: bar\r\n\r\n", 9)
testRequestReadLimitBodySuccess(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 999)
- testRequestReadLimitBodyError(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 8)
+ testRequestReadLimitBodySuccess(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\nfoobar\r\n\r\n", 999)
+ testRequestReadLimitBodyError(t, "POST /a HTTP/1.1\r\nHost: a.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa\r\n\r\n6\r\nfoobar\r\n3\r\nbaz\r\n0\r\n\r\n", 8, ErrBodyTooLarge)
}
-func testResponseReadLimitBodyError(t *testing.T, s string, maxBodySize int) {
+func testResponseReadLimitBodyError(t *testing.T, s string, maxBodySize int, expectedErr error) {
var req Response
r := bytes.NewBufferString(s)
br := bufio.NewReader(r)
@@ -1379,8 +1499,8 @@ func testResponseReadLimitBodyError(t *testing.T, s string, maxBodySize int) {
if err == nil {
t.Fatalf("expecting error. s=%q, maxBodySize=%d", s, maxBodySize)
}
- if err != ErrBodyTooLarge {
- t.Fatalf("unexpected error: %s. Expecting %s. s=%q, maxBodySize=%d", err, ErrBodyTooLarge, s, maxBodySize)
+ if err != expectedErr {
+ t.Fatalf("unexpected error: %s. Expecting %s. s=%q, maxBodySize=%d", err, expectedErr, s, maxBodySize)
}
}
@@ -1393,7 +1513,7 @@ func testResponseReadLimitBodySuccess(t *testing.T, s string, maxBodySize int) {
}
}
-func testRequestReadLimitBodyError(t *testing.T, s string, maxBodySize int) {
+func testRequestReadLimitBodyError(t *testing.T, s string, maxBodySize int, expectedErr error) {
var req Request
r := bytes.NewBufferString(s)
br := bufio.NewReader(r)
@@ -1401,8 +1521,8 @@ func testRequestReadLimitBodyError(t *testing.T, s string, maxBodySize int) {
if err == nil {
t.Fatalf("expecting error. s=%q, maxBodySize=%d", s, maxBodySize)
}
- if err != ErrBodyTooLarge {
- t.Fatalf("unexpected error: %s. Expecting %s. s=%q, maxBodySize=%d", err, ErrBodyTooLarge, s, maxBodySize)
+ if err != expectedErr {
+ t.Fatalf("unexpected error: %s. Expecting %s. s=%q, maxBodySize=%d", err, expectedErr, s, maxBodySize)
}
}
@@ -1490,52 +1610,49 @@ func TestRequestWriteRequestURINoHost(t *testing.T) {
func TestSetRequestBodyStreamFixedSize(t *testing.T) {
t.Parallel()
- testSetRequestBodyStream(t, "a", false)
- testSetRequestBodyStream(t, string(createFixedBody(4097)), false)
- testSetRequestBodyStream(t, string(createFixedBody(100500)), false)
+ testSetRequestBodyStream(t, "a")
+ testSetRequestBodyStream(t, string(createFixedBody(4097)))
+ testSetRequestBodyStream(t, string(createFixedBody(100500)))
}
func TestSetResponseBodyStreamFixedSize(t *testing.T) {
t.Parallel()
- testSetResponseBodyStream(t, "a", false)
- testSetResponseBodyStream(t, string(createFixedBody(4097)), false)
- testSetResponseBodyStream(t, string(createFixedBody(100500)), false)
+ testSetResponseBodyStream(t, "a")
+ testSetResponseBodyStream(t, string(createFixedBody(4097)))
+ testSetResponseBodyStream(t, string(createFixedBody(100500)))
}
func TestSetRequestBodyStreamChunked(t *testing.T) {
t.Parallel()
- testSetRequestBodyStream(t, "", true)
+ testSetRequestBodyStreamChunked(t, "", map[string]string{"Foo": "bar"})
body := "foobar baz aaa bbb ccc"
- testSetRequestBodyStream(t, body, true)
+ testSetRequestBodyStreamChunked(t, body, nil)
body = string(createFixedBody(10001))
- testSetRequestBodyStream(t, body, true)
+ testSetRequestBodyStreamChunked(t, body, map[string]string{"Foo": "test", "Bar": "test"})
}
func TestSetResponseBodyStreamChunked(t *testing.T) {
t.Parallel()
- testSetResponseBodyStream(t, "", true)
+ testSetResponseBodyStreamChunked(t, "", map[string]string{"Foo": "bar"})
body := "foobar baz aaa bbb ccc"
- testSetResponseBodyStream(t, body, true)
+ testSetResponseBodyStreamChunked(t, body, nil)
body = string(createFixedBody(10001))
- testSetResponseBodyStream(t, body, true)
+ testSetResponseBodyStreamChunked(t, body, map[string]string{"Foo": "test", "Bar": "test"})
}
-func testSetRequestBodyStream(t *testing.T, body string, chunked bool) {
+func testSetRequestBodyStream(t *testing.T, body string) {
var req Request
req.Header.SetHost("foobar.com")
req.Header.SetMethod(MethodPost)
bodySize := len(body)
- if chunked {
- bodySize = -1
- }
if req.IsBodyStream() {
t.Fatalf("IsBodyStream must return false")
}
@@ -1563,12 +1680,56 @@ func testSetRequestBodyStream(t *testing.T, body string, chunked bool) {
}
}
-func testSetResponseBodyStream(t *testing.T, body string, chunked bool) {
+func testSetRequestBodyStreamChunked(t *testing.T, body string, trailer map[string]string) {
+ var req Request
+ req.Header.SetHost("foobar.com")
+ req.Header.SetMethod(MethodPost)
+
+ if req.IsBodyStream() {
+ t.Fatalf("IsBodyStream must return false")
+ }
+ req.SetBodyStream(bytes.NewBufferString(body), -1)
+ if !req.IsBodyStream() {
+ t.Fatalf("IsBodyStream must return true")
+ }
+
+ var w bytes.Buffer
+ bw := bufio.NewWriter(&w)
+ for k := range trailer {
+ err := req.Header.AddTrailer(k)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ }
+ if err := req.Write(bw); err != nil {
+ t.Fatalf("unexpected error when writing request: %s. body=%q", err, body)
+ }
+ for k, v := range trailer {
+ req.Header.Set(k, v)
+ }
+ if err := bw.Flush(); err != nil {
+ t.Fatalf("unexpected error when flushing request: %s. body=%q", err, body)
+ }
+
+ var req1 Request
+ br := bufio.NewReader(&w)
+ if err := req1.Read(br); err != nil {
+ t.Fatalf("unexpected error when reading request: %s. body=%q", err, body)
+ }
+ if string(req1.Body()) != body {
+ t.Fatalf("unexpected body %q. Expecting %q", req1.Body(), body)
+ }
+ for k, v := range trailer {
+ r := req.Header.Peek(k)
+ if string(r) != v {
+ t.Fatalf("unexpected trailer %s. Expecting %s. Got %q", k, v, r)
+ }
+ }
+}
+
+func testSetResponseBodyStream(t *testing.T, body string) {
var resp Response
bodySize := len(body)
- if chunked {
- bodySize = -1
- }
if resp.IsBodyStream() {
t.Fatalf("IsBodyStream must return false")
}
@@ -1596,6 +1757,50 @@ func testSetResponseBodyStream(t *testing.T, body string, chunked bool) {
}
}
+func testSetResponseBodyStreamChunked(t *testing.T, body string, trailer map[string]string) {
+ var resp Response
+ if resp.IsBodyStream() {
+ t.Fatalf("IsBodyStream must return false")
+ }
+ resp.SetBodyStream(bytes.NewBufferString(body), -1)
+ if !resp.IsBodyStream() {
+ t.Fatalf("IsBodyStream must return true")
+ }
+
+ var w bytes.Buffer
+ bw := bufio.NewWriter(&w)
+ for k := range trailer {
+ err := resp.Header.AddTrailer(k)
+ if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+ }
+ if err := resp.Write(bw); err != nil {
+ t.Fatalf("unexpected error when writing response: %s. body=%q", err, body)
+ }
+ if err := bw.Flush(); err != nil {
+ t.Fatalf("unexpected error when flushing response: %s. body=%q", err, body)
+ }
+ for k, v := range trailer {
+ resp.Header.Set(k, v)
+ }
+
+ var resp1 Response
+ br := bufio.NewReader(&w)
+ if err := resp1.Read(br); err != nil {
+ t.Fatalf("unexpected error when reading response: %s. body=%q", err, body)
+ }
+ if string(resp1.Body()) != body {
+ t.Fatalf("unexpected body %q. Expecting %q", resp1.Body(), body)
+ }
+ for k, v := range trailer {
+ r := resp.Header.Peek(k)
+ if string(r) != v {
+ t.Fatalf("unexpected trailer %s. Expecting %s. Got %q", k, v, r)
+ }
+ }
+}
+
func TestRound2(t *testing.T) {
t.Parallel()
@@ -1622,7 +1827,7 @@ func TestRequestReadChunked(t *testing.T) {
var req Request
- s := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n3\r\nabc\r\n5\r\n12345\r\n0\r\n\r\ntrail"
+ s := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n3\r\nabc\r\n5\r\n12345\r\n0\r\n\r\nTrail: test\r\n\r\n"
r := bytes.NewBufferString(s)
rb := bufio.NewReader(r)
err := req.Read(rb)
@@ -1633,8 +1838,8 @@ func TestRequestReadChunked(t *testing.T) {
if string(req.Body()) != expectedBody {
t.Fatalf("Unexpected body %q. Expected %q", req.Body(), expectedBody)
}
- verifyRequestHeader(t, &req.Header, 8, "/foo", "google.com", "", "aa/bb")
- verifyTrailer(t, rb, "trail")
+ verifyRequestHeader(t, &req.Header, -1, "/foo", "google.com", "", "aa/bb")
+ verifyTrailer(t, rb, map[string]string{"Trail": "test"}, true)
}
// See: https://github.com/erikdubbelboer/fasthttp/issues/34
@@ -1661,25 +1866,25 @@ func TestResponseReadWithoutBody(t *testing.T) {
var resp Response
- testResponseReadWithoutBody(t, &resp, "HTTP/1.1 304 Not Modified\r\nContent-Type: aa\r\nContent-Length: 1235\r\n\r\nfoobar", false,
- 304, 1235, "aa", "foobar")
+ testResponseReadWithoutBody(t, &resp, "HTTP/1.1 304 Not Modified\r\nContent-Type: aa\r\nContent-Length: 1235\r\n\r\n", false,
+ 304, 1235, "aa", nil)
- testResponseReadWithoutBody(t, &resp, "HTTP/1.1 204 Foo Bar\r\nContent-Type: aab\r\nTransfer-Encoding: chunked\r\n\r\n123\r\nss", false,
- 204, -1, "aab", "123\r\nss")
+ 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,
+ 204, -1, "aab", map[string]string{"Foo": "bar"})
- testResponseReadWithoutBody(t, &resp, "HTTP/1.1 123 AAA\r\nContent-Type: xxx\r\nContent-Length: 3434\r\n\r\naaaa", false,
- 123, 3434, "xxx", "aaaa")
+ testResponseReadWithoutBody(t, &resp, "HTTP/1.1 123 AAA\r\nContent-Type: xxx\r\nContent-Length: 3434\r\n\r\n", false,
+ 123, 3434, "xxx", nil)
- testResponseReadWithoutBody(t, &resp, "HTTP 200 OK\r\nContent-Type: text/xml\r\nContent-Length: 123\r\n\r\nxxxx", true,
- 200, 123, "text/xml", "xxxx")
+ testResponseReadWithoutBody(t, &resp, "HTTP 200 OK\r\nContent-Type: text/xml\r\nContent-Length: 123\r\n\r\nfoobar\r\n", true,
+ 200, 123, "text/xml", nil)
// '100 Continue' must be skipped.
- 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\nfoobar", true,
- 329, 894, "qwe", "foobar")
+ 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,
+ 329, 894, "qwe", nil)
}
func testResponseReadWithoutBody(t *testing.T, resp *Response, s string, skipBody bool,
- expectedStatusCode, expectedContentLength int, expectedContentType, expectedTrailer string) {
+ expectedStatusCode, expectedContentLength int, expectedContentType string, expectedTrailer map[string]string) {
r := bytes.NewBufferString(s)
rb := bufio.NewReader(r)
resp.SkipBody = skipBody
@@ -1691,12 +1896,12 @@ func testResponseReadWithoutBody(t *testing.T, resp *Response, s string, skipBod
t.Fatalf("Unexpected response body %q. Expected %q. response=%q", resp.Body(), "", s)
}
verifyResponseHeader(t, &resp.Header, expectedStatusCode, expectedContentLength, expectedContentType)
- verifyTrailer(t, rb, expectedTrailer)
+ verifyResponseTrailer(t, &resp.Header, expectedTrailer)
// verify that ordinal response is read after null-body response
resp.SkipBody = false
testResponseReadSuccess(t, resp, "HTTP/1.1 300 OK\r\nContent-Length: 5\r\nContent-Type: bar\r\n\r\n56789aaa",
- 300, 5, "bar", "56789", "aaa")
+ 300, 5, "bar", "56789", nil)
}
func TestRequestSuccess(t *testing.T) {
@@ -1872,40 +2077,54 @@ func TestResponseReadSuccess(t *testing.T) {
// usual response
testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Length: 10\r\nContent-Type: foo/bar\r\n\r\n0123456789",
- 200, 10, "foo/bar", "0123456789", "")
+ 200, 10, "foo/bar", "0123456789", nil)
// zero response
testResponseReadSuccess(t, resp, "HTTP/1.1 500 OK\r\nContent-Length: 0\r\nContent-Type: foo/bar\r\n\r\n",
- 500, 0, "foo/bar", "", "")
+ 500, 0, "foo/bar", "", nil)
// response with trailer
- testResponseReadSuccess(t, resp, "HTTP/1.1 300 OK\r\nContent-Length: 5\r\nContent-Type: bar\r\n\r\n56789aaa",
- 300, 5, "bar", "56789", "aaa")
+ testResponseReadSuccess(t, resp, "HTTP/1.1 300 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: bar\r\n\r\n5\r\n56789\r\n0\r\nfoo: bar\r\n\r\n",
+ 300, -1, "bar", "56789", map[string]string{"Foo": "bar"})
- // no conent-length ('identity' transfer-encoding)
- testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: foobar\r\n\r\nzxxc",
- 200, 4, "foobar", "zxxc", "")
+ // response with trailer disableNormalizing
+ resp.Header.DisableNormalizing()
+ testResponseReadSuccess(t, resp, "HTTP/1.1 300 OK\r\nTransfer-Encoding: chunked\r\nContent-Type: bar\r\n\r\n5\r\n56789\r\n0\r\nfoo: bar\r\n\r\n",
+ 300, -1, "bar", "56789", map[string]string{"foo": "bar"})
+
+ // no content-length ('identity' transfer-encoding)
+ testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: foobar\r\n\r\nzxxxx",
+ 200, 5, "foobar", "zxxxx", nil)
// explicitly stated 'Transfer-Encoding: identity'
testResponseReadSuccess(t, resp, "HTTP/1.1 234 ss\r\nContent-Type: xxx\r\n\r\nxag",
- 234, 3, "xxx", "xag", "")
+ 234, 3, "xxx", "xag", nil)
// big 'identity' response
body := string(createFixedBody(100500))
testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: aa\r\n\r\n"+body,
- 200, 100500, "aa", body, "")
+ 200, 100500, "aa", body, nil)
// chunked response
- testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nqwer\r\n2\r\nty\r\n0\r\n\r\nzzzzz",
- 200, 6, "text/html", "qwerty", "zzzzz")
+ testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\n\r\n4\r\nqwer\r\n2\r\nty\r\n0\r\nFoo2: bar2\r\n\r\n",
+ 200, -1, "text/html", "qwerty", map[string]string{"Foo2": "bar2"})
// chunked response with non-chunked Transfer-Encoding.
- testResponseReadSuccess(t, resp, "HTTP/1.1 230 OK\r\nContent-Type: text\r\nTransfer-Encoding: aaabbb\r\n\r\n2\r\ner\r\n2\r\nty\r\n0\r\n\r\nwe",
- 230, 4, "text", "erty", "we")
+ testResponseReadSuccess(t, resp, "HTTP/1.1 230 OK\r\nContent-Type: text\r\nTransfer-Encoding: aaabbb\r\n\r\n2\r\ner\r\n2\r\nty\r\n0\r\nFoo3: bar3\r\n\r\n",
+ 230, -1, "text", "erty", map[string]string{"Foo3": "bar3"})
+
+ // chunked response with content-length
+ testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: foo/bar\r\nContent-Length: 123\r\nTransfer-Encoding: chunked\r\n\r\n4\r\ntest\r\n0\r\nFoo4:bar4\r\n\r\n",
+ 200, -1, "foo/bar", "test", map[string]string{"Foo4": "bar4"})
+
+ // chunked response with empty body
+ testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\n\r\n0\r\nFoo5: bar5\r\n\r\n",
+ 200, -1, "text/html", "", map[string]string{"Foo5": "bar5"})
+
+ // chunked response with chunk extension
+ testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\n\r\n3;ext\r\naaa\r\n0\r\nFoo6: bar6\r\n\r\n",
+ 200, -1, "text/html", "aaa", map[string]string{"Foo6": "bar6"})
- // zero chunked response
- testResponseReadSuccess(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nzzz",
- 200, 0, "text/html", "", "zzz")
}
func TestResponseReadError(t *testing.T) {
@@ -1922,8 +2141,13 @@ func TestResponseReadError(t *testing.T) {
// empty body
testResponseReadError(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nContent-Length: 1234\r\n\r\n")
- // short body
+ // invalid chunked body
testResponseReadError(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nContent-Length: 1234\r\n\r\nshort")
+
+ // chunked body without end chunk
+ testResponseReadError(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nTransfer-Encoding: chunked\r\n\r\nfoo")
+
+ testResponseReadError(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nTransfer-Encoding: chunked\r\n\r\n3\r\nfoo")
}
func testResponseReadError(t *testing.T, resp *Response, response string) {
@@ -1934,12 +2158,12 @@ func testResponseReadError(t *testing.T, resp *Response, response string) {
t.Fatalf("Expecting error for response=%q", response)
}
- testResponseReadSuccess(t, resp, "HTTP/1.1 303 Redisred sedfs sdf\r\nContent-Type: aaa\r\nContent-Length: 5\r\n\r\nHELLOaaa",
- 303, 5, "aaa", "HELLO", "aaa")
+ testResponseReadSuccess(t, resp, "HTTP/1.1 303 Redisred sedfs sdf\r\nContent-Type: aaa\r\nContent-Length: 5\r\n\r\nHELLO",
+ 303, 5, "aaa", "HELLO", nil)
}
func testResponseReadSuccess(t *testing.T, resp *Response, response string, expectedStatusCode, expectedContentLength int,
- expectedContenType, expectedBody, expectedTrailer string) {
+ expectedContentType, expectedBody string, expectedTrailer map[string]string) {
r := bytes.NewBufferString(response)
rb := bufio.NewReader(r)
@@ -1948,11 +2172,11 @@ func testResponseReadSuccess(t *testing.T, resp *Response, response string, expe
t.Fatalf("Unexpected error: %s", err)
}
- verifyResponseHeader(t, &resp.Header, expectedStatusCode, expectedContentLength, expectedContenType)
+ verifyResponseHeader(t, &resp.Header, expectedStatusCode, expectedContentLength, expectedContentType)
if !bytes.Equal(resp.Body(), []byte(expectedBody)) {
t.Fatalf("Unexpected body %q. Expected %q", resp.Body(), []byte(expectedBody))
}
- verifyTrailer(t, rb, expectedTrailer)
+ verifyResponseTrailer(t, &resp.Header, expectedTrailer)
}
func TestReadBodyFixedSize(t *testing.T) {
@@ -2109,28 +2333,24 @@ func testRequestPostArgsSuccess(t *testing.T, req *Request, s string, expectedAr
func testReadBodyChunked(t *testing.T, bodySize int) {
body := createFixedBody(bodySize)
- chunkedBody := createChunkedBody(body)
- expectedTrailer := []byte("chunked shit")
- chunkedBody = append(chunkedBody, expectedTrailer...)
+ expectedTrailer := map[string]string{"Foo": "bar"}
+ chunkedBody := createChunkedBody(body, expectedTrailer, true)
r := bytes.NewBuffer(chunkedBody)
br := bufio.NewReader(r)
- b, err := readBody(br, -1, 0, nil)
+ b, err := readBodyChunked(br, 0, nil)
if err != nil {
t.Fatalf("Unexpected error for bodySize=%d: %s. body=%q, chunkedBody=%q", bodySize, err, body, chunkedBody)
}
if !bytes.Equal(b, body) {
t.Fatalf("Unexpected response read for bodySize=%d: %q. Expected %q. chunkedBody=%q", bodySize, b, body, chunkedBody)
}
- verifyTrailer(t, br, string(expectedTrailer))
+ verifyTrailer(t, br, expectedTrailer, false)
}
func testReadBodyFixedSize(t *testing.T, bodySize int) {
body := createFixedBody(bodySize)
- expectedTrailer := []byte("traler aaaa")
- bodyWithTrailer := append(body, expectedTrailer...)
-
- r := bytes.NewBuffer(bodyWithTrailer)
+ r := bytes.NewBuffer(body)
br := bufio.NewReader(r)
b, err := readBody(br, bodySize, 0, nil)
if err != nil {
@@ -2139,7 +2359,7 @@ func testReadBodyFixedSize(t *testing.T, bodySize int) {
if !bytes.Equal(b, body) {
t.Fatalf("Unexpected response read for bodySize=%d: %q. Expected %q", bodySize, b, body)
}
- verifyTrailer(t, br, string(expectedTrailer))
+ verifyTrailer(t, br, nil, false)
}
func createFixedBody(bodySize int) []byte {
@@ -2150,7 +2370,7 @@ func createFixedBody(bodySize int) []byte {
return b
}
-func createChunkedBody(body []byte) []byte {
+func createChunkedBody(body []byte, trailer map[string]string, withEnd bool) []byte {
var b []byte
chunkSize := 1
for len(body) > 0 {
@@ -2163,7 +2383,17 @@ func createChunkedBody(body []byte) []byte {
body = body[chunkSize:]
chunkSize++
}
- return append(b, []byte("0\r\n\r\n")...)
+ if withEnd {
+ b = append(b, "0\r\n"...)
+ for k, v := range trailer {
+ b = append(b, k...)
+ b = append(b, ": "...)
+ b = append(b, v...)
+ b = append(b, "\r\n"...)
+ }
+ b = append(b, "\r\n"...)
+ }
+ return b
}
func TestWriteMultipartForm(t *testing.T) {