netramesh

Форк
0
/
request_test.go 
1048 строк · 29.2 Кб
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
	"encoding/base64"
12
	"fmt"
13
	"io"
14
	"io/ioutil"
15
	"mime/multipart"
16
	. "net/http"
17
	"net/url"
18
	"os"
19
	"reflect"
20
	"regexp"
21
	"strings"
22
	"testing"
23
)
24

25
func TestQuery(t *testing.T) {
26
	req := &Request{Method: "GET"}
27
	req.URL, _ = url.Parse("http://www.google.com/search?q=foo&q=bar")
28
	if q := req.FormValue("q"); q != "foo" {
29
		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
30
	}
31
}
32

33
func TestParseFormQuery(t *testing.T) {
34
	req, _ := NewRequest("POST", "http://www.google.com/search?q=foo&q=bar&both=x&prio=1&orphan=nope&empty=not",
35
		strings.NewReader("z=post&both=y&prio=2&=nokey&orphan;empty=&"))
36
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
37

38
	if q := req.FormValue("q"); q != "foo" {
39
		t.Errorf(`req.FormValue("q") = %q, want "foo"`, q)
40
	}
41
	if z := req.FormValue("z"); z != "post" {
42
		t.Errorf(`req.FormValue("z") = %q, want "post"`, z)
43
	}
44
	if bq, found := req.PostForm["q"]; found {
45
		t.Errorf(`req.PostForm["q"] = %q, want no entry in map`, bq)
46
	}
47
	if bz := req.PostFormValue("z"); bz != "post" {
48
		t.Errorf(`req.PostFormValue("z") = %q, want "post"`, bz)
49
	}
50
	if qs := req.Form["q"]; !reflect.DeepEqual(qs, []string{"foo", "bar"}) {
51
		t.Errorf(`req.Form["q"] = %q, want ["foo", "bar"]`, qs)
52
	}
53
	if both := req.Form["both"]; !reflect.DeepEqual(both, []string{"y", "x"}) {
54
		t.Errorf(`req.Form["both"] = %q, want ["y", "x"]`, both)
55
	}
56
	if prio := req.FormValue("prio"); prio != "2" {
57
		t.Errorf(`req.FormValue("prio") = %q, want "2" (from body)`, prio)
58
	}
59
	if orphan := req.Form["orphan"]; !reflect.DeepEqual(orphan, []string{"", "nope"}) {
60
		t.Errorf(`req.FormValue("orphan") = %q, want "" (from body)`, orphan)
61
	}
62
	if empty := req.Form["empty"]; !reflect.DeepEqual(empty, []string{"", "not"}) {
63
		t.Errorf(`req.FormValue("empty") = %q, want "" (from body)`, empty)
64
	}
65
	if nokey := req.Form[""]; !reflect.DeepEqual(nokey, []string{"nokey"}) {
66
		t.Errorf(`req.FormValue("nokey") = %q, want "nokey" (from body)`, nokey)
67
	}
68
}
69

70
// Tests that we only parse the form automatically for certain methods.
71
func TestParseFormQueryMethods(t *testing.T) {
72
	for _, method := range []string{"POST", "PATCH", "PUT", "FOO"} {
73
		req, _ := NewRequest(method, "http://www.google.com/search",
74
			strings.NewReader("foo=bar"))
75
		req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
76
		want := "bar"
77
		if method == "FOO" {
78
			want = ""
79
		}
80
		if got := req.FormValue("foo"); got != want {
81
			t.Errorf(`for method %s, FormValue("foo") = %q; want %q`, method, got, want)
82
		}
83
	}
84
}
85

86
type stringMap map[string][]string
87
type parseContentTypeTest struct {
88
	shouldError bool
89
	contentType stringMap
90
}
91

