mirror of
https://github.com/valyala/fasthttp.git
synced 2026-06-25 17:45:28 +03:00
103adc311e
Compressing small bodies has little sense, since the compressed result size may exceed the original body size. This should save CPU time when the server responds with small responses.
1693 lines
48 KiB
Go
1693 lines
48 KiB
Go
package fasthttp
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"mime/multipart"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestResponseWriteGzipNilBody(t *testing.T) {
|
|
var r Response
|
|
w := &bytes.Buffer{}
|
|
bw := bufio.NewWriter(w)
|
|
if err := r.WriteGzip(bw); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if err := bw.Flush(); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestResponseWriteDeflateNilBody(t *testing.T) {
|
|
var r Response
|
|
w := &bytes.Buffer{}
|
|
bw := bufio.NewWriter(w)
|
|
if err := r.WriteDeflate(bw); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if err := bw.Flush(); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
}
|
|
|
|
func TestResponseSwapBodySerial(t *testing.T) {
|
|
testResponseSwapBody(t)
|
|
}
|
|
|
|
func TestResponseSwapBodyConcurrent(t *testing.T) {
|
|
ch := make(chan struct{})
|
|
for i := 0; i < 10; i++ {
|
|
go func() {
|
|
testResponseSwapBody(t)
|
|
ch <- struct{}{}
|
|
}()
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
select {
|
|
case <-ch:
|
|
case <-time.After(time.Second):
|
|
t.Fatalf("timeout")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testResponseSwapBody(t *testing.T) {
|
|
var b []byte
|
|
r := AcquireResponse()
|
|
for i := 0; i < 20; i++ {
|
|
bOrig := r.Body()
|
|
b = r.SwapBody(b)
|
|
if !bytes.Equal(bOrig, b) {
|
|
t.Fatalf("unexpected body returned: %q. Expecting %q", b, bOrig)
|
|
}
|
|
r.AppendBodyString("foobar")
|
|
}
|
|
|
|
s := "aaaabbbbcccc"
|
|
b = b[:0]
|
|
for i := 0; i < 10; i++ {
|
|
r.SetBodyStream(bytes.NewBufferString(s), len(s))
|
|
b = r.SwapBody(b)
|
|
if string(b) != s {
|
|
t.Fatalf("unexpected body returned: %q. Expecting %q", b, s)
|
|
}
|
|
b = r.SwapBody(b)
|
|
if len(b) > 0 {
|
|
t.Fatalf("unexpected body with non-zero size returned: %q", b)
|
|
}
|
|
}
|
|
ReleaseResponse(r)
|
|
}
|
|
|
|
func TestRequestSwapBodySerial(t *testing.T) {
|
|
testRequestSwapBody(t)
|
|
}
|
|
|
|
func TestRequestSwapBodyConcurrent(t *testing.T) {
|
|
ch := make(chan struct{})
|
|
for i := 0; i < 10; i++ {
|
|
go func() {
|
|
testRequestSwapBody(t)
|
|
ch <- struct{}{}
|
|
}()
|
|
}
|
|
|
|
for i := 0; i < 10; i++ {
|
|
select {
|
|
case <-ch:
|
|
case <-time.After(time.Second):
|
|
t.Fatalf("timeout")
|
|
}
|
|
}
|
|
}
|
|
|
|
func testRequestSwapBody(t *testing.T) {
|
|
var b []byte
|
|
r := AcquireRequest()
|
|
for i := 0; i < 20; i++ {
|
|
bOrig := r.Body()
|
|
b = r.SwapBody(b)
|
|
if !bytes.Equal(bOrig, b) {
|
|
t.Fatalf("unexpected body returned: %q. Expecting %q", b, bOrig)
|
|
}
|
|
r.AppendBodyString("foobar")
|
|
}
|
|
|
|
s := "aaaabbbbcccc"
|
|
b = b[:0]
|
|
for i := 0; i < 10; i++ {
|
|
r.SetBodyStream(bytes.NewBufferString(s), len(s))
|
|
b = r.SwapBody(b)
|
|
if string(b) != s {
|
|
t.Fatalf("unexpected body returned: %q. Expecting %q", b, s)
|
|
}
|
|
b = r.SwapBody(b)
|
|
if len(b) > 0 {
|
|
t.Fatalf("unexpected body with non-zero size returned: %q", b)
|
|
}
|
|
}
|
|
ReleaseRequest(r)
|
|
}
|
|
|
|
func TestRequestHostFromRequestURI(t *testing.T) {
|
|
hExpected := "foobar.com"
|
|
var req Request
|
|
req.SetRequestURI("http://proxy-host:123/foobar?baz")
|
|
req.SetHost(hExpected)
|
|
h := req.Host()
|
|
if string(h) != hExpected {
|
|
t.Fatalf("unexpected host set: %q. Expecting %q", h, hExpected)
|
|
}
|
|
}
|
|
|
|
func TestRequestHostFromHeader(t *testing.T) {
|
|
hExpected := "foobar.com"
|
|
var req Request
|
|
req.Header.SetHost(hExpected)
|
|
h := req.Host()
|
|
if string(h) != hExpected {
|
|
t.Fatalf("unexpected host set: %q. Expecting %q", h, hExpected)
|
|
}
|
|
}
|
|
|
|
func TestRequestContentTypeWithCharsetIssue100(t *testing.T) {
|
|
expectedContentType := "application/x-www-form-urlencoded; charset=UTF-8"
|
|
expectedBody := "0123=56789"
|
|
s := fmt.Sprintf("POST / HTTP/1.1\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
|
|
expectedContentType, len(expectedBody), expectedBody)
|
|
|
|
br := bufio.NewReader(bytes.NewBufferString(s))
|
|
var r Request
|
|
if err := r.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
body := r.Body()
|
|
if string(body) != expectedBody {
|
|
t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody)
|
|
}
|
|
ct := r.Header.ContentType()
|
|
if string(ct) != expectedContentType {
|
|
t.Fatalf("unexpected content-type %q. Expecting %q", ct, expectedContentType)
|
|
}
|
|
args := r.PostArgs()
|
|
if args.Len() != 1 {
|
|
t.Fatalf("unexpected number of POST args: %d. Expecting 1", args.Len())
|
|
}
|
|
av := args.Peek("0123")
|
|
if string(av) != "56789" {
|
|
t.Fatalf("unexpected POST arg value: %q. Expecting %q", av, "56789")
|
|
}
|
|
}
|
|
|
|
func TestRequestReadMultipartFormWithFile(t *testing.T) {
|
|
s := `POST /upload HTTP/1.1
|
|
Host: localhost:10000
|
|
Content-Length: 521
|
|
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg
|
|
|
|
------WebKitFormBoundaryJwfATyF8tmxSJnLg
|
|
Content-Disposition: form-data; name="f1"
|
|
|
|
value1
|
|
------WebKitFormBoundaryJwfATyF8tmxSJnLg
|
|
Content-Disposition: form-data; name="fileaaa"; filename="TODO"
|
|
Content-Type: application/octet-stream
|
|
|
|
- SessionClient with referer and cookies support.
|
|
- Client with requests' pipelining support.
|
|
- ProxyHandler similar to FSHandler.
|
|
- WebSockets. See https://tools.ietf.org/html/rfc6455 .
|
|
- HTTP/2.0. See https://tools.ietf.org/html/rfc7540 .
|
|
|
|
------WebKitFormBoundaryJwfATyF8tmxSJnLg--
|
|
tailfoobar`
|
|
|
|
br := bufio.NewReader(bytes.NewBufferString(s))
|
|
|
|
var r Request
|
|
if err := r.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
tail, err := ioutil.ReadAll(br)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if string(tail) != "tailfoobar" {
|
|
t.Fatalf("unexpected tail %q. Expecting %q", tail, "tailfoobar")
|
|
}
|
|
|
|
f, err := r.MultipartForm()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
defer r.RemoveMultipartFormFiles()
|
|
|
|
// verify values
|
|
if len(f.Value) != 1 {
|
|
t.Fatalf("unexpected number of values in multipart form: %d. Expecting 1", len(f.Value))
|
|
}
|
|
for k, vv := range f.Value {
|
|
if k != "f1" {
|
|
t.Fatalf("unexpected value name %q. Expecting %q", k, "f1")
|
|
}
|
|
if len(vv) != 1 {
|
|
t.Fatalf("unexpected number of values %d. Expecting 1", len(vv))
|
|
}
|
|
v := vv[0]
|
|
if v != "value1" {
|
|
t.Fatalf("unexpected value %q. Expecting %q", v, "value1")
|
|
}
|
|
}
|
|
|
|
// verify files
|
|
if len(f.File) != 1 {
|
|
t.Fatalf("unexpected number of file values in multipart form: %d. Expecting 1", len(f.File))
|
|
}
|
|
for k, vv := range f.File {
|
|
if k != "fileaaa" {
|
|
t.Fatalf("unexpected file value name %q. Expecting %q", k, "fileaaa")
|
|
}
|
|
if len(vv) != 1 {
|
|
t.Fatalf("unexpected number of file values %d. Expecting 1", len(vv))
|
|
}
|
|
v := vv[0]
|
|
if v.Filename != "TODO" {
|
|
t.Fatalf("unexpected filename %q. Expecting %q", v.Filename, "TODO")
|
|
}
|
|
ct := v.Header.Get("Content-Type")
|
|
if ct != "application/octet-stream" {
|
|
t.Fatalf("unexpected content-type %q. Expecting %q", ct, "application/octet-stream")
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRequestRequestURI(t *testing.T) {
|
|
var r Request
|
|
|
|
// Set request uri via SetRequestURI()
|
|
uri := "/foo/bar?baz"
|
|
r.SetRequestURI(uri)
|
|
if string(r.RequestURI()) != uri {
|
|
t.Fatalf("unexpected request uri %q. Expecting %q", r.RequestURI(), uri)
|
|
}
|
|
|
|
// Set request uri via Request.URI().Update()
|
|
r.Reset()
|
|
uri = "/aa/bbb?ccc=sdfsdf"
|
|
r.URI().Update(uri)
|
|
if string(r.RequestURI()) != uri {
|
|
t.Fatalf("unexpected request uri %q. Expecting %q", r.RequestURI(), uri)
|
|
}
|
|
|
|
// update query args in the request uri
|
|
qa := r.URI().QueryArgs()
|
|
qa.Reset()
|
|
qa.Set("foo", "bar")
|
|
uri = "/aa/bbb?foo=bar"
|
|
if string(r.RequestURI()) != uri {
|
|
t.Fatalf("unexpected request uri %q. Expecting %q", r.RequestURI(), uri)
|
|
}
|
|
}
|
|
|
|
func TestRequestUpdateURI(t *testing.T) {
|
|
var r Request
|
|
r.Header.SetHost("aaa.bbb")
|
|
r.SetRequestURI("/lkjkl/kjl")
|
|
|
|
// Modify request uri and host via URI() object and make sure
|
|
// the requestURI and Host header are properly updated
|
|
u := r.URI()
|
|
u.SetPath("/123/432.html")
|
|
u.SetHost("foobar.com")
|
|
a := u.QueryArgs()
|
|
a.Set("aaa", "bcse")
|
|
|
|
s := r.String()
|
|
if !strings.HasPrefix(s, "GET /123/432.html?aaa=bcse") {
|
|
t.Fatalf("cannot find %q in %q", "GET /123/432.html?aaa=bcse", s)
|
|
}
|
|
if strings.Index(s, "\r\nHost: foobar.com\r\n") < 0 {
|
|
t.Fatalf("cannot find %q in %q", "\r\nHost: foobar.com\r\n", s)
|
|
}
|
|
}
|
|
|
|
func TestRequestBodyStreamMultipleBodyCalls(t *testing.T) {
|
|
var r Request
|
|
|
|
s := "foobar baz abc"
|
|
if r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return false")
|
|
}
|
|
r.SetBodyStream(bytes.NewBufferString(s), len(s))
|
|
if !r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return true")
|
|
}
|
|
for i := 0; i < 10; i++ {
|
|
body := r.Body()
|
|
if string(body) != s {
|
|
t.Fatalf("unexpected body %q. Expecting %q. iteration %d", body, s, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestResponseBodyStreamMultipleBodyCalls(t *testing.T) {
|
|
var r Response
|
|
|
|
s := "foobar baz abc"
|
|
if r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return false")
|
|
}
|
|
r.SetBodyStream(bytes.NewBufferString(s), len(s))
|
|
if !r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return true")
|
|
}
|
|
for i := 0; i < 10; i++ {
|
|
body := r.Body()
|
|
if string(body) != s {
|
|
t.Fatalf("unexpected body %q. Expecting %q. iteration %d", body, s, i)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRequestBodyWriteToPlain(t *testing.T) {
|
|
var r Request
|
|
|
|
expectedS := "foobarbaz"
|
|
r.AppendBodyString(expectedS)
|
|
|
|
testBodyWriteTo(t, &r, expectedS, true)
|
|
}
|
|
|
|
func TestResponseBodyWriteToPlain(t *testing.T) {
|
|
var r Response
|
|
|
|
expectedS := "foobarbaz"
|
|
r.AppendBodyString(expectedS)
|
|
|
|
testBodyWriteTo(t, &r, expectedS, true)
|
|
}
|
|
|
|
func TestResponseBodyWriteToStream(t *testing.T) {
|
|
var r Response
|
|
|
|
expectedS := "aaabbbccc"
|
|
buf := bytes.NewBufferString(expectedS)
|
|
if r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return false")
|
|
}
|
|
r.SetBodyStream(buf, len(expectedS))
|
|
if !r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return true")
|
|
}
|
|
|
|
testBodyWriteTo(t, &r, expectedS, false)
|
|
}
|
|
|
|
func TestRequestBodyWriteToMultipart(t *testing.T) {
|
|
expectedS := "--foobar\r\nContent-Disposition: form-data; name=\"key_0\"\r\n\r\nvalue_0\r\n--foobar--\r\n"
|
|
s := fmt.Sprintf("POST / HTTP/1.1\r\nHost: aaa\r\nContent-Type: multipart/form-data; boundary=foobar\r\nContent-Length: %d\r\n\r\n%s",
|
|
len(expectedS), expectedS)
|
|
|
|
var r Request
|
|
br := bufio.NewReader(bytes.NewBufferString(s))
|
|
if err := r.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
testBodyWriteTo(t, &r, expectedS, true)
|
|
}
|
|
|
|
type bodyWriterTo interface {
|
|
BodyWriteTo(io.Writer) error
|
|
Body() []byte
|
|
}
|
|
|
|
func testBodyWriteTo(t *testing.T, bw bodyWriterTo, expectedS string, isRetainedBody bool) {
|
|
var buf ByteBuffer
|
|
if err := bw.BodyWriteTo(&buf); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
s := buf.B
|
|
if string(s) != expectedS {
|
|
t.Fatalf("unexpected result %q. Expecting %q", s, expectedS)
|
|
}
|
|
|
|
body := bw.Body()
|
|
if isRetainedBody {
|
|
if string(body) != expectedS {
|
|
t.Fatalf("unexpected body %q. Expecting %q", body, expectedS)
|
|
}
|
|
} else {
|
|
if len(body) > 0 {
|
|
t.Fatalf("unexpected non-zero body after BodyWriteTo: %q", body)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestRequestReadEOF(t *testing.T) {
|
|
var r Request
|
|
|
|
br := bufio.NewReader(&bytes.Buffer{})
|
|
err := r.Read(br)
|
|
if err == nil {
|
|
t.Fatalf("expecting error")
|
|
}
|
|
if err != io.EOF {
|
|
t.Fatalf("unexpected error: %s. Expecting %s", err, io.EOF)
|
|
}
|
|
|
|
// incomplete request mustn't return io.EOF
|
|
br = bufio.NewReader(bytes.NewBufferString("POST / HTTP/1.1\r\nContent-Type: aa\r\nContent-Length: 1234\r\n\r\nIncomplete body"))
|
|
err = r.Read(br)
|
|
if err == nil {
|
|
t.Fatalf("expecting error")
|
|
}
|
|
if err == io.EOF {
|
|
t.Fatalf("expecting non-EOF error")
|
|
}
|
|
}
|
|
|
|
func TestResponseReadEOF(t *testing.T) {
|
|
var r Response
|
|
|
|
br := bufio.NewReader(&bytes.Buffer{})
|
|
err := r.Read(br)
|
|
if err == nil {
|
|
t.Fatalf("expecting error")
|
|
}
|
|
if err != io.EOF {
|
|
t.Fatalf("unexpected error: %s. Expecting %s", err, io.EOF)
|
|
}
|
|
|
|
// incomplete response mustn't return io.EOF
|
|
br = bufio.NewReader(bytes.NewBufferString("HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nContent-Length: 123\r\n\r\nIncomplete body"))
|
|
err = r.Read(br)
|
|
if err == nil {
|
|
t.Fatalf("expecting error")
|
|
}
|
|
if err == io.EOF {
|
|
t.Fatalf("expecting non-EOF error")
|
|
}
|
|
}
|
|
|
|
func TestResponseWriteTo(t *testing.T) {
|
|
var r Response
|
|
|
|
r.SetBodyString("foobar")
|
|
|
|
s := r.String()
|
|
var buf ByteBuffer
|
|
n, err := r.WriteTo(&buf)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if n != int64(len(s)) {
|
|
t.Fatalf("unexpected response length %d. Expecting %d", n, len(s))
|
|
}
|
|
if string(buf.B) != s {
|
|
t.Fatalf("unexpected response %q. Expecting %q", buf.B, s)
|
|
}
|
|
}
|
|
|
|
func TestRequestWriteTo(t *testing.T) {
|
|
var r Request
|
|
|
|
r.SetRequestURI("http://foobar.com/aaa/bbb")
|
|
|
|
s := r.String()
|
|
var buf ByteBuffer
|
|
n, err := r.WriteTo(&buf)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if n != int64(len(s)) {
|
|
t.Fatalf("unexpected request length %d. Expecting %d", n, len(s))
|
|
}
|
|
if string(buf.B) != s {
|
|
t.Fatalf("unexpected request %q. Expecting %q", buf.B, s)
|
|
}
|
|
}
|
|
|
|
func TestResponseSkipBody(t *testing.T) {
|
|
var r Response
|
|
|
|
// set StatusNotModified
|
|
r.Header.SetStatusCode(StatusNotModified)
|
|
r.SetBodyString("foobar")
|
|
s := r.String()
|
|
if strings.Contains(s, "\r\n\r\nfoobar") {
|
|
t.Fatalf("unexpected non-zero body in response %q", s)
|
|
}
|
|
if strings.Contains(s, "Content-Length: ") {
|
|
t.Fatalf("unexpected content-length in response %q", s)
|
|
}
|
|
if strings.Contains(s, "Content-Type: ") {
|
|
t.Fatalf("unexpected content-type in response %q", s)
|
|
}
|
|
|
|
// set StatusNoContent
|
|
r.Header.SetStatusCode(StatusNoContent)
|
|
r.SetBodyString("foobar")
|
|
s = r.String()
|
|
if strings.Contains(s, "\r\n\r\nfoobar") {
|
|
t.Fatalf("unexpected non-zero body in response %q", s)
|
|
}
|
|
if strings.Contains(s, "Content-Length: ") {
|
|
t.Fatalf("unexpected content-length in response %q", s)
|
|
}
|
|
if strings.Contains(s, "Content-Type: ") {
|
|
t.Fatalf("unexpected content-type in response %q", s)
|
|
}
|
|
|
|
// explicitly skip body
|
|
r.Header.SetStatusCode(StatusOK)
|
|
r.SkipBody = true
|
|
r.SetBodyString("foobar")
|
|
s = r.String()
|
|
if strings.Contains(s, "\r\n\r\nfoobar") {
|
|
t.Fatalf("unexpected non-zero body in response %q", s)
|
|
}
|
|
if !strings.Contains(s, "Content-Length: 6\r\n") {
|
|
t.Fatalf("expecting content-length in response %q", s)
|
|
}
|
|
if !strings.Contains(s, "Content-Type: ") {
|
|
t.Fatalf("expecting content-type in response %q", s)
|
|
}
|
|
}
|
|
|
|
func TestRequestNoContentLength(t *testing.T) {
|
|
var r Request
|
|
|
|
r.Header.SetMethod("HEAD")
|
|
r.Header.SetHost("foobar")
|
|
|
|
s := r.String()
|
|
if strings.Contains(s, "Content-Length: ") {
|
|
t.Fatalf("unexpected content-length in HEAD request %q", s)
|
|
}
|
|
|
|
r.Header.SetMethod("POST")
|
|
fmt.Fprintf(r.BodyWriter(), "foobar body")
|
|
s = r.String()
|
|
if !strings.Contains(s, "Content-Length: ") {
|
|
t.Fatalf("missing content-length header in non-GET request %q", s)
|
|
}
|
|
}
|
|
|
|
func TestRequestReadGzippedBody(t *testing.T) {
|
|
var r Request
|
|
|
|
bodyOriginal := "foo bar baz compress me better!"
|
|
body := AppendGzipBytes(nil, []byte(bodyOriginal))
|
|
s := fmt.Sprintf("POST /foobar HTTP/1.1\r\nContent-Type: foo/bar\r\nContent-Encoding: gzip\r\nContent-Length: %d\r\n\r\n%s",
|
|
len(body), body)
|
|
br := bufio.NewReader(bytes.NewBufferString(s))
|
|
if err := r.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
if string(r.Header.Peek("Content-Encoding")) != "gzip" {
|
|
t.Fatalf("unexpected content-encoding: %q. Expecting %q", r.Header.Peek("Content-Encoding"), "gzip")
|
|
}
|
|
if r.Header.ContentLength() != len(body) {
|
|
t.Fatalf("unexpected content-length: %d. Expecting %d", r.Header.ContentLength(), len(body))
|
|
}
|
|
if string(r.Body()) != string(body) {
|
|
t.Fatalf("unexpected body: %q. Expecting %q", r.Body(), body)
|
|
}
|
|
|
|
bodyGunzipped, err := AppendGunzipBytes(nil, r.Body())
|
|
if err != nil {
|
|
t.Fatalf("unexpected error when uncompressing data: %s", err)
|
|
}
|
|
if string(bodyGunzipped) != bodyOriginal {
|
|
t.Fatalf("unexpected uncompressed body %q. Expecting %q", bodyGunzipped, bodyOriginal)
|
|
}
|
|
}
|
|
|
|
func TestRequestReadPostNoBody(t *testing.T) {
|
|
var r Request
|
|
|
|
s := "POST /foo/bar HTTP/1.1\r\nContent-Type: aaa/bbb\r\n\r\naaaa"
|
|
br := bufio.NewReader(bytes.NewBufferString(s))
|
|
if err := r.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
if string(r.Header.RequestURI()) != "/foo/bar" {
|
|
t.Fatalf("unexpected request uri %q. Expecting %q", r.Header.RequestURI(), "/foo/bar")
|
|
}
|
|
if string(r.Header.ContentType()) != "aaa/bbb" {
|
|
t.Fatalf("unexpected content-type %q. Expecting %q", r.Header.ContentType(), "aaa/bbb")
|
|
}
|
|
if len(r.Body()) != 0 {
|
|
t.Fatalf("unexpected body found %q. Expecting empty body", r.Body())
|
|
}
|
|
if r.Header.ContentLength() != 0 {
|
|
t.Fatalf("unexpected content-length: %d. Expecting 0", r.Header.ContentLength())
|
|
}
|
|
|
|
tail, err := ioutil.ReadAll(br)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if string(tail) != "aaaa" {
|
|
t.Fatalf("unexpected tail %q. Expecting %q", tail, "aaaa")
|
|
}
|
|
}
|
|
|
|
func TestRequestContinueReadBody(t *testing.T) {
|
|
s := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343"
|
|
br := bufio.NewReader(bytes.NewBufferString(s))
|
|
|
|
var r Request
|
|
if err := r.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if !r.MayContinue() {
|
|
t.Fatalf("MayContinue must return true")
|
|
}
|
|
|
|
if err := r.ContinueReadBody(br, 0); err != nil {
|
|
t.Fatalf("error when reading request body: %s", err)
|
|
}
|
|
body := r.Body()
|
|
if string(body) != "abcde" {
|
|
t.Fatalf("unexpected body %q. Expecting %q", body, "abcde")
|
|
}
|
|
|
|
tail, err := ioutil.ReadAll(br)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if string(tail) != "f4343" {
|
|
t.Fatalf("unexpected tail %q. Expecting %q", tail, "f4343")
|
|
}
|
|
}
|
|
|
|
func TestRequestMayContinue(t *testing.T) {
|
|
var r Request
|
|
if r.MayContinue() {
|
|
t.Fatalf("MayContinue on empty request must return false")
|
|
}
|
|
|
|
r.Header.Set("Expect", "123sdfds")
|
|
if r.MayContinue() {
|
|
t.Fatalf("MayContinue on invalid Expect header must return false")
|
|
}
|
|
|
|
r.Header.Set("Expect", "100-continue")
|
|
if !r.MayContinue() {
|
|
t.Fatalf("MayContinue on 'Expect: 100-continue' header must return true")
|
|
}
|
|
}
|
|
|
|
func TestResponseGzipStream(t *testing.T) {
|
|
var r Response
|
|
if r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return false")
|
|
}
|
|
r.SetBodyStreamWriter(func(w *bufio.Writer) {
|
|
fmt.Fprintf(w, "foo")
|
|
w.Flush()
|
|
time.Sleep(time.Millisecond)
|
|
w.Write([]byte("barbaz"))
|
|
w.Flush()
|
|
time.Sleep(time.Millisecond)
|
|
fmt.Fprintf(w, "1234")
|
|
if err := w.Flush(); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
})
|
|
if !r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return true")
|
|
}
|
|
testResponseGzipExt(t, &r, "foobarbaz1234")
|
|
}
|
|
|
|
func TestResponseDeflateStream(t *testing.T) {
|
|
var r Response
|
|
if r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return false")
|
|
}
|
|
r.SetBodyStreamWriter(func(w *bufio.Writer) {
|
|
w.Write([]byte("foo"))
|
|
w.Flush()
|
|
fmt.Fprintf(w, "barbaz")
|
|
w.Flush()
|
|
w.Write([]byte("1234"))
|
|
if err := w.Flush(); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
})
|
|
if !r.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return true")
|
|
}
|
|
testResponseDeflateExt(t, &r, "foobarbaz1234")
|
|
}
|
|
|
|
func TestResponseDeflate(t *testing.T) {
|
|
for _, s := range compressTestcases {
|
|
testResponseDeflate(t, s)
|
|
}
|
|
}
|
|
|
|
func TestResponseGzip(t *testing.T) {
|
|
for _, s := range compressTestcases {
|
|
testResponseGzip(t, s)
|
|
}
|
|
}
|
|
|
|
func testResponseDeflate(t *testing.T, s string) {
|
|
var r Response
|
|
r.SetBodyString(s)
|
|
testResponseDeflateExt(t, &r, s)
|
|
}
|
|
|
|
func testResponseDeflateExt(t *testing.T, r *Response, s string) {
|
|
isBodyStream := r.IsBodyStream()
|
|
var buf bytes.Buffer
|
|
var err error
|
|
bw := bufio.NewWriter(&buf)
|
|
if err = r.WriteDeflate(bw); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if err = bw.Flush(); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
var r1 Response
|
|
br := bufio.NewReader(&buf)
|
|
if err = r1.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
ce := r1.Header.Peek("Content-Encoding")
|
|
var body []byte
|
|
if len(s) >= minCompressLen || isBodyStream {
|
|
if string(ce) != "deflate" {
|
|
t.Fatalf("unexpected Content-Encoding %q. Expecting %q", ce, "deflate")
|
|
}
|
|
body, err = r1.BodyInflate()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
} else {
|
|
if len(ce) > 0 {
|
|
t.Fatalf("expecting empty Content-Encoding. Got %q", ce)
|
|
}
|
|
body = r1.Body()
|
|
}
|
|
if string(body) != s {
|
|
t.Fatalf("unexpected body %q. Expecting %q", body, s)
|
|
}
|
|
}
|
|
|
|
func testResponseGzip(t *testing.T, s string) {
|
|
var r Response
|
|
r.SetBodyString(s)
|
|
testResponseGzipExt(t, &r, s)
|
|
}
|
|
|
|
func testResponseGzipExt(t *testing.T, r *Response, s string) {
|
|
isBodyStream := r.IsBodyStream()
|
|
var buf bytes.Buffer
|
|
var err error
|
|
bw := bufio.NewWriter(&buf)
|
|
if err = r.WriteGzip(bw); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if err = bw.Flush(); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
var r1 Response
|
|
br := bufio.NewReader(&buf)
|
|
if err = r1.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
ce := r1.Header.Peek("Content-Encoding")
|
|
var body []byte
|
|
if len(s) > minCompressLen || isBodyStream {
|
|
if string(ce) != "gzip" {
|
|
t.Fatalf("unexpected Content-Encoding %q. Expecting %q", ce, "gzip")
|
|
}
|
|
body, err = r1.BodyGunzip()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
} else {
|
|
if len(ce) > 0 {
|
|
t.Fatalf("Expecting empty Content-Encoding. Got %q", ce)
|
|
}
|
|
body = r1.Body()
|
|
}
|
|
if string(body) != s {
|
|
t.Fatalf("unexpected body %q. Expecting %q", body, s)
|
|
}
|
|
}
|
|
|
|
func TestRequestMultipartForm(t *testing.T) {
|
|
var w bytes.Buffer
|
|
mw := multipart.NewWriter(&w)
|
|
for i := 0; i < 10; i++ {
|
|
k := fmt.Sprintf("key_%d", i)
|
|
v := fmt.Sprintf("value_%d", i)
|
|
if err := mw.WriteField(k, v); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
}
|
|
boundary := mw.Boundary()
|
|
if err := mw.Close(); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
formData := w.Bytes()
|
|
for i := 0; i < 5; i++ {
|
|
formData = testRequestMultipartForm(t, boundary, formData, 10)
|
|
}
|
|
|
|
// verify request unmarshalling / marshalling
|
|
s := "POST / HTTP/1.1\r\nHost: aaa\r\nContent-Type: multipart/form-data; boundary=foobar\r\nContent-Length: 213\r\n\r\n--foobar\r\nContent-Disposition: form-data; name=\"key_0\"\r\n\r\nvalue_0\r\n--foobar\r\nContent-Disposition: form-data; name=\"key_1\"\r\n\r\nvalue_1\r\n--foobar\r\nContent-Disposition: form-data; name=\"key_2\"\r\n\r\nvalue_2\r\n--foobar--\r\n"
|
|
|
|
var req Request
|
|
br := bufio.NewReader(bytes.NewBufferString(s))
|
|
if err := req.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
s = req.String()
|
|
br = bufio.NewReader(bytes.NewBufferString(s))
|
|
if err := req.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
testRequestMultipartForm(t, "foobar", req.Body(), 3)
|
|
}
|
|
|
|
func testRequestMultipartForm(t *testing.T, boundary string, formData []byte, partsCount int) []byte {
|
|
s := fmt.Sprintf("POST / HTTP/1.1\r\nHost: aaa\r\nContent-Type: multipart/form-data; boundary=%s\r\nContent-Length: %d\r\n\r\n%s",
|
|
boundary, len(formData), formData)
|
|
|
|
var req Request
|
|
|
|
r := bytes.NewBufferString(s)
|
|
br := bufio.NewReader(r)
|
|
if err := req.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
|
|
f, err := req.MultipartForm()
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
defer req.RemoveMultipartFormFiles()
|
|
|
|
if len(f.File) > 0 {
|
|
t.Fatalf("unexpected files found in the multipart form: %d", len(f.File))
|
|
}
|
|
|
|
if len(f.Value) != partsCount {
|
|
t.Fatalf("unexpected number of values found: %d. Expecting %d", len(f.Value), partsCount)
|
|
}
|
|
|
|
for k, vv := range f.Value {
|
|
if len(vv) != 1 {
|
|
t.Fatalf("unexpected number of values found for key=%q: %d. Expecting 1", k, len(vv))
|
|
}
|
|
if !strings.HasPrefix(k, "key_") {
|
|
t.Fatalf("unexpected key prefix=%q. Expecting %q", k, "key_")
|
|
}
|
|
v := vv[0]
|
|
if !strings.HasPrefix(v, "value_") {
|
|
t.Fatalf("unexpected value prefix=%q. expecting %q", v, "value_")
|
|
}
|
|
if k[len("key_"):] != v[len("value_"):] {
|
|
t.Fatalf("key and value suffixes don't match: %q vs %q", k, v)
|
|
}
|
|
}
|
|
|
|
return req.Body()
|
|
}
|
|
|
|
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)
|
|
|
|
// 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\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)
|
|
|
|
// 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)
|
|
}
|
|
|
|
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)
|
|
|
|
// 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\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)
|
|
}
|
|
|
|
func testResponseReadLimitBodyError(t *testing.T, s string, maxBodySize int) {
|
|
var req Response
|
|
r := bytes.NewBufferString(s)
|
|
br := bufio.NewReader(r)
|
|
err := req.ReadLimitBody(br, maxBodySize)
|
|
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)
|
|
}
|
|
}
|
|
|
|
func testResponseReadLimitBodySuccess(t *testing.T, s string, maxBodySize int) {
|
|
var req Response
|
|
r := bytes.NewBufferString(s)
|
|
br := bufio.NewReader(r)
|
|
if err := req.ReadLimitBody(br, maxBodySize); err != nil {
|
|
t.Fatalf("unexpected error: %s. s=%q, maxBodySize=%d", err, s, maxBodySize)
|
|
}
|
|
}
|
|
|
|
func testRequestReadLimitBodyError(t *testing.T, s string, maxBodySize int) {
|
|
var req Request
|
|
r := bytes.NewBufferString(s)
|
|
br := bufio.NewReader(r)
|
|
err := req.ReadLimitBody(br, maxBodySize)
|
|
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)
|
|
}
|
|
}
|
|
|
|
func testRequestReadLimitBodySuccess(t *testing.T, s string, maxBodySize int) {
|
|
var req Request
|
|
r := bytes.NewBufferString(s)
|
|
br := bufio.NewReader(r)
|
|
if err := req.ReadLimitBody(br, maxBodySize); err != nil {
|
|
t.Fatalf("unexpected error: %s. s=%q, maxBodySize=%d", err, s, maxBodySize)
|
|
}
|
|
}
|
|
|
|
func TestRequestString(t *testing.T) {
|
|
var r Request
|
|
r.SetRequestURI("http://foobar.com/aaa")
|
|
s := r.String()
|
|
expectedS := "GET /aaa HTTP/1.1\r\nUser-Agent: fasthttp\r\nHost: foobar.com\r\n\r\n"
|
|
if s != expectedS {
|
|
t.Fatalf("unexpected request: %q. Expecting %q", s, expectedS)
|
|
}
|
|
}
|
|
|
|
func TestRequestBodyWriter(t *testing.T) {
|
|
var r Request
|
|
w := r.BodyWriter()
|
|
for i := 0; i < 10; i++ {
|
|
fmt.Fprintf(w, "%d", i)
|
|
}
|
|
if string(r.Body()) != "0123456789" {
|
|
t.Fatalf("unexpected body %q. Expecting %q", r.Body(), "0123456789")
|
|
}
|
|
}
|
|
|
|
func TestResponseBodyWriter(t *testing.T) {
|
|
var r Response
|
|
w := r.BodyWriter()
|
|
for i := 0; i < 10; i++ {
|
|
fmt.Fprintf(w, "%d", i)
|
|
}
|
|
if string(r.Body()) != "0123456789" {
|
|
t.Fatalf("unexpected body %q. Expecting %q", r.Body(), "0123456789")
|
|
}
|
|
}
|
|
|
|
func TestRequestWriteRequestURINoHost(t *testing.T) {
|
|
var req Request
|
|
req.Header.SetRequestURI("http://google.com/foo/bar?baz=aaa")
|
|
var w bytes.Buffer
|
|
bw := bufio.NewWriter(&w)
|
|
if err := req.Write(bw); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if err := bw.Flush(); err != nil {
|
|
t.Fatalf("unexepcted error: %s", err)
|
|
}
|
|
|
|
var req1 Request
|
|
br := bufio.NewReader(&w)
|
|
if err := req1.Read(br); err != nil {
|
|
t.Fatalf("unexpected error: %s", err)
|
|
}
|
|
if string(req1.Header.Host()) != "google.com" {
|
|
t.Fatalf("unexpected host: %q. Expecting %q", req1.Header.Host(), "google.com")
|
|
}
|
|
if string(req.Header.RequestURI()) != "/foo/bar?baz=aaa" {
|
|
t.Fatalf("unexpected requestURI: %q. Expecting %q", req.Header.RequestURI(), "/foo/bar?baz=aaa")
|
|
}
|
|
|
|
// verify that Request.Write returns error on non-absolute RequestURI
|
|
req.Reset()
|
|
req.Header.SetRequestURI("/foo/bar")
|
|
w.Reset()
|
|
bw.Reset(&w)
|
|
if err := req.Write(bw); err == nil {
|
|
t.Fatalf("expecting error")
|
|
}
|
|
}
|
|
|
|
func TestSetRequestBodyStreamFixedSize(t *testing.T) {
|
|
testSetRequestBodyStream(t, "a", false)
|
|
testSetRequestBodyStream(t, string(createFixedBody(4097)), false)
|
|
testSetRequestBodyStream(t, string(createFixedBody(100500)), false)
|
|
}
|
|
|
|
func TestSetResponseBodyStreamFixedSize(t *testing.T) {
|
|
testSetResponseBodyStream(t, "a", false)
|
|
testSetResponseBodyStream(t, string(createFixedBody(4097)), false)
|
|
testSetResponseBodyStream(t, string(createFixedBody(100500)), false)
|
|
}
|
|
|
|
func TestSetRequestBodyStreamChunked(t *testing.T) {
|
|
testSetRequestBodyStream(t, "", true)
|
|
|
|
body := "foobar baz aaa bbb ccc"
|
|
testSetRequestBodyStream(t, body, true)
|
|
|
|
body = string(createFixedBody(10001))
|
|
testSetRequestBodyStream(t, body, true)
|
|
}
|
|
|
|
func TestSetResponseBodyStreamChunked(t *testing.T) {
|
|
testSetResponseBodyStream(t, "", true)
|
|
|
|
body := "foobar baz aaa bbb ccc"
|
|
testSetResponseBodyStream(t, body, true)
|
|
|
|
body = string(createFixedBody(10001))
|
|
testSetResponseBodyStream(t, body, true)
|
|
}
|
|
|
|
func testSetRequestBodyStream(t *testing.T, body string, chunked bool) {
|
|
var req Request
|
|
req.Header.SetHost("foobar.com")
|
|
req.Header.SetMethod("POST")
|
|
|
|
bodySize := len(body)
|
|
if chunked {
|
|
bodySize = -1
|
|
}
|
|
if req.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return false")
|
|
}
|
|
req.SetBodyStream(bytes.NewBufferString(body), bodySize)
|
|
if !req.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return true")
|
|
}
|
|
|
|
var w bytes.Buffer
|
|
bw := bufio.NewWriter(&w)
|
|
if err := req.Write(bw); err != nil {
|
|
t.Fatalf("unexpected error when writing request: %s. body=%q", err, body)
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
|
|
func testSetResponseBodyStream(t *testing.T, body string, chunked bool) {
|
|
var resp Response
|
|
bodySize := len(body)
|
|
if chunked {
|
|
bodySize = -1
|
|
}
|
|
if resp.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return false")
|
|
}
|
|
resp.SetBodyStream(bytes.NewBufferString(body), bodySize)
|
|
if !resp.IsBodyStream() {
|
|
t.Fatalf("IsBodyStream must return true")
|
|
}
|
|
|
|
var w bytes.Buffer
|
|
bw := bufio.NewWriter(&w)
|
|
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)
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|
|
|
|
func TestRound2(t *testing.T) {
|
|
testRound2(t, 0, 0)
|
|
testRound2(t, 1, 1)
|
|
testRound2(t, 2, 2)
|
|
testRound2(t, 3, 4)
|
|
testRound2(t, 4, 4)
|
|
testRound2(t, 5, 8)
|
|
testRound2(t, 7, 8)
|
|
testRound2(t, 8, 8)
|
|
testRound2(t, 9, 16)
|
|
testRound2(t, 0x10001, 0x20000)
|
|
}
|
|
|
|
func testRound2(t *testing.T, n, expectedRound2 int) {
|
|
if round2(n) != expectedRound2 {
|
|
t.Fatalf("Unexpected round2(%d)=%d. Expected %d", n, round2(n), expectedRound2)
|
|
}
|
|
}
|
|
|
|
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"
|
|
r := bytes.NewBufferString(s)
|
|
rb := bufio.NewReader(r)
|
|
err := req.Read(rb)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error when reading chunked request: %s", err)
|
|
}
|
|
expectedBody := "abc12345"
|
|
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")
|
|
}
|
|
|
|
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 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 123 AAA\r\nContent-Type: xxx\r\nContent-Length: 3434\r\n\r\naaaa", false,
|
|
123, 3434, "xxx", "aaaa")
|
|
|
|
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")
|
|
|
|
// '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")
|
|
}
|
|
|
|
func testResponseReadWithoutBody(t *testing.T, resp *Response, s string, skipBody bool,
|
|
expectedStatusCode, expectedContentLength int, expectedContentType, expectedTrailer string) {
|
|
r := bytes.NewBufferString(s)
|
|
rb := bufio.NewReader(r)
|
|
resp.SkipBody = skipBody
|
|
err := resp.Read(rb)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error when reading response without body: %s. response=%q", err, s)
|
|
}
|
|
if len(resp.Body()) != 0 {
|
|
t.Fatalf("Unexpected response body %q. Expected %q. response=%q", resp.Body(), "", s)
|
|
}
|
|
verifyResponseHeader(t, &resp.Header, expectedStatusCode, expectedContentLength, expectedContentType)
|
|
verifyTrailer(t, rb, 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")
|
|
}
|
|
|
|
func TestRequestSuccess(t *testing.T) {
|
|
// empty method, user-agent and body
|
|
testRequestSuccess(t, "", "/foo/bar", "google.com", "", "", "GET")
|
|
|
|
// non-empty user-agent
|
|
testRequestSuccess(t, "GET", "/foo/bar", "google.com", "MSIE", "", "GET")
|
|
|
|
// non-empty method
|
|
testRequestSuccess(t, "HEAD", "/aaa", "fobar", "", "", "HEAD")
|
|
|
|
// POST method with body
|
|
testRequestSuccess(t, "POST", "/bbb", "aaa.com", "Chrome aaa", "post body", "POST")
|
|
|
|
// PUT method with body
|
|
testRequestSuccess(t, "PUT", "/aa/bb", "a.com", "ome aaa", "put body", "PUT")
|
|
|
|
// only host is set
|
|
testRequestSuccess(t, "", "", "gooble.com", "", "", "GET")
|
|
}
|
|
|
|
func TestResponseSuccess(t *testing.T) {
|
|
// 200 response
|
|
testResponseSuccess(t, 200, "test/plain", "server", "foobar",
|
|
200, "test/plain", "server")
|
|
|
|
// response with missing statusCode
|
|
testResponseSuccess(t, 0, "text/plain", "server", "foobar",
|
|
200, "text/plain", "server")
|
|
|
|
// response with missing server
|
|
testResponseSuccess(t, 500, "aaa", "", "aaadfsd",
|
|
500, "aaa", string(defaultServerName))
|
|
|
|
// empty body
|
|
testResponseSuccess(t, 200, "bbb", "qwer", "",
|
|
200, "bbb", "qwer")
|
|
|
|
// missing content-type
|
|
testResponseSuccess(t, 200, "", "asdfsd", "asdf",
|
|
200, string(defaultContentType), "asdfsd")
|
|
}
|
|
|
|
func testResponseSuccess(t *testing.T, statusCode int, contentType, serverName, body string,
|
|
expectedStatusCode int, expectedContentType, expectedServerName string) {
|
|
var resp Response
|
|
resp.SetStatusCode(statusCode)
|
|
resp.Header.Set("Content-Type", contentType)
|
|
resp.Header.Set("Server", serverName)
|
|
resp.SetBody([]byte(body))
|
|
|
|
w := &bytes.Buffer{}
|
|
bw := bufio.NewWriter(w)
|
|
err := resp.Write(bw)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error when calling Response.Write(): %s", err)
|
|
}
|
|
if err = bw.Flush(); err != nil {
|
|
t.Fatalf("Unexpected error when flushing bufio.Writer: %s", err)
|
|
}
|
|
|
|
var resp1 Response
|
|
br := bufio.NewReader(w)
|
|
if err = resp1.Read(br); err != nil {
|
|
t.Fatalf("Unexpected error when calling Response.Read(): %s", err)
|
|
}
|
|
if resp1.StatusCode() != expectedStatusCode {
|
|
t.Fatalf("Unexpected status code: %d. Expected %d", resp1.StatusCode(), expectedStatusCode)
|
|
}
|
|
if resp1.Header.ContentLength() != len(body) {
|
|
t.Fatalf("Unexpected content-length: %d. Expected %d", resp1.Header.ContentLength(), len(body))
|
|
}
|
|
if string(resp1.Header.Peek("Content-Type")) != expectedContentType {
|
|
t.Fatalf("Unexpected content-type: %q. Expected %q", resp1.Header.Peek("Content-Type"), expectedContentType)
|
|
}
|
|
if string(resp1.Header.Peek("Server")) != expectedServerName {
|
|
t.Fatalf("Unexpected server: %q. Expected %q", resp1.Header.Peek("Server"), expectedServerName)
|
|
}
|
|
if !bytes.Equal(resp1.Body(), []byte(body)) {
|
|
t.Fatalf("Unexpected body: %q. Expected %q", resp1.Body(), body)
|
|
}
|
|
}
|
|
|
|
func TestRequestWriteError(t *testing.T) {
|
|
// no host
|
|
testRequestWriteError(t, "", "/foo/bar", "", "", "")
|
|
|
|
// get with body
|
|
testRequestWriteError(t, "GET", "/foo/bar", "aaa.com", "", "foobar")
|
|
}
|
|
|
|
func testRequestWriteError(t *testing.T, method, requestURI, host, userAgent, body string) {
|
|
var req Request
|
|
|
|
req.Header.SetMethod(method)
|
|
req.Header.SetRequestURI(requestURI)
|
|
req.Header.Set("Host", host)
|
|
req.Header.Set("User-Agent", userAgent)
|
|
req.SetBody([]byte(body))
|
|
|
|
w := &ByteBuffer{}
|
|
bw := bufio.NewWriter(w)
|
|
err := req.Write(bw)
|
|
if err == nil {
|
|
t.Fatalf("Expecting error when writing request=%#v", &req)
|
|
}
|
|
}
|
|
|
|
func testRequestSuccess(t *testing.T, method, requestURI, host, userAgent, body, expectedMethod string) {
|
|
var req Request
|
|
|
|
req.Header.SetMethod(method)
|
|
req.Header.SetRequestURI(requestURI)
|
|
req.Header.Set("Host", host)
|
|
req.Header.Set("User-Agent", userAgent)
|
|
req.SetBody([]byte(body))
|
|
|
|
contentType := "foobar"
|
|
if method == "POST" {
|
|
req.Header.Set("Content-Type", contentType)
|
|
}
|
|
|
|
w := &bytes.Buffer{}
|
|
bw := bufio.NewWriter(w)
|
|
err := req.Write(bw)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error when calling Request.Write(): %s", err)
|
|
}
|
|
if err = bw.Flush(); err != nil {
|
|
t.Fatalf("Unexpected error when flushing bufio.Writer: %s", err)
|
|
}
|
|
|
|
var req1 Request
|
|
br := bufio.NewReader(w)
|
|
if err = req1.Read(br); err != nil {
|
|
t.Fatalf("Unexpected error when calling Request.Read(): %s", err)
|
|
}
|
|
if string(req1.Header.Method()) != expectedMethod {
|
|
t.Fatalf("Unexpected method: %q. Expected %q", req1.Header.Method(), expectedMethod)
|
|
}
|
|
if len(requestURI) == 0 {
|
|
requestURI = "/"
|
|
}
|
|
if string(req1.Header.RequestURI()) != requestURI {
|
|
t.Fatalf("Unexpected RequestURI: %q. Expected %q", req1.Header.RequestURI(), requestURI)
|
|
}
|
|
if string(req1.Header.Peek("Host")) != host {
|
|
t.Fatalf("Unexpected host: %q. Expected %q", req1.Header.Peek("Host"), host)
|
|
}
|
|
if len(userAgent) == 0 {
|
|
userAgent = string(defaultUserAgent)
|
|
}
|
|
if string(req1.Header.Peek("User-Agent")) != userAgent {
|
|
t.Fatalf("Unexpected user-agent: %q. Expected %q", req1.Header.Peek("User-Agent"), userAgent)
|
|
}
|
|
if !bytes.Equal(req1.Body(), []byte(body)) {
|
|
t.Fatalf("Unexpected body: %q. Expected %q", req1.Body(), body)
|
|
}
|
|
|
|
if method == "POST" && string(req1.Header.Peek("Content-Type")) != contentType {
|
|
t.Fatalf("Unexpected content-type: %q. Expected %q", req1.Header.Peek("Content-Type"), contentType)
|
|
}
|
|
}
|
|
|
|
func TestResponseReadSuccess(t *testing.T) {
|
|
resp := &Response{}
|
|
|
|
// 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", "")
|
|
|
|
// 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", "", "")
|
|
|
|
// 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")
|
|
|
|
// 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", "")
|
|
|
|
// 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", "")
|
|
|
|
// 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, "")
|
|
|
|
// 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")
|
|
|
|
// 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")
|
|
|
|
// 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) {
|
|
resp := &Response{}
|
|
|
|
// empty response
|
|
testResponseReadError(t, resp, "")
|
|
|
|
// invalid header
|
|
testResponseReadError(t, resp, "foobar")
|
|
|
|
// empty body
|
|
testResponseReadError(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nContent-Length: 1234\r\n\r\n")
|
|
|
|
// short body
|
|
testResponseReadError(t, resp, "HTTP/1.1 200 OK\r\nContent-Type: aaa\r\nContent-Length: 1234\r\n\r\nshort")
|
|
}
|
|
|
|
func testResponseReadError(t *testing.T, resp *Response, response string) {
|
|
r := bytes.NewBufferString(response)
|
|
rb := bufio.NewReader(r)
|
|
err := resp.Read(rb)
|
|
if err == nil {
|
|
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")
|
|
}
|
|
|
|
func testResponseReadSuccess(t *testing.T, resp *Response, response string, expectedStatusCode, expectedContentLength int,
|
|
expectedContenType, expectedBody, expectedTrailer string) {
|
|
|
|
r := bytes.NewBufferString(response)
|
|
rb := bufio.NewReader(r)
|
|
err := resp.Read(rb)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error: %s", err)
|
|
}
|
|
|
|
verifyResponseHeader(t, &resp.Header, expectedStatusCode, expectedContentLength, expectedContenType)
|
|
if !bytes.Equal(resp.Body(), []byte(expectedBody)) {
|
|
t.Fatalf("Unexpected body %q. Expected %q", resp.Body(), []byte(expectedBody))
|
|
}
|
|
verifyTrailer(t, rb, expectedTrailer)
|
|
}
|
|
|
|
func TestReadBodyFixedSize(t *testing.T) {
|
|
var b []byte
|
|
|
|
// zero-size body
|
|
testReadBodyFixedSize(t, b, 0)
|
|
|
|
// small-size body
|
|
testReadBodyFixedSize(t, b, 3)
|
|
|
|
// medium-size body
|
|
testReadBodyFixedSize(t, b, 1024)
|
|
|
|
// large-size body
|
|
testReadBodyFixedSize(t, b, 1024*1024)
|
|
|
|
// smaller body after big one
|
|
testReadBodyFixedSize(t, b, 34345)
|
|
}
|
|
|
|
func TestReadBodyChunked(t *testing.T) {
|
|
var b []byte
|
|
|
|
// zero-size body
|
|
testReadBodyChunked(t, b, 0)
|
|
|
|
// small-size body
|
|
testReadBodyChunked(t, b, 5)
|
|
|
|
// medium-size body
|
|
testReadBodyChunked(t, b, 43488)
|
|
|
|
// big body
|
|
testReadBodyChunked(t, b, 3*1024*1024)
|
|
|
|
// smaler body after big one
|
|
testReadBodyChunked(t, b, 12343)
|
|
}
|
|
|
|
func TestRequestURITLS(t *testing.T) {
|
|
uriNoScheme := "//foobar.com/baz/aa?bb=dd&dd#sdf"
|
|
requestURI := "http:" + uriNoScheme
|
|
requestURITLS := "https:" + uriNoScheme
|
|
|
|
var req Request
|
|
|
|
req.isTLS = true
|
|
req.SetRequestURI(requestURI)
|
|
uri := req.URI().String()
|
|
if uri != requestURITLS {
|
|
t.Fatalf("unexpected request uri: %q. Expecting %q", uri, requestURITLS)
|
|
}
|
|
|
|
req.Reset()
|
|
req.SetRequestURI(requestURI)
|
|
uri = req.URI().String()
|
|
if uri != requestURI {
|
|
t.Fatalf("unexpected request uri: %q. Expecting %q", uri, requestURI)
|
|
}
|
|
}
|
|
|
|
func TestRequestURI(t *testing.T) {
|
|
host := "foobar.com"
|
|
requestURI := "/aaa/bb+b%20d?ccc=ddd&qqq#1334dfds&=d"
|
|
expectedPathOriginal := "/aaa/bb+b%20d"
|
|
expectedPath := "/aaa/bb+b d"
|
|
expectedQueryString := "ccc=ddd&qqq"
|
|
expectedHash := "1334dfds&=d"
|
|
|
|
var req Request
|
|
req.Header.Set("Host", host)
|
|
req.Header.SetRequestURI(requestURI)
|
|
|
|
uri := req.URI()
|
|
if string(uri.Host()) != host {
|
|
t.Fatalf("Unexpected host %q. Expected %q", uri.Host(), host)
|
|
}
|
|
if string(uri.PathOriginal()) != expectedPathOriginal {
|
|
t.Fatalf("Unexpected source path %q. Expected %q", uri.PathOriginal(), expectedPathOriginal)
|
|
}
|
|
if string(uri.Path()) != expectedPath {
|
|
t.Fatalf("Unexpected path %q. Expected %q", uri.Path(), expectedPath)
|
|
}
|
|
if string(uri.QueryString()) != expectedQueryString {
|
|
t.Fatalf("Unexpected query string %q. Expected %q", uri.QueryString(), expectedQueryString)
|
|
}
|
|
if string(uri.Hash()) != expectedHash {
|
|
t.Fatalf("Unexpected hash %q. Expected %q", uri.Hash(), expectedHash)
|
|
}
|
|
}
|
|
|
|
func TestRequestPostArgsSuccess(t *testing.T) {
|
|
var req Request
|
|
|
|
testRequestPostArgsSuccess(t, &req, "POST / HTTP/1.1\r\nHost: aaa.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 0\r\n\r\n", 0, "foo=", "=")
|
|
|
|
testRequestPostArgsSuccess(t, &req, "POST / HTTP/1.1\r\nHost: aaa.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 18\r\n\r\nfoo&b%20r=b+z=&qwe", 3, "foo=", "b r=b z=", "qwe=")
|
|
}
|
|
|
|
func TestRequestPostArgsError(t *testing.T) {
|
|
var req Request
|
|
|
|
// non-post
|
|
testRequestPostArgsError(t, &req, "GET /aa HTTP/1.1\r\nHost: aaa\r\n\r\n")
|
|
|
|
// invalid content-type
|
|
testRequestPostArgsError(t, &req, "POST /aa HTTP/1.1\r\nHost: aaa\r\nContent-Type: text/html\r\nContent-Length: 5\r\n\r\nabcde")
|
|
}
|
|
|
|
func testRequestPostArgsError(t *testing.T, req *Request, s string) {
|
|
r := bytes.NewBufferString(s)
|
|
br := bufio.NewReader(r)
|
|
err := req.Read(br)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error when reading %q: %s", s, err)
|
|
}
|
|
ss := req.PostArgs().String()
|
|
if len(ss) != 0 {
|
|
t.Fatalf("unexpected post args: %q. Expecting empty post args", ss)
|
|
}
|
|
}
|
|
|
|
func testRequestPostArgsSuccess(t *testing.T, req *Request, s string, expectedArgsLen int, expectedArgs ...string) {
|
|
r := bytes.NewBufferString(s)
|
|
br := bufio.NewReader(r)
|
|
err := req.Read(br)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error when reading %q: %s", s, err)
|
|
}
|
|
|
|
args := req.PostArgs()
|
|
if args.Len() != expectedArgsLen {
|
|
t.Fatalf("Unexpected args len %d. Expected %d for %q", args.Len(), expectedArgsLen, s)
|
|
}
|
|
for _, x := range expectedArgs {
|
|
tmp := strings.SplitN(x, "=", 2)
|
|
k := tmp[0]
|
|
v := tmp[1]
|
|
vv := string(args.Peek(k))
|
|
if vv != v {
|
|
t.Fatalf("Unexpected value for key %q: %q. Expected %q for %q", k, vv, v, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func testReadBodyChunked(t *testing.T, b []byte, bodySize int) {
|
|
body := createFixedBody(bodySize)
|
|
chunkedBody := createChunkedBody(body)
|
|
expectedTrailer := []byte("chunked shit")
|
|
chunkedBody = append(chunkedBody, expectedTrailer...)
|
|
|
|
r := bytes.NewBuffer(chunkedBody)
|
|
br := bufio.NewReader(r)
|
|
b, err := readBody(br, -1, 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))
|
|
}
|
|
|
|
func testReadBodyFixedSize(t *testing.T, b []byte, bodySize int) {
|
|
body := createFixedBody(bodySize)
|
|
expectedTrailer := []byte("traler aaaa")
|
|
bodyWithTrailer := append(body, expectedTrailer...)
|
|
|
|
r := bytes.NewBuffer(bodyWithTrailer)
|
|
br := bufio.NewReader(r)
|
|
b, err := readBody(br, bodySize, 0, nil)
|
|
if err != nil {
|
|
t.Fatalf("Unexpected error in ReadResponseBody(%d): %s", bodySize, err)
|
|
}
|
|
if !bytes.Equal(b, body) {
|
|
t.Fatalf("Unexpected response read for bodySize=%d: %q. Expected %q", bodySize, b, body)
|
|
}
|
|
verifyTrailer(t, br, string(expectedTrailer))
|
|
}
|
|
|
|
func createFixedBody(bodySize int) []byte {
|
|
var b []byte
|
|
for i := 0; i < bodySize; i++ {
|
|
b = append(b, byte(i%10)+'0')
|
|
}
|
|
return b
|
|
}
|
|
|
|
func createChunkedBody(body []byte) []byte {
|
|
var b []byte
|
|
chunkSize := 1
|
|
for len(body) > 0 {
|
|
if chunkSize > len(body) {
|
|
chunkSize = len(body)
|
|
}
|
|
b = append(b, []byte(fmt.Sprintf("%x\r\n", chunkSize))...)
|
|
b = append(b, body[:chunkSize]...)
|
|
b = append(b, []byte("\r\n")...)
|
|
body = body[chunkSize:]
|
|
chunkSize++
|
|
}
|
|
return append(b, []byte("0\r\n\r\n")...)
|
|
}
|