github.com/useflyent/fhttp@v0.0.0-20211004035111-333f430cfbbf/request_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package http_test
     6  
     7  import (
     8  	"bufio"
     9  	"bytes"
    10  	"context"
    11  	"crypto/rand"
    12  	"encoding/base64"
    13  	"fmt"
    14  	"io"
    15  	"math"
    16  	"mime/multipart"
    17  	"net/url"
    18  	"os"
    19  	"reflect"
    20  	"regexp"
    21  	"strings"
    22  	"testing"
    23  
    24  	. "github.com/useflyent/fhttp"
    25  	"github.com/useflyent/fhttp/httptest"
    26  )
    27  
    28  func TestQuery(t *testing.T) {
    29  	req := &Request{Method: "GET"}
    30  	req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
    31  	if q := req.FormValue("q"); q != "foo" {
    32  		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
    33  	}
    34  }
    35  
    36  func TestParseFormQuery(t *testing.T) {
    37  	req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&orphan=nope&empty=not",
    38  		strings.NewReader("z=post&both=y&prio=2&=nokey&orphan;empty=&"))
    39  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
    40  
    41  	if q := req.FormValue("q"); q != "foo" {
    42  		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
    43  	}
    44  	if z := req.FormValue("z"); z != "post" {
    45  		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
    46  	}
    47  	if bq, found := req.PostForm["q"]; found {
    48  		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
    49  	}
    50  	if bz := req.PostFormValue("z"); bz != "post" {
    51  		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
    52  	}
    53  	if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
    54  		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
    55  	}
    56  	if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
    57  		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
    58  	}
    59  	if prio := req.FormValue("prio"); prio != "2" {
    60  		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
    61  	}
    62  	if orphan := req.Form["orphan"]; !reflect.DeepEqual(orphan, []string{"", "nope"}) {
    63  		t.Errorf(`req.FormValue("orphan") = %q, want "" (from body)`, orphan)
    64  	}
    65  	if empty := req.Form["empty"]; !reflect.DeepEqual(empty, []string{"", "not"}) {
    66  		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
    67  	}
    68  	if nokey := req.Form[""]; !reflect.DeepEqual(nokey, []string{"nokey"}) {
    69  		t.Errorf(`req.FormValue("nokey") = %q, want "nokey" (from body)`, nokey)
    70  	}
    71  }
    72  
    73  // Tests that we only parse the form automatically for certain methods.
    74  func TestParseFormQueryMethods(t *testing.T) {
    75  	for _, method := range []string{"POST", "PATCH", "PUT", "FOO"} {
    76  		req, _ := NewRequest(method, "http://www.google.com/search",
    77  			strings.NewReader("foo=bar"))
    78  		req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
    79  		want := "bar"
    80  		if method == "FOO" {
    81  			want = ""
    82  		}
    83  		if got := req.FormValue("foo"); got != want {
    84  			t.Errorf(`for method %s, FormValue("foo") = %q; want %q`, method, got, want)
    85  		}
    86  	}
    87  }
    88  
    89  func TestParseFormUnknownContentType(t *testing.T) {
    90  	for _, test := range []struct {
    91  		name        string
    92  		wantErr     string
    93  		contentType Header
    94  	}{
    95  		{"text", "", Header{"Content-Type": {"text/plain"}}},
    96  		// Empty content type is legal - may be treated as
    97  		// application/octet-stream (RFC 7231, section 3.1.1.5)
    98  		{"empty", "", Header{}},
    99  		{"boundary", "mime: invalid media parameter", Header{"Content-Type": {"text/plain; boundary="}}},
   100  		{"unknown", "", Header{"Content-Type": {"application/unknown"}}},
   101  	} {
   102  		t.Run(test.name,
   103  			func(t *testing.T) {
   104  				req := &Request{
   105  					Method: "POST",
   106  					Header: test.contentType,
   107  					Body:   io.NopCloser(strings.NewReader("body")),
   108  				}
   109  				err := req.ParseForm()
   110  				switch {
   111  				case err == nil && test.wantErr != "":
   112  					t.Errorf("unexpected success; want error %q", test.wantErr)
   113  				case err != nil && test.wantErr == "":
   114  					t.Errorf("want success, got error: %v", err)
   115  				case test.wantErr != "" && test.wantErr != fmt.Sprint(err):
   116  					t.Errorf("got error %q; want %q", err, test.wantErr)
   117  				}
   118  			},
   119  		)
   120  	}
   121  }
   122  
   123  func TestParseFormInitializeOnError(t *testing.T) {
   124  	nilBody, _ := NewRequest("POST", "http://www.google.com/search?q=foo", nil)
   125  	tests := []*Request{
   126  		nilBody,
   127  		{Method: "GET", URL: nil},
   128  	}
   129  	for i, req := range tests {
   130  		err := req.ParseForm()
   131  		if req.Form == nil {
   132  			t.Errorf("%d. Form not initialized, error %v", i, err)
   133  		}
   134  		if req.PostForm == nil {
   135  			t.Errorf("%d. PostForm not initialized, error %v", i, err)
   136  		}
   137  	}
   138  }
   139  
   140  func TestMultipartReader(t *testing.T) {
   141  	tests := []struct {
   142  		shouldError bool
   143  		contentType string
   144  	}{
   145  		{false, `multipart/form-data; boundary="foo123"`},
   146  		{false, `multipart/mixed; boundary="foo123"`},
   147  		{true, `text/plain`},
   148  	}
   149  
   150  	for i, test := range tests {
   151  		req := &Request{
   152  			Method: "POST",
   153  			Header: Header{"Content-Type": {test.contentType}},
   154  			Body:   io.NopCloser(new(bytes.Buffer)),
   155  		}
   156  		multipart, err := req.MultipartReader()
   157  		if test.shouldError {
   158  			if err == nil || multipart != nil {
   159  				t.Errorf("test %d: unexpectedly got nil-error (%v) or non-nil-multipart (%v)", i, err, multipart)
   160  			}
   161  			continue
   162  		}
   163  		if err != nil || multipart == nil {
   164  			t.Errorf("test %d: unexpectedly got error (%v) or nil-multipart (%v)", i, err, multipart)
   165  		}
   166  	}
   167  }
   168  
   169  // Issue 9305: ParseMultipartForm should populate PostForm too
   170  func TestParseMultipartFormPopulatesPostForm(t *testing.T) {
   171  	postData :=
   172  		`--xxx
   173  Content-Disposition: form-data; name="field1"
   174  
   175  value1
   176  --xxx
   177  Content-Disposition: form-data; name="field2"
   178  
   179  value2
   180  --xxx
   181  Content-Disposition: form-data; name="file"; filename="file"
   182  Content-Type: application/octet-stream
   183  Content-Transfer-Encoding: binary
   184  
   185  binary data
   186  --xxx--
   187  `
   188  	req := &Request{
   189  		Method: "POST",
   190  		Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
   191  		Body:   io.NopCloser(strings.NewReader(postData)),
   192  	}
   193  
   194  	initialFormItems := map[string]string{
   195  		"language": "Go",
   196  		"name":     "gopher",
   197  		"skill":    "go-ing",
   198  		"field2":   "initial-value2",
   199  	}
   200  
   201  	req.Form = make(url.Values)
   202  	for k, v := range initialFormItems {
   203  		req.Form.Add(k, v)
   204  	}
   205  
   206  	err := req.ParseMultipartForm(10000)
   207  	if err != nil {
   208  		t.Fatalf("unexpected multipart error %v", err)
   209  	}
   210  
   211  	wantForm := url.Values{
   212  		"language": []string{"Go"},
   213  		"name":     []string{"gopher"},
   214  		"skill":    []string{"go-ing"},
   215  		"field1":   []string{"value1"},
   216  		"field2":   []string{"initial-value2", "value2"},
   217  	}
   218  	if !reflect.DeepEqual(req.Form, wantForm) {
   219  		t.Fatalf("req.Form = %v, want %v", req.Form, wantForm)
   220  	}
   221  
   222  	wantPostForm := url.Values{
   223  		"field1": []string{"value1"},
   224  		"field2": []string{"value2"},
   225  	}
   226  	if !reflect.DeepEqual(req.PostForm, wantPostForm) {
   227  		t.Fatalf("req.PostForm = %v, want %v", req.PostForm, wantPostForm)
   228  	}
   229  }
   230  
   231  func TestParseMultipartForm(t *testing.T) {
   232  	req := &Request{
   233  		Method: "POST",
   234  		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
   235  		Body:   io.NopCloser(new(bytes.Buffer)),
   236  	}
   237  	err := req.ParseMultipartForm(25)
   238  	if err == nil {
   239  		t.Error("expected multipart EOF, got nil")
   240  	}
   241  
   242  	req.Header = Header{"Content-Type": {"text/plain"}}
   243  	err = req.ParseMultipartForm(25)
   244  	if err != ErrNotMultipart {
   245  		t.Error("expected ErrNotMultipart for text/plain")
   246  	}
   247  }
   248  
   249  // Issue #40430: Test that if maxMemory for ParseMultipartForm when combined with
   250  // the payload size and the internal leeway buffer size of 10MiB overflows, that we
   251  // correctly return an error.
   252  func TestMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T) {
   253  	defer afterTest(t)
   254  
   255  	payloadSize := 1 << 10
   256  	cst := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
   257  		// The combination of:
   258  		//      MaxInt64 + payloadSize + (internal spare of 10MiB)
   259  		// triggers the overflow. See issue https://golang.org/issue/40430/
   260  		if err := req.ParseMultipartForm(math.MaxInt64); err != nil {
   261  			Error(rw, err.Error(), StatusBadRequest)
   262  			return
   263  		}
   264  	}))
   265  	defer cst.Close()
   266  	fBuf := new(bytes.Buffer)
   267  	mw := multipart.NewWriter(fBuf)
   268  	mf, err := mw.CreateFormFile("file", "myfile.txt")
   269  	if err != nil {
   270  		t.Fatal(err)
   271  	}
   272  	if _, err := mf.Write(bytes.Repeat([]byte("abc"), payloadSize)); err != nil {
   273  		t.Fatal(err)
   274  	}
   275  	if err := mw.Close(); err != nil {
   276  		t.Fatal(err)
   277  	}
   278  	req, err := NewRequest("POST", cst.URL, fBuf)
   279  	if err != nil {
   280  		t.Fatal(err)
   281  	}
   282  	req.Header.Set("Content-Type", mw.FormDataContentType())
   283  	res, err := cst.Client().Do(req)
   284  	if err != nil {
   285  		t.Fatal(err)
   286  	}
   287  	res.Body.Close()
   288  	if g, w := res.StatusCode, StatusOK; g != w {
   289  		t.Fatalf("Status code mismatch: got %d, want %d", g, w)
   290  	}
   291  }
   292  
   293  func TestRedirect_h1(t *testing.T) { testRedirect(t, h1Mode) }
   294  func TestRedirect_h2(t *testing.T) { testRedirect(t, h2Mode) }
   295  func testRedirect(t *testing.T, h2 bool) {
   296  	defer afterTest(t)
   297  	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
   298  		switch r.URL.Path {
   299  		case "/":
   300  			w.Header().Set("Location", "/foo/")
   301  			w.WriteHeader(StatusSeeOther)
   302  		case "/foo/":
   303  			fmt.Fprintf(w, "foo")
   304  		default:
   305  			w.WriteHeader(StatusBadRequest)
   306  		}
   307  	}))
   308  	defer cst.close()
   309  
   310  	var end = regexp.MustCompile("/foo/$")
   311  	r, err := cst.c.Get(cst.ts.URL)
   312  	if err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	r.Body.Close()
   316  	url := r.Request.URL.String()
   317  	if r.StatusCode != 200 || !end.MatchString(url) {
   318  		t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
   319  	}
   320  }
   321  
   322  func TestSetBasicAuth(t *testing.T) {
   323  	r, _ := NewRequest("GET", "http://example.com/", nil)
   324  	r.SetBasicAuth("Aladdin", "open sesame")
   325  	if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e {
   326  		t.Errorf("got header %q, want %q", g, e)
   327  	}
   328  }
   329  
   330  func TestMultipartRequest(t *testing.T) {
   331  	// Test that we can read the Values and files of a
   332  	// multipart request with FormValue and FormFile,
   333  	// and that ParseMultipartForm can be called multiple times.
   334  	req := newTestMultipartRequest(t)
   335  	if err := req.ParseMultipartForm(25); err != nil {
   336  		t.Fatal("ParseMultipartForm first call:", err)
   337  	}
   338  	defer req.MultipartForm.RemoveAll()
   339  	validateTestMultipartContents(t, req, false)
   340  	if err := req.ParseMultipartForm(25); err != nil {
   341  		t.Fatal("ParseMultipartForm second call:", err)
   342  	}
   343  	validateTestMultipartContents(t, req, false)
   344  }
   345  
   346  func TestMultipartRequestAuto(t *testing.T) {
   347  	// Test that FormValue and FormFile automatically invoke
   348  	// ParseMultipartForm and return the right Values.
   349  	req := newTestMultipartRequest(t)
   350  	defer func() {
   351  		if req.MultipartForm != nil {
   352  			req.MultipartForm.RemoveAll()
   353  		}
   354  	}()
   355  	validateTestMultipartContents(t, req, true)
   356  }
   357  
   358  func TestMissingFileMultipartRequest(t *testing.T) {
   359  	// Test that FormFile returns an error if
   360  	// the named file is missing.
   361  	req := newTestMultipartRequest(t)
   362  	testMissingFile(t, req)
   363  }
   364  
   365  // Test that FormValue invokes ParseMultipartForm.
   366  func TestFormValueCallsParseMultipartForm(t *testing.T) {
   367  	req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
   368  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
   369  	if req.Form != nil {
   370  		t.Fatal("Unexpected request Form, want nil")
   371  	}
   372  	req.FormValue("z")
   373  	if req.Form == nil {
   374  		t.Fatal("ParseMultipartForm not called by FormValue")
   375  	}
   376  }
   377  
   378  // Test that FormFile invokes ParseMultipartForm.
   379  func TestFormFileCallsParseMultipartForm(t *testing.T) {
   380  	req := newTestMultipartRequest(t)
   381  	if req.Form != nil {
   382  		t.Fatal("Unexpected request Form, want nil")
   383  	}
   384  	req.FormFile("")
   385  	if req.Form == nil {
   386  		t.Fatal("ParseMultipartForm not called by FormFile")
   387  	}
   388  }
   389  
   390  // Test that ParseMultipartForm errors if called
   391  // after MultipartReader on the same request.
   392  func TestParseMultipartFormOrder(t *testing.T) {
   393  	req := newTestMultipartRequest(t)
   394  	if _, err := req.MultipartReader(); err != nil {
   395  		t.Fatalf("MultipartReader: %v", err)
   396  	}
   397  	if err := req.ParseMultipartForm(1024); err == nil {
   398  		t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
   399  	}
   400  }
   401  
   402  // Test that MultipartReader errors if called
   403  // after ParseMultipartForm on the same request.
   404  func TestMultipartReaderOrder(t *testing.T) {
   405  	req := newTestMultipartRequest(t)
   406  	if err := req.ParseMultipartForm(25); err != nil {
   407  		t.Fatalf("ParseMultipartForm: %v", err)
   408  	}
   409  	defer req.MultipartForm.RemoveAll()
   410  	if _, err := req.MultipartReader(); err == nil {
   411  		t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
   412  	}
   413  }
   414  
   415  // Test that FormFile errors if called after
   416  // MultipartReader on the same request.
   417  func TestFormFileOrder(t *testing.T) {
   418  	req := newTestMultipartRequest(t)
   419  	if _, err := req.MultipartReader(); err != nil {
   420  		t.Fatalf("MultipartReader: %v", err)
   421  	}
   422  	if _, _, err := req.FormFile(""); err == nil {
   423  		t.Fatal("expected an error from FormFile after call to MultipartReader")
   424  	}
   425  }
   426  
   427  var readRequestErrorTests = []struct {
   428  	in  string
   429  	err string
   430  
   431  	header Header
   432  }{
   433  	0: {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", "", Header{"Header": {"foo"}}},
   434  	1: {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF.Error(), nil},
   435  	2: {"", io.EOF.Error(), nil},
   436  	3: {
   437  		in:  "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
   438  		err: "http: method cannot contain a Content-Length",
   439  	},
   440  	4: {
   441  		in:     "HEAD / HTTP/1.1\r\n\r\n",
   442  		header: Header{},
   443  	},
   444  
   445  	// Multiple Content-Length Values should either be
   446  	// deduplicated if same or reject otherwise
   447  	// See Issue 16490.
   448  	5: {
   449  		in:  "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
   450  		err: "cannot contain multiple Content-Length headers",
   451  	},
   452  	6: {
   453  		in:  "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
   454  		err: "cannot contain multiple Content-Length headers",
   455  	},
   456  	7: {
   457  		in:     "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
   458  		err:    "",
   459  		header: Header{"Content-Length": {"6"}},
   460  	},
   461  	8: {
   462  		in:  "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
   463  		err: "cannot contain multiple Content-Length headers",
   464  	},
   465  	9: {
   466  		in:  "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
   467  		err: "cannot contain multiple Content-Length headers",
   468  	},
   469  	10: {
   470  		in:     "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
   471  		header: Header{"Content-Length": {"0"}},
   472  	},
   473  }
   474  
   475  func TestReadRequestErrors(t *testing.T) {
   476  	for i, tt := range readRequestErrorTests {
   477  		req, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
   478  		if err == nil {
   479  			if tt.err != "" {
   480  				t.Errorf("#%d: got nil err; want %q", i, tt.err)
   481  			}
   482  
   483  			if !reflect.DeepEqual(tt.header, req.Header) {
   484  				t.Errorf("#%d: gotHeader: %q wantHeader: %q", i, req.Header, tt.header)
   485  			}
   486  			continue
   487  		}
   488  
   489  		if tt.err == "" || !strings.Contains(err.Error(), tt.err) {
   490  			t.Errorf("%d: got error = %v; want %v", i, err, tt.err)
   491  		}
   492  	}
   493  }
   494  
   495  var newRequestHostTests = []struct {
   496  	in, out string
   497  }{
   498  	{"http://www.example.com/", "www.example.com"},
   499  	{"http://www.example.com:8080/", "www.example.com:8080"},
   500  
   501  	{"http://192.168.0.1/", "192.168.0.1"},
   502  	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
   503  	{"http://192.168.0.1:/", "192.168.0.1"},
   504  
   505  	{"http://[fe80::1]/", "[fe80::1]"},
   506  	{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
   507  	{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
   508  	{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
   509  	{"http://[fe80::1%25en0]:/", "[fe80::1%en0]"},
   510  }
   511  
   512  func TestNewRequestHost(t *testing.T) {
   513  	for i, tt := range newRequestHostTests {
   514  		req, err := NewRequest("GET", tt.in, nil)
   515  		if err != nil {
   516  			t.Errorf("#%v: %v", i, err)
   517  			continue
   518  		}
   519  		if req.Host != tt.out {
   520  			t.Errorf("got %q; want %q", req.Host, tt.out)
   521  		}
   522  	}
   523  }
   524  
   525  func TestRequestInvalidMethod(t *testing.T) {
   526  	_, err := NewRequest("bad method", "http://foo.com/", nil)
   527  	if err == nil {
   528  		t.Error("expected error from NewRequest with invalid method")
   529  	}
   530  	req, err := NewRequest("GET", "http://foo.example/", nil)
   531  	if err != nil {
   532  		t.Fatal(err)
   533  	}
   534  	req.Method = "bad method"
   535  	_, err = DefaultClient.Do(req)
   536  	if err == nil || !strings.Contains(err.Error(), "invalid method") {
   537  		t.Errorf("Transport error = %v; want invalid method", err)
   538  	}
   539  
   540  	req, err = NewRequest("", "http://foo.com/", nil)
   541  	if err != nil {
   542  		t.Errorf("NewRequest(empty method) = %v; want nil", err)
   543  	} else if req.Method != "GET" {
   544  		t.Errorf("NewRequest(empty method) has method %q; want GET", req.Method)
   545  	}
   546  }
   547  
   548  func TestNewRequestContentLength(t *testing.T) {
   549  	readByte := func(r io.Reader) io.Reader {
   550  		var b [1]byte
   551  		r.Read(b[:])
   552  		return r
   553  	}
   554  	tests := []struct {
   555  		r    io.Reader
   556  		want int64
   557  	}{
   558  		{bytes.NewReader([]byte("123")), 3},
   559  		{bytes.NewBuffer([]byte("1234")), 4},
   560  		{strings.NewReader("12345"), 5},
   561  		{strings.NewReader(""), 0},
   562  		{NoBody, 0},
   563  
   564  		// Not detected. During Go 1.8 we tried to make these set to -1, but
   565  		// due to Issue 18117, we keep these returning 0, even though they're
   566  		// unknown.
   567  		{struct{ io.Reader }{strings.NewReader("xyz")}, 0},
   568  		{io.NewSectionReader(strings.NewReader("x"), 0, 6), 0},
   569  		{readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0},
   570  	}
   571  	for i, tt := range tests {
   572  		req, err := NewRequest("POST", "http://localhost/", tt.r)
   573  		if err != nil {
   574  			t.Fatal(err)
   575  		}
   576  		if req.ContentLength != tt.want {
   577  			t.Errorf("test[%d]: ContentLength(%T) = %d; want %d", i, tt.r, req.ContentLength, tt.want)
   578  		}
   579  	}
   580  }
   581  
   582  var parseHTTPVersionTests = []struct {
   583  	vers         string
   584  	major, minor int
   585  	ok           bool
   586  }{
   587  	{"HTTP/0.9", 0, 9, true},
   588  	{"HTTP/1.0", 1, 0, true},
   589  	{"HTTP/1.1", 1, 1, true},
   590  	{"HTTP/3.14", 3, 14, true},
   591  
   592  	{"HTTP", 0, 0, false},
   593  	{"HTTP/one.one", 0, 0, false},
   594  	{"HTTP/1.1/", 0, 0, false},
   595  	{"HTTP/-1,0", 0, 0, false},
   596  	{"HTTP/0,-1", 0, 0, false},
   597  	{"HTTP/", 0, 0, false},
   598  	{"HTTP/1,1", 0, 0, false},
   599  }
   600  
   601  func TestParseHTTPVersion(t *testing.T) {
   602  	for _, tt := range parseHTTPVersionTests {
   603  		major, minor, ok := ParseHTTPVersion(tt.vers)
   604  		if ok != tt.ok || major != tt.major || minor != tt.minor {
   605  			type version struct {
   606  				major, minor int
   607  				ok           bool
   608  			}
   609  			t.Errorf("failed to parse %q, expected: %#v, got %#v", tt.vers, version{tt.major, tt.minor, tt.ok}, version{major, minor, ok})
   610  		}
   611  	}
   612  }
   613  
   614  type getBasicAuthTest struct {
   615  	username, password string
   616  	ok                 bool
   617  }
   618  
   619  type basicAuthCredentialsTest struct {
   620  	username, password string
   621  }
   622  
   623  var getBasicAuthTests = []struct {
   624  	username, password string
   625  	ok                 bool
   626  }{
   627  	{"Aladdin", "open sesame", true},
   628  	{"Aladdin", "open:sesame", true},
   629  	{"", "", true},
   630  }
   631  
   632  func TestGetBasicAuth(t *testing.T) {
   633  	for _, tt := range getBasicAuthTests {
   634  		r, _ := NewRequest("GET", "http://example.com/", nil)
   635  		r.SetBasicAuth(tt.username, tt.password)
   636  		username, password, ok := r.BasicAuth()
   637  		if ok != tt.ok || username != tt.username || password != tt.password {
   638  			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
   639  				getBasicAuthTest{tt.username, tt.password, tt.ok})
   640  		}
   641  	}
   642  	// Unauthenticated request.
   643  	r, _ := NewRequest("GET", "http://example.com/", nil)
   644  	username, password, ok := r.BasicAuth()
   645  	if ok {
   646  		t.Errorf("expected false from BasicAuth when the request is unauthenticated")
   647  	}
   648  	want := basicAuthCredentialsTest{"", ""}
   649  	if username != want.username || password != want.password {
   650  		t.Errorf("expected credentials: %#v when the request is unauthenticated, got %#v",
   651  			want, basicAuthCredentialsTest{username, password})
   652  	}
   653  }
   654  
   655  var parseBasicAuthTests = []struct {
   656  	header, username, password string
   657  	ok                         bool
   658  }{
   659  	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
   660  
   661  	// Case doesn't matter:
   662  	{"BASIC " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
   663  	{"basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
   664  
   665  	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open:sesame")), "Aladdin", "open:sesame", true},
   666  	{"Basic " + base64.StdEncoding.EncodeToString([]byte(":")), "", "", true},
   667  	{"Basic" + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
   668  	{base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
   669  	{"Basic ", "", "", false},
   670  	{"Basic Aladdin:open sesame", "", "", false},
   671  	{`Digest username="Aladdin"`, "", "", false},
   672  }
   673  
   674  func TestParseBasicAuth(t *testing.T) {
   675  	for _, tt := range parseBasicAuthTests {
   676  		r, _ := NewRequest("GET", "http://example.com/", nil)
   677  		r.Header.Set("Authorization", tt.header)
   678  		username, password, ok := r.BasicAuth()
   679  		if ok != tt.ok || username != tt.username || password != tt.password {
   680  			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
   681  				getBasicAuthTest{tt.username, tt.password, tt.ok})
   682  		}
   683  	}
   684  }
   685  
   686  type logWrites struct {
   687  	t   *testing.T
   688  	dst *[]string
   689  }
   690  
   691  func (l logWrites) WriteByte(c byte) error {
   692  	l.t.Fatalf("unexpected WriteByte call")
   693  	return nil
   694  }
   695  
   696  func (l logWrites) Write(p []byte) (n int, err error) {
   697  	*l.dst = append(*l.dst, string(p))
   698  	return len(p), nil
   699  }
   700  
   701  func TestRequestWriteBufferedWriter(t *testing.T) {
   702  	got := []string{}
   703  	req, _ := NewRequest("GET", "http://foo.com/", nil)
   704  	req.Write(logWrites{t, &got})
   705  	want := []string{
   706  		"GET / HTTP/1.1\r\n",
   707  		"Host: foo.com\r\n",
   708  		"User-Agent: " + DefaultUserAgent + "\r\n",
   709  		"\r\n",
   710  	}
   711  	if !reflect.DeepEqual(got, want) {
   712  		t.Errorf("Writes = %q\n  Want = %q", got, want)
   713  	}
   714  }
   715  
   716  func TestRequestBadHost(t *testing.T) {
   717  	got := []string{}
   718  	req, err := NewRequest("GET", "http://foo/after", nil)
   719  	if err != nil {
   720  		t.Fatal(err)
   721  	}
   722  	req.Host = "foo.com with spaces"
   723  	req.URL.Host = "foo.com with spaces"
   724  	req.Write(logWrites{t, &got})
   725  	want := []string{
   726  		"GET /after HTTP/1.1\r\n",
   727  		"Host: foo.com\r\n",
   728  		"User-Agent: " + DefaultUserAgent + "\r\n",
   729  		"\r\n",
   730  	}
   731  	if !reflect.DeepEqual(got, want) {
   732  		t.Errorf("Writes = %q\n  Want = %q", got, want)
   733  	}
   734  }
   735  
   736  func TestStarRequest(t *testing.T) {
   737  	req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n")))
   738  	if err != nil {
   739  		return
   740  	}
   741  	if req.ContentLength != 0 {
   742  		t.Errorf("ContentLength = %d; want 0", req.ContentLength)
   743  	}
   744  	if req.Body == nil {
   745  		t.Errorf("Body = nil; want non-nil")
   746  	}
   747  
   748  	// Request.Write has Client semantics for Body/ContentLength,
   749  	// where ContentLength 0 means unknown if Body is non-nil, and
   750  	// thus chunking will happen unless we change semantics and
   751  	// signal that we want to serialize it as exactly zero.  The
   752  	// only way to do that for outbound requests is with a nil
   753  	// Body:
   754  	clientReq := *req
   755  	clientReq.Body = nil
   756  
   757  	var out bytes.Buffer
   758  	if err := clientReq.Write(&out); err != nil {
   759  		t.Fatal(err)
   760  	}
   761  
   762  	if strings.Contains(out.String(), "chunked") {
   763  		t.Error("wrote chunked request; want no body")
   764  	}
   765  	back, err := ReadRequest(bufio.NewReader(bytes.NewReader(out.Bytes())))
   766  	if err != nil {
   767  		t.Fatal(err)
   768  	}
   769  	// Ignore the Headers (the User-Agent breaks the deep equal,
   770  	// but we don't care about it)
   771  	req.Header = nil
   772  	back.Header = nil
   773  	if !reflect.DeepEqual(req, back) {
   774  		t.Errorf("Original request doesn't match Request read back.")
   775  		t.Logf("Original: %#v", req)
   776  		t.Logf("Original.URL: %#v", req.URL)
   777  		t.Logf("Wrote: %s", out.Bytes())
   778  		t.Logf("Read back (doesn't match Original): %#v", back)
   779  	}
   780  }
   781  
   782  type responseWriterJustWriter struct {
   783  	io.Writer
   784  }
   785  
   786  func (responseWriterJustWriter) Header() Header  { panic("should not be called") }
   787  func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") }
   788  
   789  // delayedEOFReader never returns (n > 0, io.EOF), instead putting
   790  // off the io.EOF until a subsequent Read call.
   791  type delayedEOFReader struct {
   792  	r io.Reader
   793  }
   794  
   795  func (dr delayedEOFReader) Read(p []byte) (n int, err error) {
   796  	n, err = dr.r.Read(p)
   797  	if n > 0 && err == io.EOF {
   798  		err = nil
   799  	}
   800  	return
   801  }
   802  
   803  func TestIssue10884_MaxBytesEOF(t *testing.T) {
   804  	dst := io.Discard
   805  	_, err := io.Copy(dst, MaxBytesReader(
   806  		responseWriterJustWriter{dst},
   807  		io.NopCloser(delayedEOFReader{strings.NewReader("12345")}),
   808  		5))
   809  	if err != nil {
   810  		t.Fatal(err)
   811  	}
   812  }
   813  
   814  // Issue 14981: MaxBytesReader's return error wasn't sticky. It
   815  // doesn't technically need to be, but people expected it to be.
   816  func TestMaxBytesReaderStickyError(t *testing.T) {
   817  	isSticky := func(r io.Reader) error {
   818  		var log bytes.Buffer
   819  		buf := make([]byte, 1000)
   820  		var firstErr error
   821  		for {
   822  			n, err := r.Read(buf)
   823  			fmt.Fprintf(&log, "Read(%d) = %d, %v\n", len(buf), n, err)
   824  			if err == nil {
   825  				continue
   826  			}
   827  			if firstErr == nil {
   828  				firstErr = err
   829  				continue
   830  			}
   831  			if !reflect.DeepEqual(err, firstErr) {
   832  				return fmt.Errorf("non-sticky error. got log:\n%s", log.Bytes())
   833  			}
   834  			t.Logf("Got log: %s", log.Bytes())
   835  			return nil
   836  		}
   837  	}
   838  	tests := [...]struct {
   839  		readable int
   840  		limit    int64
   841  	}{
   842  		0: {99, 100},
   843  		1: {100, 100},
   844  		2: {101, 100},
   845  	}
   846  	for i, tt := range tests {
   847  		rc := MaxBytesReader(nil, io.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit)
   848  		if err := isSticky(rc); err != nil {
   849  			t.Errorf("%d. error: %v", i, err)
   850  		}
   851  	}
   852  }
   853  
   854  func TestWithContextDeepCopiesURL(t *testing.T) {
   855  	req, err := NewRequest("POST", "https://golang.org/", nil)
   856  	if err != nil {
   857  		t.Fatal(err)
   858  	}
   859  
   860  	reqCopy := req.WithContext(context.Background())
   861  	reqCopy.URL.Scheme = "http"
   862  
   863  	firstURL, secondURL := req.URL.String(), reqCopy.URL.String()
   864  	if firstURL == secondURL {
   865  		t.Errorf("unexpected change to original request's URL")
   866  	}
   867  
   868  	// And also check we don't crash on nil (Issue 20601)
   869  	req.URL = nil
   870  	reqCopy = req.WithContext(context.Background())
   871  	if reqCopy.URL != nil {
   872  		t.Error("expected nil URL in cloned request")
   873  	}
   874  }
   875  
   876  // Ensure that Request.Clone creates a deep copy of TransferEncoding.
   877  // See issue 41907.
   878  func TestRequestCloneTransferEncoding(t *testing.T) {
   879  	body := strings.NewReader("body")
   880  	req, _ := NewRequest("POST", "https://example.org/", body)
   881  	req.TransferEncoding = []string{
   882  		"encoding1",
   883  	}
   884  
   885  	clonedReq := req.Clone(context.Background())
   886  	// modify original after deep copy
   887  	req.TransferEncoding[0] = "encoding2"
   888  
   889  	if req.TransferEncoding[0] != "encoding2" {
   890  		t.Error("expected req.TransferEncoding to be changed")
   891  	}
   892  	if clonedReq.TransferEncoding[0] != "encoding1" {
   893  		t.Error("expected clonedReq.TransferEncoding to be unchanged")
   894  	}
   895  }
   896  
   897  func TestNoPanicOnRoundTripWithBasicAuth_h1(t *testing.T) {
   898  	testNoPanicWithBasicAuth(t, h1Mode)
   899  }
   900  
   901  func TestNoPanicOnRoundTripWithBasicAuth_h2(t *testing.T) {
   902  	testNoPanicWithBasicAuth(t, h2Mode)
   903  }
   904  
   905  // Issue 34878: verify we don't panic when including basic auth (Go 1.13 regression)
   906  func testNoPanicWithBasicAuth(t *testing.T, h2 bool) {
   907  	defer afterTest(t)
   908  	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {}))
   909  	defer cst.close()
   910  
   911  	u, err := url.Parse(cst.ts.URL)
   912  	if err != nil {
   913  		t.Fatal(err)
   914  	}
   915  	u.User = url.UserPassword("foo", "bar")
   916  	req := &Request{
   917  		URL:    u,
   918  		Method: "GET",
   919  	}
   920  	if _, err := cst.c.Do(req); err != nil {
   921  		t.Fatalf("Unexpected error: %v", err)
   922  	}
   923  }
   924  
   925  // verify that NewRequest sets Request.GetBody and that it works
   926  func TestNewRequestGetBody(t *testing.T) {
   927  	tests := []struct {
   928  		r io.Reader
   929  	}{
   930  		{r: strings.NewReader("hello")},
   931  		{r: bytes.NewReader([]byte("hello"))},
   932  		{r: bytes.NewBuffer([]byte("hello"))},
   933  	}
   934  	for i, tt := range tests {
   935  		req, err := NewRequest("POST", "http://foo.tld/", tt.r)
   936  		if err != nil {
   937  			t.Errorf("test[%d]: %v", i, err)
   938  			continue
   939  		}
   940  		if req.Body == nil {
   941  			t.Errorf("test[%d]: Body = nil", i)
   942  			continue
   943  		}
   944  		if req.GetBody == nil {
   945  			t.Errorf("test[%d]: GetBody = nil", i)
   946  			continue
   947  		}
   948  		slurp1, err := io.ReadAll(req.Body)
   949  		if err != nil {
   950  			t.Errorf("test[%d]: ReadAll(Body) = %v", i, err)
   951  		}
   952  		newBody, err := req.GetBody()
   953  		if err != nil {
   954  			t.Errorf("test[%d]: GetBody = %v", i, err)
   955  		}
   956  		slurp2, err := io.ReadAll(newBody)
   957  		if err != nil {
   958  			t.Errorf("test[%d]: ReadAll(GetBody()) = %v", i, err)
   959  		}
   960  		if string(slurp1) != string(slurp2) {
   961  			t.Errorf("test[%d]: Body %q != GetBody %q", i, slurp1, slurp2)
   962  		}
   963  	}
   964  }
   965  
   966  func testMissingFile(t *testing.T, req *Request) {
   967  	f, fh, err := req.FormFile("missing")
   968  	if f != nil {
   969  		t.Errorf("FormFile file = %v, want nil", f)
   970  	}
   971  	if fh != nil {
   972  		t.Errorf("FormFile file header = %q, want nil", fh)
   973  	}
   974  	if err != ErrMissingFile {
   975  		t.Errorf("FormFile err = %q, want ErrMissingFile", err)
   976  	}
   977  }
   978  
   979  func newTestMultipartRequest(t *testing.T) *Request {
   980  	b := strings.NewReader(strings.ReplaceAll(message, "\n", "\r\n"))
   981  	req, err := NewRequest("POST", "/", b)
   982  	if err != nil {
   983  		t.Fatal("NewRequest:", err)
   984  	}
   985  	ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
   986  	req.Header.Set("Content-type", ctype)
   987  	return req
   988  }
   989  
   990  func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
   991  	if g, e := req.FormValue("texta"), textaValue; g != e {
   992  		t.Errorf("texta value = %q, want %q", g, e)
   993  	}
   994  	if g, e := req.FormValue("textb"), textbValue; g != e {
   995  		t.Errorf("textb value = %q, want %q", g, e)
   996  	}
   997  	if g := req.FormValue("missing"); g != "" {
   998  		t.Errorf("missing value = %q, want empty string", g)
   999  	}
  1000  
  1001  	assertMem := func(n string, fd multipart.File) {
  1002  		if _, ok := fd.(*os.File); ok {
  1003  			t.Error(n, " is *os.File, should not be")
  1004  		}
  1005  	}
  1006  	fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
  1007  	defer fda.Close()
  1008  	assertMem("filea", fda)
  1009  	fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
  1010  	defer fdb.Close()
  1011  	if allMem {
  1012  		assertMem("fileb", fdb)
  1013  	} else {
  1014  		if _, ok := fdb.(*os.File); !ok {
  1015  			t.Errorf("fileb has unexpected underlying type %T", fdb)
  1016  		}
  1017  	}
  1018  
  1019  	testMissingFile(t, req)
  1020  }
  1021  
  1022  func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
  1023  	f, fh, err := req.FormFile(key)
  1024  	if err != nil {
  1025  		t.Fatalf("FormFile(%q): %q", key, err)
  1026  	}
  1027  	if fh.Filename != expectFilename {
  1028  		t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
  1029  	}
  1030  	var b bytes.Buffer
  1031  	_, err = io.Copy(&b, f)
  1032  	if err != nil {
  1033  		t.Fatal("copying contents:", err)
  1034  	}
  1035  	if g := b.String(); g != expectContent {
  1036  		t.Errorf("contents = %q, want %q", g, expectContent)
  1037  	}
  1038  	return f
  1039  }
  1040  
  1041  const (
  1042  	fileaContents = "This is a test file."
  1043  	filebContents = "Another test file."
  1044  	textaValue    = "foo"
  1045  	textbValue    = "bar"
  1046  	boundary      = `MyBoundary`
  1047  )
  1048  
  1049  const message = `
  1050  --MyBoundary
  1051  Content-Disposition: form-data; name="filea"; filename="filea.txt"
  1052  Content-Type: text/plain
  1053  
  1054  ` + fileaContents + `
  1055  --MyBoundary
  1056  Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
  1057  Content-Type: text/plain
  1058  
  1059  ` + filebContents + `
  1060  --MyBoundary
  1061  Content-Disposition: form-data; name="texta"
  1062  
  1063  ` + textaValue + `
  1064  --MyBoundary
  1065  Content-Disposition: form-data; name="textb"
  1066  
  1067  ` + textbValue + `
  1068  --MyBoundary--
  1069  `
  1070  
  1071  func benchmarkReadRequest(b *testing.B, request string) {
  1072  	request = request + "\n"                            // final \n
  1073  	request = strings.ReplaceAll(request, "\n", "\r\n") // expand \n to \r\n
  1074  	b.SetBytes(int64(len(request)))
  1075  	r := bufio.NewReader(&infiniteReader{buf: []byte(request)})
  1076  	b.ReportAllocs()
  1077  	b.ResetTimer()
  1078  	for i := 0; i < b.N; i++ {
  1079  		_, err := ReadRequest(r)
  1080  		if err != nil {
  1081  			b.Fatalf("failed to read request: %v", err)
  1082  		}
  1083  	}
  1084  }
  1085  
  1086  // infiniteReader satisfies Read requests as if the contents of buf
  1087  // loop indefinitely.
  1088  type infiniteReader struct {
  1089  	buf    []byte
  1090  	offset int
  1091  }
  1092  
  1093  func (r *infiniteReader) Read(b []byte) (int, error) {
  1094  	n := copy(b, r.buf[r.offset:])
  1095  	r.offset = (r.offset + n) % len(r.buf)
  1096  	return n, nil
  1097  }
  1098  
  1099  func BenchmarkReadRequestChrome(b *testing.B) {
  1100  	// https://github.com/felixge/node-http-perf/blob/master/fixtures/get.http
  1101  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1102  Host: localhost:8080
  1103  Connection: keep-alive
  1104  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  1105  User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.52 Safari/537.17
  1106  Accept-Encoding: gzip,deflate,sdch
  1107  Accept-Language: en-US,en;q=0.8
  1108  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
  1109  Cookie: __utma=1.1978842379.1323102373.1323102373.1323102373.1; EPi:NumberOfVisits=1,2012-02-28T13:42:18; CrmSession=5b707226b9563e1bc69084d07a107c98; plushContainerWidth=100%25; plushNoTopMenu=0; hudson_auto_refresh=false
  1110  `)
  1111  }
  1112  
  1113  func BenchmarkReadRequestCurl(b *testing.B) {
  1114  	// curl http://localhost:8080/
  1115  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1116  User-Agent: curl/7.27.0
  1117  Host: localhost:8080
  1118  Accept: */*
  1119  `)
  1120  }
  1121  
  1122  func BenchmarkReadRequestApachebench(b *testing.B) {
  1123  	// ab -n 1 -c 1 http://localhost:8080/
  1124  	benchmarkReadRequest(b, `GET / HTTP/1.0
  1125  Host: localhost:8080
  1126  User-Agent: ApacheBench/2.3
  1127  Accept: */*
  1128  `)
  1129  }
  1130  
  1131  func BenchmarkReadRequestSiege(b *testing.B) {
  1132  	// siege -r 1 -c 1 http://localhost:8080/
  1133  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1134  Host: localhost:8080
  1135  Accept: */*
  1136  Accept-Encoding: gzip
  1137  User-Agent: JoeDog/1.00 [en] (X11; I; Siege 2.70)
  1138  Connection: keep-alive
  1139  `)
  1140  }
  1141  
  1142  func BenchmarkReadRequestWrk(b *testing.B) {
  1143  	// wrk -t 1 -r 1 -c 1 http://localhost:8080/
  1144  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1145  Host: localhost:8080
  1146  `)
  1147  }
  1148  
  1149  const (
  1150  	withTLS = true
  1151  	noTLS   = false
  1152  )
  1153  
  1154  func BenchmarkFileAndServer_1KB(b *testing.B) {
  1155  	benchmarkFileAndServer(b, 1<<10)
  1156  }
  1157  
  1158  func BenchmarkFileAndServer_16MB(b *testing.B) {
  1159  	benchmarkFileAndServer(b, 1<<24)
  1160  }
  1161  
  1162  func BenchmarkFileAndServer_64MB(b *testing.B) {
  1163  	benchmarkFileAndServer(b, 1<<26)
  1164  }
  1165  
  1166  func benchmarkFileAndServer(b *testing.B, n int64) {
  1167  	f, err := os.CreateTemp(os.TempDir(), "go-bench-http-file-and-server")
  1168  	if err != nil {
  1169  		b.Fatalf("Failed to create temp file: %v", err)
  1170  	}
  1171  
  1172  	defer func() {
  1173  		f.Close()
  1174  		os.RemoveAll(f.Name())
  1175  	}()
  1176  
  1177  	if _, err := io.CopyN(f, rand.Reader, n); err != nil {
  1178  		b.Fatalf("Failed to copy %d bytes: %v", n, err)
  1179  	}
  1180  
  1181  	b.Run("NoTLS", func(b *testing.B) {
  1182  		runFileAndServerBenchmarks(b, noTLS, f, n)
  1183  	})
  1184  
  1185  	b.Run("TLS", func(b *testing.B) {
  1186  		runFileAndServerBenchmarks(b, withTLS, f, n)
  1187  	})
  1188  }
  1189  
  1190  func runFileAndServerBenchmarks(b *testing.B, tlsOption bool, f *os.File, n int64) {
  1191  	handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
  1192  		defer req.Body.Close()
  1193  		nc, err := io.Copy(io.Discard, req.Body)
  1194  		if err != nil {
  1195  			panic(err)
  1196  		}
  1197  
  1198  		if nc != n {
  1199  			panic(fmt.Errorf("Copied %d Wanted %d bytes", nc, n))
  1200  		}
  1201  	})
  1202  
  1203  	var cst *httptest.Server
  1204  	if tlsOption == withTLS {
  1205  		cst = httptest.NewTLSServer(handler)
  1206  	} else {
  1207  		cst = httptest.NewServer(handler)
  1208  	}
  1209  
  1210  	defer cst.Close()
  1211  	b.ResetTimer()
  1212  	for i := 0; i < b.N; i++ {
  1213  		// Perform some setup.
  1214  		b.StopTimer()
  1215  		if _, err := f.Seek(0, 0); err != nil {
  1216  			b.Fatalf("Failed to seek back to file: %v", err)
  1217  		}
  1218  
  1219  		b.StartTimer()
  1220  		req, err := NewRequest("PUT", cst.URL, io.NopCloser(f))
  1221  		if err != nil {
  1222  			b.Fatal(err)
  1223  		}
  1224  
  1225  		req.ContentLength = n
  1226  		// Prevent mime sniffing by setting the Content-Type.
  1227  		req.Header.Set("Content-Type", "application/octet-stream")
  1228  		res, err := cst.Client().Do(req)
  1229  		if err != nil {
  1230  			b.Fatalf("Failed to make request to backend: %v", err)
  1231  		}
  1232  
  1233  		res.Body.Close()
  1234  		b.SetBytes(n)
  1235  	}
  1236  }