Source file src/net/http/request_test.go

     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  	"encoding/json"
    14  	"errors"
    15  	"fmt"
    16  	"io"
    17  	"math"
    18  	"mime/multipart"
    19  	"net/http"
    20  	. "net/http"
    21  	"net/http/httptest"
    22  	"net/url"
    23  	"os"
    24  	"reflect"
    25  	"regexp"
    26  	"slices"
    27  	"strings"
    28  	"testing"
    29  )
    30  
    31  func TestQuery(t *testing.T) {
    32  	req := &Request{Method: "GET"}
    33  	req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
    34  	if q := req.FormValue("q"); q != "foo" {
    35  		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
    36  	}
    37  }
    38  
    39  // Issue #25192: Test that ParseForm fails but still parses the form when a URL
    40  // containing a semicolon is provided.
    41  func TestParseFormSemicolonSeparator(t *testing.T) {
    42  	for _, method := range []string{"POST", "PATCH", "PUT", "GET"} {
    43  		req, _ := NewRequest(method, "http://www.google.com/search?q=foo;q=bar&a=1",
    44  			strings.NewReader("q"))
    45  		err := req.ParseForm()
    46  		if err == nil {
    47  			t.Fatalf(`for method %s, ParseForm expected an error, got success`, method)
    48  		}
    49  		wantForm := url.Values{"a": []string{"1"}}
    50  		if !reflect.DeepEqual(req.Form, wantForm) {
    51  			t.Fatalf("for method %s, ParseForm expected req.Form = %v, want %v", method, req.Form, wantForm)
    52  		}
    53  	}
    54  }
    55  
    56  func TestParseFormQuery(t *testing.T) {
    57  	req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&orphan=nope&empty=not",
    58  		strings.NewReader("z=post&both=y&prio=2&=nokey&orphan&empty=&"))
    59  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
    60  
    61  	if q := req.FormValue("q"); q != "foo" {
    62  		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
    63  	}
    64  	if z := req.FormValue("z"); z != "post" {
    65  		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
    66  	}
    67  	if bq, found := req.PostForm["q"]; found {
    68  		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
    69  	}
    70  	if bz := req.PostFormValue("z"); bz != "post" {
    71  		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
    72  	}
    73  	if qs := req.Form["q"]; !slices.Equal(qs, []string{"foo", "bar"}) {
    74  		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
    75  	}
    76  	if both := req.Form["both"]; !slices.Equal(both, []string{"y", "x"}) {
    77  		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
    78  	}
    79  	if prio := req.FormValue("prio"); prio != "2" {
    80  		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
    81  	}
    82  	if orphan := req.Form["orphan"]; !slices.Equal(orphan, []string{"", "nope"}) {
    83  		t.Errorf(`req.FormValue("orphan") = %q, want "" (from body)`, orphan)
    84  	}
    85  	if empty := req.Form["empty"]; !slices.Equal(empty, []string{"", "not"}) {
    86  		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
    87  	}
    88  	if nokey := req.Form[""]; !slices.Equal(nokey, []string{"nokey"}) {
    89  		t.Errorf(`req.FormValue("nokey") = %q, want "nokey" (from body)`, nokey)
    90  	}
    91  }
    92  
    93  // Tests that we only parse the form automatically for certain methods.
    94  func TestParseFormQueryMethods(t *testing.T) {
    95  	for _, method := range []string{"POST", "PATCH", "PUT", "FOO"} {
    96  		req, _ := NewRequest(method, "http://www.google.com/search",
    97  			strings.NewReader("foo=bar"))
    98  		req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
    99  		want := "bar"
   100  		if method == "FOO" {
   101  			want = ""
   102  		}
   103  		if got := req.FormValue("foo"); got != want {
   104  			t.Errorf(`for method %s, FormValue("foo") = %q; want %q`, method, got, want)
   105  		}
   106  	}
   107  }
   108  
   109  func TestParseFormUnknownContentType(t *testing.T) {
   110  	for _, test := range []struct {
   111  		name        string
   112  		wantErr     string
   113  		contentType Header
   114  	}{
   115  		{"text", "", Header{"Content-Type": {"text/plain"}}},
   116  		// Empty content type is legal - may be treated as
   117  		// application/octet-stream (RFC 7231, section 3.1.1.5)
   118  		{"empty", "", Header{}},
   119  		{"boundary", "mime: invalid media parameter", Header{"Content-Type": {"text/plain; boundary="}}},
   120  		{"unknown", "", Header{"Content-Type": {"application/unknown"}}},
   121  	} {
   122  		t.Run(test.name,
   123  			func(t *testing.T) {
   124  				req := &Request{
   125  					Method: "POST",
   126  					Header: test.contentType,
   127  					Body:   io.NopCloser(strings.NewReader("body")),
   128  				}
   129  				err := req.ParseForm()
   130  				switch {
   131  				case err == nil && test.wantErr != "":
   132  					t.Errorf("unexpected success; want error %q", test.wantErr)
   133  				case err != nil && test.wantErr == "":
   134  					t.Errorf("want success, got error: %v", err)
   135  				case test.wantErr != "" && test.wantErr != fmt.Sprint(err):
   136  					t.Errorf("got error %q; want %q", err, test.wantErr)
   137  				}
   138  			},
   139  		)
   140  	}
   141  }
   142  
   143  func TestParseFormInitializeOnError(t *testing.T) {
   144  	nilBody, _ := NewRequest("POST", "http://www.google.com/search?q=foo", nil)
   145  	tests := []*Request{
   146  		nilBody,
   147  		{Method: "GET", URL: nil},
   148  	}
   149  	for i, req := range tests {
   150  		err := req.ParseForm()
   151  		if req.Form == nil {
   152  			t.Errorf("%d. Form not initialized, error %v", i, err)
   153  		}
   154  		if req.PostForm == nil {
   155  			t.Errorf("%d. PostForm not initialized, error %v", i, err)
   156  		}
   157  	}
   158  }
   159  
   160  func TestMultipartReader(t *testing.T) {
   161  	tests := []struct {
   162  		shouldError bool
   163  		contentType string
   164  	}{
   165  		{false, `multipart/form-data; boundary="foo123"`},
   166  		{false, `multipart/mixed; boundary="foo123"`},
   167  		{true, `text/plain`},
   168  	}
   169  
   170  	for i, test := range tests {
   171  		req := &Request{
   172  			Method: "POST",
   173  			Header: Header{"Content-Type": {test.contentType}},
   174  			Body:   io.NopCloser(new(bytes.Buffer)),
   175  		}
   176  		multipart, err := req.MultipartReader()
   177  		if test.shouldError {
   178  			if err == nil || multipart != nil {
   179  				t.Errorf("test %d: unexpectedly got nil-error (%v) or non-nil-multipart (%v)", i, err, multipart)
   180  			}
   181  			continue
   182  		}
   183  		if err != nil || multipart == nil {
   184  			t.Errorf("test %d: unexpectedly got error (%v) or nil-multipart (%v)", i, err, multipart)
   185  		}
   186  	}
   187  }
   188  
   189  // Issue 9305: ParseMultipartForm should populate PostForm too
   190  func TestParseMultipartFormPopulatesPostForm(t *testing.T) {
   191  	postData :=
   192  		`--xxx
   193  Content-Disposition: form-data; name="field1"
   194  
   195  value1
   196  --xxx
   197  Content-Disposition: form-data; name="field2"
   198  
   199  value2
   200  --xxx
   201  Content-Disposition: form-data; name="file"; filename="file"
   202  Content-Type: application/octet-stream
   203  Content-Transfer-Encoding: binary
   204  
   205  binary data
   206  --xxx--
   207  `
   208  	req := &Request{
   209  		Method: "POST",
   210  		Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
   211  		Body:   io.NopCloser(strings.NewReader(postData)),
   212  	}
   213  
   214  	initialFormItems := map[string]string{
   215  		"language": "Go",
   216  		"name":     "gopher",
   217  		"skill":    "go-ing",
   218  		"field2":   "initial-value2",
   219  	}
   220  
   221  	req.Form = make(url.Values)
   222  	for k, v := range initialFormItems {
   223  		req.Form.Add(k, v)
   224  	}
   225  
   226  	err := req.ParseMultipartForm(10000)
   227  	if err != nil {
   228  		t.Fatalf("unexpected multipart error %v", err)
   229  	}
   230  
   231  	wantForm := url.Values{
   232  		"language": []string{"Go"},
   233  		"name":     []string{"gopher"},
   234  		"skill":    []string{"go-ing"},
   235  		"field1":   []string{"value1"},
   236  		"field2":   []string{"initial-value2", "value2"},
   237  	}
   238  	if !reflect.DeepEqual(req.Form, wantForm) {
   239  		t.Fatalf("req.Form = %v, want %v", req.Form, wantForm)
   240  	}
   241  
   242  	wantPostForm := url.Values{
   243  		"field1": []string{"value1"},
   244  		"field2": []string{"value2"},
   245  	}
   246  	if !reflect.DeepEqual(req.PostForm, wantPostForm) {
   247  		t.Fatalf("req.PostForm = %v, want %v", req.PostForm, wantPostForm)
   248  	}
   249  }
   250  
   251  func TestParseMultipartForm(t *testing.T) {
   252  	req := &Request{
   253  		Method: "POST",
   254  		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
   255  		Body:   io.NopCloser(new(bytes.Buffer)),
   256  	}
   257  	err := req.ParseMultipartForm(25)
   258  	if err == nil {
   259  		t.Error("expected multipart EOF, got nil")
   260  	}
   261  
   262  	req.Header = Header{"Content-Type": {"text/plain"}}
   263  	err = req.ParseMultipartForm(25)
   264  	if err != ErrNotMultipart {
   265  		t.Error("expected ErrNotMultipart for text/plain")
   266  	}
   267  }
   268  
   269  // Issue 45789: multipart form should not include directory path in filename
   270  func TestParseMultipartFormFilename(t *testing.T) {
   271  	postData :=
   272  		`--xxx
   273  Content-Disposition: form-data; name="file"; filename="../usr/foobar.txt/"
   274  Content-Type: text/plain
   275  
   276  --xxx--
   277  `
   278  	req := &Request{
   279  		Method: "POST",
   280  		Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
   281  		Body:   io.NopCloser(strings.NewReader(postData)),
   282  	}
   283  	_, hdr, err := req.FormFile("file")
   284  	if err != nil {
   285  		t.Fatal(err)
   286  	}
   287  	if hdr.Filename != "foobar.txt" {
   288  		t.Errorf("expected only the last element of the path, got %q", hdr.Filename)
   289  	}
   290  }
   291  
   292  // Issue #40430: Test that if maxMemory for ParseMultipartForm when combined with
   293  // the payload size and the internal leeway buffer size of 10MiB overflows, that we
   294  // correctly return an error.
   295  func TestMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T) {
   296  	run(t, testMaxInt64ForMultipartFormMaxMemoryOverflow)
   297  }
   298  func testMaxInt64ForMultipartFormMaxMemoryOverflow(t *testing.T, mode testMode) {
   299  	payloadSize := 1 << 10
   300  	cst := newClientServerTest(t, mode, HandlerFunc(func(rw ResponseWriter, req *Request) {
   301  		// The combination of:
   302  		//      MaxInt64 + payloadSize + (internal spare of 10MiB)
   303  		// triggers the overflow. See issue https://golang.org/issue/40430/
   304  		if err := req.ParseMultipartForm(math.MaxInt64); err != nil {
   305  			Error(rw, err.Error(), StatusBadRequest)
   306  			return
   307  		}
   308  	})).ts
   309  	fBuf := new(bytes.Buffer)
   310  	mw := multipart.NewWriter(fBuf)
   311  	mf, err := mw.CreateFormFile("file", "myfile.txt")
   312  	if err != nil {
   313  		t.Fatal(err)
   314  	}
   315  	if _, err := mf.Write(bytes.Repeat([]byte("abc"), payloadSize)); err != nil {
   316  		t.Fatal(err)
   317  	}
   318  	if err := mw.Close(); err != nil {
   319  		t.Fatal(err)
   320  	}
   321  	req, err := NewRequest("POST", cst.URL, fBuf)
   322  	if err != nil {
   323  		t.Fatal(err)
   324  	}
   325  	req.Header.Set("Content-Type", mw.FormDataContentType())
   326  	res, err := cst.Client().Do(req)
   327  	if err != nil {
   328  		t.Fatal(err)
   329  	}
   330  	res.Body.Close()
   331  	if g, w := res.StatusCode, StatusOK; g != w {
   332  		t.Fatalf("Status code mismatch: got %d, want %d", g, w)
   333  	}
   334  }
   335  
   336  func TestRequestRedirect(t *testing.T) { run(t, testRequestRedirect) }
   337  func testRequestRedirect(t *testing.T, mode testMode) {
   338  	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {
   339  		switch r.URL.Path {
   340  		case "/":
   341  			w.Header().Set("Location", "/foo/")
   342  			w.WriteHeader(StatusSeeOther)
   343  		case "/foo/":
   344  			fmt.Fprintf(w, "foo")
   345  		default:
   346  			w.WriteHeader(StatusBadRequest)
   347  		}
   348  	}))
   349  
   350  	var end = regexp.MustCompile("/foo/$")
   351  	r, err := cst.c.Get(cst.ts.URL)
   352  	if err != nil {
   353  		t.Fatal(err)
   354  	}
   355  	r.Body.Close()
   356  	url := r.Request.URL.String()
   357  	if r.StatusCode != 200 || !end.MatchString(url) {
   358  		t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
   359  	}
   360  }
   361  
   362  func TestSetBasicAuth(t *testing.T) {
   363  	r, _ := NewRequest("GET", "http://example.com/", nil)
   364  	r.SetBasicAuth("Aladdin", "open sesame")
   365  	if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e {
   366  		t.Errorf("got header %q, want %q", g, e)
   367  	}
   368  }
   369  
   370  func TestMultipartRequest(t *testing.T) {
   371  	// Test that we can read the values and files of a
   372  	// multipart request with FormValue and FormFile,
   373  	// and that ParseMultipartForm can be called multiple times.
   374  	req := newTestMultipartRequest(t)
   375  	if err := req.ParseMultipartForm(25); err != nil {
   376  		t.Fatal("ParseMultipartForm first call:", err)
   377  	}
   378  	defer req.MultipartForm.RemoveAll()
   379  	validateTestMultipartContents(t, req, false)
   380  	if err := req.ParseMultipartForm(25); err != nil {
   381  		t.Fatal("ParseMultipartForm second call:", err)
   382  	}
   383  	validateTestMultipartContents(t, req, false)
   384  }
   385  
   386  // Issue #25192: Test that ParseMultipartForm fails but still parses the
   387  // multi-part form when a URL containing a semicolon is provided.
   388  func TestParseMultipartFormSemicolonSeparator(t *testing.T) {
   389  	req := newTestMultipartRequest(t)
   390  	req.URL = &url.URL{RawQuery: "q=foo;q=bar"}
   391  	if err := req.ParseMultipartForm(25); err == nil {
   392  		t.Fatal("ParseMultipartForm expected error due to invalid semicolon, got nil")
   393  	}
   394  	defer req.MultipartForm.RemoveAll()
   395  	validateTestMultipartContents(t, req, false)
   396  }
   397  
   398  func TestMultipartRequestAuto(t *testing.T) {
   399  	// Test that FormValue and FormFile automatically invoke
   400  	// ParseMultipartForm and return the right values.
   401  	req := newTestMultipartRequest(t)
   402  	defer func() {
   403  		if req.MultipartForm != nil {
   404  			req.MultipartForm.RemoveAll()
   405  		}
   406  	}()
   407  	validateTestMultipartContents(t, req, true)
   408  }
   409  
   410  func TestMissingFileMultipartRequest(t *testing.T) {
   411  	// Test that FormFile returns an error if
   412  	// the named file is missing.
   413  	req := newTestMultipartRequest(t)
   414  	testMissingFile(t, req)
   415  }
   416  
   417  // Test that FormValue invokes ParseMultipartForm.
   418  func TestFormValueCallsParseMultipartForm(t *testing.T) {
   419  	req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
   420  	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
   421  	if req.Form != nil {
   422  		t.Fatal("Unexpected request Form, want nil")
   423  	}
   424  	req.FormValue("z")
   425  	if req.Form == nil {
   426  		t.Fatal("ParseMultipartForm not called by FormValue")
   427  	}
   428  }
   429  
   430  // Test that FormFile invokes ParseMultipartForm.
   431  func TestFormFileCallsParseMultipartForm(t *testing.T) {
   432  	req := newTestMultipartRequest(t)
   433  	if req.Form != nil {
   434  		t.Fatal("Unexpected request Form, want nil")
   435  	}
   436  	req.FormFile("")
   437  	if req.Form == nil {
   438  		t.Fatal("ParseMultipartForm not called by FormFile")
   439  	}
   440  }
   441  
   442  // Test that ParseMultipartForm errors if called
   443  // after MultipartReader on the same request.
   444  func TestParseMultipartFormOrder(t *testing.T) {
   445  	req := newTestMultipartRequest(t)
   446  	if _, err := req.MultipartReader(); err != nil {
   447  		t.Fatalf("MultipartReader: %v", err)
   448  	}
   449  	if err := req.ParseMultipartForm(1024); err == nil {
   450  		t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
   451  	}
   452  }
   453  
   454  // Test that MultipartReader errors if called
   455  // after ParseMultipartForm on the same request.
   456  func TestMultipartReaderOrder(t *testing.T) {
   457  	req := newTestMultipartRequest(t)
   458  	if err := req.ParseMultipartForm(25); err != nil {
   459  		t.Fatalf("ParseMultipartForm: %v", err)
   460  	}
   461  	defer req.MultipartForm.RemoveAll()
   462  	if _, err := req.MultipartReader(); err == nil {
   463  		t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
   464  	}
   465  }
   466  
   467  // Test that FormFile errors if called after
   468  // MultipartReader on the same request.
   469  func TestFormFileOrder(t *testing.T) {
   470  	req := newTestMultipartRequest(t)
   471  	if _, err := req.MultipartReader(); err != nil {
   472  		t.Fatalf("MultipartReader: %v", err)
   473  	}
   474  	if _, _, err := req.FormFile(""); err == nil {
   475  		t.Fatal("expected an error from FormFile after call to MultipartReader")
   476  	}
   477  }
   478  
   479  var readRequestErrorTests = []struct {
   480  	in  string
   481  	err string
   482  
   483  	header Header
   484  }{
   485  	0: {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", "", Header{"Header": {"foo"}}},
   486  	1: {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF.Error(), nil},
   487  	2: {"", io.EOF.Error(), nil},
   488  	3: {
   489  		in:     "HEAD / HTTP/1.1\r\n\r\n",
   490  		header: Header{},
   491  	},
   492  
   493  	// Multiple Content-Length values should either be
   494  	// deduplicated if same or reject otherwise
   495  	// See Issue 16490.
   496  	4: {
   497  		in:  "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
   498  		err: "cannot contain multiple Content-Length headers",
   499  	},
   500  	5: {
   501  		in:  "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
   502  		err: "cannot contain multiple Content-Length headers",
   503  	},
   504  	6: {
   505  		in:     "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
   506  		err:    "",
   507  		header: Header{"Content-Length": {"6"}},
   508  	},
   509  	7: {
   510  		in:  "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
   511  		err: "cannot contain multiple Content-Length headers",
   512  	},
   513  	8: {
   514  		in:  "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
   515  		err: "cannot contain multiple Content-Length headers",
   516  	},
   517  	9: {
   518  		in:     "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
   519  		header: Header{"Content-Length": {"0"}},
   520  	},
   521  	10: {
   522  		in:  "HEAD / HTTP/1.1\r\nHost: foo\r\nHost: bar\r\n\r\n\r\n\r\n",
   523  		err: "too many Host headers",
   524  	},
   525  }
   526  
   527  func TestReadRequestErrors(t *testing.T) {
   528  	for i, tt := range readRequestErrorTests {
   529  		req, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
   530  		if err == nil {
   531  			if tt.err != "" {
   532  				t.Errorf("#%d: got nil err; want %q", i, tt.err)
   533  			}
   534  
   535  			if !reflect.DeepEqual(tt.header, req.Header) {
   536  				t.Errorf("#%d: gotHeader: %q wantHeader: %q", i, req.Header, tt.header)
   537  			}
   538  			continue
   539  		}
   540  
   541  		if tt.err == "" || !strings.Contains(err.Error(), tt.err) {
   542  			t.Errorf("%d: got error = %v; want %v", i, err, tt.err)
   543  		}
   544  	}
   545  }
   546  
   547  var newRequestHostTests = []struct {
   548  	in, out string
   549  }{
   550  	{"http://www.example.com/", "www.example.com"},
   551  	{"http://www.example.com:8080/", "www.example.com:8080"},
   552  
   553  	{"http://192.168.0.1/", "192.168.0.1"},
   554  	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
   555  	{"http://192.168.0.1:/", "192.168.0.1"},
   556  
   557  	{"http://[fe80::1]/", "[fe80::1]"},
   558  	{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
   559  	{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
   560  	{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
   561  	{"http://[fe80::1%25en0]:/", "[fe80::1%en0]"},
   562  }
   563  
   564  func TestNewRequestHost(t *testing.T) {
   565  	for i, tt := range newRequestHostTests {
   566  		req, err := NewRequest("GET", tt.in, nil)
   567  		if err != nil {
   568  			t.Errorf("#%v: %v", i, err)
   569  			continue
   570  		}
   571  		if req.Host != tt.out {
   572  			t.Errorf("got %q; want %q", req.Host, tt.out)
   573  		}
   574  	}
   575  }
   576  
   577  func TestRequestInvalidMethod(t *testing.T) {
   578  	_, err := NewRequest("bad method", "http://foo.com/", nil)
   579  	if err == nil {
   580  		t.Error("expected error from NewRequest with invalid method")
   581  	}
   582  	req, err := NewRequest("GET", "http://foo.example/", nil)
   583  	if err != nil {
   584  		t.Fatal(err)
   585  	}
   586  	req.Method = "bad method"
   587  	_, err = DefaultClient.Do(req)
   588  	if err == nil || !strings.Contains(err.Error(), "invalid method") {
   589  		t.Errorf("Transport error = %v; want invalid method", err)
   590  	}
   591  
   592  	req, err = NewRequest("", "http://foo.com/", nil)
   593  	if err != nil {
   594  		t.Errorf("NewRequest(empty method) = %v; want nil", err)
   595  	} else if req.Method != "GET" {
   596  		t.Errorf("NewRequest(empty method) has method %q; want GET", req.Method)
   597  	}
   598  }
   599  
   600  func TestNewRequestContentLength(t *testing.T) {
   601  	readByte := func(r io.Reader) io.Reader {
   602  		var b [1]byte
   603  		r.Read(b[:])
   604  		return r
   605  	}
   606  	tests := []struct {
   607  		r    io.Reader
   608  		want int64
   609  	}{
   610  		{bytes.NewReader([]byte("123")), 3},
   611  		{bytes.NewBuffer([]byte("1234")), 4},
   612  		{strings.NewReader("12345"), 5},
   613  		{strings.NewReader(""), 0},
   614  		{NoBody, 0},
   615  
   616  		// Not detected. During Go 1.8 we tried to make these set to -1, but
   617  		// due to Issue 18117, we keep these returning 0, even though they're
   618  		// unknown.
   619  		{struct{ io.Reader }{strings.NewReader("xyz")}, 0},
   620  		{io.NewSectionReader(strings.NewReader("x"), 0, 6), 0},
   621  		{readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0},
   622  	}
   623  	for i, tt := range tests {
   624  		req, err := NewRequest("POST", "http://localhost/", tt.r)
   625  		if err != nil {
   626  			t.Fatal(err)
   627  		}
   628  		if req.ContentLength != tt.want {
   629  			t.Errorf("test[%d]: ContentLength(%T) = %d; want %d", i, tt.r, req.ContentLength, tt.want)
   630  		}
   631  	}
   632  }
   633  
   634  var parseHTTPVersionTests = []struct {
   635  	vers         string
   636  	major, minor int
   637  	ok           bool
   638  }{
   639  	{"HTTP/0.0", 0, 0, true},
   640  	{"HTTP/0.9", 0, 9, true},
   641  	{"HTTP/1.0", 1, 0, true},
   642  	{"HTTP/1.1", 1, 1, true},
   643  
   644  	{"HTTP", 0, 0, false},
   645  	{"HTTP/one.one", 0, 0, false},
   646  	{"HTTP/1.1/", 0, 0, false},
   647  	{"HTTP/-1,0", 0, 0, false},
   648  	{"HTTP/0,-1", 0, 0, false},
   649  	{"HTTP/", 0, 0, false},
   650  	{"HTTP/1,1", 0, 0, false},
   651  	{"HTTP/+1.1", 0, 0, false},
   652  	{"HTTP/1.+1", 0, 0, false},
   653  	{"HTTP/0000000001.1", 0, 0, false},
   654  	{"HTTP/1.0000000001", 0, 0, false},
   655  	{"HTTP/3.14", 0, 0, false},
   656  	{"HTTP/12.3", 0, 0, false},
   657  }
   658  
   659  func TestParseHTTPVersion(t *testing.T) {
   660  	for _, tt := range parseHTTPVersionTests {
   661  		major, minor, ok := ParseHTTPVersion(tt.vers)
   662  		if ok != tt.ok || major != tt.major || minor != tt.minor {
   663  			type version struct {
   664  				major, minor int
   665  				ok           bool
   666  			}
   667  			t.Errorf("failed to parse %q, expected: %#v, got %#v", tt.vers, version{tt.major, tt.minor, tt.ok}, version{major, minor, ok})
   668  		}
   669  	}
   670  }
   671  
   672  type getBasicAuthTest struct {
   673  	username, password string
   674  	ok                 bool
   675  }
   676  
   677  type basicAuthCredentialsTest struct {
   678  	username, password string
   679  }
   680  
   681  var getBasicAuthTests = []struct {
   682  	username, password string
   683  	ok                 bool
   684  }{
   685  	{"Aladdin", "open sesame", true},
   686  	{"Aladdin", "open:sesame", true},
   687  	{"", "", true},
   688  }
   689  
   690  func TestGetBasicAuth(t *testing.T) {
   691  	for _, tt := range getBasicAuthTests {
   692  		r, _ := NewRequest("GET", "http://example.com/", nil)
   693  		r.SetBasicAuth(tt.username, tt.password)
   694  		username, password, ok := r.BasicAuth()
   695  		if ok != tt.ok || username != tt.username || password != tt.password {
   696  			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
   697  				getBasicAuthTest{tt.username, tt.password, tt.ok})
   698  		}
   699  	}
   700  	// Unauthenticated request.
   701  	r, _ := NewRequest("GET", "http://example.com/", nil)
   702  	username, password, ok := r.BasicAuth()
   703  	if ok {
   704  		t.Errorf("expected false from BasicAuth when the request is unauthenticated")
   705  	}
   706  	want := basicAuthCredentialsTest{"", ""}
   707  	if username != want.username || password != want.password {
   708  		t.Errorf("expected credentials: %#v when the request is unauthenticated, got %#v",
   709  			want, basicAuthCredentialsTest{username, password})
   710  	}
   711  }
   712  
   713  var parseBasicAuthTests = []struct {
   714  	header, username, password string
   715  	ok                         bool
   716  }{
   717  	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
   718  
   719  	// Case doesn't matter:
   720  	{"BASIC " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
   721  	{"basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
   722  
   723  	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open:sesame")), "Aladdin", "open:sesame", true},
   724  	{"Basic " + base64.StdEncoding.EncodeToString([]byte(":")), "", "", true},
   725  	{"Basic" + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
   726  	{base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
   727  	{"Basic ", "", "", false},
   728  	{"Basic Aladdin:open sesame", "", "", false},
   729  	{`Digest username="Aladdin"`, "", "", false},
   730  }
   731  
   732  func TestParseBasicAuth(t *testing.T) {
   733  	for _, tt := range parseBasicAuthTests {
   734  		r, _ := NewRequest("GET", "http://example.com/", nil)
   735  		r.Header.Set("Authorization", tt.header)
   736  		username, password, ok := r.BasicAuth()
   737  		if ok != tt.ok || username != tt.username || password != tt.password {
   738  			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
   739  				getBasicAuthTest{tt.username, tt.password, tt.ok})
   740  		}
   741  	}
   742  }
   743  
   744  type logWrites struct {
   745  	t   *testing.T
   746  	dst *[]string
   747  }
   748  
   749  func (l logWrites) WriteByte(c byte) error {
   750  	l.t.Fatalf("unexpected WriteByte call")
   751  	return nil
   752  }
   753  
   754  func (l logWrites) Write(p []byte) (n int, err error) {
   755  	*l.dst = append(*l.dst, string(p))
   756  	return len(p), nil
   757  }
   758  
   759  func TestRequestWriteBufferedWriter(t *testing.T) {
   760  	got := []string{}
   761  	req, _ := NewRequest("GET", "http://foo.com/", nil)
   762  	req.Write(logWrites{t, &got})
   763  	want := []string{
   764  		"GET / HTTP/1.1\r\n",
   765  		"Host: foo.com\r\n",
   766  		"User-Agent: " + DefaultUserAgent + "\r\n",
   767  		"\r\n",
   768  	}
   769  	if !slices.Equal(got, want) {
   770  		t.Errorf("Writes = %q\n  Want = %q", got, want)
   771  	}
   772  }
   773  
   774  func TestRequestBadHostHeader(t *testing.T) {
   775  	got := []string{}
   776  	req, err := NewRequest("GET", "http://foo/after", nil)
   777  	if err != nil {
   778  		t.Fatal(err)
   779  	}
   780  	req.Host = "foo.com\nnewline"
   781  	req.URL.Host = "foo.com\nnewline"
   782  	req.Write(logWrites{t, &got})
   783  	want := []string{
   784  		"GET /after HTTP/1.1\r\n",
   785  		"Host: \r\n",
   786  		"User-Agent: " + DefaultUserAgent + "\r\n",
   787  		"\r\n",
   788  	}
   789  	if !slices.Equal(got, want) {
   790  		t.Errorf("Writes = %q\n  Want = %q", got, want)
   791  	}
   792  }
   793  
   794  func TestRequestBadUserAgent(t *testing.T) {
   795  	got := []string{}
   796  	req, err := NewRequest("GET", "http://foo/after", nil)
   797  	if err != nil {
   798  		t.Fatal(err)
   799  	}
   800  	req.Header.Set("User-Agent", "evil\r\nX-Evil: evil")
   801  	req.Write(logWrites{t, &got})
   802  	want := []string{
   803  		"GET /after HTTP/1.1\r\n",
   804  		"Host: foo\r\n",
   805  		"User-Agent: evil  X-Evil: evil\r\n",
   806  		"\r\n",
   807  	}
   808  	if !slices.Equal(got, want) {
   809  		t.Errorf("Writes = %q\n  Want = %q", got, want)
   810  	}
   811  }
   812  
   813  func TestStarRequest(t *testing.T) {
   814  	req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n")))
   815  	if err != nil {
   816  		return
   817  	}
   818  	if req.ContentLength != 0 {
   819  		t.Errorf("ContentLength = %d; want 0", req.ContentLength)
   820  	}
   821  	if req.Body == nil {
   822  		t.Errorf("Body = nil; want non-nil")
   823  	}
   824  
   825  	// Request.Write has Client semantics for Body/ContentLength,
   826  	// where ContentLength 0 means unknown if Body is non-nil, and
   827  	// thus chunking will happen unless we change semantics and
   828  	// signal that we want to serialize it as exactly zero.  The
   829  	// only way to do that for outbound requests is with a nil
   830  	// Body:
   831  	clientReq := *req
   832  	clientReq.Body = nil
   833  
   834  	var out strings.Builder
   835  	if err := clientReq.Write(&out); err != nil {
   836  		t.Fatal(err)
   837  	}
   838  
   839  	if strings.Contains(out.String(), "chunked") {
   840  		t.Error("wrote chunked request; want no body")
   841  	}
   842  	back, err := ReadRequest(bufio.NewReader(strings.NewReader(out.String())))
   843  	if err != nil {
   844  		t.Fatal(err)
   845  	}
   846  	// Ignore the Headers (the User-Agent breaks the deep equal,
   847  	// but we don't care about it)
   848  	req.Header = nil
   849  	back.Header = nil
   850  	if !reflect.DeepEqual(req, back) {
   851  		t.Errorf("Original request doesn't match Request read back.")
   852  		t.Logf("Original: %#v", req)
   853  		t.Logf("Original.URL: %#v", req.URL)
   854  		t.Logf("Wrote: %s", out.String())
   855  		t.Logf("Read back (doesn't match Original): %#v", back)
   856  	}
   857  }
   858  
   859  type responseWriterJustWriter struct {
   860  	io.Writer
   861  }
   862  
   863  func (responseWriterJustWriter) Header() Header  { panic("should not be called") }
   864  func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") }
   865  
   866  // delayedEOFReader never returns (n > 0, io.EOF), instead putting
   867  // off the io.EOF until a subsequent Read call.
   868  type delayedEOFReader struct {
   869  	r io.Reader
   870  }
   871  
   872  func (dr delayedEOFReader) Read(p []byte) (n int, err error) {
   873  	n, err = dr.r.Read(p)
   874  	if n > 0 && err == io.EOF {
   875  		err = nil
   876  	}
   877  	return
   878  }
   879  
   880  func TestIssue10884_MaxBytesEOF(t *testing.T) {
   881  	dst := io.Discard
   882  	_, err := io.Copy(dst, MaxBytesReader(
   883  		responseWriterJustWriter{dst},
   884  		io.NopCloser(delayedEOFReader{strings.NewReader("12345")}),
   885  		5))
   886  	if err != nil {
   887  		t.Fatal(err)
   888  	}
   889  }
   890  
   891  // Issue 14981: MaxBytesReader's return error wasn't sticky. It
   892  // doesn't technically need to be, but people expected it to be.
   893  func TestMaxBytesReaderStickyError(t *testing.T) {
   894  	isSticky := func(r io.Reader) error {
   895  		var log bytes.Buffer
   896  		buf := make([]byte, 1000)
   897  		var firstErr error
   898  		for {
   899  			n, err := r.Read(buf)
   900  			fmt.Fprintf(&log, "Read(%d) = %d, %v\n", len(buf), n, err)
   901  			if err == nil {
   902  				continue
   903  			}
   904  			if firstErr == nil {
   905  				firstErr = err
   906  				continue
   907  			}
   908  			if !reflect.DeepEqual(err, firstErr) {
   909  				return fmt.Errorf("non-sticky error. got log:\n%s", log.Bytes())
   910  			}
   911  			t.Logf("Got log: %s", log.Bytes())
   912  			return nil
   913  		}
   914  	}
   915  	tests := [...]struct {
   916  		readable int
   917  		limit    int64
   918  	}{
   919  		0: {99, 100},
   920  		1: {100, 100},
   921  		2: {101, 100},
   922  	}
   923  	for i, tt := range tests {
   924  		rc := MaxBytesReader(nil, io.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit)
   925  		if err := isSticky(rc); err != nil {
   926  			t.Errorf("%d. error: %v", i, err)
   927  		}
   928  	}
   929  }
   930  
   931  // Issue 45101: maxBytesReader's Read panicked when n < -1. This test
   932  // also ensures that Read treats negative limits as equivalent to 0.
   933  func TestMaxBytesReaderDifferentLimits(t *testing.T) {
   934  	const testStr = "1234"
   935  	tests := [...]struct {
   936  		limit   int64
   937  		lenP    int
   938  		wantN   int
   939  		wantErr bool
   940  	}{
   941  		0: {
   942  			limit:   -123,
   943  			lenP:    0,
   944  			wantN:   0,
   945  			wantErr: false, // Ensure we won't return an error when the limit is negative, but we don't need to read.
   946  		},
   947  		1: {
   948  			limit:   -100,
   949  			lenP:    32 * 1024,
   950  			wantN:   0,
   951  			wantErr: true,
   952  		},
   953  		2: {
   954  			limit:   -2,
   955  			lenP:    1,
   956  			wantN:   0,
   957  			wantErr: true,
   958  		},
   959  		3: {
   960  			limit:   -1,
   961  			lenP:    2,
   962  			wantN:   0,
   963  			wantErr: true,
   964  		},
   965  		4: {
   966  			limit:   0,
   967  			lenP:    3,
   968  			wantN:   0,
   969  			wantErr: true,
   970  		},
   971  		5: {
   972  			limit:   1,
   973  			lenP:    4,
   974  			wantN:   1,
   975  			wantErr: true,
   976  		},
   977  		6: {
   978  			limit:   2,
   979  			lenP:    5,
   980  			wantN:   2,
   981  			wantErr: true,
   982  		},
   983  		7: {
   984  			limit:   3,
   985  			lenP:    2,
   986  			wantN:   2,
   987  			wantErr: false,
   988  		},
   989  		8: {
   990  			limit:   int64(len(testStr)),
   991  			lenP:    len(testStr),
   992  			wantN:   len(testStr),
   993  			wantErr: false,
   994  		},
   995  		9: {
   996  			limit:   100,
   997  			lenP:    6,
   998  			wantN:   len(testStr),
   999  			wantErr: false,
  1000  		},
  1001  		10: { /* Issue 54408 */
  1002  			limit:   int64(1<<63 - 1),
  1003  			lenP:    len(testStr),
  1004  			wantN:   len(testStr),
  1005  			wantErr: false,
  1006  		},
  1007  	}
  1008  	for i, tt := range tests {
  1009  		rc := MaxBytesReader(nil, io.NopCloser(strings.NewReader(testStr)), tt.limit)
  1010  
  1011  		n, err := rc.Read(make([]byte, tt.lenP))
  1012  
  1013  		if n != tt.wantN {
  1014  			t.Errorf("%d. n: %d, want n: %d", i, n, tt.wantN)
  1015  		}
  1016  
  1017  		if (err != nil) != tt.wantErr {
  1018  			t.Errorf("%d. error: %v", i, err)
  1019  		}
  1020  	}
  1021  }
  1022  
  1023  func TestWithContextNilURL(t *testing.T) {
  1024  	req, err := NewRequest("POST", "https://golang.org/", nil)
  1025  	if err != nil {
  1026  		t.Fatal(err)
  1027  	}
  1028  
  1029  	// Issue 20601
  1030  	req.URL = nil
  1031  	reqCopy := req.WithContext(context.Background())
  1032  	if reqCopy.URL != nil {
  1033  		t.Error("expected nil URL in cloned request")
  1034  	}
  1035  }
  1036  
  1037  // Ensure that Request.Clone creates a deep copy of TransferEncoding.
  1038  // See issue 41907.
  1039  func TestRequestCloneTransferEncoding(t *testing.T) {
  1040  	body := strings.NewReader("body")
  1041  	req, _ := NewRequest("POST", "https://example.org/", body)
  1042  	req.TransferEncoding = []string{
  1043  		"encoding1",
  1044  	}
  1045  
  1046  	clonedReq := req.Clone(context.Background())
  1047  	// modify original after deep copy
  1048  	req.TransferEncoding[0] = "encoding2"
  1049  
  1050  	if req.TransferEncoding[0] != "encoding2" {
  1051  		t.Error("expected req.TransferEncoding to be changed")
  1052  	}
  1053  	if clonedReq.TransferEncoding[0] != "encoding1" {
  1054  		t.Error("expected clonedReq.TransferEncoding to be unchanged")
  1055  	}
  1056  }
  1057  
  1058  // Ensure that Request.Clone works correctly with PathValue.
  1059  // See issue 64911.
  1060  func TestRequestClonePathValue(t *testing.T) {
  1061  	req, _ := http.NewRequest("GET", "https://example.org/", nil)
  1062  	req.SetPathValue("p1", "orig")
  1063  
  1064  	clonedReq := req.Clone(context.Background())
  1065  	clonedReq.SetPathValue("p2", "copy")
  1066  
  1067  	// Ensure that any modifications to the cloned
  1068  	// request do not pollute the original request.
  1069  	if g, w := req.PathValue("p2"), ""; g != w {
  1070  		t.Fatalf("p2 mismatch got %q, want %q", g, w)
  1071  	}
  1072  	if g, w := req.PathValue("p1"), "orig"; g != w {
  1073  		t.Fatalf("p1 mismatch got %q, want %q", g, w)
  1074  	}
  1075  
  1076  	// Assert on the changes to the cloned request.
  1077  	if g, w := clonedReq.PathValue("p1"), "orig"; g != w {
  1078  		t.Fatalf("p1 mismatch got %q, want %q", g, w)
  1079  	}
  1080  	if g, w := clonedReq.PathValue("p2"), "copy"; g != w {
  1081  		t.Fatalf("p2 mismatch got %q, want %q", g, w)
  1082  	}
  1083  }
  1084  
  1085  // Issue 34878: verify we don't panic when including basic auth (Go 1.13 regression)
  1086  func TestNoPanicOnRoundTripWithBasicAuth(t *testing.T) { run(t, testNoPanicWithBasicAuth) }
  1087  func testNoPanicWithBasicAuth(t *testing.T, mode testMode) {
  1088  	cst := newClientServerTest(t, mode, HandlerFunc(func(w ResponseWriter, r *Request) {}))
  1089  
  1090  	u, err := url.Parse(cst.ts.URL)
  1091  	if err != nil {
  1092  		t.Fatal(err)
  1093  	}
  1094  	u.User = url.UserPassword("foo", "bar")
  1095  	req := &Request{
  1096  		URL:    u,
  1097  		Method: "GET",
  1098  	}
  1099  	if _, err := cst.c.Do(req); err != nil {
  1100  		t.Fatalf("Unexpected error: %v", err)
  1101  	}
  1102  }
  1103  
  1104  // verify that NewRequest sets Request.GetBody and that it works
  1105  func TestNewRequestGetBody(t *testing.T) {
  1106  	tests := []struct {
  1107  		r io.Reader
  1108  	}{
  1109  		{r: strings.NewReader("hello")},
  1110  		{r: bytes.NewReader([]byte("hello"))},
  1111  		{r: bytes.NewBuffer([]byte("hello"))},
  1112  	}
  1113  	for i, tt := range tests {
  1114  		req, err := NewRequest("POST", "http://foo.tld/", tt.r)
  1115  		if err != nil {
  1116  			t.Errorf("test[%d]: %v", i, err)
  1117  			continue
  1118  		}
  1119  		if req.Body == nil {
  1120  			t.Errorf("test[%d]: Body = nil", i)
  1121  			continue
  1122  		}
  1123  		if req.GetBody == nil {
  1124  			t.Errorf("test[%d]: GetBody = nil", i)
  1125  			continue
  1126  		}
  1127  		slurp1, err := io.ReadAll(req.Body)
  1128  		if err != nil {
  1129  			t.Errorf("test[%d]: ReadAll(Body) = %v", i, err)
  1130  		}
  1131  		newBody, err := req.GetBody()
  1132  		if err != nil {
  1133  			t.Errorf("test[%d]: GetBody = %v", i, err)
  1134  		}
  1135  		slurp2, err := io.ReadAll(newBody)
  1136  		if err != nil {
  1137  			t.Errorf("test[%d]: ReadAll(GetBody()) = %v", i, err)
  1138  		}
  1139  		if string(slurp1) != string(slurp2) {
  1140  			t.Errorf("test[%d]: Body %q != GetBody %q", i, slurp1, slurp2)
  1141  		}
  1142  	}
  1143  }
  1144  
  1145  func testMissingFile(t *testing.T, req *Request) {
  1146  	f, fh, err := req.FormFile("missing")
  1147  	if f != nil {
  1148  		t.Errorf("FormFile file = %v, want nil", f)
  1149  	}
  1150  	if fh != nil {
  1151  		t.Errorf("FormFile file header = %v, want nil", fh)
  1152  	}
  1153  	if err != ErrMissingFile {
  1154  		t.Errorf("FormFile err = %q, want ErrMissingFile", err)
  1155  	}
  1156  }
  1157  
  1158  func newTestMultipartRequest(t *testing.T) *Request {
  1159  	b := strings.NewReader(strings.ReplaceAll(message, "\n", "\r\n"))
  1160  	req, err := NewRequest("POST", "/", b)
  1161  	if err != nil {
  1162  		t.Fatal("NewRequest:", err)
  1163  	}
  1164  	ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
  1165  	req.Header.Set("Content-type", ctype)
  1166  	return req
  1167  }
  1168  
  1169  func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
  1170  	if g, e := req.FormValue("texta"), textaValue; g != e {
  1171  		t.Errorf("texta value = %q, want %q", g, e)
  1172  	}
  1173  	if g, e := req.FormValue("textb"), textbValue; g != e {
  1174  		t.Errorf("textb value = %q, want %q", g, e)
  1175  	}
  1176  	if g := req.FormValue("missing"); g != "" {
  1177  		t.Errorf("missing value = %q, want empty string", g)
  1178  	}
  1179  
  1180  	assertMem := func(n string, fd multipart.File) {
  1181  		if _, ok := fd.(*os.File); ok {
  1182  			t.Error(n, " is *os.File, should not be")
  1183  		}
  1184  	}
  1185  	fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
  1186  	defer fda.Close()
  1187  	assertMem("filea", fda)
  1188  	fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
  1189  	defer fdb.Close()
  1190  	if allMem {
  1191  		assertMem("fileb", fdb)
  1192  	} else {
  1193  		if _, ok := fdb.(*os.File); !ok {
  1194  			t.Errorf("fileb has unexpected underlying type %T", fdb)
  1195  		}
  1196  	}
  1197  
  1198  	testMissingFile(t, req)
  1199  }
  1200  
  1201  func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
  1202  	f, fh, err := req.FormFile(key)
  1203  	if err != nil {
  1204  		t.Fatalf("FormFile(%q): %q", key, err)
  1205  	}
  1206  	if fh.Filename != expectFilename {
  1207  		t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
  1208  	}
  1209  	var b strings.Builder
  1210  	_, err = io.Copy(&b, f)
  1211  	if err != nil {
  1212  		t.Fatal("copying contents:", err)
  1213  	}
  1214  	if g := b.String(); g != expectContent {
  1215  		t.Errorf("contents = %q, want %q", g, expectContent)
  1216  	}
  1217  	return f
  1218  }
  1219  
  1220  // Issue 53181: verify Request.Cookie return the correct Cookie.
  1221  // Return ErrNoCookie instead of the first cookie when name is "".
  1222  func TestRequestCookie(t *testing.T) {
  1223  	for _, tt := range []struct {
  1224  		name        string
  1225  		value       string
  1226  		expectedErr error
  1227  	}{
  1228  		{
  1229  			name:        "foo",
  1230  			value:       "bar",
  1231  			expectedErr: nil,
  1232  		},
  1233  		{
  1234  			name:        "",
  1235  			expectedErr: ErrNoCookie,
  1236  		},
  1237  	} {
  1238  		req, err := NewRequest("GET", "http://example.com/", nil)
  1239  		if err != nil {
  1240  			t.Fatal(err)
  1241  		}
  1242  		req.AddCookie(&Cookie{Name: tt.name, Value: tt.value})
  1243  		c, err := req.Cookie(tt.name)
  1244  		if err != tt.expectedErr {
  1245  			t.Errorf("got %v, want %v", err, tt.expectedErr)
  1246  		}
  1247  
  1248  		// skip if error occurred.
  1249  		if err != nil {
  1250  			continue
  1251  		}
  1252  		if c.Value != tt.value {
  1253  			t.Errorf("got %v, want %v", c.Value, tt.value)
  1254  		}
  1255  		if c.Name != tt.name {
  1256  			t.Errorf("got %s, want %v", tt.name, c.Name)
  1257  		}
  1258  	}
  1259  }
  1260  
  1261  func TestRequestCookiesByName(t *testing.T) {
  1262  	tests := []struct {
  1263  		in     []*Cookie
  1264  		filter string
  1265  		want   []*Cookie
  1266  	}{
  1267  		{
  1268  			in: []*Cookie{
  1269  				{Name: "foo", Value: "foo-1"},
  1270  				{Name: "bar", Value: "bar"},
  1271  			},
  1272  			filter: "foo",
  1273  			want:   []*Cookie{{Name: "foo", Value: "foo-1"}},
  1274  		},
  1275  		{
  1276  			in: []*Cookie{
  1277  				{Name: "foo", Value: "foo-1"},
  1278  				{Name: "foo", Value: "foo-2"},
  1279  				{Name: "bar", Value: "bar"},
  1280  			},
  1281  			filter: "foo",
  1282  			want: []*Cookie{
  1283  				{Name: "foo", Value: "foo-1"},
  1284  				{Name: "foo", Value: "foo-2"},
  1285  			},
  1286  		},
  1287  		{
  1288  			in: []*Cookie{
  1289  				{Name: "bar", Value: "bar"},
  1290  			},
  1291  			filter: "foo",
  1292  			want:   []*Cookie{},
  1293  		},
  1294  		{
  1295  			in: []*Cookie{
  1296  				{Name: "bar", Value: "bar"},
  1297  			},
  1298  			filter: "",
  1299  			want:   []*Cookie{},
  1300  		},
  1301  		{
  1302  			in:     []*Cookie{},
  1303  			filter: "foo",
  1304  			want:   []*Cookie{},
  1305  		},
  1306  	}
  1307  
  1308  	for _, tt := range tests {
  1309  		t.Run(tt.filter, func(t *testing.T) {
  1310  			req, err := NewRequest("GET", "http://example.com/", nil)
  1311  			if err != nil {
  1312  				t.Fatal(err)
  1313  			}
  1314  			for _, c := range tt.in {
  1315  				req.AddCookie(c)
  1316  			}
  1317  
  1318  			got := req.CookiesNamed(tt.filter)
  1319  
  1320  			if !reflect.DeepEqual(got, tt.want) {
  1321  				asStr := func(v any) string {
  1322  					blob, _ := json.MarshalIndent(v, "", "  ")
  1323  					return string(blob)
  1324  				}
  1325  				t.Fatalf("Result mismatch\n\tGot: %s\n\tWant: %s", asStr(got), asStr(tt.want))
  1326  			}
  1327  		})
  1328  	}
  1329  }
  1330  
  1331  const (
  1332  	fileaContents = "This is a test file."
  1333  	filebContents = "Another test file."
  1334  	textaValue    = "foo"
  1335  	textbValue    = "bar"
  1336  	boundary      = `MyBoundary`
  1337  )
  1338  
  1339  const message = `
  1340  --MyBoundary
  1341  Content-Disposition: form-data; name="filea"; filename="filea.txt"
  1342  Content-Type: text/plain
  1343  
  1344  ` + fileaContents + `
  1345  --MyBoundary
  1346  Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
  1347  Content-Type: text/plain
  1348  
  1349  ` + filebContents + `
  1350  --MyBoundary
  1351  Content-Disposition: form-data; name="texta"
  1352  
  1353  ` + textaValue + `
  1354  --MyBoundary
  1355  Content-Disposition: form-data; name="textb"
  1356  
  1357  ` + textbValue + `
  1358  --MyBoundary--
  1359  `
  1360  
  1361  func benchmarkReadRequest(b *testing.B, request string) {
  1362  	request = request + "\n"                            // final \n
  1363  	request = strings.ReplaceAll(request, "\n", "\r\n") // expand \n to \r\n
  1364  	b.SetBytes(int64(len(request)))
  1365  	r := bufio.NewReader(&infiniteReader{buf: []byte(request)})
  1366  	b.ReportAllocs()
  1367  	b.ResetTimer()
  1368  	for i := 0; i < b.N; i++ {
  1369  		_, err := ReadRequest(r)
  1370  		if err != nil {
  1371  			b.Fatalf("failed to read request: %v", err)
  1372  		}
  1373  	}
  1374  }
  1375  
  1376  // infiniteReader satisfies Read requests as if the contents of buf
  1377  // loop indefinitely.
  1378  type infiniteReader struct {
  1379  	buf    []byte
  1380  	offset int
  1381  }
  1382  
  1383  func (r *infiniteReader) Read(b []byte) (int, error) {
  1384  	n := copy(b, r.buf[r.offset:])
  1385  	r.offset = (r.offset + n) % len(r.buf)
  1386  	return n, nil
  1387  }
  1388  
  1389  func BenchmarkReadRequestChrome(b *testing.B) {
  1390  	// https://github.com/felixge/node-http-perf/blob/master/fixtures/get.http
  1391  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1392  Host: localhost:8080
  1393  Connection: keep-alive
  1394  Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  1395  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
  1396  Accept-Encoding: gzip,deflate,sdch
  1397  Accept-Language: en-US,en;q=0.8
  1398  Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
  1399  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
  1400  `)
  1401  }
  1402  
  1403  func BenchmarkReadRequestCurl(b *testing.B) {
  1404  	// curl http://localhost:8080/
  1405  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1406  User-Agent: curl/7.27.0
  1407  Host: localhost:8080
  1408  Accept: */*
  1409  `)
  1410  }
  1411  
  1412  func BenchmarkReadRequestApachebench(b *testing.B) {
  1413  	// ab -n 1 -c 1 http://localhost:8080/
  1414  	benchmarkReadRequest(b, `GET / HTTP/1.0
  1415  Host: localhost:8080
  1416  User-Agent: ApacheBench/2.3
  1417  Accept: */*
  1418  `)
  1419  }
  1420  
  1421  func BenchmarkReadRequestSiege(b *testing.B) {
  1422  	// siege -r 1 -c 1 http://localhost:8080/
  1423  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1424  Host: localhost:8080
  1425  Accept: */*
  1426  Accept-Encoding: gzip
  1427  User-Agent: JoeDog/1.00 [en] (X11; I; Siege 2.70)
  1428  Connection: keep-alive
  1429  `)
  1430  }
  1431  
  1432  func BenchmarkReadRequestWrk(b *testing.B) {
  1433  	// wrk -t 1 -r 1 -c 1 http://localhost:8080/
  1434  	benchmarkReadRequest(b, `GET / HTTP/1.1
  1435  Host: localhost:8080
  1436  `)
  1437  }
  1438  
  1439  func BenchmarkFileAndServer_1KB(b *testing.B) {
  1440  	benchmarkFileAndServer(b, 1<<10)
  1441  }
  1442  
  1443  func BenchmarkFileAndServer_16MB(b *testing.B) {
  1444  	benchmarkFileAndServer(b, 1<<24)
  1445  }
  1446  
  1447  func BenchmarkFileAndServer_64MB(b *testing.B) {
  1448  	benchmarkFileAndServer(b, 1<<26)
  1449  }
  1450  
  1451  func benchmarkFileAndServer(b *testing.B, n int64) {
  1452  	f, err := os.CreateTemp(os.TempDir(), "go-bench-http-file-and-server")
  1453  	if err != nil {
  1454  		b.Fatalf("Failed to create temp file: %v", err)
  1455  	}
  1456  
  1457  	defer func() {
  1458  		f.Close()
  1459  		os.RemoveAll(f.Name())
  1460  	}()
  1461  
  1462  	if _, err := io.CopyN(f, rand.Reader, n); err != nil {
  1463  		b.Fatalf("Failed to copy %d bytes: %v", n, err)
  1464  	}
  1465  
  1466  	run(b, func(b *testing.B, mode testMode) {
  1467  		runFileAndServerBenchmarks(b, mode, f, n)
  1468  	}, []testMode{http1Mode, https1Mode, http2Mode})
  1469  }
  1470  
  1471  func runFileAndServerBenchmarks(b *testing.B, mode testMode, f *os.File, n int64) {
  1472  	handler := HandlerFunc(func(rw ResponseWriter, req *Request) {
  1473  		defer req.Body.Close()
  1474  		nc, err := io.Copy(io.Discard, req.Body)
  1475  		if err != nil {
  1476  			panic(err)
  1477  		}
  1478  
  1479  		if nc != n {
  1480  			panic(fmt.Errorf("Copied %d Wanted %d bytes", nc, n))
  1481  		}
  1482  	})
  1483  
  1484  	cst := newClientServerTest(b, mode, handler).ts
  1485  
  1486  	b.ResetTimer()
  1487  	for i := 0; i < b.N; i++ {
  1488  		// Perform some setup.
  1489  		b.StopTimer()
  1490  		if _, err := f.Seek(0, 0); err != nil {
  1491  			b.Fatalf("Failed to seek back to file: %v", err)
  1492  		}
  1493  
  1494  		b.StartTimer()
  1495  		req, err := NewRequest("PUT", cst.URL, io.NopCloser(f))
  1496  		if err != nil {
  1497  			b.Fatal(err)
  1498  		}
  1499  
  1500  		req.ContentLength = n
  1501  		// Prevent mime sniffing by setting the Content-Type.
  1502  		req.Header.Set("Content-Type", "application/octet-stream")
  1503  		res, err := cst.Client().Do(req)
  1504  		if err != nil {
  1505  			b.Fatalf("Failed to make request to backend: %v", err)
  1506  		}
  1507  
  1508  		res.Body.Close()
  1509  		b.SetBytes(n)
  1510  	}
  1511  }
  1512  
  1513  func TestErrNotSupported(t *testing.T) {
  1514  	if !errors.Is(ErrNotSupported, errors.ErrUnsupported) {
  1515  		t.Error("errors.Is(ErrNotSupported, errors.ErrUnsupported) failed")
  1516  	}
  1517  }
  1518  
  1519  func TestPathValueNoMatch(t *testing.T) {
  1520  	// Check that PathValue and SetPathValue work on a Request that was never matched.
  1521  	var r Request
  1522  	if g, w := r.PathValue("x"), ""; g != w {
  1523  		t.Errorf("got %q, want %q", g, w)
  1524  	}
  1525  	r.SetPathValue("x", "a")
  1526  	if g, w := r.PathValue("x"), "a"; g != w {
  1527  		t.Errorf("got %q, want %q", g, w)
  1528  	}
  1529  }
  1530  
  1531  func TestPathValueAndPattern(t *testing.T) {
  1532  	for _, test := range []struct {
  1533  		pattern string
  1534  		url     string
  1535  		want    map[string]string
  1536  	}{
  1537  		{
  1538  			"/{a}/is/{b}/{c...}",
  1539  			"/now/is/the/time/for/all",
  1540  			map[string]string{
  1541  				"a": "now",
  1542  				"b": "the",
  1543  				"c": "time/for/all",
  1544  				"d": "",
  1545  			},
  1546  		},
  1547  		{
  1548  			"/names/{name}/{other...}",
  1549  			"/names/%2fjohn/address",
  1550  			map[string]string{
  1551  				"name":  "/john",
  1552  				"other": "address",
  1553  			},
  1554  		},
  1555  		{
  1556  			"/names/{name}/{other...}",
  1557  			"/names/john%2Fdoe/there/is%2F/more",
  1558  			map[string]string{
  1559  				"name":  "john/doe",
  1560  				"other": "there/is//more",
  1561  			},
  1562  		},
  1563  		{
  1564  			"/names/{name}/{other...}",
  1565  			"/names/n/*",
  1566  			map[string]string{
  1567  				"name":  "n",
  1568  				"other": "*",
  1569  			},
  1570  		},
  1571  	} {
  1572  		mux := NewServeMux()
  1573  		mux.HandleFunc(test.pattern, func(w ResponseWriter, r *Request) {
  1574  			for name, want := range test.want {
  1575  				got := r.PathValue(name)
  1576  				if got != want {
  1577  					t.Errorf("%q, %q: got %q, want %q", test.pattern, name, got, want)
  1578  				}
  1579  			}
  1580  			if r.Pattern != test.pattern {
  1581  				t.Errorf("pattern: got %s, want %s", r.Pattern, test.pattern)
  1582  			}
  1583  		})
  1584  		server := httptest.NewServer(mux)
  1585  		defer server.Close()
  1586  		res, err := Get(server.URL + test.url)
  1587  		if err != nil {
  1588  			t.Fatal(err)
  1589  		}
  1590  		res.Body.Close()
  1591  	}
  1592  }
  1593  
  1594  func TestSetPathValue(t *testing.T) {
  1595  	mux := NewServeMux()
  1596  	mux.HandleFunc("/a/{b}/c/{d...}", func(_ ResponseWriter, r *Request) {
  1597  		kvs := map[string]string{
  1598  			"b": "X",
  1599  			"d": "Y",
  1600  			"a": "Z",
  1601  		}
  1602  		for k, v := range kvs {
  1603  			r.SetPathValue(k, v)
  1604  		}
  1605  		for k, w := range kvs {
  1606  			if g := r.PathValue(k); g != w {
  1607  				t.Errorf("got %q, want %q", g, w)
  1608  			}
  1609  		}
  1610  	})
  1611  	server := httptest.NewServer(mux)
  1612  	defer server.Close()
  1613  	res, err := Get(server.URL + "/a/b/c/d/e")
  1614  	if err != nil {
  1615  		t.Fatal(err)
  1616  	}
  1617  	res.Body.Close()
  1618  }
  1619  
  1620  func TestStatus(t *testing.T) {
  1621  	// The main purpose of this test is to check 405 responses and the Allow header.
  1622  	h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {})
  1623  	mux := NewServeMux()
  1624  	mux.Handle("GET /g", h)
  1625  	mux.Handle("POST /p", h)
  1626  	mux.Handle("PATCH /p", h)
  1627  	mux.Handle("PUT /r", h)
  1628  	mux.Handle("GET /r/", h)
  1629  	server := httptest.NewServer(mux)
  1630  	defer server.Close()
  1631  
  1632  	for _, test := range []struct {
  1633  		method, path string
  1634  		wantStatus   int
  1635  		wantAllow    string
  1636  	}{
  1637  		{"GET", "/g", 200, ""},
  1638  		{"HEAD", "/g", 200, ""},
  1639  		{"POST", "/g", 405, "GET, HEAD"},
  1640  		{"GET", "/x", 404, ""},
  1641  		{"GET", "/p", 405, "PATCH, POST"},
  1642  		{"GET", "/./p", 405, "PATCH, POST"},
  1643  		{"GET", "/r/", 200, ""},
  1644  		{"GET", "/r", 200, ""}, // redirected
  1645  		{"HEAD", "/r/", 200, ""},
  1646  		{"HEAD", "/r", 200, ""}, // redirected
  1647  		{"PUT", "/r/", 405, "GET, HEAD"},
  1648  		{"PUT", "/r", 200, ""},
  1649  	} {
  1650  		req, err := http.NewRequest(test.method, server.URL+test.path, nil)
  1651  		if err != nil {
  1652  			t.Fatal(err)
  1653  		}
  1654  		res, err := http.DefaultClient.Do(req)
  1655  		if err != nil {
  1656  			t.Fatal(err)
  1657  		}
  1658  		res.Body.Close()
  1659  		if g, w := res.StatusCode, test.wantStatus; g != w {
  1660  			t.Errorf("%s %s: got %d, want %d", test.method, test.path, g, w)
  1661  		}
  1662  		if g, w := res.Header.Get("Allow"), test.wantAllow; g != w {
  1663  			t.Errorf("%s %s, Allow: got %q, want %q", test.method, test.path, g, w)
  1664  		}
  1665  	}
  1666  }
  1667  

View as plain text