github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/pkg/net/http/client_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 // Tests for client.go 6 7 package http_test 8 9 import ( 10 "bytes" 11 "crypto/tls" 12 "crypto/x509" 13 "encoding/base64" 14 "errors" 15 "fmt" 16 "io" 17 "io/ioutil" 18 "log" 19 "net" 20 . "net/http" 21 "net/http/httptest" 22 "net/url" 23 "reflect" 24 "sort" 25 "strconv" 26 "strings" 27 "sync" 28 "testing" 29 "time" 30 ) 31 32 var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 33 w.Header().Set("Last-Modified", "sometime") 34 fmt.Fprintf(w, "User-agent: go\nDisallow: /something/") 35 }) 36 37 // pedanticReadAll works like ioutil.ReadAll but additionally 38 // verifies that r obeys the documented io.Reader contract. 39 func pedanticReadAll(r io.Reader) (b []byte, err error) { 40 var bufa [64]byte 41 buf := bufa[:] 42 for { 43 n, err := r.Read(buf) 44 if n == 0 && err == nil { 45 return nil, fmt.Errorf("Read: n=0 with err=nil") 46 } 47 b = append(b, buf[:n]...) 48 if err == io.EOF { 49 n, err := r.Read(buf) 50 if n != 0 || err != io.EOF { 51 return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err) 52 } 53 return b, nil 54 } 55 if err != nil { 56 return b, err 57 } 58 } 59 } 60 61 type chanWriter chan string 62 63 func (w chanWriter) Write(p []byte) (n int, err error) { 64 w <- string(p) 65 return len(p), nil 66 } 67 68 func TestClient(t *testing.T) { 69 defer afterTest(t) 70 ts := httptest.NewServer(robotsTxtHandler) 71 defer ts.Close() 72 73 r, err := Get(ts.URL) 74 var b []byte 75 if err == nil { 76 b, err = pedanticReadAll(r.Body) 77 r.Body.Close() 78 } 79 if err != nil { 80 t.Error(err) 81 } else if s := string(b); !strings.HasPrefix(s, "User-agent:") { 82 t.Errorf("Incorrect page body (did not begin with User-agent): %q", s) 83 } 84 } 85 86 func TestClientHead(t *testing.T) { 87 defer afterTest(t) 88 ts := httptest.NewServer(robotsTxtHandler) 89 defer ts.Close() 90 91 r, err := Head(ts.URL) 92 if err != nil { 93 t.Fatal(err) 94 } 95 if _, ok := r.Header["Last-Modified"]; !ok { 96 t.Error("Last-Modified header not found.") 97 } 98 } 99 100 type recordingTransport struct { 101 req *Request 102 } 103 104 func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error) { 105 t.req = req 106 return nil, errors.New("dummy impl") 107 } 108 109 func TestGetRequestFormat(t *testing.T) { 110 defer afterTest(t) 111 tr := &recordingTransport{} 112 client := &Client{Transport: tr} 113 url := "http://dummy.faketld/" 114 client.Get(url) // Note: doesn't hit network 115 if tr.req.Method != "GET" { 116 t.Errorf("expected method %q; got %q", "GET", tr.req.Method) 117 } 118 if tr.req.URL.String() != url { 119 t.Errorf("expected URL %q; got %q", url, tr.req.URL.String()) 120 } 121 if tr.req.Header == nil { 122 t.Errorf("expected non-nil request Header") 123 } 124 } 125 126 func TestPostRequestFormat(t *testing.T) { 127 defer afterTest(t) 128 tr := &recordingTransport{} 129 client := &Client{Transport: tr} 130 131 url := "http://dummy.faketld/" 132 json := `{"key":"value"}` 133 b := strings.NewReader(json) 134 client.Post(url, "application/json", b) // Note: doesn't hit network 135 136 if tr.req.Method != "POST" { 137 t.Errorf("got method %q, want %q", tr.req.Method, "POST") 138 } 139 if tr.req.URL.String() != url { 140 t.Errorf("got URL %q, want %q", tr.req.URL.String(), url) 141 } 142 if tr.req.Header == nil { 143 t.Fatalf("expected non-nil request Header") 144 } 145 if tr.req.Close { 146 t.Error("got Close true, want false") 147 } 148 if g, e := tr.req.ContentLength, int64(len(json)); g != e { 149 t.Errorf("got ContentLength %d, want %d", g, e) 150 } 151 } 152 153 func TestPostFormRequestFormat(t *testing.T) { 154 defer afterTest(t) 155 tr := &recordingTransport{} 156 client := &Client{Transport: tr} 157 158 urlStr := "http://dummy.faketld/" 159 form := make(url.Values) 160 form.Set("foo", "bar") 161 form.Add("foo", "bar2") 162 form.Set("bar", "baz") 163 client.PostForm(urlStr, form) // Note: doesn't hit network 164 165 if tr.req.Method != "POST" { 166 t.Errorf("got method %q, want %q", tr.req.Method, "POST") 167 } 168 if tr.req.URL.String() != urlStr { 169 t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr) 170 } 171 if tr.req.Header == nil { 172 t.Fatalf("expected non-nil request Header") 173 } 174 if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e { 175 t.Errorf("got Content-Type %q, want %q", g, e) 176 } 177 if tr.req.Close { 178 t.Error("got Close true, want false") 179 } 180 // Depending on map iteration, body can be either of these. 181 expectedBody := "foo=bar&foo=bar2&bar=baz" 182 expectedBody1 := "bar=baz&foo=bar&foo=bar2" 183 if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e { 184 t.Errorf("got ContentLength %d, want %d", g, e) 185 } 186 bodyb, err := ioutil.ReadAll(tr.req.Body) 187 if err != nil { 188 t.Fatalf("ReadAll on req.Body: %v", err) 189 } 190 if g := string(bodyb); g != expectedBody && g != expectedBody1 { 191 t.Errorf("got body %q, want %q or %q", g, expectedBody, expectedBody1) 192 } 193 } 194 195 func TestClientRedirects(t *testing.T) { 196 defer afterTest(t) 197 var ts *httptest.Server 198 ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 199 n, _ := strconv.Atoi(r.FormValue("n")) 200 // Test Referer header. (7 is arbitrary position to test at) 201 if n == 7 { 202 if g, e := r.Referer(), ts.URL+"/?n=6"; e != g { 203 t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g) 204 } 205 } 206 if n < 15 { 207 Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound) 208 return 209 } 210 fmt.Fprintf(w, "n=%d", n) 211 })) 212 defer ts.Close() 213 214 c := &Client{} 215 _, err := c.Get(ts.URL) 216 if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g { 217 t.Errorf("with default client Get, expected error %q, got %q", e, g) 218 } 219 220 // HEAD request should also have the ability to follow redirects. 221 _, err = c.Head(ts.URL) 222 if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g { 223 t.Errorf("with default client Head, expected error %q, got %q", e, g) 224 } 225 226 // Do should also follow redirects. 227 greq, _ := NewRequest("GET", ts.URL, nil) 228 _, err = c.Do(greq) 229 if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g { 230 t.Errorf("with default client Do, expected error %q, got %q", e, g) 231 } 232 233 var checkErr error 234 var lastVia []*Request 235 c = &Client{CheckRedirect: func(_ *Request, via []*Request) error { 236 lastVia = via 237 return checkErr 238 }} 239 res, err := c.Get(ts.URL) 240 if err != nil { 241 t.Fatalf("Get error: %v", err) 242 } 243 res.Body.Close() 244 finalUrl := res.Request.URL.String() 245 if e, g := "<nil>", fmt.Sprintf("%v", err); e != g { 246 t.Errorf("with custom client, expected error %q, got %q", e, g) 247 } 248 if !strings.HasSuffix(finalUrl, "/?n=15") { 249 t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl) 250 } 251 if e, g := 15, len(lastVia); e != g { 252 t.Errorf("expected lastVia to have contained %d elements; got %d", e, g) 253 } 254 255 checkErr = errors.New("no redirects allowed") 256 res, err = c.Get(ts.URL) 257 if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr { 258 t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err) 259 } 260 if res == nil { 261 t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)") 262 } 263 res.Body.Close() 264 if res.Header.Get("Location") == "" { 265 t.Errorf("no Location header in Response") 266 } 267 } 268 269 func TestPostRedirects(t *testing.T) { 270 defer afterTest(t) 271 var log struct { 272 sync.Mutex 273 bytes.Buffer 274 } 275 var ts *httptest.Server 276 ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 277 log.Lock() 278 fmt.Fprintf(&log.Buffer, "%s %s ", r.Method, r.RequestURI) 279 log.Unlock() 280 if v := r.URL.Query().Get("code"); v != "" { 281 code, _ := strconv.Atoi(v) 282 if code/100 == 3 { 283 w.Header().Set("Location", ts.URL) 284 } 285 w.WriteHeader(code) 286 } 287 })) 288 defer ts.Close() 289 tests := []struct { 290 suffix string 291 want int // response code 292 }{ 293 {"/", 200}, 294 {"/?code=301", 301}, 295 {"/?code=302", 200}, 296 {"/?code=303", 200}, 297 {"/?code=404", 404}, 298 } 299 for _, tt := range tests { 300 res, err := Post(ts.URL+tt.suffix, "text/plain", strings.NewReader("Some content")) 301 if err != nil { 302 t.Fatal(err) 303 } 304 if res.StatusCode != tt.want { 305 t.Errorf("POST %s: status code = %d; want %d", tt.suffix, res.StatusCode, tt.want) 306 } 307 } 308 log.Lock() 309 got := log.String() 310 log.Unlock() 311 want := "POST / POST /?code=301 POST /?code=302 GET / POST /?code=303 GET / POST /?code=404 " 312 if got != want { 313 t.Errorf("Log differs.\n Got: %q\nWant: %q", got, want) 314 } 315 } 316 317 var expectedCookies = []*Cookie{ 318 {Name: "ChocolateChip", Value: "tasty"}, 319 {Name: "First", Value: "Hit"}, 320 {Name: "Second", Value: "Hit"}, 321 } 322 323 var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 324 for _, cookie := range r.Cookies() { 325 SetCookie(w, cookie) 326 } 327 if r.URL.Path == "/" { 328 SetCookie(w, expectedCookies[1]) 329 Redirect(w, r, "/second", StatusMovedPermanently) 330 } else { 331 SetCookie(w, expectedCookies[2]) 332 w.Write([]byte("hello")) 333 } 334 }) 335 336 func TestClientSendsCookieFromJar(t *testing.T) { 337 tr := &recordingTransport{} 338 client := &Client{Transport: tr} 339 client.Jar = &TestJar{perURL: make(map[string][]*Cookie)} 340 us := "http://dummy.faketld/" 341 u, _ := url.Parse(us) 342 client.Jar.SetCookies(u, expectedCookies) 343 344 client.Get(us) // Note: doesn't hit network 345 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 346 347 client.Head(us) // Note: doesn't hit network 348 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 349 350 client.Post(us, "text/plain", strings.NewReader("body")) // Note: doesn't hit network 351 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 352 353 client.PostForm(us, url.Values{}) // Note: doesn't hit network 354 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 355 356 req, _ := NewRequest("GET", us, nil) 357 client.Do(req) // Note: doesn't hit network 358 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 359 360 req, _ = NewRequest("POST", us, nil) 361 client.Do(req) // Note: doesn't hit network 362 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 363 } 364 365 // Just enough correctness for our redirect tests. Uses the URL.Host as the 366 // scope of all cookies. 367 type TestJar struct { 368 m sync.Mutex 369 perURL map[string][]*Cookie 370 } 371 372 func (j *TestJar) SetCookies(u *url.URL, cookies []*Cookie) { 373 j.m.Lock() 374 defer j.m.Unlock() 375 if j.perURL == nil { 376 j.perURL = make(map[string][]*Cookie) 377 } 378 j.perURL[u.Host] = cookies 379 } 380 381 func (j *TestJar) Cookies(u *url.URL) []*Cookie { 382 j.m.Lock() 383 defer j.m.Unlock() 384 return j.perURL[u.Host] 385 } 386 387 func TestRedirectCookiesJar(t *testing.T) { 388 defer afterTest(t) 389 var ts *httptest.Server 390 ts = httptest.NewServer(echoCookiesRedirectHandler) 391 defer ts.Close() 392 c := &Client{ 393 Jar: new(TestJar), 394 } 395 u, _ := url.Parse(ts.URL) 396 c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]}) 397 resp, err := c.Get(ts.URL) 398 if err != nil { 399 t.Fatalf("Get: %v", err) 400 } 401 resp.Body.Close() 402 matchReturnedCookies(t, expectedCookies, resp.Cookies()) 403 } 404 405 func matchReturnedCookies(t *testing.T, expected, given []*Cookie) { 406 if len(given) != len(expected) { 407 t.Logf("Received cookies: %v", given) 408 t.Errorf("Expected %d cookies, got %d", len(expected), len(given)) 409 } 410 for _, ec := range expected { 411 foundC := false 412 for _, c := range given { 413 if ec.Name == c.Name && ec.Value == c.Value { 414 foundC = true 415 break 416 } 417 } 418 if !foundC { 419 t.Errorf("Missing cookie %v", ec) 420 } 421 } 422 } 423 424 func TestJarCalls(t *testing.T) { 425 defer afterTest(t) 426 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 427 pathSuffix := r.RequestURI[1:] 428 if r.RequestURI == "/nosetcookie" { 429 return // dont set cookies for this path 430 } 431 SetCookie(w, &Cookie{Name: "name" + pathSuffix, Value: "val" + pathSuffix}) 432 if r.RequestURI == "/" { 433 Redirect(w, r, "http://secondhost.fake/secondpath", 302) 434 } 435 })) 436 defer ts.Close() 437 jar := new(RecordingJar) 438 c := &Client{ 439 Jar: jar, 440 Transport: &Transport{ 441 Dial: func(_ string, _ string) (net.Conn, error) { 442 return net.Dial("tcp", ts.Listener.Addr().String()) 443 }, 444 }, 445 } 446 _, err := c.Get("http://firsthost.fake/") 447 if err != nil { 448 t.Fatal(err) 449 } 450 _, err = c.Get("http://firsthost.fake/nosetcookie") 451 if err != nil { 452 t.Fatal(err) 453 } 454 got := jar.log.String() 455 want := `Cookies("http://firsthost.fake/") 456 SetCookie("http://firsthost.fake/", [name=val]) 457 Cookies("http://secondhost.fake/secondpath") 458 SetCookie("http://secondhost.fake/secondpath", [namesecondpath=valsecondpath]) 459 Cookies("http://firsthost.fake/nosetcookie") 460 ` 461 if got != want { 462 t.Errorf("Got Jar calls:\n%s\nWant:\n%s", got, want) 463 } 464 } 465 466 // RecordingJar keeps a log of calls made to it, without 467 // tracking any cookies. 468 type RecordingJar struct { 469 mu sync.Mutex 470 log bytes.Buffer 471 } 472 473 func (j *RecordingJar) SetCookies(u *url.URL, cookies []*Cookie) { 474 j.logf("SetCookie(%q, %v)\n", u, cookies) 475 } 476 477 func (j *RecordingJar) Cookies(u *url.URL) []*Cookie { 478 j.logf("Cookies(%q)\n", u) 479 return nil 480 } 481 482 func (j *RecordingJar) logf(format string, args ...interface{}) { 483 j.mu.Lock() 484 defer j.mu.Unlock() 485 fmt.Fprintf(&j.log, format, args...) 486 } 487 488 func TestStreamingGet(t *testing.T) { 489 defer afterTest(t) 490 say := make(chan string) 491 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 492 w.(Flusher).Flush() 493 for str := range say { 494 w.Write([]byte(str)) 495 w.(Flusher).Flush() 496 } 497 })) 498 defer ts.Close() 499 500 c := &Client{} 501 res, err := c.Get(ts.URL) 502 if err != nil { 503 t.Fatal(err) 504 } 505 var buf [10]byte 506 for _, str := range []string{"i", "am", "also", "known", "as", "comet"} { 507 say <- str 508 n, err := io.ReadFull(res.Body, buf[0:len(str)]) 509 if err != nil { 510 t.Fatalf("ReadFull on %q: %v", str, err) 511 } 512 if n != len(str) { 513 t.Fatalf("Receiving %q, only read %d bytes", str, n) 514 } 515 got := string(buf[0:n]) 516 if got != str { 517 t.Fatalf("Expected %q, got %q", str, got) 518 } 519 } 520 close(say) 521 _, err = io.ReadFull(res.Body, buf[0:1]) 522 if err != io.EOF { 523 t.Fatalf("at end expected EOF, got %v", err) 524 } 525 } 526 527 type writeCountingConn struct { 528 net.Conn 529 count *int 530 } 531 532 func (c *writeCountingConn) Write(p []byte) (int, error) { 533 *c.count++ 534 return c.Conn.Write(p) 535 } 536 537 // TestClientWrites verifies that client requests are buffered and we 538 // don't send a TCP packet per line of the http request + body. 539 func TestClientWrites(t *testing.T) { 540 defer afterTest(t) 541 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 542 })) 543 defer ts.Close() 544 545 writes := 0 546 dialer := func(netz string, addr string) (net.Conn, error) { 547 c, err := net.Dial(netz, addr) 548 if err == nil { 549 c = &writeCountingConn{c, &writes} 550 } 551 return c, err 552 } 553 c := &Client{Transport: &Transport{Dial: dialer}} 554 555 _, err := c.Get(ts.URL) 556 if err != nil { 557 t.Fatal(err) 558 } 559 if writes != 1 { 560 t.Errorf("Get request did %d Write calls, want 1", writes) 561 } 562 563 writes = 0 564 _, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}}) 565 if err != nil { 566 t.Fatal(err) 567 } 568 if writes != 1 { 569 t.Errorf("Post request did %d Write calls, want 1", writes) 570 } 571 } 572 573 func TestClientInsecureTransport(t *testing.T) { 574 defer afterTest(t) 575 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 576 w.Write([]byte("Hello")) 577 })) 578 errc := make(chanWriter, 10) // but only expecting 1 579 ts.Config.ErrorLog = log.New(errc, "", 0) 580 defer ts.Close() 581 582 // TODO(bradfitz): add tests for skipping hostname checks too? 583 // would require a new cert for testing, and probably 584 // redundant with these tests. 585 for _, insecure := range []bool{true, false} { 586 tr := &Transport{ 587 TLSClientConfig: &tls.Config{ 588 InsecureSkipVerify: insecure, 589 }, 590 } 591 defer tr.CloseIdleConnections() 592 c := &Client{Transport: tr} 593 res, err := c.Get(ts.URL) 594 if (err == nil) != insecure { 595 t.Errorf("insecure=%v: got unexpected err=%v", insecure, err) 596 } 597 if res != nil { 598 res.Body.Close() 599 } 600 } 601 602 select { 603 case v := <-errc: 604 if !strings.Contains(v, "TLS handshake error") { 605 t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v) 606 } 607 case <-time.After(5 * time.Second): 608 t.Errorf("timeout waiting for logged error") 609 } 610 611 } 612 613 func TestClientErrorWithRequestURI(t *testing.T) { 614 defer afterTest(t) 615 req, _ := NewRequest("GET", "http://localhost:1234/", nil) 616 req.RequestURI = "/this/field/is/illegal/and/should/error/" 617 _, err := DefaultClient.Do(req) 618 if err == nil { 619 t.Fatalf("expected an error") 620 } 621 if !strings.Contains(err.Error(), "RequestURI") { 622 t.Errorf("wanted error mentioning RequestURI; got error: %v", err) 623 } 624 } 625 626 func newTLSTransport(t *testing.T, ts *httptest.Server) *Transport { 627 certs := x509.NewCertPool() 628 for _, c := range ts.TLS.Certificates { 629 roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1]) 630 if err != nil { 631 t.Fatalf("error parsing server's root cert: %v", err) 632 } 633 for _, root := range roots { 634 certs.AddCert(root) 635 } 636 } 637 return &Transport{ 638 TLSClientConfig: &tls.Config{RootCAs: certs}, 639 } 640 } 641 642 func TestClientWithCorrectTLSServerName(t *testing.T) { 643 defer afterTest(t) 644 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 645 if r.TLS.ServerName != "127.0.0.1" { 646 t.Errorf("expected client to set ServerName 127.0.0.1, got: %q", r.TLS.ServerName) 647 } 648 })) 649 defer ts.Close() 650 651 c := &Client{Transport: newTLSTransport(t, ts)} 652 if _, err := c.Get(ts.URL); err != nil { 653 t.Fatalf("expected successful TLS connection, got error: %v", err) 654 } 655 } 656 657 func TestClientWithIncorrectTLSServerName(t *testing.T) { 658 defer afterTest(t) 659 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) 660 defer ts.Close() 661 errc := make(chanWriter, 10) // but only expecting 1 662 ts.Config.ErrorLog = log.New(errc, "", 0) 663 664 trans := newTLSTransport(t, ts) 665 trans.TLSClientConfig.ServerName = "badserver" 666 c := &Client{Transport: trans} 667 _, err := c.Get(ts.URL) 668 if err == nil { 669 t.Fatalf("expected an error") 670 } 671 if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") { 672 t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err) 673 } 674 select { 675 case v := <-errc: 676 if !strings.Contains(v, "TLS handshake error") { 677 t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v) 678 } 679 case <-time.After(5 * time.Second): 680 t.Errorf("timeout waiting for logged error") 681 } 682 } 683 684 // Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName 685 // when not empty. 686 // 687 // tls.Config.ServerName (non-empty, set to "example.com") takes 688 // precedence over "some-other-host.tld" which previously incorrectly 689 // took precedence. We don't actually connect to (or even resolve) 690 // "some-other-host.tld", though, because of the Transport.Dial hook. 691 // 692 // The httptest.Server has a cert with "example.com" as its name. 693 func TestTransportUsesTLSConfigServerName(t *testing.T) { 694 defer afterTest(t) 695 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 696 w.Write([]byte("Hello")) 697 })) 698 defer ts.Close() 699 700 tr := newTLSTransport(t, ts) 701 tr.TLSClientConfig.ServerName = "example.com" // one of httptest's Server cert names 702 tr.Dial = func(netw, addr string) (net.Conn, error) { 703 return net.Dial(netw, ts.Listener.Addr().String()) 704 } 705 defer tr.CloseIdleConnections() 706 c := &Client{Transport: tr} 707 res, err := c.Get("https://some-other-host.tld/") 708 if err != nil { 709 t.Fatal(err) 710 } 711 res.Body.Close() 712 } 713 714 func TestResponseSetsTLSConnectionState(t *testing.T) { 715 defer afterTest(t) 716 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 717 w.Write([]byte("Hello")) 718 })) 719 defer ts.Close() 720 721 tr := newTLSTransport(t, ts) 722 tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA} 723 tr.Dial = func(netw, addr string) (net.Conn, error) { 724 return net.Dial(netw, ts.Listener.Addr().String()) 725 } 726 defer tr.CloseIdleConnections() 727 c := &Client{Transport: tr} 728 res, err := c.Get("https://example.com/") 729 if err != nil { 730 t.Fatal(err) 731 } 732 defer res.Body.Close() 733 if res.TLS == nil { 734 t.Fatal("Response didn't set TLS Connection State.") 735 } 736 if got, want := res.TLS.CipherSuite, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA; got != want { 737 t.Errorf("TLS Cipher Suite = %d; want %d", got, want) 738 } 739 } 740 741 // Verify Response.ContentLength is populated. http://golang.org/issue/4126 742 func TestClientHeadContentLength(t *testing.T) { 743 defer afterTest(t) 744 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 745 if v := r.FormValue("cl"); v != "" { 746 w.Header().Set("Content-Length", v) 747 } 748 })) 749 defer ts.Close() 750 tests := []struct { 751 suffix string 752 want int64 753 }{ 754 {"/?cl=1234", 1234}, 755 {"/?cl=0", 0}, 756 {"", -1}, 757 } 758 for _, tt := range tests { 759 req, _ := NewRequest("HEAD", ts.URL+tt.suffix, nil) 760 res, err := DefaultClient.Do(req) 761 if err != nil { 762 t.Fatal(err) 763 } 764 if res.ContentLength != tt.want { 765 t.Errorf("Content-Length = %d; want %d", res.ContentLength, tt.want) 766 } 767 bs, err := ioutil.ReadAll(res.Body) 768 if err != nil { 769 t.Fatal(err) 770 } 771 if len(bs) != 0 { 772 t.Errorf("Unexpected content: %q", bs) 773 } 774 } 775 } 776 777 func TestEmptyPasswordAuth(t *testing.T) { 778 defer afterTest(t) 779 gopher := "gopher" 780 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 781 auth := r.Header.Get("Authorization") 782 if strings.HasPrefix(auth, "Basic ") { 783 encoded := auth[6:] 784 decoded, err := base64.StdEncoding.DecodeString(encoded) 785 if err != nil { 786 t.Fatal(err) 787 } 788 expected := gopher + ":" 789 s := string(decoded) 790 if expected != s { 791 t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) 792 } 793 } else { 794 t.Errorf("Invalid auth %q", auth) 795 } 796 })) 797 defer ts.Close() 798 c := &Client{} 799 req, err := NewRequest("GET", ts.URL, nil) 800 if err != nil { 801 t.Fatal(err) 802 } 803 req.URL.User = url.User(gopher) 804 resp, err := c.Do(req) 805 if err != nil { 806 t.Fatal(err) 807 } 808 defer resp.Body.Close() 809 } 810 811 func TestBasicAuth(t *testing.T) { 812 defer afterTest(t) 813 tr := &recordingTransport{} 814 client := &Client{Transport: tr} 815 816 url := "http://My%20User:My%20Pass@dummy.faketld/" 817 expected := "My User:My Pass" 818 client.Get(url) 819 820 if tr.req.Method != "GET" { 821 t.Errorf("got method %q, want %q", tr.req.Method, "GET") 822 } 823 if tr.req.URL.String() != url { 824 t.Errorf("got URL %q, want %q", tr.req.URL.String(), url) 825 } 826 if tr.req.Header == nil { 827 t.Fatalf("expected non-nil request Header") 828 } 829 auth := tr.req.Header.Get("Authorization") 830 if strings.HasPrefix(auth, "Basic ") { 831 encoded := auth[6:] 832 decoded, err := base64.StdEncoding.DecodeString(encoded) 833 if err != nil { 834 t.Fatal(err) 835 } 836 s := string(decoded) 837 if expected != s { 838 t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) 839 } 840 } else { 841 t.Errorf("Invalid auth %q", auth) 842 } 843 } 844 845 func TestClientTimeout(t *testing.T) { 846 if testing.Short() { 847 t.Skip("skipping in short mode") 848 } 849 defer afterTest(t) 850 sawRoot := make(chan bool, 1) 851 sawSlow := make(chan bool, 1) 852 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 853 if r.URL.Path == "/" { 854 sawRoot <- true 855 Redirect(w, r, "/slow", StatusFound) 856 return 857 } 858 if r.URL.Path == "/slow" { 859 w.Write([]byte("Hello")) 860 w.(Flusher).Flush() 861 sawSlow <- true 862 time.Sleep(2 * time.Second) 863 return 864 } 865 })) 866 defer ts.Close() 867 const timeout = 500 * time.Millisecond 868 c := &Client{ 869 Timeout: timeout, 870 } 871 872 res, err := c.Get(ts.URL) 873 if err != nil { 874 t.Fatal(err) 875 } 876 877 select { 878 case <-sawRoot: 879 // good. 880 default: 881 t.Fatal("handler never got / request") 882 } 883 884 select { 885 case <-sawSlow: 886 // good. 887 default: 888 t.Fatal("handler never got /slow request") 889 } 890 891 errc := make(chan error, 1) 892 go func() { 893 _, err := ioutil.ReadAll(res.Body) 894 errc <- err 895 res.Body.Close() 896 }() 897 898 const failTime = timeout * 2 899 select { 900 case err := <-errc: 901 if err == nil { 902 t.Error("expected error from ReadAll") 903 } 904 // Expected error. 905 case <-time.After(failTime): 906 t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout) 907 } 908 } 909 910 func TestClientRedirectEatsBody(t *testing.T) { 911 defer afterTest(t) 912 saw := make(chan string, 2) 913 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 914 saw <- r.RemoteAddr 915 if r.URL.Path == "/" { 916 Redirect(w, r, "/foo", StatusFound) // which includes a body 917 } 918 })) 919 defer ts.Close() 920 921 res, err := Get(ts.URL) 922 if err != nil { 923 t.Fatal(err) 924 } 925 _, err = ioutil.ReadAll(res.Body) 926 if err != nil { 927 t.Fatal(err) 928 } 929 res.Body.Close() 930 931 var first string 932 select { 933 case first = <-saw: 934 default: 935 t.Fatal("server didn't see a request") 936 } 937 938 var second string 939 select { 940 case second = <-saw: 941 default: 942 t.Fatal("server didn't see a second request") 943 } 944 945 if first != second { 946 t.Fatal("server saw different client ports before & after the redirect") 947 } 948 } 949 950 // eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF. 951 type eofReaderFunc func() 952 953 func (f eofReaderFunc) Read(p []byte) (n int, err error) { 954 f() 955 return 0, io.EOF 956 } 957 958 func TestClientTrailers(t *testing.T) { 959 defer afterTest(t) 960 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 961 w.Header().Set("Connection", "close") 962 w.Header().Set("Trailer", "Server-Trailer-A, Server-Trailer-B") 963 w.Header().Add("Trailer", "Server-Trailer-C") 964 965 var decl []string 966 for k := range r.Trailer { 967 decl = append(decl, k) 968 } 969 sort.Strings(decl) 970 971 slurp, err := ioutil.ReadAll(r.Body) 972 if err != nil { 973 t.Errorf("Server reading request body: %v", err) 974 } 975 if string(slurp) != "foo" { 976 t.Errorf("Server read request body %q; want foo", slurp) 977 } 978 if r.Trailer == nil { 979 io.WriteString(w, "nil Trailer") 980 } else { 981 fmt.Fprintf(w, "decl: %v, vals: %s, %s", 982 decl, 983 r.Trailer.Get("Client-Trailer-A"), 984 r.Trailer.Get("Client-Trailer-B")) 985 } 986 987 // TODO: golang.org/issue/7759: there's no way yet for 988 // the server to set trailers without hijacking, so do 989 // that for now, just to test the client. Later, in 990 // Go 1.4, it should be implicit that any mutations 991 // to w.Header() after the initial write are the 992 // trailers to be sent, if and only if they were 993 // previously declared with w.Header().Set("Trailer", 994 // ..keys..) 995 w.(Flusher).Flush() 996 conn, buf, _ := w.(Hijacker).Hijack() 997 t := Header{} 998 t.Set("Server-Trailer-A", "valuea") 999 t.Set("Server-Trailer-C", "valuec") // skipping B 1000 buf.WriteString("0\r\n") // eof 1001 t.Write(buf) 1002 buf.WriteString("\r\n") // end of trailers 1003 buf.Flush() 1004 conn.Close() 1005 })) 1006 defer ts.Close() 1007 1008 var req *Request 1009 req, _ = NewRequest("POST", ts.URL, io.MultiReader( 1010 eofReaderFunc(func() { 1011 req.Trailer["Client-Trailer-A"] = []string{"valuea"} 1012 }), 1013 strings.NewReader("foo"), 1014 eofReaderFunc(func() { 1015 req.Trailer["Client-Trailer-B"] = []string{"valueb"} 1016 }), 1017 )) 1018 req.Trailer = Header{ 1019 "Client-Trailer-A": nil, // to be set later 1020 "Client-Trailer-B": nil, // to be set later 1021 } 1022 req.ContentLength = -1 1023 res, err := DefaultClient.Do(req) 1024 if err != nil { 1025 t.Fatal(err) 1026 } 1027 if err := wantBody(res, err, "decl: [Client-Trailer-A Client-Trailer-B], vals: valuea, valueb"); err != nil { 1028 t.Error(err) 1029 } 1030 want := Header{ 1031 "Server-Trailer-A": []string{"valuea"}, 1032 "Server-Trailer-B": nil, 1033 "Server-Trailer-C": []string{"valuec"}, 1034 } 1035 if !reflect.DeepEqual(res.Trailer, want) { 1036 t.Errorf("Response trailers = %#v; want %#v", res.Trailer, want) 1037 } 1038 }