92
var parseContentTypeTests = []parseContentTypeTest{
93
	{false, stringMap{"Content-Type": {"text/plain"}}},
94
	// Empty content type is legal - may be treated as
95
	// application/octet-stream (RFC 7231, section 3.1.1.5)
96
	{false, stringMap{}},
97
	{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
98
	{false, stringMap{"Content-Type": {"application/unknown"}}},
99
}
100

101
func TestParseFormUnknownContentType(t *testing.T) {
102
	for i, test := range parseContentTypeTests {
103
		req := &Request{
104
			Method: "POST",
105
			Header: Header(test.contentType),
106
			Body:   ioutil.NopCloser(strings.NewReader("body")),
107
		}
108
		err := req.ParseForm()
109
		switch {
110
		case err == nil && test.shouldError:
111
			t.Errorf("test %d should have returned error", i)
112
		case err != nil && !test.shouldError:
113
			t.Errorf("test %d should not have returned error, got %v", i, err)
114
		}
115
	}
116
}
117

118
func TestParseFormInitializeOnError(t *testing.T) {
119
	nilBody, _ := NewRequest("POST", "http://www.google.com/search?q=foo", nil)
120
	tests := []*Request{
121
		nilBody,
122
		{Method: "GET", URL: nil},
123
	}
124
	for i, req := range tests {
125
		err := req.ParseForm()
126
		if req.Form == nil {
127
			t.Errorf("%d. Form not initialized, error %v", i, err)
128
		}
129
		if req.PostForm == nil {
130
			t.Errorf("%d. PostForm not initialized, error %v", i, err)
131
		}
132
	}
133
}
134

135
func TestMultipartReader(t *testing.T) {
136
	req := &Request{
137
		Method: "POST",
138
		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
139
		Body:   ioutil.NopCloser(new(bytes.Buffer)),
140
	}
141
	multipart, err := req.MultipartReader()
142
	if multipart == nil {
143
		t.Errorf("expected multipart; error: %v", err)
144
	}
145

146
	req = &Request{
147
		Method: "POST",
148
		Header: Header{"Content-Type": {`multipart/mixed; boundary="foo123"`}},
149
		Body:   ioutil.NopCloser(new(bytes.Buffer)),
150
	}
151
	multipart, err = req.MultipartReader()
152
	if multipart == nil {
153
		t.Errorf("expected multipart; error: %v", err)
154
	}
155

156
	req.Header = Header{"Content-Type": {"text/plain"}}
157
	multipart, err = req.MultipartReader()
158
	if multipart != nil {
159
		t.Error("unexpected multipart for text/plain")
160
	}
161
}
162

163
// Issue 9305: ParseMultipartForm should populate PostForm too
164
func TestParseMultipartFormPopulatesPostForm(t *testing.T) {
165
	postData :=
166
		`--xxx
167
Content-Disposition: form-data; name="field1"
168

169
value1
170
--xxx
171
Content-Disposition: form-data; name="field2"
172

173
value2
174
--xxx
175
Content-Disposition: form-data; name="file"; filename="file"
176
Content-Type: application/octet-stream
177
Content-Transfer-Encoding: binary
178

179
binary data
180
--xxx--
181
`
182
	req := &Request{
183
		Method: "POST",
184
		Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}},
185
		Body:   ioutil.NopCloser(strings.NewReader(postData)),
186
	}
187

188
	initialFormItems := map[string]string{
189
		"language": "Go",
190
		"name":     "gopher",
191
		"skill":    "go-ing",
192
		"field2":   "initial-value2",
193
	}
194

195
	req.Form = make(url.Values)
196
	for k, v := range initialFormItems {
197
		req.Form.Add(k, v)
198
	}
199

200
	err := req.ParseMultipartForm(10000)
201
	if err != nil {
202
		t.Fatalf("unexpected multipart error %v", err)
203
	}
204

205
	wantForm := url.Values{
206
		"language": []string{"Go"},
207
		"name":     []string{"gopher"},
208
		"skill":    []string{"go-ing"},
209
		"field1":   []string{"value1"},
210
		"field2":   []string{"initial-value2", "value2"},
211
	}
212
	if !reflect.DeepEqual(req.Form, wantForm) {
213
		t.Fatalf("req.Form = %v, want %v", req.Form, wantForm)
214
	}
215

216
	wantPostForm := url.Values{
217
		"field1": []string{"value1"},
218
		"field2": []string{"value2"},
219
	}
220
	if !reflect.DeepEqual(req.PostForm, wantPostForm) {
221
		t.Fatalf("req.PostForm = %v, want %v", req.PostForm, wantPostForm)
222
	}
223
}
224

225
func TestParseMultipartForm(t *testing.T) {
226
	req := &Request{
227
		Method: "POST",
228
		Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}},
229
		Body:   ioutil.NopCloser(new(bytes.Buffer)),
230
	}
231
	err := req.ParseMultipartForm(25)
232
	if err == nil {
233
		t.Error("expected multipart EOF, got nil")
234
	}
235

236
	req.Header = Header{"Content-Type": {"text/plain"}}
237
	err = req.ParseMultipartForm(25)
238
	if err != ErrNotMultipart {
239
		t.Error("expected ErrNotMultipart for text/plain")
240
	}
241
}
242

243
func TestRedirect_h1(t *testing.T) { testRedirect(t, h1Mode) }
244
func TestRedirect_h2(t *testing.T) { testRedirect(t, h2Mode) }
245
func testRedirect(t *testing.T, h2 bool) {
246
	defer afterTest(t)
247
	cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
248
		switch r.URL.Path {
249
		case "/":
250
			w.Header().Set("Location", "/foo/")
251
			w.WriteHeader(StatusSeeOther)
252
		case "/foo/":
253
			fmt.Fprintf(w, "foo")
254
		default:
255
			w.WriteHeader(StatusBadRequest)
256
		}
257
	}))
