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