github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/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 "net" 19 . "net/http" 20 "net/http/httptest" 21 "net/url" 22 "strconv" 23 "strings" 24 "sync" 25 "testing" 26 ) 27 28 var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 29 w.Header().Set("Last-Modified", "sometime") 30 fmt.Fprintf(w, "User-agent: go\nDisallow: /something/") 31 }) 32 33 // pedanticReadAll works like ioutil.ReadAll but additionally 34 // verifies that r obeys the documented io.Reader contract. 35 func pedanticReadAll(r io.Reader) (b []byte, err error) { 36 var bufa [64]byte 37 buf := bufa[:] 38 for { 39 n, err := r.Read(buf) 40 if n == 0 && err == nil { 41 return nil, fmt.Errorf("Read: n=0 with err=nil") 42 } 43 b = append(b, buf[:n]...) 44 if err == io.EOF { 45 n, err := r.Read(buf) 46 if n != 0 || err != io.EOF { 47 return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err) 48 } 49 return b, nil 50 } 51 if err != nil { 52 return b, err 53 } 54 } 55 } 56 57 func TestClient(t *testing.T) { 58 defer afterTest(t) 59 ts := httptest.NewServer(robotsTxtHandler) 60 defer ts.Close() 61 62 r, err := Get(ts.URL) 63 var b []byte 64 if err == nil { 65 b, err = pedanticReadAll(r.Body) 66 r.Body.Close() 67 } 68 if err != nil { 69 t.Error(err) 70 } else if s := string(b); !strings.HasPrefix(s, "User-agent:") { 71 t.Errorf("Incorrect page body (did not begin with User-agent): %q", s) 72 } 73 } 74 75 func TestClientHead(t *testing.T) { 76 defer afterTest(t) 77 ts := httptest.NewServer(robotsTxtHandler) 78 defer ts.Close() 79 80 r, err := Head(ts.URL) 81 if err != nil { 82 t.Fatal(err) 83 } 84 if _, ok := r.Header["Last-Modified"]; !ok { 85 t.Error("Last-Modified header not found.") 86 } 87 } 88 89 type recordingTransport struct { 90 req *Request 91 } 92 93 func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error) { 94 t.req = req 95 return nil, errors.New("dummy impl") 96 } 97 98 func TestGetRequestFormat(t *testing.T) { 99 defer afterTest(t) 100 tr := &recordingTransport{} 101 client := &Client{Transport: tr} 102 url := "http://dummy.faketld/" 103 client.Get(url) // Note: doesn't hit network 104 if tr.req.Method != "GET" { 105 t.Errorf("expected method %q; got %q", "GET", tr.req.Method) 106 } 107 if tr.req.URL.String() != url { 108 t.Errorf("expected URL %q; got %q", url, tr.req.URL.String()) 109 } 110 if tr.req.Header == nil { 111 t.Errorf("expected non-nil request Header") 112 } 113 } 114 115 func TestPostRequestFormat(t *testing.T) { 116 defer afterTest(t) 117 tr := &recordingTransport{} 118 client := &Client{Transport: tr} 119 120 url := "http://dummy.faketld/" 121 json := `{"key":"value"}` 122 b := strings.NewReader(json) 123 client.Post(url, "application/json", b) // Note: doesn't hit network 124 125 if tr.req.Method != "POST" { 126 t.Errorf("got method %q, want %q", tr.req.Method, "POST") 127 } 128 if tr.req.URL.String() != url { 129 t.Errorf("got URL %q, want %q", tr.req.URL.String(), url) 130 } 131 if tr.req.Header == nil { 132 t.Fatalf("expected non-nil request Header") 133 } 134 if tr.req.Close { 135 t.Error("got Close true, want false") 136 } 137 if g, e := tr.req.ContentLength, int64(len(json)); g != e { 138 t.Errorf("got ContentLength %d, want %d", g, e) 139 } 140 } 141 142 func TestPostFormRequestFormat(t *testing.T) { 143 defer afterTest(t) 144 tr := &recordingTransport{} 145 client := &Client{Transport: tr} 146 147 urlStr := "http://dummy.faketld/" 148 form := make(url.Values) 149 form.Set("foo", "bar") 150 form.Add("foo", "bar2") 151 form.Set("bar", "baz") 152 client.PostForm(urlStr, form) // Note: doesn't hit network 153 154 if tr.req.Method != "POST" { 155 t.Errorf("got method %q, want %q", tr.req.Method, "POST") 156 } 157 if tr.req.URL.String() != urlStr { 158 t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr) 159 } 160 if tr.req.Header == nil { 161 t.Fatalf("expected non-nil request Header") 162 } 163 if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e { 164 t.Errorf("got Content-Type %q, want %q", g, e) 165 } 166 if tr.req.Close { 167 t.Error("got Close true, want false") 168 } 169 // Depending on map iteration, body can be either of these. 170 expectedBody := "foo=bar&foo=bar2&bar=baz" 171 expectedBody1 := "bar=baz&foo=bar&foo=bar2" 172 if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e { 173 t.Errorf("got ContentLength %d, want %d", g, e) 174 } 175 bodyb, err := ioutil.ReadAll(tr.req.Body) 176 if err != nil { 177 t.Fatalf("ReadAll on req.Body: %v", err) 178 } 179 if g := string(bodyb); g != expectedBody && g != expectedBody1 { 180 t.Errorf("got body %q, want %q or %q", g, expectedBody, expectedBody1) 181 } 182 } 183 184 func TestClientRedirects(t *testing.T) { 185 defer afterTest(t) 186 var ts *httptest.Server 187 ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 188 n, _ := strconv.Atoi(r.FormValue("n")) 189 // Test Referer header. (7 is arbitrary position to test at) 190 if n == 7 { 191 if g, e := r.Referer(), ts.URL+"/?n=6"; e != g { 192 t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g) 193 } 194 } 195 if n < 15 { 196 Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound) 197 return 198 } 199 fmt.Fprintf(w, "n=%d", n) 200 })) 201 defer ts.Close() 202 203 c := &Client{} 204 _, err := c.Get(ts.URL) 205 if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g { 206 t.Errorf("with default client Get, expected error %q, got %q", e, g) 207 } 208 209 // HEAD request should also have the ability to follow redirects. 210 _, err = c.Head(ts.URL) 211 if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g { 212 t.Errorf("with default client Head, expected error %q, got %q", e, g) 213 } 214 215 // Do should also follow redirects. 216 greq, _ := NewRequest("GET", ts.URL, nil) 217 _, err = c.Do(greq) 218 if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g { 219 t.Errorf("with default client Do, expected error %q, got %q", e, g) 220 } 221 222 var checkErr error 223 var lastVia []*Request 224 c = &Client{CheckRedirect: func(_ *Request, via []*Request) error { 225 lastVia = via 226 return checkErr 227 }} 228 res, err := c.Get(ts.URL) 229 if err != nil { 230 t.Fatalf("Get error: %v", err) 231 } 232 res.Body.Close() 233 finalUrl := res.Request.URL.String() 234 if e, g := "<nil>", fmt.Sprintf("%v", err); e != g { 235 t.Errorf("with custom client, expected error %q, got %q", e, g) 236 } 237 if !strings.HasSuffix(finalUrl, "/?n=15") { 238 t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl) 239 } 240 if e, g := 15, len(lastVia); e != g { 241 t.Errorf("expected lastVia to have contained %d elements; got %d", e, g) 242 } 243 244 checkErr = errors.New("no redirects allowed") 245 res, err = c.Get(ts.URL) 246 if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr { 247 t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err) 248 } 249 if res == nil { 250 t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)") 251 } 252 res.Body.Close() 253 if res.Header.Get("Location") == "" { 254 t.Errorf("no Location header in Response") 255 } 256 } 257 258 func TestPostRedirects(t *testing.T) { 259 defer afterTest(t) 260 var log struct { 261 sync.Mutex 262 bytes.Buffer 263 } 264 var ts *httptest.Server 265 ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 266 log.Lock() 267 fmt.Fprintf(&log.Buffer, "%s %s ", r.Method, r.RequestURI) 268 log.Unlock() 269 if v := r.URL.Query().Get("code"); v != "" { 270 code, _ := strconv.Atoi(v) 271 if code/100 == 3 { 272 w.Header().Set("Location", ts.URL) 273 } 274 w.WriteHeader(code) 275 } 276 })) 277 defer ts.Close() 278 tests := []struct { 279 suffix string 280 want int // response code 281 }{ 282 {"/", 200}, 283 {"/?code=301", 301}, 284 {"/?code=302", 200}, 285 {"/?code=303", 200}, 286 {"/?code=404", 404}, 287 } 288 for _, tt := range tests { 289 res, err := Post(ts.URL+tt.suffix, "text/plain", strings.NewReader("Some content")) 290 if err != nil { 291 t.Fatal(err) 292 } 293 if res.StatusCode != tt.want { 294 t.Errorf("POST %s: status code = %d; want %d", tt.suffix, res.StatusCode, tt.want) 295 } 296 } 297 log.Lock() 298 got := log.String() 299 log.Unlock() 300 want := "POST / POST /?code=301 POST /?code=302 GET / POST /?code=303 GET / POST /?code=404 " 301 if got != want { 302 t.Errorf("Log differs.\n Got: %q\nWant: %q", got, want) 303 } 304 } 305 306 var expectedCookies = []*Cookie{ 307 {Name: "ChocolateChip", Value: "tasty"}, 308 {Name: "First", Value: "Hit"}, 309 {Name: "Second", Value: "Hit"}, 310 } 311 312 var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 313 for _, cookie := range r.Cookies() { 314 SetCookie(w, cookie) 315 } 316 if r.URL.Path == "/" { 317 SetCookie(w, expectedCookies[1]) 318 Redirect(w, r, "/second", StatusMovedPermanently) 319 } else { 320 SetCookie(w, expectedCookies[2]) 321 w.Write([]byte("hello")) 322 } 323 }) 324 325 func TestClientSendsCookieFromJar(t *testing.T) { 326 tr := &recordingTransport{} 327 client := &Client{Transport: tr} 328 client.Jar = &TestJar{perURL: make(map[string][]*Cookie)} 329 us := "http://dummy.faketld/" 330 u, _ := url.Parse(us) 331 client.Jar.SetCookies(u, expectedCookies) 332 333 client.Get(us) // Note: doesn't hit network 334 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 335 336 client.Head(us) // Note: doesn't hit network 337 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 338 339 client.Post(us, "text/plain", strings.NewReader("body")) // Note: doesn't hit network 340 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 341 342 client.PostForm(us, url.Values{}) // Note: doesn't hit network 343 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 344 345 req, _ := NewRequest("GET", us, nil) 346 client.Do(req) // Note: doesn't hit network 347 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 348 349 req, _ = NewRequest("POST", us, nil) 350 client.Do(req) // Note: doesn't hit network 351 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 352 } 353 354 // Just enough correctness for our redirect tests. Uses the URL.Host as the 355 // scope of all cookies. 356 type TestJar struct { 357 m sync.Mutex 358 perURL map[string][]*Cookie 359 } 360 361 func (j *TestJar) SetCookies(u *url.URL, cookies []*Cookie) { 362 j.m.Lock() 363 defer j.m.Unlock() 364 if j.perURL == nil { 365 j.perURL = make(map[string][]*Cookie) 366 } 367 j.perURL[u.Host] = cookies 368 } 369 370 func (j *TestJar) Cookies(u *url.URL) []*Cookie { 371 j.m.Lock() 372 defer j.m.Unlock() 373 return j.perURL[u.Host] 374 } 375 376 func TestRedirectCookiesOnRequest(t *testing.T) { 377 defer afterTest(t) 378 var ts *httptest.Server 379 ts = httptest.NewServer(echoCookiesRedirectHandler) 380 defer ts.Close() 381 c := &Client{} 382 req, _ := NewRequest("GET", ts.URL, nil) 383 req.AddCookie(expectedCookies[0]) 384 // TODO: Uncomment when an implementation of a RFC6265 cookie jar lands. 385 _ = c 386 // resp, _ := c.Do(req) 387 // matchReturnedCookies(t, expectedCookies, resp.Cookies()) 388 389 req, _ = NewRequest("GET", ts.URL, nil) 390 // resp, _ = c.Do(req) 391 // matchReturnedCookies(t, expectedCookies[1:], resp.Cookies()) 392 } 393 394 func TestRedirectCookiesJar(t *testing.T) { 395 defer afterTest(t) 396 var ts *httptest.Server 397 ts = httptest.NewServer(echoCookiesRedirectHandler) 398 defer ts.Close() 399 c := &Client{ 400 Jar: new(TestJar), 401 } 402 u, _ := url.Parse(ts.URL) 403 c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]}) 404 resp, err := c.Get(ts.URL) 405 if err != nil { 406 t.Fatalf("Get: %v", err) 407 } 408 resp.Body.Close() 409 matchReturnedCookies(t, expectedCookies, resp.Cookies()) 410 } 411 412 func matchReturnedCookies(t *testing.T, expected, given []*Cookie) { 413 t.Logf("Received cookies: %v", given) 414 if len(given) != len(expected) { 415 t.Errorf("Expected %d cookies, got %d", len(expected), len(given)) 416 } 417 for _, ec := range expected { 418 foundC := false 419 for _, c := range given { 420 if ec.Name == c.Name && ec.Value == c.Value { 421 foundC = true 422 break 423 } 424 } 425 if !foundC { 426 t.Errorf("Missing cookie %v", ec) 427 } 428 } 429 } 430 431 func TestJarCalls(t *testing.T) { 432 defer afterTest(t) 433 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 434 pathSuffix := r.RequestURI[1:] 435 if r.RequestURI == "/nosetcookie" { 436 return // dont set cookies for this path 437 } 438 SetCookie(w, &Cookie{Name: "name" + pathSuffix, Value: "val" + pathSuffix}) 439 if r.RequestURI == "/" { 440 Redirect(w, r, "http://secondhost.fake/secondpath", 302) 441 } 442 })) 443 defer ts.Close() 444 jar := new(RecordingJar) 445 c := &Client{ 446 Jar: jar, 447 Transport: &Transport{ 448 Dial: func(_ string, _ string) (net.Conn, error) { 449 return net.Dial("tcp", ts.Listener.Addr().String()) 450 }, 451 }, 452 } 453 _, err := c.Get("http://firsthost.fake/") 454 if err != nil { 455 t.Fatal(err) 456 } 457 _, err = c.Get("http://firsthost.fake/nosetcookie") 458 if err != nil { 459 t.Fatal(err) 460 } 461 got := jar.log.String() 462 want := `Cookies("http://firsthost.fake/") 463 SetCookie("http://firsthost.fake/", [name=val]) 464 Cookies("http://secondhost.fake/secondpath") 465 SetCookie("http://secondhost.fake/secondpath", [namesecondpath=valsecondpath]) 466 Cookies("http://firsthost.fake/nosetcookie") 467 ` 468 if got != want { 469 t.Errorf("Got Jar calls:\n%s\nWant:\n%s", got, want) 470 } 471 } 472 473 // RecordingJar keeps a log of calls made to it, without 474 // tracking any cookies. 475 type RecordingJar struct { 476 mu sync.Mutex 477 log bytes.Buffer 478 } 479 480 func (j *RecordingJar) SetCookies(u *url.URL, cookies []*Cookie) { 481 j.logf("SetCookie(%q, %v)\n", u, cookies) 482 } 483 484 func (j *RecordingJar) Cookies(u *url.URL) []*Cookie { 485 j.logf("Cookies(%q)\n", u) 486 return nil 487 } 488 489 func (j *RecordingJar) logf(format string, args ...interface{}) { 490 j.mu.Lock() 491 defer j.mu.Unlock() 492 fmt.Fprintf(&j.log, format, args...) 493 } 494 495 func TestStreamingGet(t *testing.T) { 496 defer afterTest(t) 497 say := make(chan string) 498 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 499 w.(Flusher).Flush() 500 for str := range say { 501 w.Write([]byte(str)) 502 w.(Flusher).Flush() 503 } 504 })) 505 defer ts.Close() 506 507 c := &Client{} 508 res, err := c.Get(ts.URL) 509 if err != nil { 510 t.Fatal(err) 511 } 512 var buf [10]byte 513 for _, str := range []string{"i", "am", "also", "known", "as", "comet"} { 514 say <- str 515 n, err := io.ReadFull(res.Body, buf[0:len(str)]) 516 if err != nil { 517 t.Fatalf("ReadFull on %q: %v", str, err) 518 } 519 if n != len(str) { 520 t.Fatalf("Receiving %q, only read %d bytes", str, n) 521 } 522 got := string(buf[0:n]) 523 if got != str { 524 t.Fatalf("Expected %q, got %q", str, got) 525 } 526 } 527 close(say) 528 _, err = io.ReadFull(res.Body, buf[0:1]) 529 if err != io.EOF { 530 t.Fatalf("at end expected EOF, got %v", err) 531 } 532 } 533 534 type writeCountingConn struct { 535 net.Conn 536 count *int 537 } 538 539 func (c *writeCountingConn) Write(p []byte) (int, error) { 540 *c.count++ 541 return c.Conn.Write(p) 542 } 543 544 // TestClientWrites verifies that client requests are buffered and we 545 // don't send a TCP packet per line of the http request + body. 546 func TestClientWrites(t *testing.T) { 547 defer afterTest(t) 548 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 549 })) 550 defer ts.Close() 551 552 writes := 0 553 dialer := func(netz string, addr string) (net.Conn, error) { 554 c, err := net.Dial(netz, addr) 555 if err == nil { 556 c = &writeCountingConn{c, &writes} 557 } 558 return c, err 559 } 560 c := &Client{Transport: &Transport{Dial: dialer}} 561 562 _, err := c.Get(ts.URL) 563 if err != nil { 564 t.Fatal(err) 565 } 566 if writes != 1 { 567 t.Errorf("Get request did %d Write calls, want 1", writes) 568 } 569 570 writes = 0 571 _, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}}) 572 if err != nil { 573 t.Fatal(err) 574 } 575 if writes != 1 { 576 t.Errorf("Post request did %d Write calls, want 1", writes) 577 } 578 } 579 580 func TestClientInsecureTransport(t *testing.T) { 581 defer afterTest(t) 582 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 583 w.Write([]byte("Hello")) 584 })) 585 defer ts.Close() 586 587 // TODO(bradfitz): add tests for skipping hostname checks too? 588 // would require a new cert for testing, and probably 589 // redundant with these tests. 590 for _, insecure := range []bool{true, false} { 591 tr := &Transport{ 592 TLSClientConfig: &tls.Config{ 593 InsecureSkipVerify: insecure, 594 }, 595 } 596 defer tr.CloseIdleConnections() 597 c := &Client{Transport: tr} 598 res, err := c.Get(ts.URL) 599 if (err == nil) != insecure { 600 t.Errorf("insecure=%v: got unexpected err=%v", insecure, err) 601 } 602 if res != nil { 603 res.Body.Close() 604 } 605 } 606 } 607 608 func TestClientErrorWithRequestURI(t *testing.T) { 609 defer afterTest(t) 610 req, _ := NewRequest("GET", "http://localhost:1234/", nil) 611 req.RequestURI = "/this/field/is/illegal/and/should/error/" 612 _, err := DefaultClient.Do(req) 613 if err == nil { 614 t.Fatalf("expected an error") 615 } 616 if !strings.Contains(err.Error(), "RequestURI") { 617 t.Errorf("wanted error mentioning RequestURI; got error: %v", err) 618 } 619 } 620 621 func newTLSTransport(t *testing.T, ts *httptest.Server) *Transport { 622 certs := x509.NewCertPool() 623 for _, c := range ts.TLS.Certificates { 624 roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1]) 625 if err != nil { 626 t.Fatalf("error parsing server's root cert: %v", err) 627 } 628 for _, root := range roots { 629 certs.AddCert(root) 630 } 631 } 632 return &Transport{ 633 TLSClientConfig: &tls.Config{RootCAs: certs}, 634 } 635 } 636 637 func TestClientWithCorrectTLSServerName(t *testing.T) { 638 defer afterTest(t) 639 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 640 if r.TLS.ServerName != "127.0.0.1" { 641 t.Errorf("expected client to set ServerName 127.0.0.1, got: %q", r.TLS.ServerName) 642 } 643 })) 644 defer ts.Close() 645 646 c := &Client{Transport: newTLSTransport(t, ts)} 647 if _, err := c.Get(ts.URL); err != nil { 648 t.Fatalf("expected successful TLS connection, got error: %v", err) 649 } 650 } 651 652 func TestClientWithIncorrectTLSServerName(t *testing.T) { 653 defer afterTest(t) 654 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) 655 defer ts.Close() 656 657 trans := newTLSTransport(t, ts) 658 trans.TLSClientConfig.ServerName = "badserver" 659 c := &Client{Transport: trans} 660 _, err := c.Get(ts.URL) 661 if err == nil { 662 t.Fatalf("expected an error") 663 } 664 if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") { 665 t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err) 666 } 667 } 668 669 // Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName 670 // when not empty. 671 // 672 // tls.Config.ServerName (non-empty, set to "example.com") takes 673 // precedence over "some-other-host.tld" which previously incorrectly 674 // took precedence. We don't actually connect to (or even resolve) 675 // "some-other-host.tld", though, because of the Transport.Dial hook. 676 // 677 // The httptest.Server has a cert with "example.com" as its name. 678 func TestTransportUsesTLSConfigServerName(t *testing.T) { 679 defer afterTest(t) 680 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 681 w.Write([]byte("Hello")) 682 })) 683 defer ts.Close() 684 685 tr := newTLSTransport(t, ts) 686 tr.TLSClientConfig.ServerName = "example.com" // one of httptest's Server cert names 687 tr.Dial = func(netw, addr string) (net.Conn, error) { 688 return net.Dial(netw, ts.Listener.Addr().String()) 689 } 690 defer tr.CloseIdleConnections() 691 c := &Client{Transport: tr} 692 res, err := c.Get("https://some-other-host.tld/") 693 if err != nil { 694 t.Fatal(err) 695 } 696 res.Body.Close() 697 } 698 699 // Verify Response.ContentLength is populated. http://golang.org/issue/4126 700 func TestClientHeadContentLength(t *testing.T) { 701 defer afterTest(t) 702 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 703 if v := r.FormValue("cl"); v != "" { 704 w.Header().Set("Content-Length", v) 705 } 706 })) 707 defer ts.Close() 708 tests := []struct { 709 suffix string 710 want int64 711 }{ 712 {"/?cl=1234", 1234}, 713 {"/?cl=0", 0}, 714 {"", -1}, 715 } 716 for _, tt := range tests { 717 req, _ := NewRequest("HEAD", ts.URL+tt.suffix, nil) 718 res, err := DefaultClient.Do(req) 719 if err != nil { 720 t.Fatal(err) 721 } 722 if res.ContentLength != tt.want { 723 t.Errorf("Content-Length = %d; want %d", res.ContentLength, tt.want) 724 } 725 bs, err := ioutil.ReadAll(res.Body) 726 if err != nil { 727 t.Fatal(err) 728 } 729 if len(bs) != 0 { 730 t.Errorf("Unexpected content: %q", bs) 731 } 732 } 733 } 734 735 func TestEmptyPasswordAuth(t *testing.T) { 736 defer afterTest(t) 737 gopher := "gopher" 738 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 739 auth := r.Header.Get("Authorization") 740 if strings.HasPrefix(auth, "Basic ") { 741 encoded := auth[6:] 742 decoded, err := base64.StdEncoding.DecodeString(encoded) 743 if err != nil { 744 t.Fatal(err) 745 } 746 expected := gopher + ":" 747 s := string(decoded) 748 if expected != s { 749 t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) 750 } 751 } else { 752 t.Errorf("Invalid auth %q", auth) 753 } 754 })) 755 defer ts.Close() 756 c := &Client{} 757 req, err := NewRequest("GET", ts.URL, nil) 758 if err != nil { 759 t.Fatal(err) 760 } 761 req.URL.User = url.User(gopher) 762 resp, err := c.Do(req) 763 if err != nil { 764 t.Fatal(err) 765 } 766 defer resp.Body.Close() 767 } 768 769 func TestBasicAuth(t *testing.T) { 770 defer afterTest(t) 771 tr := &recordingTransport{} 772 client := &Client{Transport: tr} 773 774 url := "http://My%20User:My%20Pass@dummy.faketld/" 775 expected := "My User:My Pass" 776 client.Get(url) 777 778 if tr.req.Method != "GET" { 779 t.Errorf("got method %q, want %q", tr.req.Method, "GET") 780 } 781 if tr.req.URL.String() != url { 782 t.Errorf("got URL %q, want %q", tr.req.URL.String(), url) 783 } 784 if tr.req.Header == nil { 785 t.Fatalf("expected non-nil request Header") 786 } 787 auth := tr.req.Header.Get("Authorization") 788 if strings.HasPrefix(auth, "Basic ") { 789 encoded := auth[6:] 790 decoded, err := base64.StdEncoding.DecodeString(encoded) 791 if err != nil { 792 t.Fatal(err) 793 } 794 s := string(decoded) 795 if expected != s { 796 t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) 797 } 798 } else { 799 t.Errorf("Invalid auth %q", auth) 800 } 801 }