258
	defer cst.close()
259

260
	var end = regexp.MustCompile("/foo/$")
261
	r, err := cst.c.Get(cst.ts.URL)
262
	if err != nil {
263
		t.Fatal(err)
264
	}
265
	r.Body.Close()
266
	url := r.Request.URL.String()
267
	if r.StatusCode != 200 || !end.MatchString(url) {
268
		t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url)
269
	}
270
}
271

272
func TestSetBasicAuth(t *testing.T) {
273
	r, _ := NewRequest("GET", "http://example.com/", nil)
274
	r.SetBasicAuth("Aladdin", "open sesame")
275
	if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e {
276
		t.Errorf("got header %q, want %q", g, e)
277
	}
278
}
279

280
func TestMultipartRequest(t *testing.T) {
281
	// Test that we can read the values and files of a
282
	// multipart request with FormValue and FormFile,
283
	// and that ParseMultipartForm can be called multiple times.
284
	req := newTestMultipartRequest(t)
285
	if err := req.ParseMultipartForm(25); err != nil {
286
		t.Fatal("ParseMultipartForm first call:", err)
287
	}
288
	defer req.MultipartForm.RemoveAll()
289
	validateTestMultipartContents(t, req, false)
290
	if err := req.ParseMultipartForm(25); err != nil {
291
		t.Fatal("ParseMultipartForm second call:", err)
292
	}
293
	validateTestMultipartContents(t, req, false)
294
}
295

296
func TestMultipartRequestAuto(t *testing.T) {
297
	// Test that FormValue and FormFile automatically invoke
298
	// ParseMultipartForm and return the right values.
299
	req := newTestMultipartRequest(t)
300
	defer func() {
301
		if req.MultipartForm != nil {
302
			req.MultipartForm.RemoveAll()
303
		}
304
	}()
305
	validateTestMultipartContents(t, req, true)
306
}
307

308
func TestMissingFileMultipartRequest(t *testing.T) {
309
	// Test that FormFile returns an error if
310
	// the named file is missing.
311
	req := newTestMultipartRequest(t)
312
	testMissingFile(t, req)
313
}
314

315
// Test that FormValue invokes ParseMultipartForm.
316
func TestFormValueCallsParseMultipartForm(t *testing.T) {
317
	req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post"))
318
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")
319
	if req.Form != nil {
320
		t.Fatal("Unexpected request Form, want nil")
321
	}
322
	req.FormValue("z")
323
	if req.Form == nil {
324
		t.Fatal("ParseMultipartForm not called by FormValue")
325
	}
326
}
327

328
// Test that FormFile invokes ParseMultipartForm.
329
func TestFormFileCallsParseMultipartForm(t *testing.T) {
330
	req := newTestMultipartRequest(t)
331
	if req.Form != nil {
332
		t.Fatal("Unexpected request Form, want nil")
333
	}
334
	req.FormFile("")
335
	if req.Form == nil {
336
		t.Fatal("ParseMultipartForm not called by FormFile")
337
	}
338
}
339

340
// Test that ParseMultipartForm errors if called
341
// after MultipartReader on the same request.
342
func TestParseMultipartFormOrder(t *testing.T) {
343
	req := newTestMultipartRequest(t)
344
	if _, err := req.MultipartReader(); err != nil {
345
		t.Fatalf("MultipartReader: %v", err)
346
	}
347
	if err := req.ParseMultipartForm(1024); err == nil {
348
		t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader")
349
	}
350
}
351

352
// Test that MultipartReader errors if called
353
// after ParseMultipartForm on the same request.
354
func TestMultipartReaderOrder(t *testing.T) {
355
	req := newTestMultipartRequest(t)
356
	if err := req.ParseMultipartForm(25); err != nil {
357
		t.Fatalf("ParseMultipartForm: %v", err)
358
	}
359
	defer req.MultipartForm.RemoveAll()
360
	if _, err := req.MultipartReader(); err == nil {
361
		t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm")
362
	}
363
}
364

365
// Test that FormFile errors if called after
366
// MultipartReader on the same request.
367
func TestFormFileOrder(t *testing.T) {
368
	req := newTestMultipartRequest(t)
369
	if _, err := req.MultipartReader(); err != nil {
370
		t.Fatalf("MultipartReader: %v", err)
371
	}
372
	if _, _, err := req.FormFile(""); err == nil {
373
		t.Fatal("expected an error from FormFile after call to MultipartReader")
374
	}
375
}
376

