golang.org/toolchain@v0.0.1-go1.9rc2.windows-amd64/src/net/http/request_test.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package http_test 6 7 import ( 8 "bufio" 9 "bytes" 10 "context" 11 "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 - should be treated as 95 // application/octet-stream (RFC 2616, section 7.2.1) 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.Header = Header{"Content-Type": {"text/plain"}} 147 multipart, err = req.MultipartReader() 148 if multipart != nil { 149 t.Error("unexpected multipart for text/plain") 150 } 151 } 152 153 // Issue 9305: ParseMultipartForm should populate PostForm too 154 func TestParseMultipartFormPopulatesPostForm(t *testing.T) { 155 postData := 156 `--xxx 157 Content-Disposition: form-data; name="field1" 158 159 value1 160 --xxx 161 Content-Disposition: form-data; name="field2" 162 163 value2 164 --xxx 165 Content-Disposition: form-data; name="file"; filename="file" 166 Content-Type: application/octet-stream 167 Content-Transfer-Encoding: binary 168 169 binary data 170 --xxx-- 171 ` 172 req := &Request{ 173 Method: "POST", 174 Header: Header{"Content-Type": {`multipart/form-data; boundary=xxx`}}, 175 Body: ioutil.NopCloser(strings.NewReader(postData)), 176 } 177 178 initialFormItems := map[string]string{ 179 "language": "Go", 180 "name": "gopher", 181 "skill": "go-ing", 182 "field2": "initial-value2", 183 } 184 185 req.Form = make(url.Values) 186 for k, v := range initialFormItems { 187 req.Form.Add(k, v) 188 } 189 190 err := req.ParseMultipartForm(10000) 191 if err != nil { 192 t.Fatalf("unexpected multipart error %v", err) 193 } 194 195 wantForm := url.Values{ 196 "language": []string{"Go"}, 197 "name": []string{"gopher"}, 198 "skill": []string{"go-ing"}, 199 "field1": []string{"value1"}, 200 "field2": []string{"initial-value2", "value2"}, 201 } 202 if !reflect.DeepEqual(req.Form, wantForm) { 203 t.Fatalf("req.Form = %v, want %v", req.Form, wantForm) 204 } 205 206 wantPostForm := url.Values{ 207 "field1": []string{"value1"}, 208 "field2": []string{"value2"}, 209 } 210 if !reflect.DeepEqual(req.PostForm, wantPostForm) { 211 t.Fatalf("req.PostForm = %v, want %v", req.PostForm, wantPostForm) 212 } 213 } 214 215 func TestParseMultipartForm(t *testing.T) { 216 req := &Request{ 217 Method: "POST", 218 Header: Header{"Content-Type": {`multipart/form-data; boundary="foo123"`}}, 219 Body: ioutil.NopCloser(new(bytes.Buffer)), 220 } 221 err := req.ParseMultipartForm(25) 222 if err == nil { 223 t.Error("expected multipart EOF, got nil") 224 } 225 226 req.Header = Header{"Content-Type": {"text/plain"}} 227 err = req.ParseMultipartForm(25) 228 if err != ErrNotMultipart { 229 t.Error("expected ErrNotMultipart for text/plain") 230 } 231 } 232 233 func TestRedirect_h1(t *testing.T) { testRedirect(t, h1Mode) } 234 func TestRedirect_h2(t *testing.T) { testRedirect(t, h2Mode) } 235 func testRedirect(t *testing.T, h2 bool) { 236 defer afterTest(t) 237 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 238 switch r.URL.Path { 239 case "/": 240 w.Header().Set("Location", "/foo/") 241 w.WriteHeader(StatusSeeOther) 242 case "/foo/": 243 fmt.Fprintf(w, "foo") 244 default: 245 w.WriteHeader(StatusBadRequest) 246 } 247 })) 248 defer cst.close() 249 250 var end = regexp.MustCompile("/foo/$") 251 r, err := cst.c.Get(cst.ts.URL) 252 if err != nil { 253 t.Fatal(err) 254 } 255 r.Body.Close() 256 url := r.Request.URL.String() 257 if r.StatusCode != 200 || !end.MatchString(url) { 258 t.Fatalf("Get got status %d at %q, want 200 matching /foo/$", r.StatusCode, url) 259 } 260 } 261 262 func TestSetBasicAuth(t *testing.T) { 263 r, _ := NewRequest("GET", "http://example.com/", nil) 264 r.SetBasicAuth("Aladdin", "open sesame") 265 if g, e := r.Header.Get("Authorization"), "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="; g != e { 266 t.Errorf("got header %q, want %q", g, e) 267 } 268 } 269 270 func TestMultipartRequest(t *testing.T) { 271 // Test that we can read the values and files of a 272 // multipart request with FormValue and FormFile, 273 // and that ParseMultipartForm can be called multiple times. 274 req := newTestMultipartRequest(t) 275 if err := req.ParseMultipartForm(25); err != nil { 276 t.Fatal("ParseMultipartForm first call:", err) 277 } 278 defer req.MultipartForm.RemoveAll() 279 validateTestMultipartContents(t, req, false) 280 if err := req.ParseMultipartForm(25); err != nil { 281 t.Fatal("ParseMultipartForm second call:", err) 282 } 283 validateTestMultipartContents(t, req, false) 284 } 285 286 func TestMultipartRequestAuto(t *testing.T) { 287 // Test that FormValue and FormFile automatically invoke 288 // ParseMultipartForm and return the right values. 289 req := newTestMultipartRequest(t) 290 defer func() { 291 if req.MultipartForm != nil { 292 req.MultipartForm.RemoveAll() 293 } 294 }() 295 validateTestMultipartContents(t, req, true) 296 } 297 298 func TestMissingFileMultipartRequest(t *testing.T) { 299 // Test that FormFile returns an error if 300 // the named file is missing. 301 req := newTestMultipartRequest(t) 302 testMissingFile(t, req) 303 } 304 305 // Test that FormValue invokes ParseMultipartForm. 306 func TestFormValueCallsParseMultipartForm(t *testing.T) { 307 req, _ := NewRequest("POST", "http://www.google.com/", strings.NewReader("z=post")) 308 req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") 309 if req.Form != nil { 310 t.Fatal("Unexpected request Form, want nil") 311 } 312 req.FormValue("z") 313 if req.Form == nil { 314 t.Fatal("ParseMultipartForm not called by FormValue") 315 } 316 } 317 318 // Test that FormFile invokes ParseMultipartForm. 319 func TestFormFileCallsParseMultipartForm(t *testing.T) { 320 req := newTestMultipartRequest(t) 321 if req.Form != nil { 322 t.Fatal("Unexpected request Form, want nil") 323 } 324 req.FormFile("") 325 if req.Form == nil { 326 t.Fatal("ParseMultipartForm not called by FormFile") 327 } 328 } 329 330 // Test that ParseMultipartForm errors if called 331 // after MultipartReader on the same request. 332 func TestParseMultipartFormOrder(t *testing.T) { 333 req := newTestMultipartRequest(t) 334 if _, err := req.MultipartReader(); err != nil { 335 t.Fatalf("MultipartReader: %v", err) 336 } 337 if err := req.ParseMultipartForm(1024); err == nil { 338 t.Fatal("expected an error from ParseMultipartForm after call to MultipartReader") 339 } 340 } 341 342 // Test that MultipartReader errors if called 343 // after ParseMultipartForm on the same request. 344 func TestMultipartReaderOrder(t *testing.T) { 345 req := newTestMultipartRequest(t) 346 if err := req.ParseMultipartForm(25); err != nil { 347 t.Fatalf("ParseMultipartForm: %v", err) 348 } 349 defer req.MultipartForm.RemoveAll() 350 if _, err := req.MultipartReader(); err == nil { 351 t.Fatal("expected an error from MultipartReader after call to ParseMultipartForm") 352 } 353 } 354 355 // Test that FormFile errors if called after 356 // MultipartReader on the same request. 357 func TestFormFileOrder(t *testing.T) { 358 req := newTestMultipartRequest(t) 359 if _, err := req.MultipartReader(); err != nil { 360 t.Fatalf("MultipartReader: %v", err) 361 } 362 if _, _, err := req.FormFile(""); err == nil { 363 t.Fatal("expected an error from FormFile after call to MultipartReader") 364 } 365 } 366 367 var readRequestErrorTests = []struct { 368 in string 369 err string 370 371 header Header 372 }{ 373 0: {"GET / HTTP/1.1\r\nheader:foo\r\n\r\n", "", Header{"Header": {"foo"}}}, 374 1: {"GET / HTTP/1.1\r\nheader:foo\r\n", io.ErrUnexpectedEOF.Error(), nil}, 375 2: {"", io.EOF.Error(), nil}, 376 3: { 377 in: "HEAD / HTTP/1.1\r\nContent-Length:4\r\n\r\n", 378 err: "http: method cannot contain a Content-Length", 379 }, 380 4: { 381 in: "HEAD / HTTP/1.1\r\n\r\n", 382 header: Header{}, 383 }, 384 385 // Multiple Content-Length values should either be 386 // deduplicated if same or reject otherwise 387 // See Issue 16490. 388 5: { 389 in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 0\r\n\r\nGopher hey\r\n", 390 err: "cannot contain multiple Content-Length headers", 391 }, 392 6: { 393 in: "POST / HTTP/1.1\r\nContent-Length: 10\r\nContent-Length: 6\r\n\r\nGopher\r\n", 394 err: "cannot contain multiple Content-Length headers", 395 }, 396 7: { 397 in: "PUT / HTTP/1.1\r\nContent-Length: 6 \r\nContent-Length: 6\r\nContent-Length:6\r\n\r\nGopher\r\n", 398 err: "", 399 header: Header{"Content-Length": {"6"}}, 400 }, 401 8: { 402 in: "PUT / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 6 \r\n\r\n", 403 err: "cannot contain multiple Content-Length headers", 404 }, 405 9: { 406 in: "POST / HTTP/1.1\r\nContent-Length:\r\nContent-Length: 3\r\n\r\n", 407 err: "cannot contain multiple Content-Length headers", 408 }, 409 10: { 410 in: "HEAD / HTTP/1.1\r\nContent-Length:0\r\nContent-Length: 0\r\n\r\n", 411 header: Header{"Content-Length": {"0"}}, 412 }, 413 } 414 415 func TestReadRequestErrors(t *testing.T) { 416 for i, tt := range readRequestErrorTests { 417 req, err := ReadRequest(bufio.NewReader(strings.NewReader(tt.in))) 418 if err == nil { 419 if tt.err != "" { 420 t.Errorf("#%d: got nil err; want %q", i, tt.err) 421 } 422 423 if !reflect.DeepEqual(tt.header, req.Header) { 424 t.Errorf("#%d: gotHeader: %q wantHeader: %q", i, req.Header, tt.header) 425 } 426 continue 427 } 428 429 if tt.err == "" || !strings.Contains(err.Error(), tt.err) { 430 t.Errorf("%d: got error = %v; want %v", i, err, tt.err) 431 } 432 } 433 } 434 435 var newRequestHostTests = []struct { 436 in, out string 437 }{ 438 {"http://www.example.com/", "www.example.com"}, 439 {"http://www.example.com:8080/", "www.example.com:8080"}, 440 441 {"http://192.168.0.1/", "192.168.0.1"}, 442 {"http://192.168.0.1:8080/", "192.168.0.1:8080"}, 443 {"http://192.168.0.1:/", "192.168.0.1"}, 444 445 {"http://[fe80::1]/", "[fe80::1]"}, 446 {"http://[fe80::1]:8080/", "[fe80::1]:8080"}, 447 {"http://[fe80::1%25en0]/", "[fe80::1%en0]"}, 448 {"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"}, 449 {"http://[fe80::1%25en0]:/", "[fe80::1%en0]"}, 450 } 451 452 func TestNewRequestHost(t *testing.T) { 453 for i, tt := range newRequestHostTests { 454 req, err := NewRequest("GET", tt.in, nil) 455 if err != nil { 456 t.Errorf("#%v: %v", i, err) 457 continue 458 } 459 if req.Host != tt.out { 460 t.Errorf("got %q; want %q", req.Host, tt.out) 461 } 462 } 463 } 464 465 func TestRequestInvalidMethod(t *testing.T) { 466 _, err := NewRequest("bad method", "http://foo.com/", nil) 467 if err == nil { 468 t.Error("expected error from NewRequest with invalid method") 469 } 470 req, err := NewRequest("GET", "http://foo.example/", nil) 471 if err != nil { 472 t.Fatal(err) 473 } 474 req.Method = "bad method" 475 _, err = DefaultClient.Do(req) 476 if err == nil || !strings.Contains(err.Error(), "invalid method") { 477 t.Errorf("Transport error = %v; want invalid method", err) 478 } 479 480 req, err = NewRequest("", "http://foo.com/", nil) 481 if err != nil { 482 t.Errorf("NewRequest(empty method) = %v; want nil", err) 483 } else if req.Method != "GET" { 484 t.Errorf("NewRequest(empty method) has method %q; want GET", req.Method) 485 } 486 } 487 488 func TestNewRequestContentLength(t *testing.T) { 489 readByte := func(r io.Reader) io.Reader { 490 var b [1]byte 491 r.Read(b[:]) 492 return r 493 } 494 tests := []struct { 495 r io.Reader 496 want int64 497 }{ 498 {bytes.NewReader([]byte("123")), 3}, 499 {bytes.NewBuffer([]byte("1234")), 4}, 500 {strings.NewReader("12345"), 5}, 501 {strings.NewReader(""), 0}, 502 {NoBody, 0}, 503 504 // Not detected. During Go 1.8 we tried to make these set to -1, but 505 // due to Issue 18117, we keep these returning 0, even though they're 506 // unknown. 507 {struct{ io.Reader }{strings.NewReader("xyz")}, 0}, 508 {io.NewSectionReader(strings.NewReader("x"), 0, 6), 0}, 509 {readByte(io.NewSectionReader(strings.NewReader("xy"), 0, 6)), 0}, 510 } 511 for i, tt := range tests { 512 req, err := NewRequest("POST", "http://localhost/", tt.r) 513 if err != nil { 514 t.Fatal(err) 515 } 516 if req.ContentLength != tt.want { 517 t.Errorf("test[%d]: ContentLength(%T) = %d; want %d", i, tt.r, req.ContentLength, tt.want) 518 } 519 } 520 } 521 522 var parseHTTPVersionTests = []struct { 523 vers string 524 major, minor int 525 ok bool 526 }{ 527 {"HTTP/0.9", 0, 9, true}, 528 {"HTTP/1.0", 1, 0, true}, 529 {"HTTP/1.1", 1, 1, true}, 530 {"HTTP/3.14", 3, 14, true}, 531 532 {"HTTP", 0, 0, false}, 533 {"HTTP/one.one", 0, 0, false}, 534 {"HTTP/1.1/", 0, 0, false}, 535 {"HTTP/-1,0", 0, 0, false}, 536 {"HTTP/0,-1", 0, 0, false}, 537 {"HTTP/", 0, 0, false}, 538 {"HTTP/1,1", 0, 0, false}, 539 } 540 541 func TestParseHTTPVersion(t *testing.T) { 542 for _, tt := range parseHTTPVersionTests { 543 major, minor, ok := ParseHTTPVersion(tt.vers) 544 if ok != tt.ok || major != tt.major || minor != tt.minor { 545 type version struct { 546 major, minor int 547 ok bool 548 } 549 t.Errorf("failed to parse %q, expected: %#v, got %#v", tt.vers, version{tt.major, tt.minor, tt.ok}, version{major, minor, ok}) 550 } 551 } 552 } 553 554 type getBasicAuthTest struct { 555 username, password string 556 ok bool 557 } 558 559 type basicAuthCredentialsTest struct { 560 username, password string 561 } 562 563 var getBasicAuthTests = []struct { 564 username, password string 565 ok bool 566 }{ 567 {"Aladdin", "open sesame", true}, 568 {"Aladdin", "open:sesame", true}, 569 {"", "", true}, 570 } 571 572 func TestGetBasicAuth(t *testing.T) { 573 for _, tt := range getBasicAuthTests { 574 r, _ := NewRequest("GET", "http://example.com/", nil) 575 r.SetBasicAuth(tt.username, tt.password) 576 username, password, ok := r.BasicAuth() 577 if ok != tt.ok || username != tt.username || password != tt.password { 578 t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok}, 579 getBasicAuthTest{tt.username, tt.password, tt.ok}) 580 } 581 } 582 // Unauthenticated request. 583 r, _ := NewRequest("GET", "http://example.com/", nil) 584 username, password, ok := r.BasicAuth() 585 if ok { 586 t.Errorf("expected false from BasicAuth when the request is unauthenticated") 587 } 588 want := basicAuthCredentialsTest{"", ""} 589 if username != want.username || password != want.password { 590 t.Errorf("expected credentials: %#v when the request is unauthenticated, got %#v", 591 want, basicAuthCredentialsTest{username, password}) 592 } 593 } 594 595 var parseBasicAuthTests = []struct { 596 header, username, password string 597 ok bool 598 }{ 599 {"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "Aladdin", "open sesame", true}, 600 {"Basic " + base64.StdEncoding.EncodeToString([]byte("Aladdin:open:sesame")), "Aladdin", "open:sesame", true}, 601 {"Basic " + base64.StdEncoding.EncodeToString([]byte(":")), "", "", true}, 602 {"Basic" + base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false}, 603 {base64.StdEncoding.EncodeToString([]byte("Aladdin:open sesame")), "", "", false}, 604 {"Basic ", "", "", false}, 605 {"Basic Aladdin:open sesame", "", "", false}, 606 {`Digest username="Aladdin"`, "", "", false}, 607 } 608 609 func TestParseBasicAuth(t *testing.T) { 610 for _, tt := range parseBasicAuthTests { 611 r, _ := NewRequest("GET", "http://example.com/", nil) 612 r.Header.Set("Authorization", tt.header) 613 username, password, ok := r.BasicAuth() 614 if ok != tt.ok || username != tt.username || password != tt.password { 615 t.Errorf("BasicAuth() = %#v, want %#v", getBasicAuthTest{username, password, ok}, 616 getBasicAuthTest{tt.username, tt.password, tt.ok}) 617 } 618 } 619 } 620 621 type logWrites struct { 622 t *testing.T 623 dst *[]string 624 } 625 626 func (l logWrites) WriteByte(c byte) error { 627 l.t.Fatalf("unexpected WriteByte call") 628 return nil 629 } 630 631 func (l logWrites) Write(p []byte) (n int, err error) { 632 *l.dst = append(*l.dst, string(p)) 633 return len(p), nil 634 } 635 636 func TestRequestWriteBufferedWriter(t *testing.T) { 637 got := []string{} 638 req, _ := NewRequest("GET", "http://foo.com/", nil) 639 req.Write(logWrites{t, &got}) 640 want := []string{ 641 "GET / HTTP/1.1\r\n", 642 "Host: foo.com\r\n", 643 "User-Agent: " + DefaultUserAgent + "\r\n", 644 "\r\n", 645 } 646 if !reflect.DeepEqual(got, want) { 647 t.Errorf("Writes = %q\n Want = %q", got, want) 648 } 649 } 650 651 func TestRequestBadHost(t *testing.T) { 652 got := []string{} 653 req, err := NewRequest("GET", "http://foo/after", nil) 654 if err != nil { 655 t.Fatal(err) 656 } 657 req.Host = "foo.com with spaces" 658 req.URL.Host = "foo.com with spaces" 659 req.Write(logWrites{t, &got}) 660 want := []string{ 661 "GET /after HTTP/1.1\r\n", 662 "Host: foo.com\r\n", 663 "User-Agent: " + DefaultUserAgent + "\r\n", 664 "\r\n", 665 } 666 if !reflect.DeepEqual(got, want) { 667 t.Errorf("Writes = %q\n Want = %q", got, want) 668 } 669 } 670 671 func TestStarRequest(t *testing.T) { 672 req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n"))) 673 if err != nil { 674 return 675 } 676 if req.ContentLength != 0 { 677 t.Errorf("ContentLength = %d; want 0", req.ContentLength) 678 } 679 if req.Body == nil { 680 t.Errorf("Body = nil; want non-nil") 681 } 682 683 // Request.Write has Client semantics for Body/ContentLength, 684 // where ContentLength 0 means unknown if Body is non-nil, and 685 // thus chunking will happen unless we change semantics and 686 // signal that we want to serialize it as exactly zero. The 687 // only way to do that for outbound requests is with a nil 688 // Body: 689 clientReq := *req 690 clientReq.Body = nil 691 692 var out bytes.Buffer 693 if err := clientReq.Write(&out); err != nil { 694 t.Fatal(err) 695 } 696 697 if strings.Contains(out.String(), "chunked") { 698 t.Error("wrote chunked request; want no body") 699 } 700 back, err := ReadRequest(bufio.NewReader(bytes.NewReader(out.Bytes()))) 701 if err != nil { 702 t.Fatal(err) 703 } 704 // Ignore the Headers (the User-Agent breaks the deep equal, 705 // but we don't care about it) 706 req.Header = nil 707 back.Header = nil 708 if !reflect.DeepEqual(req, back) { 709 t.Errorf("Original request doesn't match Request read back.") 710 t.Logf("Original: %#v", req) 711 t.Logf("Original.URL: %#v", req.URL) 712 t.Logf("Wrote: %s", out.Bytes()) 713 t.Logf("Read back (doesn't match Original): %#v", back) 714 } 715 } 716 717 type responseWriterJustWriter struct { 718 io.Writer 719 } 720 721 func (responseWriterJustWriter) Header() Header { panic("should not be called") } 722 func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") } 723 724 // delayedEOFReader never returns (n > 0, io.EOF), instead putting 725 // off the io.EOF until a subsequent Read call. 726 type delayedEOFReader struct { 727 r io.Reader 728 } 729 730 func (dr delayedEOFReader) Read(p []byte) (n int, err error) { 731 n, err = dr.r.Read(p) 732 if n > 0 && err == io.EOF { 733 err = nil 734 } 735 return 736 } 737 738 func TestIssue10884_MaxBytesEOF(t *testing.T) { 739 dst := ioutil.Discard 740 _, err := io.Copy(dst, MaxBytesReader( 741 responseWriterJustWriter{dst}, 742 ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}), 743 5)) 744 if err != nil { 745 t.Fatal(err) 746 } 747 } 748 749 // Issue 14981: MaxBytesReader's return error wasn't sticky. It 750 // doesn't technically need to be, but people expected it to be. 751 func TestMaxBytesReaderStickyError(t *testing.T) { 752 isSticky := func(r io.Reader) error { 753 var log bytes.Buffer 754 buf := make([]byte, 1000) 755 var firstErr error 756 for { 757 n, err := r.Read(buf) 758 fmt.Fprintf(&log, "Read(%d) = %d, %v\n", len(buf), n, err) 759 if err == nil { 760 continue 761 } 762 if firstErr == nil { 763 firstErr = err 764 continue 765 } 766 if !reflect.DeepEqual(err, firstErr) { 767 return fmt.Errorf("non-sticky error. got log:\n%s", log.Bytes()) 768 } 769 t.Logf("Got log: %s", log.Bytes()) 770 return nil 771 } 772 } 773 tests := [...]struct { 774 readable int 775 limit int64 776 }{ 777 0: {99, 100}, 778 1: {100, 100}, 779 2: {101, 100}, 780 } 781 for i, tt := range tests { 782 rc := MaxBytesReader(nil, ioutil.NopCloser(bytes.NewReader(make([]byte, tt.readable))), tt.limit) 783 if err := isSticky(rc); err != nil { 784 t.Errorf("%d. error: %v", i, err) 785 } 786 } 787 } 788 789 func TestWithContextDeepCopiesURL(t *testing.T) { 790 req, err := NewRequest("POST", "https://golang.org/", nil) 791 if err != nil { 792 t.Fatal(err) 793 } 794 795 reqCopy := req.WithContext(context.Background()) 796 reqCopy.URL.Scheme = "http" 797 798 firstURL, secondURL := req.URL.String(), reqCopy.URL.String() 799 if firstURL == secondURL { 800 t.Errorf("unexpected change to original request's URL") 801 } 802 803 // And also check we don't crash on nil (Issue 20601) 804 req.URL = nil 805 reqCopy = req.WithContext(context.Background()) 806 if reqCopy.URL != nil { 807 t.Error("expected nil URL in cloned request") 808 } 809 } 810 811 // verify that NewRequest sets Request.GetBody and that it works 812 func TestNewRequestGetBody(t *testing.T) { 813 tests := []struct { 814 r io.Reader 815 }{ 816 {r: strings.NewReader("hello")}, 817 {r: bytes.NewReader([]byte("hello"))}, 818 {r: bytes.NewBuffer([]byte("hello"))}, 819 } 820 for i, tt := range tests { 821 req, err := NewRequest("POST", "http://foo.tld/", tt.r) 822 if err != nil { 823 t.Errorf("test[%d]: %v", i, err) 824 continue 825 } 826 if req.Body == nil { 827 t.Errorf("test[%d]: Body = nil", i) 828 continue 829 } 830 if req.GetBody == nil { 831 t.Errorf("test[%d]: GetBody = nil", i) 832 continue 833 } 834 slurp1, err := ioutil.ReadAll(req.Body) 835 if err != nil { 836 t.Errorf("test[%d]: ReadAll(Body) = %v", i, err) 837 } 838 newBody, err := req.GetBody() 839 if err != nil { 840 t.Errorf("test[%d]: GetBody = %v", i, err) 841 } 842 slurp2, err := ioutil.ReadAll(newBody) 843 if err != nil { 844 t.Errorf("test[%d]: ReadAll(GetBody()) = %v", i, err) 845 } 846 if string(slurp1) != string(slurp2) { 847 t.Errorf("test[%d]: Body %q != GetBody %q", i, slurp1, slurp2) 848 } 849 } 850 } 851 852 func testMissingFile(t *testing.T, req *Request) { 853 f, fh, err := req.FormFile("missing") 854 if f != nil { 855 t.Errorf("FormFile file = %v, want nil", f) 856 } 857 if fh != nil { 858 t.Errorf("FormFile file header = %q, want nil", fh) 859 } 860 if err != ErrMissingFile { 861 t.Errorf("FormFile err = %q, want ErrMissingFile", err) 862 } 863 } 864 865 func newTestMultipartRequest(t *testing.T) *Request { 866 b := strings.NewReader(strings.Replace(message, "\n", "\r\n", -1)) 867 req, err := NewRequest("POST", "/", b) 868 if err != nil { 869 t.Fatal("NewRequest:", err) 870 } 871 ctype := fmt.Sprintf(`multipart/form-data; boundary="%s"`, boundary) 872 req.Header.Set("Content-type", ctype) 873 return req 874 } 875 876 func validateTestMultipartContents(t *testing.T, req *Request, allMem bool) { 877 if g, e := req.FormValue("texta"), textaValue; g != e { 878 t.Errorf("texta value = %q, want %q", g, e) 879 } 880 if g, e := req.FormValue("textb"), textbValue; g != e { 881 t.Errorf("textb value = %q, want %q", g, e) 882 } 883 if g := req.FormValue("missing"); g != "" { 884 t.Errorf("missing value = %q, want empty string", g) 885 } 886 887 assertMem := func(n string, fd multipart.File) { 888 if _, ok := fd.(*os.File); ok { 889 t.Error(n, " is *os.File, should not be") 890 } 891 } 892 fda := testMultipartFile(t, req, "filea", "filea.txt", fileaContents) 893 defer fda.Close() 894 assertMem("filea", fda) 895 fdb := testMultipartFile(t, req, "fileb", "fileb.txt", filebContents) 896 defer fdb.Close() 897 if allMem { 898 assertMem("fileb", fdb) 899 } else { 900 if _, ok := fdb.(*os.File); !ok { 901 t.Errorf("fileb has unexpected underlying type %T", fdb) 902 } 903 } 904 905 testMissingFile(t, req) 906 } 907 908 func testMultipartFile(t *testing.T, req *Request, key, expectFilename, expectContent string) multipart.File { 909 f, fh, err := req.FormFile(key) 910 if err != nil { 911 t.Fatalf("FormFile(%q): %q", key, err) 912 } 913 if fh.Filename != expectFilename { 914 t.Errorf("filename = %q, want %q", fh.Filename, expectFilename) 915 } 916 var b bytes.Buffer 917 _, err = io.Copy(&b, f) 918 if err != nil { 919 t.Fatal("copying contents:", err) 920 } 921 if g := b.String(); g != expectContent { 922 t.Errorf("contents = %q, want %q", g, expectContent) 923 } 924 return f 925 } 926 927 const ( 928 fileaContents = "This is a test file." 929 filebContents = "Another test file." 930 textaValue = "foo" 931 textbValue = "bar" 932 boundary = `MyBoundary` 933 ) 934 935 const message = ` 936 --MyBoundary 937 Content-Disposition: form-data; name="filea"; filename="filea.txt" 938 Content-Type: text/plain 939 940 ` + fileaContents + ` 941 --MyBoundary 942 Content-Disposition: form-data; name="fileb"; filename="fileb.txt" 943 Content-Type: text/plain 944 945 ` + filebContents + ` 946 --MyBoundary 947 Content-Disposition: form-data; name="texta" 948 949 ` + textaValue + ` 950 --MyBoundary 951 Content-Disposition: form-data; name="textb" 952 953 ` + textbValue + ` 954 --MyBoundary-- 955 ` 956 957 func benchmarkReadRequest(b *testing.B, request string) { 958 request = request + "\n" // final \n 959 request = strings.Replace(request, "\n", "\r\n", -1) // expand \n to \r\n 960 b.SetBytes(int64(len(request))) 961 r := bufio.NewReader(&infiniteReader{buf: []byte(request)}) 962 b.ReportAllocs() 963 b.ResetTimer() 964 for i := 0; i < b.N; i++ { 965 _, err := ReadRequest(r) 966 if err != nil { 967 b.Fatalf("failed to read request: %v", err) 968 } 969 } 970 } 971 972 // infiniteReader satisfies Read requests as if the contents of buf 973 // loop indefinitely. 974 type infiniteReader struct { 975 buf []byte 976 offset int 977 } 978 979 func (r *infiniteReader) Read(b []byte) (int, error) { 980 n := copy(b, r.buf[r.offset:]) 981 r.offset = (r.offset + n) % len(r.buf) 982 return n, nil 983 } 984 985 func BenchmarkReadRequestChrome(b *testing.B) { 986 // https://github.com/felixge/node-http-perf/blob/master/fixtures/get.http 987 benchmarkReadRequest(b, `GET / HTTP/1.1 988 Host: localhost:8080 989 Connection: keep-alive 990 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 991 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 992 Accept-Encoding: gzip,deflate,sdch 993 Accept-Language: en-US,en;q=0.8 994 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 995 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 996 `) 997 } 998 999 func BenchmarkReadRequestCurl(b *testing.B) { 1000 // curl http://localhost:8080/ 1001 benchmarkReadRequest(b, `GET / HTTP/1.1 1002 User-Agent: curl/7.27.0 1003 Host: localhost:8080 1004 Accept: */* 1005 `) 1006 } 1007 1008 func BenchmarkReadRequestApachebench(b *testing.B) { 1009 // ab -n 1 -c 1 http://localhost:8080/ 1010 benchmarkReadRequest(b, `GET / HTTP/1.0 1011 Host: localhost:8080 1012 User-Agent: ApacheBench/2.3 1013 Accept: */* 1014 `) 1015 } 1016 1017 func BenchmarkReadRequestSiege(b *testing.B) { 1018 // siege -r 1 -c 1 http://localhost:8080/ 1019 benchmarkReadRequest(b, `GET / HTTP/1.1 1020 Host: localhost:8080 1021 Accept: */* 1022 Accept-Encoding: gzip 1023 User-Agent: JoeDog/1.00 [en] (X11; I; Siege 2.70) 1024 Connection: keep-alive 1025 `) 1026 } 1027 1028 func BenchmarkReadRequestWrk(b *testing.B) { 1029 // wrk -t 1 -r 1 -c 1 http://localhost:8080/ 1030 benchmarkReadRequest(b, `GET / HTTP/1.1 1031 Host: localhost:8080 1032 `) 1033 }