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