377
var readRequestErrorTests = []struct {
378
	in  string
379
	err string
380

381
	header Header
382
}{
383
	0: {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", "", Header{"Header": {"foo"}}},
384
	1: {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF.Error(), nil},
385
	2: {"", io.EOF.Error(), nil},
386
	3: {
387
		in:  "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n",
388
		err: "http: method cannot contain a Content-Length",
389
	},
390
	4: {
391
		in:     "HEAD / HTTP/1.1\r\n\r\n",
392
		header: Header{},
393
	},
394

395
	// Multiple Content-Length values should either be
396
	// deduplicated if same or reject otherwise
397
	// See Issue 16490.
398
	5: {
399
		in:  "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n",
400
		err: "cannot contain multiple Content-Length headers",
401
	},
402
	6: {
403
		in:  "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n",
404
		err: "cannot contain multiple Content-Length headers",
405
	},
406
	7: {
407
		in:     "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n",
408
		err:    "",
409
		header: Header{"Content-Length": {"6"}},
410
	},
411
	8: {
412
		in:  "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n",
413
		err: "cannot contain multiple Content-Length headers",
414
	},
415
	9: {
416
		in:  "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n",
417
		err: "cannot contain multiple Content-Length headers",
418
	},
419
	10: {
420
		in:     "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n",
421
		header: Header{"Content-Length": {"0"}},
422
	},
423
}
424

425
func TestReadRequestErrors(t *testing.T) {
426
	for i, tt := range readRequestErrorTests {
427
		req, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in)))
428
		if err == nil {
429
			if tt.err != "" {
430
				t.Errorf("#%d: got nil err; want %q", i, tt.err)
431
			}
432

433
			if !reflect.DeepEqual(tt.header, req.Header) {
434
				t.Errorf("#%d: gotHeader: %q wantHeader: %q", i, req.Header, tt.header)
435
			}
436
			continue
437
		}
438

439
		if tt.err == "" || !strings.Contains(err.Error(), tt.err) {
440
			t.Errorf("%d: got error = %v; want %v", i, err, tt.err)
441
		}
442
	}
443
}
444

