github.com/cloudwego/hertz@v0.9.3/pkg/protocol/http1/req/request_test.go (about)

     1  /*
     2   * Copyright 2022 CloudWeGo Authors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   *
    16   * The MIT License (MIT)
    17   *
    18   * Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors
    19   *
    20   * Permission is hereby granted, free of charge, to any person obtaining a copy
    21   * of this software and associated documentation files (the "Software"), to deal
    22   * in the Software without restriction, including without limitation the rights
    23   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    24   * copies of the Software, and to permit persons to whom the Software is
    25   * furnished to do so, subject to the following conditions:
    26   *
    27   * The above copyright notice and this permission notice shall be included in
    28   * all copies or substantial portions of the Software.
    29   *
    30   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    31   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    32   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    33   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    34   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    35   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    36   * THE SOFTWARE.
    37   *
    38   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    39   * Modifications are Copyright 2022 CloudWeGo Authors.
    40   */
    41  
    42  package req
    43  
    44  import (
    45  	"bufio"
    46  	"bytes"
    47  	"encoding/base64"
    48  	"errors"
    49  	"fmt"
    50  	"io"
    51  	"io/ioutil"
    52  	"mime/multipart"
    53  	"net/url"
    54  	"strings"
    55  	"testing"
    56  
    57  	"github.com/cloudwego/hertz/internal/bytesconv"
    58  	"github.com/cloudwego/hertz/internal/bytestr"
    59  	"github.com/cloudwego/hertz/pkg/common/bytebufferpool"
    60  	"github.com/cloudwego/hertz/pkg/common/compress"
    61  	errs "github.com/cloudwego/hertz/pkg/common/errors"
    62  	"github.com/cloudwego/hertz/pkg/common/test/assert"
    63  	"github.com/cloudwego/hertz/pkg/common/test/mock"
    64  	"github.com/cloudwego/hertz/pkg/common/utils"
    65  	"github.com/cloudwego/hertz/pkg/network"
    66  	"github.com/cloudwego/hertz/pkg/protocol"
    67  	"github.com/cloudwego/hertz/pkg/protocol/consts"
    68  	"github.com/cloudwego/hertz/pkg/protocol/http1/ext"
    69  	"github.com/cloudwego/netpoll"
    70  )
    71  
    72  func TestRequestContinueReadBody(t *testing.T) {
    73  	t.Parallel()
    74  	s := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343"
    75  	zr := mock.NewZeroCopyReader(s)
    76  
    77  	var r protocol.Request
    78  	if err := Read(&r, zr); err != nil {
    79  		t.Fatalf("unexpected error: %s", err)
    80  	}
    81  
    82  	if err := ContinueReadBody(&r, zr, 0, true); err != nil {
    83  		t.Fatalf("error when reading request body: %s", err)
    84  	}
    85  	body := r.Body()
    86  	if string(body) != "abcde" {
    87  		t.Fatalf("unexpected body %q. Expecting %q", body, "abcde")
    88  	}
    89  
    90  	tail, err := zr.Peek(zr.Len())
    91  	if err != nil {
    92  		t.Fatalf("unexpected error: %s", err)
    93  	}
    94  	if string(tail) != "f4343" {
    95  		t.Fatalf("unexpected tail %q. Expecting %q", tail, "f4343")
    96  	}
    97  }
    98  
    99  func TestRequestReadNoBody(t *testing.T) {
   100  	t.Parallel()
   101  
   102  	var r protocol.Request
   103  
   104  	s := "GET / HTTP/1.1\r\n\r\n"
   105  
   106  	zr := mock.NewZeroCopyReader(s)
   107  	if err := Read(&r, zr); err != nil {
   108  		t.Fatalf("unexpected error: %s", err)
   109  	}
   110  	r.SetHost("foobar")
   111  	headerStr := r.Header.String()
   112  	if strings.Contains(headerStr, "Content-Length: ") {
   113  		t.Fatalf("unexpected Content-Length")
   114  	}
   115  }
   116  
   117  func TestRequestRead(t *testing.T) {
   118  	t.Parallel()
   119  
   120  	var r protocol.Request
   121  
   122  	s := "POST / HTTP/1.1\r\n\r\n"
   123  
   124  	zr := mock.NewZeroCopyReader(s)
   125  	if err := Read(&r, zr); err != nil {
   126  		t.Fatalf("unexpected error: %s", err)
   127  	}
   128  	r.SetHost("foobar")
   129  	headerStr := r.Header.String()
   130  	if !strings.Contains(headerStr, "Content-Length: ") {
   131  		t.Fatalf("should contain Content-Length")
   132  	}
   133  	cLen := r.Header.Peek(consts.HeaderContentLength)
   134  	if string(cLen) != "0" {
   135  		t.Fatalf("unexpected Content-Length: %s, Expecting 0", string(cLen))
   136  	}
   137  }
   138  
   139  func TestRequestReadNoBodyStreaming(t *testing.T) {
   140  	t.Parallel()
   141  
   142  	var r protocol.Request
   143  	r.Header.SetContentLength(-2)
   144  	r.Header.SetMethod("GET")
   145  
   146  	s := ""
   147  
   148  	zr := mock.NewZeroCopyReader(s)
   149  	if err := ContinueReadBodyStream(&r, zr, 2048, true); err != nil {
   150  		t.Fatalf("unexpected error: %s", err)
   151  	}
   152  	r.SetHost("foobar")
   153  	headerStr := r.Header.String()
   154  	if strings.Contains(headerStr, "Content-Length: ") {
   155  		t.Fatalf("unexpected Content-Length")
   156  	}
   157  }
   158  
   159  func TestRequestReadStreaming(t *testing.T) {
   160  	t.Parallel()
   161  
   162  	var r protocol.Request
   163  	r.Header.SetContentLength(-2)
   164  	r.Header.SetMethod("POST")
   165  
   166  	s := ""
   167  
   168  	zr := mock.NewZeroCopyReader(s)
   169  	if err := ContinueReadBodyStream(&r, zr, 2048, true); err != nil {
   170  		t.Fatalf("unexpected error: %s", err)
   171  	}
   172  	r.SetHost("foobar")
   173  	headerStr := r.Header.String()
   174  	if !strings.Contains(headerStr, "Content-Length: ") {
   175  		t.Fatalf("should contain Content-Length")
   176  	}
   177  	cLen := r.Header.Peek(consts.HeaderContentLength)
   178  	if string(cLen) != "0" {
   179  		t.Fatalf("unexpected Content-Length: %s, Expecting 0", string(cLen))
   180  	}
   181  }
   182  
   183  func TestMethodAndPathAndQueryString(t *testing.T) {
   184  	s := "PUT /foo/bar?query=1 HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\nabcdef4343"
   185  	zr := mock.NewZeroCopyReader(s)
   186  
   187  	var r protocol.Request
   188  	if err := Read(&r, zr); err != nil {
   189  		t.Fatalf("unexpected error: %s", err)
   190  	}
   191  	if string(r.RequestURI()) != "/foo/bar?query=1" {
   192  		t.Fatalf("unexpected request uri %s. Expecting %s", r.RequestURI(), "/foo/bar?query=1")
   193  	}
   194  	if string(r.Method()) != "PUT" {
   195  		t.Fatalf("unexpected method %s. Expecting %s", r.Header.Method(), "PUT")
   196  	}
   197  
   198  	if string(r.Path()) != "/foo/bar" {
   199  		t.Fatalf("unexpected uri path %s. Expecting %s", r.URI().Path(), "/foo/bar")
   200  	}
   201  	if string(r.QueryString()) != "query=1" {
   202  		t.Fatalf("unexpected query string %s. Expecting %s", r.URI().QueryString(), "query=1")
   203  	}
   204  }
   205  
   206  func TestRequestSuccess(t *testing.T) {
   207  	t.Parallel()
   208  
   209  	// empty method, user-agent and body
   210  	testRequestSuccess(t, "", "/foo/bar", "google.com", "", "", consts.MethodGet)
   211  
   212  	// non-empty user-agent
   213  	testRequestSuccess(t, consts.MethodGet, "/foo/bar", "google.com", "MSIE", "", consts.MethodGet)
   214  
   215  	// non-empty method
   216  	testRequestSuccess(t, consts.MethodHead, "/aaa", "fobar", "", "", consts.MethodHead)
   217  
   218  	// POST method with body
   219  	testRequestSuccess(t, consts.MethodPost, "/bbb", "aaa.com", "Chrome aaa", "post body", consts.MethodPost)
   220  
   221  	// PUT method with body
   222  	testRequestSuccess(t, consts.MethodPut, "/aa/bb", "a.com", "ome aaa", "put body", consts.MethodPut)
   223  
   224  	// only host is set
   225  	testRequestSuccess(t, "", "", "gooble.com", "", "", consts.MethodGet)
   226  
   227  	// get with body
   228  	testRequestSuccess(t, consts.MethodGet, "/foo/bar", "aaa.com", "", "foobar", consts.MethodGet)
   229  }
   230  
   231  func TestRequestMultipartFormBoundary(t *testing.T) {
   232  	t.Parallel()
   233  
   234  	testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=foobar\r\n\r\n", "foobar")
   235  
   236  	// incorrect content-type
   237  	testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: foo/bar\r\n\r\n", "")
   238  
   239  	// empty boundary
   240  	testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=\r\n\r\n", "")
   241  
   242  	// missing boundary
   243  	testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data\r\n\r\n", "")
   244  
   245  	// boundary after other content-type params
   246  	testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data;   foo=bar;   boundary=--aaabb  \r\n\r\n", "--aaabb")
   247  
   248  	// quoted boundary
   249  	testRequestMultipartFormBoundary(t, "POST / HTTP/1.1\r\nContent-Type: multipart/form-data; boundary=\"foobar\"\r\n\r\n", "foobar")
   250  
   251  	var h protocol.RequestHeader
   252  	h.SetMultipartFormBoundary("foobarbaz")
   253  	b := h.MultipartFormBoundary()
   254  	if string(b) != "foobarbaz" {
   255  		t.Fatalf("unexpected boundary %q. Expecting %q", b, "foobarbaz")
   256  	}
   257  }
   258  
   259  func testRequestSuccess(t *testing.T, method, requestURI, host, userAgent, body, expectedMethod string) {
   260  	var req protocol.Request
   261  
   262  	req.Header.SetMethod(method)
   263  	req.Header.SetRequestURI(requestURI)
   264  	req.Header.Set(consts.HeaderHost, host)
   265  	req.Header.Set(consts.HeaderUserAgent, userAgent)
   266  	req.SetBody([]byte(body))
   267  
   268  	contentType := "foobar"
   269  	if method == consts.MethodPost {
   270  		req.Header.Set(consts.HeaderContentType, contentType)
   271  	}
   272  
   273  	w := &bytes.Buffer{}
   274  	zw := netpoll.NewWriter(w)
   275  	err := Write(&req, zw)
   276  	if err != nil {
   277  		t.Fatalf("Unexpected error when calling Write(): %s", err)
   278  	}
   279  
   280  	if err = zw.Flush(); err != nil {
   281  		t.Fatalf("Unexpected error when flushing bufio.Writer: %s", err)
   282  	}
   283  
   284  	var req1 protocol.Request
   285  	br := bufio.NewReader(w)
   286  	zr := netpoll.NewReader(br)
   287  	if err = Read(&req1, zr); err != nil {
   288  		t.Fatalf("Unexpected error when calling Read(): %s", err)
   289  	}
   290  	if string(req1.Header.Method()) != expectedMethod {
   291  		t.Fatalf("Unexpected method: %q. Expected %q", req1.Header.Method(), expectedMethod)
   292  	}
   293  	if len(requestURI) == 0 {
   294  		requestURI = "/"
   295  	}
   296  	if string(req1.Header.RequestURI()) != requestURI {
   297  		t.Fatalf("Unexpected RequestURI: %q. Expected %q", req1.Header.RequestURI(), requestURI)
   298  	}
   299  	if string(req1.Header.Peek(consts.HeaderHost)) != host {
   300  		t.Fatalf("Unexpected host: %q. Expected %q", req1.Header.Peek(consts.HeaderHost), host)
   301  	}
   302  	if string(req1.Header.Peek(consts.HeaderUserAgent)) != userAgent {
   303  		t.Fatalf("Unexpected user-agent: %q. Expected %q", req1.Header.Peek(consts.HeaderUserAgent), userAgent)
   304  	}
   305  	if !bytes.Equal(req1.Body(), []byte(body)) {
   306  		t.Fatalf("Unexpected body: %q. Expected %q", req1.Body(), body)
   307  	}
   308  
   309  	if method == consts.MethodPost && string(req1.Header.Peek(consts.HeaderContentType)) != contentType {
   310  		t.Fatalf("Unexpected content-type: %q. Expected %q", req1.Header.Peek(consts.HeaderContentType), contentType)
   311  	}
   312  }
   313  
   314  func TestRequestWriteError(t *testing.T) {
   315  	t.Parallel()
   316  
   317  	// no host
   318  	testRequestWriteError(t, "", "/foo/bar", "", "", "")
   319  }
   320  
   321  func TestRequestPostArgsSuccess(t *testing.T) {
   322  	t.Parallel()
   323  
   324  	var req protocol.Request
   325  
   326  	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=", "=")
   327  
   328  	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=")
   329  }
   330  
   331  func testRequestPostArgsSuccess(t *testing.T, req *protocol.Request, s string, expectedArgsLen int, expectedArgs ...string) {
   332  	r := bytes.NewBufferString(s)
   333  	zr := netpoll.NewReader(r)
   334  	err := Read(req, zr)
   335  	if err != nil {
   336  		t.Fatalf("Unexpected error when reading %q: %s", s, err)
   337  	}
   338  
   339  	args := req.PostArgs()
   340  	if args.Len() != expectedArgsLen {
   341  		t.Fatalf("Unexpected args len %d. Expected %d for %q", args.Len(), expectedArgsLen, s)
   342  	}
   343  	for _, x := range expectedArgs {
   344  		tmp := strings.SplitN(x, "=", 2)
   345  		k := tmp[0]
   346  		v := tmp[1]
   347  		vv := string(args.Peek(k))
   348  		if vv != v {
   349  			t.Fatalf("Unexpected value for key %q: %q. Expected %q for %q", k, vv, v, s)
   350  		}
   351  	}
   352  }
   353  
   354  func TestRequestPostArgsBodyStream(t *testing.T) {
   355  	var req protocol.Request
   356  	s := "POST / HTTP/1.1\r\nHost: aaa.com\r\nContent-Type: application/x-www-form-urlencoded\r\nContent-Length: 8196\r\n\r\n"
   357  	contentB := make([]byte, 8192)
   358  	for i := 0; i < len(contentB); i++ {
   359  		contentB[i] = 'a'
   360  	}
   361  	content := string(contentB)
   362  	requestString := s + url.Values{"key": []string{content}}.Encode()
   363  
   364  	r := bytes.NewBufferString(requestString)
   365  	zr := netpoll.NewReader(r)
   366  	if err := ReadHeader(&req.Header, zr); err != nil {
   367  		t.Fatalf("Unexpected error when reading header %q: %s", s, err)
   368  	}
   369  
   370  	err := ReadBodyStream(&req, zr, 1024*4, false, false)
   371  	if err != nil {
   372  		t.Fatalf("Unexpected error when reading bodystream %q: %s", s, err)
   373  	}
   374  	if string(req.PostArgs().Peek("key")) != content {
   375  		assert.DeepEqual(t, content, string(req.PostArgs().Peek("key")))
   376  	}
   377  }
   378  
   379  func testRequestWriteError(t *testing.T, method, requestURI, host, userAgent, body string) {
   380  	var req protocol.Request
   381  
   382  	req.Header.SetMethod(method)
   383  	req.Header.SetRequestURI(requestURI)
   384  	req.Header.Set(consts.HeaderHost, host)
   385  	req.Header.Set(consts.HeaderUserAgent, userAgent)
   386  	req.SetBody([]byte(body))
   387  
   388  	w := &bytebufferpool.ByteBuffer{}
   389  	zw := netpoll.NewWriter(w)
   390  	err := Write(&req, zw)
   391  	if err == nil {
   392  		t.Fatalf("Expecting error when writing request=%#v", &req)
   393  	}
   394  }
   395  
   396  func TestChunkedUnexpectedEOF(t *testing.T) {
   397  	reader := &mock.EOFReader{}
   398  
   399  	_, err := ext.ReadBody(reader, -1, 0, nil)
   400  	if err != io.ErrUnexpectedEOF {
   401  		assert.DeepEqual(t, io.ErrUnexpectedEOF, err)
   402  	}
   403  
   404  	var pool bytebufferpool.Pool
   405  	var req1 protocol.Request
   406  	bs := ext.AcquireBodyStream(pool.Get(), reader, req1.Header.Trailer(), -1)
   407  	byteSlice := make([]byte, 4096)
   408  	_, err = bs.Read(byteSlice)
   409  	if err != io.ErrUnexpectedEOF {
   410  		assert.DeepEqual(t, io.ErrUnexpectedEOF, err)
   411  	}
   412  }
   413  
   414  func TestReadBodyChunked(t *testing.T) {
   415  	t.Parallel()
   416  
   417  	// zero-size body
   418  	testReadBodyChunked(t, 0)
   419  
   420  	// small-size body
   421  	testReadBodyChunked(t, 5)
   422  
   423  	// medium-size body
   424  	testReadBodyChunked(t, 43488)
   425  
   426  	// big body
   427  	testReadBodyChunked(t, 3*1024*1024)
   428  
   429  	// smaller body after big one
   430  	testReadBodyChunked(t, 12343)
   431  }
   432  
   433  func TestReadBodyFixedSize(t *testing.T) {
   434  	t.Parallel()
   435  
   436  	// zero-size body
   437  	testReadBodyFixedSize(t, 0)
   438  
   439  	// small-size body
   440  	testReadBodyFixedSize(t, 3)
   441  
   442  	// medium-size body
   443  	testReadBodyFixedSize(t, 1024)
   444  
   445  	// large-size body
   446  	testReadBodyFixedSize(t, 1024*1024)
   447  
   448  	// smaller body after big one
   449  	testReadBodyFixedSize(t, 34345)
   450  }
   451  
   452  func TestRequestWriteRequestURINoHost(t *testing.T) {
   453  	t.Parallel()
   454  
   455  	var req protocol.Request
   456  	req.Header.SetRequestURI("http://user:pass@google.com/foo/bar?baz=aaa")
   457  	var w bytes.Buffer
   458  	zw := netpoll.NewWriter(&w)
   459  	if err := Write(&req, zw); err != nil {
   460  		t.Fatalf("unexpected error: %s", err)
   461  	}
   462  
   463  	if err := zw.Flush(); err != nil {
   464  		t.Fatalf("unexpected error: %s", err)
   465  	}
   466  
   467  	var req1 protocol.Request
   468  	br := bufio.NewReader(&w)
   469  	zr := netpoll.NewReader(br)
   470  	if err := Read(&req1, zr); err != nil {
   471  		t.Fatalf("unexpected error: %s", err)
   472  	}
   473  	if string(req1.Header.Host()) != "google.com" {
   474  		t.Fatalf("unexpected host: %q. Expecting %q", req1.Header.Host(), "google.com")
   475  	}
   476  	if string(req.Header.RequestURI()) != "/foo/bar?baz=aaa" {
   477  		t.Fatalf("unexpected requestURI: %q. Expecting %q", req.Header.RequestURI(), "/foo/bar?baz=aaa")
   478  	}
   479  	// authorization
   480  	authorization := req.Header.Get(string(bytestr.StrAuthorization))
   481  	author, err := base64.StdEncoding.DecodeString(authorization[len(bytestr.StrBasicSpace):])
   482  	if err != nil {
   483  		t.Fatalf("expecting error")
   484  	}
   485  
   486  	if string(author) != "user:pass" {
   487  		t.Fatalf("unexpected Authorization: %q. Expecting %q", authorization, "user:pass")
   488  	}
   489  
   490  	// verify that Write returns error on non-absolute RequestURI
   491  	req.Reset()
   492  	req.Header.SetRequestURI("/foo/bar")
   493  	w.Reset()
   494  	if err := Write(&req, zw); err == nil {
   495  		t.Fatalf("expecting error")
   496  	}
   497  }
   498  
   499  func TestRequestWriteMultipartFile(t *testing.T) {
   500  	t.Parallel()
   501  
   502  	var req protocol.Request
   503  	req.Header.SetHost("foobar.com")
   504  	req.Header.SetMethod(consts.MethodPost)
   505  	req.SetFileReader("filea", "filea.txt", bytes.NewReader([]byte("This is filea.")))
   506  	req.SetMultipartField("fileb", "fileb.txt", "text/plain", bytes.NewReader([]byte("This is fileb.")))
   507  
   508  	var w bytes.Buffer
   509  	zw := netpoll.NewWriter(&w)
   510  	if err := Write(&req, zw); err != nil {
   511  		t.Fatalf("unexpected error: %s", err)
   512  	}
   513  	if err := zw.Flush(); err != nil {
   514  		t.Fatalf("unexpected error: %s", err)
   515  	}
   516  
   517  	var req1 protocol.Request
   518  	zr := mock.NewZeroCopyReader(w.String())
   519  	if err := Read(&req1, zr); err != nil {
   520  		t.Fatalf("unexpected error: %s", err)
   521  	}
   522  
   523  	filea, err := req1.FormFile("filea")
   524  	assert.Nil(t, err)
   525  	assert.DeepEqual(t, "filea.txt", filea.Filename)
   526  	fileb, err := req1.FormFile("fileb")
   527  	assert.Nil(t, err)
   528  	assert.DeepEqual(t, "fileb.txt", fileb.Filename)
   529  }
   530  
   531  func TestSetRequestBodyStreamChunked(t *testing.T) {
   532  	t.Parallel()
   533  
   534  	testSetRequestBodyStreamChunked(t, "", map[string]string{"Foo": "bar"})
   535  
   536  	body := "foobar baz aaa bbb ccc"
   537  	testSetRequestBodyStreamChunked(t, body, nil)
   538  
   539  	body = string(mock.CreateFixedBody(10001))
   540  	testSetRequestBodyStreamChunked(t, body, map[string]string{"Foo": "test", "Bar": "test"})
   541  }
   542  
   543  func TestSetRequestBodyStreamFixedSize(t *testing.T) {
   544  	t.Parallel()
   545  
   546  	testSetRequestBodyStream(t, "a")
   547  	testSetRequestBodyStream(t, string(mock.CreateFixedBody(4097)))
   548  	testSetRequestBodyStream(t, string(mock.CreateFixedBody(100500)))
   549  }
   550  
   551  func TestRequestHostFromRequestURI(t *testing.T) {
   552  	t.Parallel()
   553  
   554  	hExpected := "foobar.com"
   555  	var req protocol.Request
   556  	req.SetRequestURI("http://proxy-host:123/foobar?baz")
   557  	req.SetHost(hExpected)
   558  	h := bytesconv.B2s(req.Host())
   559  	if h != hExpected {
   560  		t.Fatalf("unexpected host set: %q. Expecting %q", h, hExpected)
   561  	}
   562  }
   563  
   564  func TestRequestHostFromHeader(t *testing.T) {
   565  	t.Parallel()
   566  
   567  	hExpected := "foobar.com"
   568  	var req protocol.Request
   569  	req.Header.SetHost(hExpected)
   570  	h := bytesconv.B2s(req.Host())
   571  	if h != hExpected {
   572  		t.Fatalf("unexpected host set: %q. Expecting %q", h, hExpected)
   573  	}
   574  }
   575  
   576  func TestRequestContentTypeWithCharset(t *testing.T) {
   577  	t.Parallel()
   578  
   579  	expectedContentType := consts.MIMEApplicationHTMLFormUTF8
   580  	expectedBody := "0123=56789"
   581  	s := fmt.Sprintf("POST / HTTP/1.1\r\nContent-Type: %s\r\nContent-Length: %d\r\n\r\n%s",
   582  		expectedContentType, len(expectedBody), expectedBody)
   583  
   584  	zr := mock.NewZeroCopyReader(s)
   585  	var r protocol.Request
   586  	if err := Read(&r, zr); err != nil {
   587  		t.Fatalf("unexpected error: %s", err)
   588  	}
   589  
   590  	body := r.Body()
   591  	if string(body) != expectedBody {
   592  		t.Fatalf("unexpected body %q. Expecting %q", body, expectedBody)
   593  	}
   594  	ct := r.Header.ContentType()
   595  	if string(ct) != expectedContentType {
   596  		t.Fatalf("unexpected content-type %q. Expecting %q", ct, expectedContentType)
   597  	}
   598  	args := r.PostArgs()
   599  	if args.Len() != 1 {
   600  		t.Fatalf("unexpected number of POST args: %d. Expecting 1", args.Len())
   601  	}
   602  	av := args.Peek("0123")
   603  	if string(av) != "56789" {
   604  		t.Fatalf("unexpected POST arg value: %q. Expecting %q", av, "56789")
   605  	}
   606  }
   607  
   608  func TestRequestBodyStreamMultipleBodyCalls(t *testing.T) {
   609  	t.Parallel()
   610  
   611  	var r protocol.Request
   612  
   613  	s := "foobar baz abc"
   614  	if r.IsBodyStream() {
   615  		t.Fatalf("IsBodyStream must return false")
   616  	}
   617  	r.SetBodyStream(bytes.NewBufferString(s), len(s))
   618  	if !r.IsBodyStream() {
   619  		t.Fatalf("IsBodyStream must return true")
   620  	}
   621  	for i := 0; i < 10; i++ {
   622  		body := r.Body()
   623  		if string(body) != s {
   624  			t.Fatalf("unexpected body %q. Expecting %q. iteration %d", body, s, i)
   625  		}
   626  	}
   627  }
   628  
   629  func TestRequestNoContentLength(t *testing.T) {
   630  	t.Parallel()
   631  
   632  	var r protocol.Request
   633  
   634  	r.Header.SetMethod(consts.MethodHead)
   635  	r.Header.SetHost("foobar")
   636  
   637  	s := GetHTTP1Request(&r).String()
   638  	if strings.Contains(s, "Content-Length: ") {
   639  		t.Fatalf("unexpected content-length in HEAD request %q", s)
   640  	}
   641  
   642  	r.Header.SetMethod(consts.MethodPost)
   643  	fmt.Fprintf(r.BodyWriter(), "foobar body")
   644  	s = GetHTTP1Request(&r).String()
   645  	if !strings.Contains(s, "Content-Length: ") {
   646  		t.Fatalf("missing content-length header in non-GET request %q", s)
   647  	}
   648  }
   649  
   650  func TestRequestReadGzippedBody(t *testing.T) {
   651  	t.Parallel()
   652  
   653  	var r protocol.Request
   654  
   655  	bodyOriginal := "foo bar baz compress me better!"
   656  	body := compress.AppendGzipBytes(nil, []byte(bodyOriginal))
   657  	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",
   658  		len(body), body)
   659  	zr := mock.NewZeroCopyReader(s)
   660  	if err := Read(&r, zr); err != nil {
   661  		t.Fatalf("unexpected error: %s", err)
   662  	}
   663  
   664  	if string(r.Header.Peek(consts.HeaderContentEncoding)) != "gzip" {
   665  		t.Fatalf("unexpected content-encoding: %q. Expecting %q", r.Header.Peek(consts.HeaderContentEncoding), "gzip")
   666  	}
   667  	if r.Header.ContentLength() != len(body) {
   668  		t.Fatalf("unexpected content-length: %d. Expecting %d", r.Header.ContentLength(), len(body))
   669  	}
   670  	if string(r.Body()) != string(body) {
   671  		t.Fatalf("unexpected body: %q. Expecting %q", r.Body(), body)
   672  	}
   673  
   674  	bodyGunzipped, err := compress.AppendGunzipBytes(nil, r.Body())
   675  	if err != nil {
   676  		t.Fatalf("unexpected error when uncompressing data: %s", err)
   677  	}
   678  	if string(bodyGunzipped) != bodyOriginal {
   679  		t.Fatalf("unexpected uncompressed body %q. Expecting %q", bodyGunzipped, bodyOriginal)
   680  	}
   681  }
   682  
   683  func TestRequestReadPostNoBody(t *testing.T) {
   684  	t.Parallel()
   685  
   686  	var r protocol.Request
   687  
   688  	s := "POST /foo/bar HTTP/1.1\r\nContent-Type: aaa/bbb\r\n\r\naaaa"
   689  	zr := mock.NewZeroCopyReader(s)
   690  	if err := Read(&r, zr); err != nil {
   691  		t.Fatalf("unexpected error: %s", err)
   692  	}
   693  
   694  	if string(r.Header.RequestURI()) != "/foo/bar" {
   695  		t.Fatalf("unexpected request uri %q. Expecting %q", r.Header.RequestURI(), "/foo/bar")
   696  	}
   697  	if string(r.Header.ContentType()) != "aaa/bbb" {
   698  		t.Fatalf("unexpected content-type %q. Expecting %q", r.Header.ContentType(), "aaa/bbb")
   699  	}
   700  	if len(r.Body()) != 0 {
   701  		t.Fatalf("unexpected body found %q. Expecting empty body", r.Body())
   702  	}
   703  	if r.Header.ContentLength() != 0 {
   704  		t.Fatalf("unexpected content-length: %d. Expecting 0", r.Header.ContentLength())
   705  	}
   706  
   707  	tail, err := ioutil.ReadAll(zr)
   708  	if err != nil {
   709  		t.Fatalf("unexpected error: %s", err)
   710  	}
   711  	if string(tail) != "aaaa" {
   712  		t.Fatalf("unexpected tail %q. Expecting %q", tail, "aaaa")
   713  	}
   714  }
   715  
   716  func TestRequestContinueReadBodyDisablePrereadMultipartForm(t *testing.T) {
   717  	t.Parallel()
   718  
   719  	var w bytes.Buffer
   720  	mw := multipart.NewWriter(&w)
   721  	for i := 0; i < 10; i++ {
   722  		k := fmt.Sprintf("key_%d", i)
   723  		v := fmt.Sprintf("value_%d", i)
   724  		if err := mw.WriteField(k, v); err != nil {
   725  			t.Fatalf("unexpected error: %s", err)
   726  		}
   727  	}
   728  	boundary := mw.Boundary()
   729  	if err := mw.Close(); err != nil {
   730  		t.Fatalf("unexpected error: %s", err)
   731  	}
   732  	formData := w.Bytes()
   733  
   734  	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",
   735  		boundary, len(formData), formData)
   736  	zr := mock.NewZeroCopyReader(s)
   737  
   738  	var r protocol.Request
   739  
   740  	if err := ReadHeader(&r.Header, zr); err != nil {
   741  		t.Fatalf("unexpected error reading headers: %s", err)
   742  	}
   743  
   744  	if err := ReadLimitBody(&r, zr, 10000, false, false); err != nil {
   745  		t.Fatalf("unexpected error reading body: %s", err)
   746  	}
   747  
   748  	if r.HasMultipartForm() {
   749  		t.Fatalf("The multipartForm of the Request must be nil")
   750  	}
   751  
   752  	if string(formData) != string(r.Body()) {
   753  		t.Fatalf("The body given must equal the body in the Request")
   754  	}
   755  }
   756  
   757  func TestRequestReadLimitBody(t *testing.T) {
   758  	t.Parallel()
   759  
   760  	testRequestReadLimitBodyReadOnly(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789")
   761  	// request with content-length
   762  	testRequestReadLimitBodySuccess(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 9)
   763  	testRequestReadLimitBodySuccess(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 92)
   764  	testRequestReadLimitBodyError(t, "POST /foo HTTP/1.1\r\nHost: aaa.com\r\nContent-Length: 9\r\nContent-Type: aaa\r\n\r\n123456789", 5)
   765  
   766  	// chunked request
   767  	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)
   768  	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)
   769  	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)
   770  }
   771  
   772  func testRequestReadLimitBodyReadOnly(t *testing.T, s string) {
   773  	var req protocol.Request
   774  	zr := mock.NewZeroCopyReader(s)
   775  
   776  	ReadHeader(&req.Header, zr)
   777  	if err := ReadLimitBody(&req, zr, 10, true, false); err == nil {
   778  		t.Fatalf("expected error: %s", errGetOnly.Error())
   779  	}
   780  }
   781  
   782  func TestRequestString(t *testing.T) {
   783  	t.Parallel()
   784  
   785  	var r protocol.Request
   786  	r.SetRequestURI("http://foobar.com/aaa")
   787  	s := GetHTTP1Request(&r).String()
   788  	expectedS := "GET /aaa HTTP/1.1\r\nHost: foobar.com\r\n\r\n"
   789  	if s != expectedS {
   790  		t.Fatalf("unexpected request: %q. Expecting %q", s, expectedS)
   791  	}
   792  }
   793  
   794  func TestRequestReadChunked(t *testing.T) {
   795  	t.Parallel()
   796  
   797  	var req protocol.Request
   798  
   799  	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"
   800  	zr := netpoll.NewReader(bytes.NewBufferString(s))
   801  	err := Read(&req, zr)
   802  	if err != nil {
   803  		t.Fatalf("Unexpected error when reading chunked request: %s", err)
   804  	}
   805  	expectedBody := "abc12345"
   806  	if string(req.Body()) != expectedBody {
   807  		t.Fatalf("Unexpected body %q. Expected %q", req.Body(), expectedBody)
   808  	}
   809  	verifyRequestHeader(t, &req.Header, 8, "/foo", "google.com", "", "aa/bb")
   810  	verifyTrailer(t, zr, map[string]string{"Trail": "test"})
   811  }
   812  
   813  func verifyTrailer(t *testing.T, r network.Reader, exceptedTrailers map[string]string) {
   814  	trailer := protocol.Trailer{}
   815  	keys := make([]string, 0, len(exceptedTrailers))
   816  	for k := range exceptedTrailers {
   817  		keys = append(keys, k)
   818  	}
   819  	trailer.SetTrailers([]byte(strings.Join(keys, ", ")))
   820  	err := ext.ReadTrailer(&trailer, r)
   821  	if err == io.EOF && exceptedTrailers == nil {
   822  		return
   823  	}
   824  	if err != nil {
   825  		t.Fatalf("Cannot read trailer: %v", err)
   826  	}
   827  
   828  	for k, v := range exceptedTrailers {
   829  		got := trailer.Peek(k)
   830  		if !bytes.Equal(got, []byte(v)) {
   831  			t.Fatalf("Unexpected trailer %q. Expected %q. Got %q", k, v, got)
   832  		}
   833  	}
   834  }
   835  
   836  func TestRequestChunkedWhitespace(t *testing.T) {
   837  	t.Parallel()
   838  
   839  	var req protocol.Request
   840  
   841  	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\n0\r\n\r\n"
   842  	zr := mock.NewZeroCopyReader(s)
   843  
   844  	err := Read(&req, zr)
   845  	if err != nil {
   846  		t.Fatalf("Unexpected error when reading chunked request: %s", err)
   847  	}
   848  	expectedBody := "abc"
   849  	if string(req.Body()) != expectedBody {
   850  		t.Fatalf("Unexpected body %q. Expected %q", req.Body(), expectedBody)
   851  	}
   852  }
   853  
   854  func testRequestReadLimitBodyError(t *testing.T, s string, maxBodySize int) {
   855  	var req protocol.Request
   856  	zr := mock.NewZeroCopyReader(s)
   857  
   858  	err := ReadHeaderAndLimitBody(&req, zr, maxBodySize)
   859  	if err == nil {
   860  		t.Fatalf("expecting error. s=%q, maxBodySize=%d", s, maxBodySize)
   861  	}
   862  	if !errors.Is(err, errs.ErrBodyTooLarge) {
   863  		t.Fatalf("unexpected error: %s. Expecting %s. s=%q, maxBodySize=%d", err, errBodyTooLarge, s, maxBodySize)
   864  	}
   865  }
   866  
   867  func testRequestReadLimitBodySuccess(t *testing.T, s string, maxBodySize int) {
   868  	var req protocol.Request
   869  	zr := mock.NewZeroCopyReader(s)
   870  	if err := ReadHeaderAndLimitBody(&req, zr, maxBodySize); err != nil {
   871  		t.Fatalf("unexpected error: %s. s=%q, maxBodySize=%d", err, s, maxBodySize)
   872  	}
   873  }
   874  
   875  func testSetRequestBodyStream(t *testing.T, body string) {
   876  	var req protocol.Request
   877  	req.Header.SetHost("foobar.com")
   878  	req.Header.SetMethod(consts.MethodPost)
   879  
   880  	bodySize := len(body)
   881  	if req.IsBodyStream() {
   882  		t.Fatalf("IsBodyStream must return false")
   883  	}
   884  	req.SetBodyStream(bytes.NewBufferString(body), bodySize)
   885  	if !req.IsBodyStream() {
   886  		t.Fatalf("IsBodyStream must return true")
   887  	}
   888  
   889  	var w bytes.Buffer
   890  	zw := netpoll.NewWriter(&w)
   891  	if err := Write(&req, zw); err != nil {
   892  		t.Fatalf("unexpected error when writing request: %s. body=%q", err, body)
   893  	}
   894  
   895  	if err := zw.Flush(); err != nil {
   896  		t.Fatalf("unexpected error when flushing request: %s. body=%q", err, body)
   897  	}
   898  
   899  	var req1 protocol.Request
   900  	br := bufio.NewReader(&w)
   901  	zr := netpoll.NewReader(br)
   902  	if err := Read(&req1, zr); err != nil {
   903  		t.Fatalf("unexpected error when reading request: %s. body=%q", err, body)
   904  	}
   905  	if string(req1.Body()) != body {
   906  		fmt.Println(string(req1.Body()))
   907  		fmt.Println(body)
   908  		t.Fatalf("unexpected body %q. Expecting %q", req1.Body(), body)
   909  	}
   910  }
   911  
   912  func testSetRequestBodyStreamChunked(t *testing.T, body string, trailer map[string]string) {
   913  	var req protocol.Request
   914  	req.Header.SetHost("foobar.com")
   915  	req.Header.SetMethod(consts.MethodPost)
   916  
   917  	if req.IsBodyStream() {
   918  		t.Fatalf("IsBodyStream must return false")
   919  	}
   920  	req.SetBodyStream(bytes.NewBufferString(body), -1)
   921  	if !req.IsBodyStream() {
   922  		t.Fatalf("IsBodyStream must return true")
   923  	}
   924  
   925  	var w bytes.Buffer
   926  	zw := netpoll.NewWriter(&w)
   927  	for k, v := range trailer {
   928  		err := req.Header.Trailer().Add(k, v)
   929  		if err != nil {
   930  			t.Fatalf("unexpected error: %v", err)
   931  		}
   932  	}
   933  	if err := Write(&req, zw); err != nil {
   934  		t.Fatalf("unexpected error when writing request: %v, body=%q", err, body)
   935  	}
   936  	if err := zw.Flush(); err != nil {
   937  		t.Fatalf("unexpected error when flushing request: %v, body=%q", err, body)
   938  	}
   939  
   940  	var req1 protocol.Request
   941  	br := bufio.NewReader(&w)
   942  	zr := netpoll.NewReader(br)
   943  	if err := Read(&req1, zr); err != nil {
   944  		t.Fatalf("unexpected error when reading request: %v. body=%q", err, body)
   945  	}
   946  	if string(req1.Body()) != body {
   947  		t.Fatalf("unexpected body %q. Expecting %q", req1.Body(), body)
   948  	}
   949  	for k, v := range trailer {
   950  		r := req.Header.Trailer().Peek(k)
   951  		if string(r) != v {
   952  			t.Fatalf("unexpected trailer %q. Expecting %q. Got %q", k, v, r)
   953  		}
   954  	}
   955  }
   956  
   957  func TestRequestMultipartForm(t *testing.T) {
   958  	t.Parallel()
   959  
   960  	var w bytes.Buffer
   961  	mw := multipart.NewWriter(&w)
   962  	for i := 0; i < 10; i++ {
   963  		k := fmt.Sprintf("key_%d", i)
   964  		v := fmt.Sprintf("value_%d", i)
   965  		if err := mw.WriteField(k, v); err != nil {
   966  			t.Fatalf("unexpected error: %s", err)
   967  		}
   968  	}
   969  	boundary := mw.Boundary()
   970  	if err := mw.Close(); err != nil {
   971  		t.Fatalf("unexpected error: %s", err)
   972  	}
   973  
   974  	formData := w.Bytes()
   975  	for i := 0; i < 5; i++ {
   976  		formData = testRequestMultipartForm(t, boundary, formData, 10)
   977  		testRequestMultipartFormNotPreParse(t, boundary, formData, 10)
   978  	}
   979  
   980  	// verify request unmarshalling / marshalling
   981  	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"
   982  	var r protocol.Request
   983  	zr := mock.NewZeroCopyReader(s)
   984  	if err := Read(&r, zr); err != nil {
   985  		t.Fatalf("unexpected error: %s", err)
   986  	}
   987  
   988  	s = GetHTTP1Request(&r).String()
   989  	zr = mock.NewZeroCopyReader(s)
   990  	if err := Read(&r, zr); err != nil {
   991  		t.Fatalf("unexpected error: %s", err)
   992  	}
   993  	testRequestMultipartForm(t, "foobar", r.Body(), 3)
   994  }
   995  
   996  func testRequestMultipartForm(t *testing.T, boundary string, formData []byte, partsCount int) []byte {
   997  	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",
   998  		boundary, len(formData), formData)
   999  	var req protocol.Request
  1000  
  1001  	zr := mock.NewZeroCopyReader(s)
  1002  	if err := Read(&req, zr); err != nil {
  1003  		t.Fatalf("unexpected error: %s", err)
  1004  	}
  1005  
  1006  	f, err := req.MultipartForm()
  1007  	if err != nil {
  1008  		t.Fatalf("unexpected error: %s", err)
  1009  	}
  1010  	defer req.RemoveMultipartFormFiles()
  1011  
  1012  	if len(f.File) > 0 {
  1013  		t.Fatalf("unexpected files found in the multipart form: %d", len(f.File))
  1014  	}
  1015  
  1016  	if len(f.Value) != partsCount {
  1017  		t.Fatalf("unexpected number of values found: %d. Expecting %d", len(f.Value), partsCount)
  1018  	}
  1019  
  1020  	for k, vv := range f.Value {
  1021  		if len(vv) != 1 {
  1022  			t.Fatalf("unexpected number of values found for key=%q: %d. Expecting 1", k, len(vv))
  1023  		}
  1024  		if !strings.HasPrefix(k, "key_") {
  1025  			t.Fatalf("unexpected key prefix=%q. Expecting %q", k, "key_")
  1026  		}
  1027  		v := vv[0]
  1028  		if !strings.HasPrefix(v, "value_") {
  1029  			t.Fatalf("unexpected value prefix=%q. expecting %q", v, "value_")
  1030  		}
  1031  		if k[len("key_"):] != v[len("value_"):] {
  1032  			t.Fatalf("key and value suffixes don't match: %q vs %q", k, v)
  1033  		}
  1034  	}
  1035  
  1036  	return req.Body()
  1037  }
  1038  
  1039  func testRequestMultipartFormNotPreParse(t *testing.T, boundary string, formData []byte, partsCount int) []byte {
  1040  	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",
  1041  		boundary, len(formData), formData)
  1042  	var req protocol.Request
  1043  
  1044  	zr := mock.NewZeroCopyReader(s)
  1045  	if err := Read(&req, zr, false); err != nil {
  1046  		t.Fatalf("unexpected error: %s", err)
  1047  	}
  1048  	f, err := req.MultipartForm()
  1049  	if err != nil {
  1050  		t.Fatalf("unexpected error: %s", err)
  1051  	}
  1052  	defer req.RemoveMultipartFormFiles()
  1053  
  1054  	if len(f.File) > 0 {
  1055  		t.Fatalf("unexpected files found in the multipart form: %d", len(f.File))
  1056  	}
  1057  
  1058  	if len(f.Value) != partsCount {
  1059  		t.Fatalf("unexpected number of values found: %d. Expecting %d", len(f.Value), partsCount)
  1060  	}
  1061  
  1062  	for k, vv := range f.Value {
  1063  		if len(vv) != 1 {
  1064  			t.Fatalf("unexpected number of values found for key=%q: %d. Expecting 1", k, len(vv))
  1065  		}
  1066  		if !strings.HasPrefix(k, "key_") {
  1067  			t.Fatalf("unexpected key prefix=%q. Expecting %q", k, "key_")
  1068  		}
  1069  		v := vv[0]
  1070  		if !strings.HasPrefix(v, "value_") {
  1071  			t.Fatalf("unexpected value prefix=%q. expecting %q", v, "value_")
  1072  		}
  1073  		if k[len("key_"):] != v[len("value_"):] {
  1074  			t.Fatalf("key and value suffixes don't match: %q vs %q", k, v)
  1075  		}
  1076  	}
  1077  
  1078  	return req.Body()
  1079  }
  1080  
  1081  func testReadBodyChunked(t *testing.T, bodySize int) {
  1082  	body := mock.CreateFixedBody(bodySize)
  1083  	expectedTrailer := map[string]string{"Foo": "chunked shit"}
  1084  	chunkedBody := mock.CreateChunkedBody(body, expectedTrailer, true)
  1085  
  1086  	zr := mock.NewZeroCopyReader(string(chunkedBody))
  1087  
  1088  	// p,_ := mr.Next(3687)
  1089  	b, err := ext.ReadBody(zr, -1, 0, nil)
  1090  	if err != nil {
  1091  		t.Fatalf("Unexpected error for bodySize=%d: %s. body=%q, chunkedBody=%q", bodySize, err, body, chunkedBody)
  1092  	}
  1093  	if !bytes.Equal(b, body) {
  1094  		t.Fatalf("Unexpected response read for bodySize=%d: %q. Expected %q. chunkedBody=%q", bodySize, b, body, chunkedBody)
  1095  	}
  1096  	verifyTrailer(t, zr, expectedTrailer)
  1097  }
  1098  
  1099  func testReadBodyFixedSize(t *testing.T, bodySize int) {
  1100  	body := mock.CreateFixedBody(bodySize)
  1101  
  1102  	zr := mock.NewZeroCopyReader(string(body))
  1103  	b, err := ext.ReadBody(zr, bodySize, 0, nil)
  1104  	if err != nil {
  1105  		t.Fatalf("Unexpected error in ReadResponseBody(%d): %s", bodySize, err)
  1106  	}
  1107  	if !bytes.Equal(b, body) {
  1108  		t.Fatalf("Unexpected response read for bodySize=%d: %q. Expected %q", bodySize, b, body)
  1109  	}
  1110  	verifyTrailer(t, zr, nil)
  1111  }
  1112  
  1113  func TestRequestFormFile(t *testing.T) {
  1114  	t.Parallel()
  1115  
  1116  	s := `POST /upload HTTP/1.1
  1117  Host: localhost:10000
  1118  Content-Length: 521
  1119  Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg
  1120  
  1121  ------WebKitFormBoundaryJwfATyF8tmxSJnLg
  1122  Content-Disposition: form-data; name="f1"
  1123  
  1124  value1
  1125  ------WebKitFormBoundaryJwfATyF8tmxSJnLg
  1126  Content-Disposition: form-data; name="fileaaa"; filename="TODO"
  1127  Content-Type: application/octet-stream
  1128  
  1129  - SessionClient with referer and cookies support.
  1130  - Client with requests' pipelining support.
  1131  - ProxyHandler similar to FSHandler.
  1132  - WebSockets. See https://tools.ietf.org/html/rfc6455 .
  1133  - HTTP/2.0. See https://tools.ietf.org/html/rfc7540 .
  1134  
  1135  ------WebKitFormBoundaryJwfATyF8tmxSJnLg--
  1136  tailfoobar`
  1137  
  1138  	mr := mock.NewZeroCopyReader(s)
  1139  
  1140  	var r protocol.Request
  1141  	if err := Read(&r, mr); err != nil {
  1142  		t.Fatalf("unexpected error: %s", err)
  1143  	}
  1144  
  1145  	tail, err := ioutil.ReadAll(mr)
  1146  	if err != nil {
  1147  		t.Fatalf("unexpected error: %s", err)
  1148  	}
  1149  	if string(tail) != "tailfoobar" {
  1150  		t.Fatalf("unexpected tail %q. Expecting %q", tail, "tailfoobar")
  1151  	}
  1152  	fh, err := r.FormFile("fileaaa")
  1153  	if err != nil {
  1154  		t.Fatalf("TestRequestFormFile error: %#v", err.Error())
  1155  	}
  1156  	if fh == nil {
  1157  		t.Fatalf("fh unexpected nil")
  1158  	}
  1159  }
  1160  
  1161  func TestRequest_ContinueReadBodyStream(t *testing.T) {
  1162  	// small body
  1163  	genBody := "abcdef4343"
  1164  	s := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 5\r\nContent-Type: foo/bar\r\n\r\n"
  1165  	testContinueReadBodyStream(t, s, genBody, 10, 5, 0, 5)
  1166  	testContinueReadBodyStream(t, s, genBody, 1, 5, 0, 0)
  1167  
  1168  	// big body (> 8193)
  1169  	s1 := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 9216\r\nContent-Type: foo/bar\r\n\r\n"
  1170  	genBody = strings.Repeat("1", 9*1024)
  1171  	testContinueReadBodyStream(t, s1, genBody, 10*1024, 5*1024, 4*1024, 0)
  1172  	testContinueReadBodyStream(t, s1, genBody, 10*1024, 1*1024, 8*1024, 0)
  1173  	testContinueReadBodyStream(t, s1, genBody, 10*1024, 9*1024, 0*1024, 0)
  1174  
  1175  	// normal stream
  1176  	testContinueReadBodyStream(t, s1, genBody, 1*1024, 5*1024, 4*1024, 0)
  1177  	testContinueReadBodyStream(t, s1, genBody, 1*1024, 1*1024, 8*1024, 0)
  1178  	testContinueReadBodyStream(t, s1, genBody, 1*1024, 9*1024, 0*1024, 0)
  1179  	testContinueReadBodyStream(t, s1, genBody, 5, 5*1024, 4*1024, 0)
  1180  	testContinueReadBodyStream(t, s1, genBody, 5, 1*1024, 8*1024, 0)
  1181  	testContinueReadBodyStream(t, s1, genBody, 5, 9*1024, 0, 0)
  1182  
  1183  	// critical point
  1184  	testContinueReadBodyStream(t, s1, genBody, 8*1024+1, 5*1024, 4*1024, 0)
  1185  	testContinueReadBodyStream(t, s1, genBody, 8*1024+1, 1*1024, 8*1024, 0)
  1186  	testContinueReadBodyStream(t, s1, genBody, 8*1024+1, 9*1024, 0*1024, 0)
  1187  
  1188  	// chunked body
  1189  	s2 := "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"
  1190  	testContinueReadBodyStream(t, s2, "", 10*1024, 3, 5, 5)
  1191  	s3 := "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\n"
  1192  	testContinueReadBodyStream(t, s3, "", 10*1024, 3, 5, 0)
  1193  }
  1194  
  1195  func TestRequest_Chunked(t *testing.T) {
  1196  	t.Parallel()
  1197  	s4 := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n5\r\n12345\r\n0\r\n\r\n"
  1198  	testReadChunked(t, s4, "", 3, 2)
  1199  
  1200  	s5 := "POST /foo HTTP/1.1\r\nHost: google.com\r\nTransfer-Encoding: chunked\r\nContent-Type: aa/bb\r\n\r\n5\r\n12345\r\n3\r\n1230\r\n\r\n"
  1201  	testReadChunked(t, s5, "", 3, 5)
  1202  }
  1203  
  1204  func TestRequest_ReadIncompleteStream(t *testing.T) {
  1205  	t.Parallel()
  1206  	// small body
  1207  	genBody := "abcdef4343"
  1208  	s := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 100\r\nContent-Type: foo/bar\r\n\r\n"
  1209  	testReadIncompleteStream(t, s, genBody)
  1210  
  1211  	// big body (> 8193)
  1212  	s1 := "PUT /foo/bar HTTP/1.1\r\nExpect: 100-continue\r\nContent-Length: 10000\r\nContent-Type: foo/bar\r\n\r\n"
  1213  	genBody = strings.Repeat("1", 9*1024)
  1214  	testReadIncompleteStream(t, s1, genBody)
  1215  }
  1216  
  1217  func testReadIncompleteStream(t *testing.T, header, body string) {
  1218  	mr := mock.NewZeroCopyReader(header + body)
  1219  	var r protocol.Request
  1220  	if err := ReadHeader(&r.Header, mr); err != nil {
  1221  		t.Fatalf("unexpected error: %s", err)
  1222  	}
  1223  	if err := ContinueReadBodyStream(&r, mr, 1, true); err != nil {
  1224  		t.Fatalf("error when reading request body stream: %s", err)
  1225  	}
  1226  	readBody, err := ioutil.ReadAll(r.BodyStream())
  1227  	if !bytes.Equal(readBody, []byte(body)) || len(readBody) != len(body) {
  1228  		t.Fatalf("readBody is not equal to the rawBody: %b(len: %d)", readBody, len(readBody))
  1229  	}
  1230  	if err != io.ErrUnexpectedEOF {
  1231  		t.Fatalf("error should be io.ErrUnexpectedEOF, but got: %s", err)
  1232  	}
  1233  }
  1234  
  1235  func testReadChunked(t *testing.T, header, body string, firstRead, leftBytes int) {
  1236  	mr := mock.NewZeroCopyReader(header + body)
  1237  
  1238  	var r protocol.Request
  1239  	if err := ReadHeader(&r.Header, mr); err != nil {
  1240  		t.Fatalf("unexpected error: %s", err)
  1241  	}
  1242  	if err := ContinueReadBodyStream(&r, mr, 2048, true); err != nil {
  1243  		t.Fatalf("error when reading request body stream: %s", err)
  1244  	}
  1245  	if r.Header.ContentLength() >= 0 {
  1246  		t.Fatalf("expect a chunked body")
  1247  	}
  1248  	streamRead := make([]byte, firstRead)
  1249  	fr, err := r.BodyStream().Read(streamRead)
  1250  	if err != nil {
  1251  		t.Fatalf("read stream error=%v", err)
  1252  	}
  1253  	if fr != firstRead {
  1254  		t.Fatalf("should read %d from stream body, but got %d", streamRead, fr)
  1255  	}
  1256  	leftB, _ := ioutil.ReadAll(r.BodyStream())
  1257  	if len(leftB) != leftBytes {
  1258  		t.Fatalf("should left %d bytes from stream body, but left %d", leftBytes, len(leftB))
  1259  	}
  1260  }
  1261  
  1262  func testContinueReadBodyStream(t *testing.T, header, body string, maxBodySize, firstRead, leftBytes, bytesLeftInReader int) {
  1263  	mr := mock.NewZeroCopyReader(header + body)
  1264  	var r protocol.Request
  1265  	if err := ReadHeader(&r.Header, mr); err != nil {
  1266  		t.Fatalf("unexpected error: %s", err)
  1267  	}
  1268  	if err := ContinueReadBodyStream(&r, mr, maxBodySize, true); err != nil {
  1269  		t.Fatalf("error when reading request body stream: %s", err)
  1270  	}
  1271  	fRead := firstRead
  1272  	streamRead := make([]byte, fRead)
  1273  	sR, _ := r.BodyStream().Read(streamRead)
  1274  
  1275  	if sR != firstRead {
  1276  		t.Fatalf("should read %d from stream body, but got %d", firstRead, sR)
  1277  	}
  1278  
  1279  	leftB, _ := ioutil.ReadAll(r.BodyStream())
  1280  	if len(leftB) != leftBytes {
  1281  		t.Fatalf("should left %d bytes from stream body, but left %d", leftBytes, len(leftB))
  1282  	}
  1283  	if r.Header.ContentLength() > 0 {
  1284  		gotBody := append(streamRead, leftB...)
  1285  		if !bytes.Equal([]byte(body[:r.Header.ContentLength()]), gotBody) {
  1286  			t.Fatalf("body read from stream is not equal to the origin. Got: %s", gotBody)
  1287  		}
  1288  	}
  1289  
  1290  	left, _ := mr.Peek(mr.Len())
  1291  
  1292  	if len(left) != bytesLeftInReader {
  1293  		fmt.Printf("##########header:%s,body:%s,%d:max,first:%d,left:%d,leftin:%d\n", header, body, maxBodySize, firstRead, leftBytes, bytesLeftInReader)
  1294  		fmt.Printf("##########left: %s\n", left)
  1295  		t.Fatalf("should left %d bytes in original reader. got %q", bytesLeftInReader, len(left))
  1296  	}
  1297  }
  1298  
  1299  func verifyRequestHeader(t *testing.T, h *protocol.RequestHeader, expectedContentLength int,
  1300  	expectedRequestURI, expectedHost, expectedReferer, expectedContentType string,
  1301  ) {
  1302  	if h.ContentLength() != expectedContentLength {
  1303  		t.Fatalf("Unexpected Content-Length %d. Expected %d", h.ContentLength(), expectedContentLength)
  1304  	}
  1305  	if string(h.RequestURI()) != expectedRequestURI {
  1306  		t.Fatalf("Unexpected RequestURI %q. Expected %q", h.RequestURI(), expectedRequestURI)
  1307  	}
  1308  	if string(h.Peek(consts.HeaderHost)) != expectedHost {
  1309  		t.Fatalf("Unexpected host %q. Expected %q", h.Peek(consts.HeaderHost), expectedHost)
  1310  	}
  1311  	if string(h.Peek(consts.HeaderReferer)) != expectedReferer {
  1312  		t.Fatalf("Unexpected referer %q. Expected %q", h.Peek(consts.HeaderReferer), expectedReferer)
  1313  	}
  1314  	if string(h.Peek(consts.HeaderContentType)) != expectedContentType {
  1315  		t.Fatalf("Unexpected content-type %q. Expected %q", h.Peek(consts.HeaderContentType), expectedContentType)
  1316  	}
  1317  }
  1318  
  1319  func TestRequestReadMultipartFormWithFile(t *testing.T) {
  1320  	t.Parallel()
  1321  
  1322  	s := `POST /upload HTTP/1.1
  1323  Host: localhost:10000
  1324  Content-Length: 521
  1325  Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryJwfATyF8tmxSJnLg
  1326  
  1327  ------WebKitFormBoundaryJwfATyF8tmxSJnLg
  1328  Content-Disposition: form-data; name="f1"
  1329  
  1330  value1
  1331  ------WebKitFormBoundaryJwfATyF8tmxSJnLg
  1332  Content-Disposition: form-data; name="fileaaa"; filename="TODO"
  1333  Content-Type: application/octet-stream
  1334  
  1335  - SessionClient with referer and cookies support.
  1336  - Client with requests' pipelining support.
  1337  - ProxyHandler similar to FSHandler.
  1338  - WebSockets. See https://tools.ietf.org/html/rfc6455 .
  1339  - HTTP/2.0. See https://tools.ietf.org/html/rfc7540 .
  1340  
  1341  ------WebKitFormBoundaryJwfATyF8tmxSJnLg--
  1342  tailfoobar`
  1343  
  1344  	mr := mock.NewZeroCopyReader(s)
  1345  
  1346  	var r protocol.Request
  1347  	if err := Read(&r, mr); err != nil {
  1348  		t.Fatalf("unexpected error: %s", err)
  1349  	}
  1350  
  1351  	tail, err := ioutil.ReadAll(mr)
  1352  	if err != nil {
  1353  		t.Fatalf("unexpected error: %s", err)
  1354  	}
  1355  	if string(tail) != "tailfoobar" {
  1356  		t.Fatalf("unexpected tail %q. Expecting %q", tail, "tailfoobar")
  1357  	}
  1358  
  1359  	f, err := r.MultipartForm()
  1360  	if err != nil {
  1361  		t.Fatalf("unexpected error: %s", err)
  1362  	}
  1363  	defer r.RemoveMultipartFormFiles()
  1364  
  1365  	// verify values
  1366  	if len(f.Value) != 1 {
  1367  		t.Fatalf("unexpected number of values in multipart form: %d. Expecting 1", len(f.Value))
  1368  	}
  1369  	for k, vv := range f.Value {
  1370  		if k != "f1" {
  1371  			t.Fatalf("unexpected value name %q. Expecting %q", k, "f1")
  1372  		}
  1373  		if len(vv) != 1 {
  1374  			t.Fatalf("unexpected number of values %d. Expecting 1", len(vv))
  1375  		}
  1376  		v := vv[0]
  1377  		if v != "value1" {
  1378  			t.Fatalf("unexpected value %q. Expecting %q", v, "value1")
  1379  		}
  1380  	}
  1381  
  1382  	// verify files
  1383  	if len(f.File) != 1 {
  1384  		t.Fatalf("unexpected number of file values in multipart form: %d. Expecting 1", len(f.File))
  1385  	}
  1386  	for k, vv := range f.File {
  1387  		if k != "fileaaa" {
  1388  			t.Fatalf("unexpected file value name %q. Expecting %q", k, "fileaaa")
  1389  		}
  1390  		if len(vv) != 1 {
  1391  			t.Fatalf("unexpected number of file values %d. Expecting 1", len(vv))
  1392  		}
  1393  		v := vv[0]
  1394  		if v.Filename != "TODO" {
  1395  			t.Fatalf("unexpected filename %q. Expecting %q", v.Filename, "TODO")
  1396  		}
  1397  		ct := v.Header.Get("Content-Type")
  1398  		if ct != "application/octet-stream" {
  1399  			t.Fatalf("unexpected content-type %q. Expecting %q", ct, "application/octet-stream")
  1400  		}
  1401  	}
  1402  }
  1403  
  1404  func testRequestMultipartFormBoundary(t *testing.T, s, boundary string) {
  1405  	var h protocol.RequestHeader
  1406  	zr := mock.NewZeroCopyReader(s)
  1407  
  1408  	if err := ReadHeader(&h, zr); err != nil {
  1409  		t.Fatalf("unexpected error: %s. s=%q, boundary=%q", err, s, boundary)
  1410  	}
  1411  
  1412  	b := h.MultipartFormBoundary()
  1413  	if string(b) != boundary {
  1414  		t.Fatalf("unexpected boundary %q. Expecting %q. s=%q", b, boundary, s)
  1415  	}
  1416  }
  1417  
  1418  func TestStreamNotEnoughData(t *testing.T) {
  1419  	req := protocol.AcquireRequest()
  1420  	req.Header.SetContentLength(1 << 16)
  1421  	conn := mock.NewStreamConn()
  1422  	const maxBodySize = 4 * 1024 * 1024
  1423  	err := ContinueReadBodyStream(req, conn, maxBodySize)
  1424  	assert.Nil(t, err)
  1425  	err = ext.ReleaseBodyStream(req.BodyStream())
  1426  	assert.Nil(t, err)
  1427  	assert.DeepEqual(t, 0, len(conn.Data))
  1428  }
  1429  
  1430  func TestRequestBodyStreamWithTrailer(t *testing.T) {
  1431  	t.Parallel()
  1432  
  1433  	testRequestBodyStreamWithTrailer(t, []byte("test"), false)
  1434  	testRequestBodyStreamWithTrailer(t, mock.CreateFixedBody(4097), false)
  1435  	testRequestBodyStreamWithTrailer(t, mock.CreateFixedBody(105000), false)
  1436  }
  1437  
  1438  func testRequestBodyStreamWithTrailer(t *testing.T, body []byte, disableNormalizing bool) {
  1439  	expectedTrailer := map[string]string{
  1440  		"foo": "testfoo",
  1441  		"bar": "testbar",
  1442  	}
  1443  
  1444  	var req1 protocol.Request
  1445  	if disableNormalizing {
  1446  		req1.Header.DisableNormalizing()
  1447  	}
  1448  	req1.SetHost("google.com")
  1449  	req1.SetBodyStream(bytes.NewBuffer(body), -1)
  1450  	for k, v := range expectedTrailer {
  1451  		err := req1.Header.Trailer().Set(k, v)
  1452  		if err != nil {
  1453  			t.Fatalf("unexpected error: %s", err)
  1454  		}
  1455  	}
  1456  
  1457  	w := &bytes.Buffer{}
  1458  	zw := netpoll.NewWriter(w)
  1459  	if err := Write(&req1, zw); err != nil {
  1460  		t.Fatalf("unexpected error: %s", err)
  1461  	}
  1462  	if err := zw.Flush(); err != nil {
  1463  		t.Fatalf("unexpected error: %s", err)
  1464  	}
  1465  
  1466  	var req2 protocol.Request
  1467  	if disableNormalizing {
  1468  		req2.Header.DisableNormalizing()
  1469  	}
  1470  
  1471  	br := netpoll.NewReader(w)
  1472  	if err := Read(&req2, br); err != nil {
  1473  		t.Fatalf("unexpected error: %s", err)
  1474  	}
  1475  
  1476  	reqBody := req2.Body()
  1477  	if !bytes.Equal(reqBody, body) {
  1478  		t.Fatalf("unexpected body: %q. Excepting %q", reqBody, body)
  1479  	}
  1480  
  1481  	for k, v := range expectedTrailer {
  1482  		kBytes := []byte(k)
  1483  		utils.NormalizeHeaderKey(kBytes, disableNormalizing)
  1484  		r := req2.Header.Trailer().Peek(k)
  1485  		if string(r) != v {
  1486  			t.Fatalf("unexpected trailer header %q: %q. Expecting %s", kBytes, r, v)
  1487  		}
  1488  	}
  1489  }