445
var newRequestHostTests = []struct {
446
	in, out string
447
}{
448
	{"http://www.example.com/", "www.example.com"},
449
	{"http://www.example.com:8080/", "www.example.com:8080"},
450

451
	{"http://192.168.0.1/", "192.168.0.1"},
452
	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
453
	{"http://192.168.0.1:/", "192.168.0.1"},
454

455
	{"http://[fe80::1]/", "[fe80::1]"},
456
	{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
457
	{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
458
	{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
459
	{"http://[fe80::1%25en0]:/", "[fe80::1%en0]"},
460
}
461

462
func TestNewRequestHost(t *testing.T) {
463
	for i, tt := range newRequestHostTests {
464
		req, err := NewRequest("GET", tt.in, nil)
465
		if err != nil {
466
			t.Errorf("#%v: %v", i, err)
467
			continue
468
		}
469
		if req.Host != tt.out {
470
			t.Errorf("got %q; want %q", req.Host, tt.out)
471
		}
472
	}
473
}
474

475
func TestRequestInvalidMethod(t *testing.T) {
476
	_, err := NewRequest("bad method", "http://foo.com/", nil)
477
	if err == nil {
478
		t.Error("expected error from NewRequest with invalid method")
479
	}
480
	req, err := NewRequest("GET", "http://foo.example/", nil)
481
	if err != nil {
482
		t.Fatal(err)
483
	}
484
	req.Method = "bad method"
485
	_, err = DefaultClient.Do(req)
486
	if err == nil || !strings.Contains(err.Error(), "invalid method") {
487
		t.Errorf("Transport error = %v; want invalid method", err)
488
	}
489

490
	req, err = NewRequest("", "http://foo.com/", nil)
491
	if err != nil {
492
		t.Errorf("NewRequest(empty method) = %v; want nil", err)
493
	} else if req.Method != "GET" {
494
		t.Errorf("NewRequest(empty method) has method %q; want GET", req.Method)
495
	}
496
}
497

498
func TestNewRequestContentLength(t *testing.T) {
499
	readByte := func(r io.Reader) io.Reader {
500
		var b [1]byte
501
		r.Read(b[:])
502
		return r
503
	}
504
	tests := []struct {
505
		r    io.Reader
506
		want int64
507
	}{
508
		{bytes.NewReader([]byte("123")), 3},
509
		{bytes.NewBuffer([]byte("1234")), 4},
510
		{strings.NewReader("12345"), 5},
511
		{strings.NewReader(""), 0},
512
		{NoBody, 0},
513

514
		// Not detected. During Go 1.8 we tried to make these set to -1, but
515
		// due to Issue 18117, we keep these returning 0, even though they're
516
		// unknown.
517
		{struct{ io.Reader }{strings.NewReader("xyz")}, 0},
518
		{io.NewSectionReader(strings.NewReader("x"), 0, 6), 0},
519
		{readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0},
520
	}
521
	for i, tt := range tests {
522
		req, err := NewRequest("POST", "http://localhost/", tt.r)
523
		if err != nil {
524
			t.Fatal(err)
525
		}
526
		if req.ContentLength != tt.want {
527
			t.Errorf("test[%d]: ContentLength(%T) = %d; want %d", i, tt.r, req.ContentLength, tt.want)
528
		}
529
	}
530
}
531

532
var parseHTTPVersionTests = []struct {
533
	vers         string
534
	major, minor int
535
	ok           bool
536
}{
537
	{"HTTP/0.9", 0, 9, true},
538
	{"HTTP/1.0", 1, 0, true},
539
	{"HTTP/1.1", 1, 1, true},
540
	{"HTTP/3.14", 3, 14, true},
541

542
	{"HTTP", 0, 0, false},
543
	{"HTTP/one.one", 0, 0, false},
544
	{"HTTP/1.1/", 0, 0, false},
545
	{"HTTP/-1,0", 0, 0, false},
546
	{"HTTP/0,-1", 0, 0, false},
547
	{"HTTP/", 0, 0, false},
548
	{"HTTP/1,1", 0, 0, false},
549
}
550

551
func TestParseHTTPVersion(t *testing.T) {
552
	for _, tt := range parseHTTPVersionTests {
553
		major, minor, ok := ParseHTTPVersion(tt.vers)
554
		if ok != tt.ok || major != tt.major || minor != tt.minor {
555
			type version struct {
556
				major, minor int
557
				ok           bool
558
			}
559
			t.Errorf("failed to parse %q, expected: %#v, got %#v", tt.vers, version{tt.major, tt.minor, tt.ok}, version{major, minor, ok})
560
		}
561
	}
562
}
563

564
type getBasicAuthTest struct {
565
	username, password string
566
	ok                 bool
567
}
568

569
type basicAuthCredentialsTest struct {
570
	username, password string
571
}
572

573
var getBasicAuthTests = []struct {
574
	username, password string
575
	ok                 bool
576
}{
577
	{"Aladdin", "open sesame", true},
578
	{"Aladdin", "open:sesame", true},
579
	{"", "", true},
580
}
581

582
func TestGetBasicAuth(t *testing.T) {
583
	for _, tt := range getBasicAuthTests {
584
		r, _ := NewRequest("GET", "http://example.com/", nil)
585
		r.SetBasicAuth(tt.username, tt.password)
586
		username, password, ok := r.BasicAuth()
587
		if ok != tt.ok || username != tt.username || password != tt.password {
588
			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
589
				getBasicAuthTest{tt.username, tt.password, tt.ok})
590
		}
591
	}
592
	// Unauthenticated request.
593
	r, _ := NewRequest("GET", "http://example.com/", nil)
594
	username, password, ok := r.BasicAuth()
595
	if ok {
596
		t.Errorf("expected false from BasicAuth when the request is unauthenticated")
597
	}
598
	want := basicAuthCredentialsTest{"", ""}
599
	if username != want.username || password != want.password {
600
		t.Errorf("expected credentials: %#v when the request is unauthenticated, got %#v",
601
			want, basicAuthCredentialsTest{username, password})
602
	}
603
}
604

605
var parseBasicAuthTests = []struct {
606
	header, username, password string
607
	ok                         bool
608
}{
609
	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
610

611
	// Case doesn't matter:
612
	{"BASIC " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
613
	{"basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true},
614

615
	{"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open:sesame")), "Aladdin", "open:sesame", true},
616
	{"Basic " + base64.StdEncoding.EncodeToString([]byte(":")), "", "", true},
617
	{"Basic" + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
618
	{base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false},
619
	{"Basic ", "", "", false},
620
	{"Basic Aladdin:open sesame", "", "", false},
621
	{`Digest username="Aladdin"`, "", "", false},
622
}
623

624
func TestParseBasicAuth(t *testing.T) {
625
	for _, tt := range parseBasicAuthTests {
626
		r, _ := NewRequest("GET", "http://example.com/", nil)
627
		r.Header.Set("Authorization", tt.header)
628
		username, password, ok := r.BasicAuth()
629
		if ok != tt.ok || username != tt.username || password != tt.password {
630
			t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok},
631
				getBasicAuthTest{tt.username, tt.password, tt.ok})
632
		}
633
	}
634
}
635

636
type logWrites struct {
637
	t   *testing.T
638
	dst *[]string
639
}
640

641
func (l logWrites) WriteByte(c byte) error {
642
	l.t.Fatalf("unexpected WriteByte call")
643
	return nil
644
}
645

646
func (l logWrites) Write(p []byte) (n int, err error) {
647
	*l.dst = append(*l.dst, string(p))
648
	return len(p), nil
649
}
650

651
func TestRequestWriteBufferedWriter(t *testing.T) {
652
	got := []string{}
653
	req, _ := NewRequest("GET", "http://foo.com/", nil)
654
	req.Write(logWrites{t, &got})
655
	want := []string{
656
		"GET / HTTP/1.1\r\n",
657
		"Host: foo.com\r\n",
658
		"User-Agent: " + DefaultUserAgent + "\r\n",
659
		"\r\n",
660
	}
661
	if !reflect.DeepEqual(got, want) {
662
		t.Errorf("Writes = %q\n  Want = %q", got, want)
663
	}
664
}
665

666
func TestRequestBadHost(t *testing.T) {
667
	got := []string{}
668
	req, err := NewRequest("GET", "http://foo/after", nil)
669
	if err != nil {
670
		t.Fatal(err)
671
	}
672
	req.Host = "foo.com with spaces"
673
	req.URL.Host = "foo.com with spaces"
674
	req.Write(logWrites{t, &got})
675
	want := []string{
676
		"GET /after HTTP/1.1\r\n",
677
		"Host: foo.com\r\n",
678
		"User-Agent: " + DefaultUserAgent + "\r\n",
679
		"\r\n",
680
	}
681
	if !reflect.DeepEqual(got, want) {
682
		t.Errorf("Writes = %q\n  Want = %q", got, want)
683
	}
684
}
685

686
func TestStarRequest(t *testing.T) {
687
	req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n")))
688
	if err != nil {
689
		return
690
	}
691
	if req.ContentLength != 0 {
692
		t.Errorf("ContentLength = %d; want 0", req.ContentLength)
693
	}
694
	if req.Body == nil {
695
		t.Errorf("Body = nil; want non-nil")
696
	}
697

698
	// Request.Write has Client semantics for Body/ContentLength,
699
	// where ContentLength 0 means unknown if Body is non-nil, and
700
	// thus chunking will happen unless we change semantics and
701
	// signal that we want to serialize it as exactly zero.  The
702
	// only way to do that for outbound requests is with a nil
703
	// Body:
704
	clientReq := *req
705
	clientReq.Body = nil
706

707
	var out bytes.Buffer
708
	if err := clientReq.Write(&out); err != nil {
709
		t.Fatal(err)
710
	}
711

712
	if strings.Contains(out.String(), "chunked") {
713
		t.Error("wrote chunked request; want no body")
714
	}
715
	back, err := ReadRequest(bufio.NewReader(bytes.NewReader(out.Bytes())))
716
	if err != nil {
717
		t.Fatal(err)
718
	}
719
	// Ignore the Headers (the User-Agent breaks the deep equal,
720
	// but we don't care about it)
721
	req.Header = nil
722
	back.Header = nil
723
	if !reflect.DeepEqual(req, back) {
724
		t.Errorf("Original request doesn't match Request read back.")
725
		t.Logf("Original: %#v", req)
726
		t.Logf("Original.URL: %#v", req.URL)
727
		t.Logf("Wrote: %s", out.Bytes())
728
		t.Logf("Read back (doesn't match Original): %#v", back)
729
	}
730
}
731

732
type responseWriterJustWriter struct {
733
	io.Writer
734
}
735

736
func (responseWriterJustWriter) Header() Header  { panic("should not be called") }
737
func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") }
738

739
// delayedEOFReader never returns (n > 0, io.EOF), instead putting
740
// off the io.EOF until a subsequent Read call.
741
type delayedEOFReader struct {
742
	r io.Reader
743
}
744

745
func (dr delayedEOFReader) Read(p []byte) (n int, err error) {
746
	n, err = dr.r.Read(p)
747
	if n > 0 && err == io.EOF {
748
		err = nil
749
	}
750
	return
751
}
752

753
func TestIssue10884_MaxBytesEOF(t *testing.T) {
754
	dst := ioutil.Discard
755
	_, err := io.Copy(dst, MaxBytesReader(
756
		responseWriterJustWriter{dst},
757
		ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}),
758
		5))
759
	if err != nil {
760
		t.Fatal(err)
761
	}
762
}
763

764
// Issue 14981: MaxBytesReader's return error wasn't sticky. It
765
// doesn't technically need to be, but people expected it to be.
766
func TestMaxBytesReaderStickyError(t *testing.T) {
767
	isSticky := func(r io.Reader) error {
768
		var log bytes.Buffer
769
		buf := make([]byte, 1000)
770
		var firstErr error
771
		for {
772
			n, err := r.Read(buf)
773
			fmt.Fprintf(&log, "Read(%d) = %d, %v\n", len(buf), n, err)
774
			if err == nil {
775
				continue
776
			}
777
			if firstErr == nil {
778
				firstErr = err
779
				continue
780
			}
781
			if !reflect.DeepEqual(err, firstErr) {
782
				return fmt.Errorf("non-sticky error. got log:\n%s", log.Bytes())
783
			}
784
			t.Logf("Got log: %s", log.Bytes())
785
			return nil
786
		}
787
	}
788
	tests := [...]struct {
789
		readable int
790
		limit    int64
791
	}{
792
		0: {99, 100},
793
		1: {100, 100},
794
		2: {101, 100},
795
	}
796
	for i, tt := range tests {
797
		rc := MaxBytesReader(nil, ioutil.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit)
798
		if err := isSticky(rc); err != nil {
799
			t.Errorf("%d. error: %v", i, err)
800
		}
801
	}
802
}
803

804
func TestWithContextDeepCopiesURL(t *testing.T) {
805
	req, err := NewRequest("POST", "https://golang.org/", nil)
806
	if err != nil {
807
		t.Fatal(err)
808
	}
809

810
	reqCopy := req.WithContext(context.Background())
811
	reqCopy.URL.Scheme = "http"
812

813
	firstURL, secondURL := req.URL.String(), reqCopy.URL.String()
814
	if firstURL == secondURL {
815
		t.Errorf("unexpected change to original request's URL")
816
	}
817

818
	// And also check we don't crash on nil (Issue 20601)
819
	req.URL = nil
820
	reqCopy = req.WithContext(context.Background())
821
	if reqCopy.URL != nil {
822
		t.Error("expected nil URL in cloned request")
823
	}
824
}
825

826
// verify that NewRequest sets Request.GetBody and that it works
827
func TestNewRequestGetBody(t *testing.T) {
828
	tests := []struct {
829
		r io.Reader
830
	}{
831
		{r: strings.NewReader("hello")},
832
		{r: bytes.NewReader([]byte("hello"))},
833
		{r: bytes.NewBuffer([]byte("hello"))},
834
	}
835
	for i, tt := range tests {
836
		req, err := NewRequest("POST", "http://foo.tld/", tt.r)
837
		if err != nil {
838
			t.Errorf("test[%d]: %v", i, err)
839
			continue
840
		}
841
		if req.Body == nil {
842
			t.Errorf("test[%d]: Body = nil", i)
843
			continue
844
		}
845
		if req.GetBody == nil {
846
			t.Errorf("test[%d]: GetBody = nil", i)
847
			continue
848
		}
849
		slurp1, err := ioutil.ReadAll(req.Body)
850
		if err != nil {
851
			t.Errorf("test[%d]: ReadAll(Body) = %v", i, err)
852
		}
853
		newBody, err := req.GetBody()
854
		if err != nil {
855
			t.Errorf("test[%d]: GetBody = %v", i, err)
856
		}
857
		slurp2, err := ioutil.ReadAll(newBody)
858
		if err != nil {
859
			t.Errorf("test[%d]: ReadAll(GetBody()) = %v", i, err)
860
		}
861
		if string(slurp1) != string(slurp2) {
862
			t.Errorf("test[%d]: Body %q != GetBody %q", i, slurp1, slurp2)
863
		}
864
	}
865
}
866

867
func testMissingFile(t *testing.T, req *Request) {
868
	f, fh, err := req.FormFile("missing")
869
	if f != nil {
870
		t.Errorf("FormFile file = %v, want nil", f)
871
	}
872
	if fh != nil {
873
		t.Errorf("FormFile file header = %q, want nil", fh)
874
	}
875
	if err != ErrMissingFile {
876
		t.Errorf("FormFile err = %q, want ErrMissingFile", err)
877
	}
878
}
879

880
func newTestMultipartRequest(t *testing.T) *Request {
881
	b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1))
882
	req, err := NewRequest("POST", "/", b)
883
	if err != nil {
884
		t.Fatal("NewRequest:", err)
885
	}
886
	ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary)
887
	req.Header.Set("Content-type", ctype)
888
	return req
889
}
890

891
func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) {
892
	if g, e := req.FormValue("texta"), textaValue; g != e {
893
		t.Errorf("texta value = %q, want %q", g, e)
894
	}
895
	if g, e := req.FormValue("textb"), textbValue; g != e {
896
		t.Errorf("textb value = %q, want %q", g, e)
897
	}
898
	if g := req.FormValue("missing"); g != "" {
899
		t.Errorf("missing value = %q, want empty string", g)
900
	}
901

902
	assertMem := func(n string, fd multipart.File) {
903
		if _, ok := fd.(*os.File); ok {
904
			t.Error(n, " is *os.File, should not be")
905
		}
906
	}
907
	fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents)
908
	defer fda.Close()
909
	assertMem("filea", fda)
910
	fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents)
911
	defer fdb.Close()
912
	if allMem {
913
		assertMem("fileb", fdb)
914
	} else {
915
		if _, ok := fdb.(*os.File); !ok {
916
			t.Errorf("fileb has unexpected underlying type %T", fdb)
917
		}
918
	}
919

920
	testMissingFile(t, req)
921
}
922

923
func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File {
924
	f, fh, err := req.FormFile(key)
925
	if err != nil {
926
		t.Fatalf("FormFile(%q): %q", key, err)
927
	}
928
	if fh.Filename != expectFilename {
929
		t.Errorf("filename = %q, want %q", fh.Filename, expectFilename)
930
	}
931
	var b bytes.Buffer
932
	_, err = io.Copy(&b, f)
933
	if err != nil {
934
		t.Fatal("copying contents:", err)
935
	}
936
	if g := b.String(); g != expectContent {
937
		t.Errorf("contents = %q, want %q", g, expectContent)
938
	}
939
	return f
940
}
941

942
const (
943
	fileaContents = "This is a test file."
944
	filebContents = "Another test file."
945
	textaValue    = "foo"
946
	textbValue    = "bar"
947
	boundary      = `MyBoundary`
948
)
949

950
const message = `
951
--MyBoundary
952
Content-Disposition: form-data; name="filea"; filename="filea.txt"
953
Content-Type: text/plain
954

955
` + fileaContents + `
956
--MyBoundary
957
Content-Disposition: form-data; name="fileb"; filename="fileb.txt"
958
Content-Type: text/plain
959

960
` + filebContents + `
961
--MyBoundary
962
Content-Disposition: form-data; name="texta"
963

964
` + textaValue + `
965
--MyBoundary
966
Content-Disposition: form-data; name="textb"
967

968
` + textbValue + `
969
--MyBoundary--
970
`
971

972
func benchmarkReadRequest(b *testing.B, request string) {
973
	request = request + "\n"                             // final \n
974
	request = strings.Replace(request, "\n", "\r\n", -1) // expand \n to \r\n
975
	b.SetBytes(int64(len(request)))
976
	r := bufio.NewReader(&infiniteReader{buf: []byte(request)})
977
	b.ReportAllocs()
978
	b.ResetTimer()
979
	for i := 0; i < b.N; i++ {
980
		_, err := ReadRequest(r)
981
		if err != nil {
982
			b.Fatalf("failed to read request: %v", err)
983
		}
984
	}
985
}
986

987
// infiniteReader satisfies Read requests as if the contents of buf
988
// loop indefinitely.
989
type infiniteReader struct {
990
	buf    []byte
991
	offset int
992
}
993

994
func (r *infiniteReader) Read(b []byte) (int, error) {
995
	n := copy(b, r.buf[r.offset:])
996
	r.offset = (r.offset + n) % len(r.buf)
997
	return n, nil
998
}
999

1000
func BenchmarkReadRequestChrome(b *testing.B) {
1001
	// https://github.com/felixge/node-http-perf/blob/master/fixtures/get.http
1002
	benchmarkReadRequest(b, `GET / HTTP/1.1
1003
Host: localhost:8080
1004
Connection: keep-alive
1005
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
1006
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
1007
Accept-Encoding: gzip,deflate,sdch
1008
Accept-Language: en-US,en;q=0.8
1009
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
1010
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
1011
`)
1012
}
1013

1014
func BenchmarkReadRequestCurl(b *testing.B) {
1015
	// curl http://localhost:8080/
1016
	benchmarkReadRequest(b, `GET / HTTP/1.1
1017
User-Agent: curl/7.27.0
1018
Host: localhost:8080
1019
Accept: */*
1020
`)
1021
}
1022

1023
func BenchmarkReadRequestApachebench(b *testing.B) {
1024
	// ab -n 1 -c 1 http://localhost:8080/
1025
	benchmarkReadRequest(b, `GET / HTTP/1.0
1026
Host: localhost:8080
1027
User-Agent: ApacheBench/2.3
1028
Accept: */*
1029
`)
1030
}
1031

1032
func BenchmarkReadRequestSiege(b *testing.B) {
1033
	// siege -r 1 -c 1 http://localhost:8080/
1034
	benchmarkReadRequest(b, `GET / HTTP/1.1
1035
Host: localhost:8080
1036
Accept: */*
1037
Accept-Encoding: gzip
1038
User-Agent: JoeDog/1.00 [en] (X11; I; Siege 2.70)
1039
Connection: keep-alive
1040
`)
1041
}
1042

1043
func BenchmarkReadRequestWrk(b *testing.B) {
1044
	// wrk -t 1 -r 1 -c 1 http://localhost:8080/
1045
	benchmarkReadRequest(b, `GET / HTTP/1.1
1046
Host: localhost:8080
1047
`)
1048
}
1049

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.