gitee.com/zhaochuninhefei/gmgo@v0.0.31-0.20240209061119-069254a02979/gmhttp/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 gmhttp_test 8 9 import ( 10 "bytes" 11 "context" 12 "encoding/base64" 13 "errors" 14 "fmt" 15 "io" 16 "log" 17 "net" 18 "net/url" 19 "reflect" 20 "strconv" 21 "strings" 22 "sync" 23 "sync/atomic" 24 "testing" 25 "time" 26 27 . "gitee.com/zhaochuninhefei/gmgo/gmhttp" 28 "gitee.com/zhaochuninhefei/gmgo/gmhttp/cookiejar" 29 "gitee.com/zhaochuninhefei/gmgo/gmhttp/httptest" 30 tls "gitee.com/zhaochuninhefei/gmgo/gmtls" 31 ) 32 33 var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 34 w.Header().Set("Last-Modified", "sometime") 35 _, _ = fmt.Fprintf(w, "User-agent: go\nDisallow: /something/") 36 }) 37 38 // pedanticReadAll works like io.ReadAll but additionally 39 // verifies that r obeys the documented io.Reader contract. 40 func pedanticReadAll(r io.Reader) (b []byte, err error) { 41 var bufa [64]byte 42 buf := bufa[:] 43 for { 44 n, err := r.Read(buf) 45 if n == 0 && err == nil { 46 //goland:noinspection GoErrorStringFormat 47 return nil, fmt.Errorf("Read: n=0 with err=nil") 48 } 49 b = append(b, buf[:n]...) 50 if err == io.EOF { 51 n, err := r.Read(buf) 52 if n != 0 || err != io.EOF { 53 //goland:noinspection GoErrorStringFormat 54 return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err) 55 } 56 return b, nil 57 } 58 if err != nil { 59 return b, err 60 } 61 } 62 } 63 64 type chanWriter chan string 65 66 func (w chanWriter) Write(p []byte) (n int, err error) { 67 w <- string(p) 68 return len(p), nil 69 } 70 71 func TestClient(t *testing.T) { 72 setParallel(t) 73 defer afterTest(t) 74 ts := httptest.NewServer(robotsTxtHandler) 75 defer ts.Close() 76 77 c := ts.Client() 78 r, err := c.Get(ts.URL) 79 var b []byte 80 if err == nil { 81 b, err = pedanticReadAll(r.Body) 82 _ = r.Body.Close() 83 } 84 if err != nil { 85 t.Error(err) 86 } else if s := string(b); !strings.HasPrefix(s, "User-agent:") { 87 t.Errorf("Incorrect page body (did not begin with User-agent): %q", s) 88 } 89 } 90 91 func TestClientHead_h1(t *testing.T) { testClientHead(t, h1Mode) } 92 func TestClientHead_h2(t *testing.T) { testClientHead(t, h2Mode) } 93 94 func testClientHead(t *testing.T, h2 bool) { 95 defer afterTest(t) 96 cst := newClientServerTest(t, h2, robotsTxtHandler) 97 defer cst.close() 98 99 r, err := cst.c.Head(cst.ts.URL) 100 if err != nil { 101 t.Fatal(err) 102 } 103 if _, ok := r.Header["Last-Modified"]; !ok { 104 t.Error("Last-Modified header not found.") 105 } 106 } 107 108 type recordingTransport struct { 109 req *Request 110 } 111 112 func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error) { 113 t.req = req 114 return nil, errors.New("dummy impl") 115 } 116 117 func TestGetRequestFormat(t *testing.T) { 118 setParallel(t) 119 defer afterTest(t) 120 tr := &recordingTransport{} 121 client := &Client{Transport: tr} 122 urlTest := "http://dummy.faketld/" 123 _, _ = client.Get(urlTest) // Note: doesn't hit network 124 if tr.req.Method != "GET" { 125 t.Errorf("expected method %q; got %q", "GET", tr.req.Method) 126 } 127 if tr.req.URL.String() != urlTest { 128 t.Errorf("expected URL %q; got %q", urlTest, tr.req.URL.String()) 129 } 130 if tr.req.Header == nil { 131 t.Errorf("expected non-nil request Header") 132 } 133 } 134 135 func TestPostRequestFormat(t *testing.T) { 136 defer afterTest(t) 137 tr := &recordingTransport{} 138 client := &Client{Transport: tr} 139 140 urlTest := "http://dummy.faketld/" 141 json := `{"key":"value"}` 142 b := strings.NewReader(json) 143 _, _ = client.Post(urlTest, "application/json", b) // Note: doesn't hit network 144 145 if tr.req.Method != "POST" { 146 t.Errorf("got method %q, want %q", tr.req.Method, "POST") 147 } 148 if tr.req.URL.String() != urlTest { 149 t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlTest) 150 } 151 if tr.req.Header == nil { 152 t.Fatalf("expected non-nil request Header") 153 } 154 if tr.req.Close { 155 t.Error("got Close true, want false") 156 } 157 if g, e := tr.req.ContentLength, int64(len(json)); g != e { 158 t.Errorf("got ContentLength %d, want %d", g, e) 159 } 160 } 161 162 func TestPostFormRequestFormat(t *testing.T) { 163 defer afterTest(t) 164 tr := &recordingTransport{} 165 client := &Client{Transport: tr} 166 167 urlStr := "http://dummy.faketld/" 168 form := make(url.Values) 169 form.Set("foo", "bar") 170 form.Add("foo", "bar2") 171 form.Set("bar", "baz") 172 _, _ = client.PostForm(urlStr, form) // Note: doesn't hit network 173 174 if tr.req.Method != "POST" { 175 t.Errorf("got method %q, want %q", tr.req.Method, "POST") 176 } 177 if tr.req.URL.String() != urlStr { 178 t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr) 179 } 180 if tr.req.Header == nil { 181 t.Fatalf("expected non-nil request Header") 182 } 183 if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e { 184 t.Errorf("got Content-Type %q, want %q", g, e) 185 } 186 if tr.req.Close { 187 t.Error("got Close true, want false") 188 } 189 // Depending on map iteration, body can be either of these. 190 expectedBody := "foo=bar&foo=bar2&bar=baz" 191 expectedBody1 := "bar=baz&foo=bar&foo=bar2" 192 if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e { 193 t.Errorf("got ContentLength %d, want %d", g, e) 194 } 195 bodyb, err := io.ReadAll(tr.req.Body) 196 if err != nil { 197 t.Fatalf("ReadAll on req.Body: %v", err) 198 } 199 if g := string(bodyb); g != expectedBody && g != expectedBody1 { 200 t.Errorf("got body %q, want %q or %q", g, expectedBody, expectedBody1) 201 } 202 } 203 204 func TestClientRedirects(t *testing.T) { 205 setParallel(t) 206 defer afterTest(t) 207 var ts *httptest.Server 208 ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 209 n, _ := strconv.Atoi(r.FormValue("n")) 210 // Test Referer header. (7 is arbitrary position to test at) 211 if n == 7 { 212 if g, e := r.Referer(), ts.URL+"/?n=6"; e != g { 213 t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g) 214 } 215 } 216 if n < 15 { 217 Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusTemporaryRedirect) 218 return 219 } 220 _, _ = fmt.Fprintf(w, "n=%d", n) 221 })) 222 defer ts.Close() 223 224 c := ts.Client() 225 _, err := c.Get(ts.URL) 226 if e, g := `Get "/?n=10": stopped after 10 redirects`, fmt.Sprintf("%v", err); e != g { 227 t.Errorf("with default client Get, expected error %q, got %q", e, g) 228 } 229 230 // HEAD request should also have the ability to follow redirects. 231 _, err = c.Head(ts.URL) 232 if e, g := `Head "/?n=10": stopped after 10 redirects`, fmt.Sprintf("%v", err); e != g { 233 t.Errorf("with default client Head, expected error %q, got %q", e, g) 234 } 235 236 // Do should also follow redirects. 237 greq, _ := NewRequest("GET", ts.URL, nil) 238 _, err = c.Do(greq) 239 if e, g := `Get "/?n=10": stopped after 10 redirects`, fmt.Sprintf("%v", err); e != g { 240 t.Errorf("with default client Do, expected error %q, got %q", e, g) 241 } 242 243 // Requests with an empty Method should also redirect (Issue 12705) 244 greq.Method = "" 245 _, err = c.Do(greq) 246 if e, g := `Get "/?n=10": stopped after 10 redirects`, fmt.Sprintf("%v", err); e != g { 247 t.Errorf("with default client Do and empty Method, expected error %q, got %q", e, g) 248 } 249 250 var checkErr error 251 var lastVia []*Request 252 var lastReq *Request 253 c.CheckRedirect = func(req *Request, via []*Request) error { 254 lastReq = req 255 lastVia = via 256 return checkErr 257 } 258 res, err := c.Get(ts.URL) 259 if err != nil { 260 t.Fatalf("Get error: %v", err) 261 } 262 _ = res.Body.Close() 263 finalURL := res.Request.URL.String() 264 if e, g := "<nil>", fmt.Sprintf("%v", err); e != g { 265 t.Errorf("with custom client, expected error %q, got %q", e, g) 266 } 267 if !strings.HasSuffix(finalURL, "/?n=15") { 268 t.Errorf("expected final url to end in /?n=15; got url %q", finalURL) 269 } 270 if e, g := 15, len(lastVia); e != g { 271 t.Errorf("expected lastVia to have contained %d elements; got %d", e, g) 272 } 273 274 // Test that Request.Cancel is propagated between requests (Issue 14053) 275 creq, _ := NewRequest("HEAD", ts.URL, nil) 276 cancel := make(chan struct{}) 277 creq.Cancel = cancel 278 if _, err := c.Do(creq); err != nil { 279 t.Fatal(err) 280 } 281 if lastReq == nil { 282 t.Fatal("didn't see redirect") 283 } 284 if lastReq.Cancel != cancel { 285 t.Errorf("expected lastReq to have the cancel channel set on the initial req") 286 } 287 288 checkErr = errors.New("no redirects allowed") 289 res, err = c.Get(ts.URL) 290 if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr { 291 t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err) 292 } 293 if res == nil { 294 t.Fatalf("Expected a non-nil Response on CheckRedirect failure (https://golang.org/issue/3795)") 295 } 296 _ = res.Body.Close() 297 if res.Header.Get("Location") == "" { 298 t.Errorf("no Location header in Response") 299 } 300 } 301 302 // Tests that Client redirects' contexts are derived from the original request's context. 303 func TestClientRedirectContext(t *testing.T) { 304 setParallel(t) 305 defer afterTest(t) 306 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 307 Redirect(w, r, "/", StatusTemporaryRedirect) 308 })) 309 defer ts.Close() 310 311 ctx, cancel := context.WithCancel(context.Background()) 312 c := ts.Client() 313 c.CheckRedirect = func(req *Request, via []*Request) error { 314 cancel() 315 select { 316 case <-req.Context().Done(): 317 return nil 318 case <-time.After(5 * time.Second): 319 return errors.New("redirected request's context never expired after root request canceled") 320 } 321 } 322 req, _ := NewRequestWithContext(ctx, "GET", ts.URL, nil) 323 _, err := c.Do(req) 324 ue, ok := err.(*url.Error) 325 if !ok { 326 t.Fatalf("got error %T; want *url.Error", err) 327 } 328 if ue.Err != context.Canceled { 329 t.Errorf("url.Error.Err = %v; want %v", ue.Err, context.Canceled) 330 } 331 } 332 333 type redirectTest struct { 334 suffix string 335 want int // response code 336 redirectBody string 337 } 338 339 func TestPostRedirects(t *testing.T) { 340 postRedirectTests := []redirectTest{ 341 {"/", 200, "first"}, 342 {"/?code=301&next=302", 200, "c301"}, 343 {"/?code=302&next=302", 200, "c302"}, 344 {"/?code=303&next=301", 200, "c303wc301"}, // Issue 9348 345 {"/?code=304", 304, "c304"}, 346 {"/?code=305", 305, "c305"}, 347 {"/?code=307&next=303,308,302", 200, "c307"}, 348 {"/?code=308&next=302,301", 200, "c308"}, 349 {"/?code=404", 404, "c404"}, 350 } 351 352 wantSegments := []string{ 353 `POST / "first"`, 354 `POST /?code=301&next=302 "c301"`, 355 `GET /?code=302 ""`, 356 `GET / ""`, 357 `POST /?code=302&next=302 "c302"`, 358 `GET /?code=302 ""`, 359 `GET / ""`, 360 `POST /?code=303&next=301 "c303wc301"`, 361 `GET /?code=301 ""`, 362 `GET / ""`, 363 `POST /?code=304 "c304"`, 364 `POST /?code=305 "c305"`, 365 `POST /?code=307&next=303,308,302 "c307"`, 366 `POST /?code=303&next=308,302 "c307"`, 367 `GET /?code=308&next=302 ""`, 368 `GET /?code=302 "c307"`, 369 `GET / ""`, 370 `POST /?code=308&next=302,301 "c308"`, 371 `POST /?code=302&next=301 "c308"`, 372 `GET /?code=301 ""`, 373 `GET / ""`, 374 `POST /?code=404 "c404"`, 375 } 376 want := strings.Join(wantSegments, "\n") 377 testRedirectsByMethod(t, "POST", postRedirectTests, want) 378 } 379 380 func TestDeleteRedirects(t *testing.T) { 381 deleteRedirectTests := []redirectTest{ 382 {"/", 200, "first"}, 383 {"/?code=301&next=302,308", 200, "c301"}, 384 {"/?code=302&next=302", 200, "c302"}, 385 {"/?code=303", 200, "c303"}, 386 {"/?code=307&next=301,308,303,302,304", 304, "c307"}, 387 {"/?code=308&next=307", 200, "c308"}, 388 {"/?code=404", 404, "c404"}, 389 } 390 391 wantSegments := []string{ 392 `DELETE / "first"`, 393 `DELETE /?code=301&next=302,308 "c301"`, 394 `GET /?code=302&next=308 ""`, 395 `GET /?code=308 ""`, 396 `GET / "c301"`, 397 `DELETE /?code=302&next=302 "c302"`, 398 `GET /?code=302 ""`, 399 `GET / ""`, 400 `DELETE /?code=303 "c303"`, 401 `GET / ""`, 402 `DELETE /?code=307&next=301,308,303,302,304 "c307"`, 403 `DELETE /?code=301&next=308,303,302,304 "c307"`, 404 `GET /?code=308&next=303,302,304 ""`, 405 `GET /?code=303&next=302,304 "c307"`, 406 `GET /?code=302&next=304 ""`, 407 `GET /?code=304 ""`, 408 `DELETE /?code=308&next=307 "c308"`, 409 `DELETE /?code=307 "c308"`, 410 `DELETE / "c308"`, 411 `DELETE /?code=404 "c404"`, 412 } 413 want := strings.Join(wantSegments, "\n") 414 testRedirectsByMethod(t, "DELETE", deleteRedirectTests, want) 415 } 416 417 func testRedirectsByMethod(t *testing.T, method string, table []redirectTest, want string) { 418 defer afterTest(t) 419 var logBuffer struct { 420 sync.Mutex 421 bytes.Buffer 422 } 423 var ts *httptest.Server 424 ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 425 logBuffer.Lock() 426 slurp, _ := io.ReadAll(r.Body) 427 _, _ = fmt.Fprintf(&logBuffer.Buffer, "%s %s %q", r.Method, r.RequestURI, slurp) 428 if cl := r.Header.Get("Content-Length"); r.Method == "GET" && len(slurp) == 0 && (r.ContentLength != 0 || cl != "") { 429 _, _ = fmt.Fprintf(&logBuffer.Buffer, " (but with body=%T, content-length = %v, %q)", r.Body, r.ContentLength, cl) 430 } 431 _ = logBuffer.WriteByte('\n') 432 logBuffer.Unlock() 433 urlQuery := r.URL.Query() 434 if v := urlQuery.Get("code"); v != "" { 435 location := ts.URL 436 if final := urlQuery.Get("next"); final != "" { 437 splits := strings.Split(final, ",") 438 first, rest := splits[0], splits[1:] 439 location = fmt.Sprintf("%s?code=%s", location, first) 440 if len(rest) > 0 { 441 location = fmt.Sprintf("%s&next=%s", location, strings.Join(rest, ",")) 442 } 443 } 444 code, _ := strconv.Atoi(v) 445 if code/100 == 3 { 446 w.Header().Set("Location", location) 447 } 448 w.WriteHeader(code) 449 } 450 })) 451 defer ts.Close() 452 453 c := ts.Client() 454 for _, tt := range table { 455 content := tt.redirectBody 456 req, _ := NewRequest(method, ts.URL+tt.suffix, strings.NewReader(content)) 457 req.GetBody = func() (io.ReadCloser, error) { return io.NopCloser(strings.NewReader(content)), nil } 458 res, err := c.Do(req) 459 460 if err != nil { 461 t.Fatal(err) 462 } 463 if res.StatusCode != tt.want { 464 t.Errorf("POST %s: status code = %d; want %d", tt.suffix, res.StatusCode, tt.want) 465 } 466 } 467 logBuffer.Lock() 468 got := logBuffer.String() 469 logBuffer.Unlock() 470 471 got = strings.TrimSpace(got) 472 want = strings.TrimSpace(want) 473 474 if got != want { 475 got, want, lines := removeCommonLines(got, want) 476 t.Errorf("Log differs after %d common lines.\n\nGot:\n%s\n\nWant:\n%s\n", lines, got, want) 477 } 478 } 479 480 func removeCommonLines(a, b string) (asuffix, bsuffix string, commonLines int) { 481 for { 482 nl := strings.IndexByte(a, '\n') 483 if nl < 0 { 484 return a, b, commonLines 485 } 486 line := a[:nl+1] 487 if !strings.HasPrefix(b, line) { 488 return a, b, commonLines 489 } 490 commonLines++ 491 a = a[len(line):] 492 b = b[len(line):] 493 } 494 } 495 496 func TestClientRedirectUseResponse(t *testing.T) { 497 setParallel(t) 498 defer afterTest(t) 499 const body = "Hello, world." 500 var ts *httptest.Server 501 ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 502 if strings.Contains(r.URL.Path, "/other") { 503 _, _ = io.WriteString(w, "wrong body") 504 } else { 505 w.Header().Set("Location", ts.URL+"/other") 506 w.WriteHeader(StatusFound) 507 _, _ = io.WriteString(w, body) 508 } 509 })) 510 defer ts.Close() 511 512 c := ts.Client() 513 c.CheckRedirect = func(req *Request, via []*Request) error { 514 if req.Response == nil { 515 t.Error("expected non-nil Request.Response") 516 } 517 return ErrUseLastResponse 518 } 519 res, err := c.Get(ts.URL) 520 if err != nil { 521 t.Fatal(err) 522 } 523 if res.StatusCode != StatusFound { 524 t.Errorf("status = %d; want %d", res.StatusCode, StatusFound) 525 } 526 defer func(Body io.ReadCloser) { 527 _ = Body.Close() 528 }(res.Body) 529 slurp, err := io.ReadAll(res.Body) 530 if err != nil { 531 t.Fatal(err) 532 } 533 if string(slurp) != body { 534 t.Errorf("body = %q; want %q", slurp, body) 535 } 536 } 537 538 // Issue 17773: don't follow a 308 (or 307) if the response doesn't 539 // have a Location header. 540 func TestClientRedirect308NoLocation(t *testing.T) { 541 setParallel(t) 542 defer afterTest(t) 543 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 544 w.Header().Set("Foo", "Bar") 545 w.WriteHeader(308) 546 })) 547 defer ts.Close() 548 c := ts.Client() 549 res, err := c.Get(ts.URL) 550 if err != nil { 551 t.Fatal(err) 552 } 553 _ = res.Body.Close() 554 if res.StatusCode != 308 { 555 t.Errorf("status = %d; want %d", res.StatusCode, 308) 556 } 557 if got := res.Header.Get("Foo"); got != "Bar" { 558 t.Errorf("Foo header = %q; want Bar", got) 559 } 560 } 561 562 // Don't follow a 307/308 if we can't resent the request body. 563 func TestClientRedirect308NoGetBody(t *testing.T) { 564 setParallel(t) 565 defer afterTest(t) 566 const fakeURL = "https://localhost:1234/" // won't be hit 567 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 568 w.Header().Set("Location", fakeURL) 569 w.WriteHeader(308) 570 })) 571 defer ts.Close() 572 req, err := NewRequest("POST", ts.URL, strings.NewReader("some body")) 573 if err != nil { 574 t.Fatal(err) 575 } 576 c := ts.Client() 577 req.GetBody = nil // so it can't rewind. 578 res, err := c.Do(req) 579 if err != nil { 580 t.Fatal(err) 581 } 582 _ = res.Body.Close() 583 if res.StatusCode != 308 { 584 t.Errorf("status = %d; want %d", res.StatusCode, 308) 585 } 586 if got := res.Header.Get("Location"); got != fakeURL { 587 t.Errorf("Location header = %q; want %q", got, fakeURL) 588 } 589 } 590 591 var expectedCookies = []*Cookie{ 592 {Name: "ChocolateChip", Value: "tasty"}, 593 {Name: "First", Value: "Hit"}, 594 {Name: "Second", Value: "Hit"}, 595 } 596 597 var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) { 598 for _, cookie := range r.Cookies() { 599 SetCookie(w, cookie) 600 } 601 if r.URL.Path == "/" { 602 SetCookie(w, expectedCookies[1]) 603 Redirect(w, r, "/second", StatusMovedPermanently) 604 } else { 605 SetCookie(w, expectedCookies[2]) 606 _, _ = w.Write([]byte("hello")) 607 } 608 }) 609 610 func TestClientSendsCookieFromJar(t *testing.T) { 611 defer afterTest(t) 612 tr := &recordingTransport{} 613 client := &Client{Transport: tr} 614 client.Jar = &TestJar{perURL: make(map[string][]*Cookie)} 615 us := "http://dummy.faketld/" 616 u, _ := url.Parse(us) 617 client.Jar.SetCookies(u, expectedCookies) 618 619 _, _ = client.Get(us) // Note: doesn't hit network 620 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 621 622 _, _ = client.Head(us) // Note: doesn't hit network 623 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 624 625 _, _ = client.Post(us, "text/plain", strings.NewReader("body")) // Note: doesn't hit network 626 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 627 628 _, _ = client.PostForm(us, url.Values{}) // Note: doesn't hit network 629 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 630 631 req, _ := NewRequest("GET", us, nil) 632 _, _ = client.Do(req) // Note: doesn't hit network 633 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 634 635 req, _ = NewRequest("POST", us, nil) 636 _, _ = client.Do(req) // Note: doesn't hit network 637 matchReturnedCookies(t, expectedCookies, tr.req.Cookies()) 638 } 639 640 // Just enough correctness for our redirect tests. Uses the URL.Host as the 641 // scope of all cookies. 642 type TestJar struct { 643 m sync.Mutex 644 perURL map[string][]*Cookie 645 } 646 647 func (j *TestJar) SetCookies(u *url.URL, cookies []*Cookie) { 648 j.m.Lock() 649 defer j.m.Unlock() 650 if j.perURL == nil { 651 j.perURL = make(map[string][]*Cookie) 652 } 653 j.perURL[u.Host] = cookies 654 } 655 656 func (j *TestJar) Cookies(u *url.URL) []*Cookie { 657 j.m.Lock() 658 defer j.m.Unlock() 659 return j.perURL[u.Host] 660 } 661 662 func TestRedirectCookiesJar(t *testing.T) { 663 setParallel(t) 664 defer afterTest(t) 665 var ts *httptest.Server 666 ts = httptest.NewServer(echoCookiesRedirectHandler) 667 defer ts.Close() 668 c := ts.Client() 669 c.Jar = new(TestJar) 670 u, _ := url.Parse(ts.URL) 671 c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]}) 672 resp, err := c.Get(ts.URL) 673 if err != nil { 674 t.Fatalf("Get: %v", err) 675 } 676 _ = resp.Body.Close() 677 matchReturnedCookies(t, expectedCookies, resp.Cookies()) 678 } 679 680 func matchReturnedCookies(t *testing.T, expected, given []*Cookie) { 681 if len(given) != len(expected) { 682 t.Logf("Received cookies: %v", given) 683 t.Errorf("Expected %d cookies, got %d", len(expected), len(given)) 684 } 685 for _, ec := range expected { 686 foundC := false 687 for _, c := range given { 688 if ec.Name == c.Name && ec.Value == c.Value { 689 foundC = true 690 break 691 } 692 } 693 if !foundC { 694 t.Errorf("Missing cookie %v", ec) 695 } 696 } 697 } 698 699 func TestJarCalls(t *testing.T) { 700 defer afterTest(t) 701 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 702 pathSuffix := r.RequestURI[1:] 703 if r.RequestURI == "/nosetcookie" { 704 return // don't set cookies for this path 705 } 706 SetCookie(w, &Cookie{Name: "name" + pathSuffix, Value: "val" + pathSuffix}) 707 if r.RequestURI == "/" { 708 Redirect(w, r, "http://secondhost.fake/secondpath", 302) 709 } 710 })) 711 defer ts.Close() 712 jar := new(RecordingJar) 713 c := ts.Client() 714 c.Jar = jar 715 c.Transport.(*Transport).Dial = func(_ string, _ string) (net.Conn, error) { 716 return net.Dial("tcp", ts.Listener.Addr().String()) 717 } 718 _, err := c.Get("http://firsthost.fake/") 719 if err != nil { 720 t.Fatal(err) 721 } 722 _, err = c.Get("http://firsthost.fake/nosetcookie") 723 if err != nil { 724 t.Fatal(err) 725 } 726 got := jar.log.String() 727 want := `Cookies("http://firsthost.fake/") 728 SetCookie("http://firsthost.fake/", [name=val]) 729 Cookies("http://secondhost.fake/secondpath") 730 SetCookie("http://secondhost.fake/secondpath", [namesecondpath=valsecondpath]) 731 Cookies("http://firsthost.fake/nosetcookie") 732 ` 733 if got != want { 734 t.Errorf("Got Jar calls:\n%s\nWant:\n%s", got, want) 735 } 736 } 737 738 // RecordingJar keeps a log of calls made to it, without 739 // tracking any cookies. 740 type RecordingJar struct { 741 mu sync.Mutex 742 log bytes.Buffer 743 } 744 745 func (j *RecordingJar) SetCookies(u *url.URL, cookies []*Cookie) { 746 j.logf("SetCookie(%q, %v)\n", u, cookies) 747 } 748 749 func (j *RecordingJar) Cookies(u *url.URL) []*Cookie { 750 j.logf("Cookies(%q)\n", u) 751 return nil 752 } 753 754 func (j *RecordingJar) logf(format string, args ...interface{}) { 755 j.mu.Lock() 756 defer j.mu.Unlock() 757 _, _ = fmt.Fprintf(&j.log, format, args...) 758 } 759 760 func TestStreamingGet_h1(t *testing.T) { testStreamingGet(t, h1Mode) } 761 func TestStreamingGet_h2(t *testing.T) { testStreamingGet(t, h2Mode) } 762 763 func testStreamingGet(t *testing.T, h2 bool) { 764 defer afterTest(t) 765 say := make(chan string) 766 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 767 w.(Flusher).Flush() 768 for str := range say { 769 _, _ = w.Write([]byte(str)) 770 w.(Flusher).Flush() 771 } 772 })) 773 defer cst.close() 774 775 c := cst.c 776 res, err := c.Get(cst.ts.URL) 777 if err != nil { 778 t.Fatal(err) 779 } 780 var buf [10]byte 781 for _, str := range []string{"i", "am", "also", "known", "as", "comet"} { 782 say <- str 783 n, err := io.ReadFull(res.Body, buf[0:len(str)]) 784 if err != nil { 785 t.Fatalf("ReadFull on %q: %v", str, err) 786 } 787 if n != len(str) { 788 t.Fatalf("Receiving %q, only read %d bytes", str, n) 789 } 790 got := string(buf[0:n]) 791 if got != str { 792 t.Fatalf("Expected %q, got %q", str, got) 793 } 794 } 795 close(say) 796 _, err = io.ReadFull(res.Body, buf[0:1]) 797 if err != io.EOF { 798 t.Fatalf("at end expected EOF, got %v", err) 799 } 800 } 801 802 type writeCountingConn struct { 803 net.Conn 804 count *int 805 } 806 807 func (c *writeCountingConn) Write(p []byte) (int, error) { 808 *c.count++ 809 return c.Conn.Write(p) 810 } 811 812 // TestClientWrites verifies that client requests are buffered and we 813 // don't send a TCP packet per line of the http request + body. 814 func TestClientWrites(t *testing.T) { 815 defer afterTest(t) 816 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 817 })) 818 defer ts.Close() 819 820 writes := 0 821 dialer := func(netz string, addr string) (net.Conn, error) { 822 c, err := net.Dial(netz, addr) 823 if err == nil { 824 c = &writeCountingConn{c, &writes} 825 } 826 return c, err 827 } 828 c := ts.Client() 829 c.Transport.(*Transport).Dial = dialer 830 831 _, err := c.Get(ts.URL) 832 if err != nil { 833 t.Fatal(err) 834 } 835 if writes != 1 { 836 t.Errorf("Get request did %d Write calls, want 1", writes) 837 } 838 839 writes = 0 840 _, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}}) 841 if err != nil { 842 t.Fatal(err) 843 } 844 if writes != 1 { 845 t.Errorf("Post request did %d Write calls, want 1", writes) 846 } 847 } 848 849 func TestClientInsecureTransport(t *testing.T) { 850 setParallel(t) 851 defer afterTest(t) 852 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 853 _, _ = w.Write([]byte("Hello")) 854 })) 855 errc := make(chanWriter, 10) // but only expecting 1 856 ts.Config.ErrorLog = log.New(errc, "", 0) 857 defer ts.Close() 858 859 // TODO(bradfitz): add tests for skipping hostname checks too? 860 // would require a new cert for testing, and probably 861 // redundant with these tests. 862 c := ts.Client() 863 for _, insecure := range []bool{true, false} { 864 c.Transport.(*Transport).TLSClientConfig = &tls.Config{ 865 InsecureSkipVerify: insecure, 866 } 867 res, err := c.Get(ts.URL) 868 if (err == nil) != insecure { 869 t.Errorf("insecure=%v: got unexpected err=%v", insecure, err) 870 } 871 if res != nil { 872 _ = res.Body.Close() 873 } 874 } 875 876 select { 877 case v := <-errc: 878 if !strings.Contains(v, "TLS handshake error") { 879 t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v) 880 } 881 case <-time.After(5 * time.Second): 882 t.Errorf("timeout waiting for logged error") 883 } 884 885 } 886 887 func TestClientErrorWithRequestURI(t *testing.T) { 888 defer afterTest(t) 889 req, _ := NewRequest("GET", "http://localhost:1234/", nil) 890 req.RequestURI = "/this/field/is/illegal/and/should/error/" 891 _, err := DefaultClient.Do(req) 892 if err == nil { 893 t.Fatalf("expected an error") 894 } 895 if !strings.Contains(err.Error(), "RequestURI") { 896 t.Errorf("wanted error mentioning RequestURI; got error: %v", err) 897 } 898 } 899 900 func TestClientWithCorrectTLSServerName(t *testing.T) { 901 defer afterTest(t) 902 903 const serverName = "example.com" 904 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 905 if r.TLS.ServerName != serverName { 906 t.Errorf("expected client to set ServerName %q, got: %q", serverName, r.TLS.ServerName) 907 } 908 })) 909 defer ts.Close() 910 911 c := ts.Client() 912 c.Transport.(*Transport).TLSClientConfig.ServerName = serverName 913 if _, err := c.Get(ts.URL); err != nil { 914 t.Fatalf("expected successful TLS connection, got error: %v", err) 915 } 916 } 917 918 func TestClientWithIncorrectTLSServerName(t *testing.T) { 919 defer afterTest(t) 920 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) 921 defer ts.Close() 922 errc := make(chanWriter, 10) // but only expecting 1 923 ts.Config.ErrorLog = log.New(errc, "", 0) 924 925 c := ts.Client() 926 c.Transport.(*Transport).TLSClientConfig.ServerName = "badserver" 927 _, err := c.Get(ts.URL) 928 if err == nil { 929 t.Fatalf("expected an error") 930 } 931 if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") { 932 t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err) 933 } 934 select { 935 case v := <-errc: 936 if !strings.Contains(v, "TLS handshake error") { 937 t.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v) 938 } 939 case <-time.After(5 * time.Second): 940 t.Errorf("timeout waiting for logged error") 941 } 942 } 943 944 // Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName 945 // when not empty. 946 // 947 // tls.Config.ServerName (non-empty, set to "example.com") takes 948 // precedence over "some-other-host.tld" which previously incorrectly 949 // took precedence. We don't actually connect to (or even resolve) 950 // "some-other-host.tld", though, because of the Transport.Dial hook. 951 // 952 // The httptest.Server has a cert with "example.com" as its name. 953 func TestTransportUsesTLSConfigServerName(t *testing.T) { 954 defer afterTest(t) 955 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 956 _, _ = w.Write([]byte("Hello")) 957 })) 958 defer ts.Close() 959 960 c := ts.Client() 961 tr := c.Transport.(*Transport) 962 tr.TLSClientConfig.ServerName = "example.com" // one of httptest's Server cert names 963 tr.Dial = func(netw, addr string) (net.Conn, error) { 964 return net.Dial(netw, ts.Listener.Addr().String()) 965 } 966 res, err := c.Get("https://some-other-host.tld/") 967 if err != nil { 968 t.Fatal(err) 969 } 970 _ = res.Body.Close() 971 } 972 973 func TestResponseSetsTLSConnectionState(t *testing.T) { 974 defer afterTest(t) 975 ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) { 976 _, _ = w.Write([]byte("Hello")) 977 })) 978 defer ts.Close() 979 980 c := ts.Client() 981 tr := c.Transport.(*Transport) 982 tr.TLSClientConfig.CipherSuites = []uint16{tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA} 983 tr.TLSClientConfig.MaxVersion = tls.VersionTLS12 // to get to pick the cipher suite 984 tr.Dial = func(netw, addr string) (net.Conn, error) { 985 return net.Dial(netw, ts.Listener.Addr().String()) 986 } 987 res, err := c.Get("https://example.com/") 988 if err != nil { 989 t.Fatal(err) 990 } 991 defer func(Body io.ReadCloser) { 992 _ = Body.Close() 993 }(res.Body) 994 if res.TLS == nil { 995 t.Fatal("Response didn't set TLS Connection State.") 996 } 997 if got, want := res.TLS.CipherSuite, tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA; got != want { 998 t.Errorf("TLS Cipher Suite = %d; want %d", got, want) 999 } 1000 } 1001 1002 // Check that an HTTPS client can interpret a particular TLS error 1003 // to determine that the server is speaking HTTP. 1004 // See golang.org/issue/11111. 1005 func TestHTTPSClientDetectsHTTPServer(t *testing.T) { 1006 defer afterTest(t) 1007 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {})) 1008 ts.Config.ErrorLog = quietLog 1009 defer ts.Close() 1010 1011 _, err := Get(strings.Replace(ts.URL, "http", "https", 1)) 1012 if got := err.Error(); !strings.Contains(got, "HTTP response to HTTPS client") { 1013 t.Fatalf("error = %q; want error indicating HTTP response to HTTPS request", got) 1014 } 1015 } 1016 1017 // Verify Response.ContentLength is populated. https://golang.org/issue/4126 1018 func TestClientHeadContentLength_h1(t *testing.T) { 1019 testClientHeadContentLength(t, h1Mode) 1020 } 1021 1022 func TestClientHeadContentLength_h2(t *testing.T) { 1023 testClientHeadContentLength(t, h2Mode) 1024 } 1025 1026 func testClientHeadContentLength(t *testing.T, h2 bool) { 1027 defer afterTest(t) 1028 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1029 if v := r.FormValue("cl"); v != "" { 1030 w.Header().Set("Content-Length", v) 1031 } 1032 })) 1033 defer cst.close() 1034 tests := []struct { 1035 suffix string 1036 want int64 1037 }{ 1038 {"/?cl=1234", 1234}, 1039 {"/?cl=0", 0}, 1040 {"", -1}, 1041 } 1042 for _, tt := range tests { 1043 req, _ := NewRequest("HEAD", cst.ts.URL+tt.suffix, nil) 1044 res, err := cst.c.Do(req) 1045 if err != nil { 1046 t.Fatal(err) 1047 } 1048 if res.ContentLength != tt.want { 1049 t.Errorf("Content-Length = %d; want %d", res.ContentLength, tt.want) 1050 } 1051 bs, err := io.ReadAll(res.Body) 1052 if err != nil { 1053 t.Fatal(err) 1054 } 1055 if len(bs) != 0 { 1056 t.Errorf("Unexpected content: %q", bs) 1057 } 1058 } 1059 } 1060 1061 func TestEmptyPasswordAuth(t *testing.T) { 1062 setParallel(t) 1063 defer afterTest(t) 1064 gopher := "gopher" 1065 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1066 auth := r.Header.Get("Authorization") 1067 if strings.HasPrefix(auth, "Basic ") { 1068 encoded := auth[6:] 1069 decoded, err := base64.StdEncoding.DecodeString(encoded) 1070 if err != nil { 1071 t.Fatal(err) 1072 } 1073 expected := gopher + ":" 1074 s := string(decoded) 1075 if expected != s { 1076 t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) 1077 } 1078 } else { 1079 t.Errorf("Invalid auth %q", auth) 1080 } 1081 })) 1082 defer ts.Close() 1083 req, err := NewRequest("GET", ts.URL, nil) 1084 if err != nil { 1085 t.Fatal(err) 1086 } 1087 req.URL.User = url.User(gopher) 1088 c := ts.Client() 1089 resp, err := c.Do(req) 1090 if err != nil { 1091 t.Fatal(err) 1092 } 1093 defer func(Body io.ReadCloser) { 1094 _ = Body.Close() 1095 }(resp.Body) 1096 } 1097 1098 func TestBasicAuth(t *testing.T) { 1099 defer afterTest(t) 1100 tr := &recordingTransport{} 1101 client := &Client{Transport: tr} 1102 1103 urlTest := "http://My%20User:My%20Pass@dummy.faketld/" 1104 expected := "My User:My Pass" 1105 _, _ = client.Get(urlTest) 1106 1107 if tr.req.Method != "GET" { 1108 t.Errorf("got method %q, want %q", tr.req.Method, "GET") 1109 } 1110 if tr.req.URL.String() != urlTest { 1111 t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlTest) 1112 } 1113 if tr.req.Header == nil { 1114 t.Fatalf("expected non-nil request Header") 1115 } 1116 auth := tr.req.Header.Get("Authorization") 1117 if strings.HasPrefix(auth, "Basic ") { 1118 encoded := auth[6:] 1119 decoded, err := base64.StdEncoding.DecodeString(encoded) 1120 if err != nil { 1121 t.Fatal(err) 1122 } 1123 s := string(decoded) 1124 if expected != s { 1125 t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) 1126 } 1127 } else { 1128 t.Errorf("Invalid auth %q", auth) 1129 } 1130 } 1131 1132 func TestBasicAuthHeadersPreserved(t *testing.T) { 1133 defer afterTest(t) 1134 tr := &recordingTransport{} 1135 client := &Client{Transport: tr} 1136 1137 // If Authorization header is provided, username in URL should not override it 1138 urlTest := "http://My%20User@dummy.faketld/" 1139 req, err := NewRequest("GET", urlTest, nil) 1140 if err != nil { 1141 t.Fatal(err) 1142 } 1143 req.SetBasicAuth("My User", "My Pass") 1144 expected := "My User:My Pass" 1145 _, _ = client.Do(req) 1146 1147 if tr.req.Method != "GET" { 1148 t.Errorf("got method %q, want %q", tr.req.Method, "GET") 1149 } 1150 if tr.req.URL.String() != urlTest { 1151 t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlTest) 1152 } 1153 if tr.req.Header == nil { 1154 t.Fatalf("expected non-nil request Header") 1155 } 1156 auth := tr.req.Header.Get("Authorization") 1157 if strings.HasPrefix(auth, "Basic ") { 1158 encoded := auth[6:] 1159 decoded, err := base64.StdEncoding.DecodeString(encoded) 1160 if err != nil { 1161 t.Fatal(err) 1162 } 1163 s := string(decoded) 1164 if expected != s { 1165 t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected) 1166 } 1167 } else { 1168 t.Errorf("Invalid auth %q", auth) 1169 } 1170 1171 } 1172 1173 func TestStripPasswordFromError(t *testing.T) { 1174 client := &Client{Transport: &recordingTransport{}} 1175 testCases := []struct { 1176 desc string 1177 in string 1178 out string 1179 }{ 1180 { 1181 desc: "Strip password from error message", 1182 in: "http://user:password@dummy.faketld/", 1183 out: `Get "http://user:***@dummy.faketld/": dummy impl`, 1184 }, 1185 { 1186 desc: "Don't Strip password from domain name", 1187 in: "http://user:password@password.faketld/", 1188 out: `Get "http://user:***@password.faketld/": dummy impl`, 1189 }, 1190 { 1191 desc: "Don't Strip password from path", 1192 in: "http://user:password@dummy.faketld/password", 1193 out: `Get "http://user:***@dummy.faketld/password": dummy impl`, 1194 }, 1195 { 1196 desc: "Strip escaped password", 1197 in: "http://user:pa%2Fssword@dummy.faketld/", 1198 out: `Get "http://user:***@dummy.faketld/": dummy impl`, 1199 }, 1200 } 1201 for _, tC := range testCases { 1202 t.Run(tC.desc, func(t *testing.T) { 1203 _, err := client.Get(tC.in) 1204 if err.Error() != tC.out { 1205 t.Errorf("Unexpected output for %q: expected %q, actual %q", 1206 tC.in, tC.out, err.Error()) 1207 } 1208 }) 1209 } 1210 } 1211 1212 func TestClientTimeout_h1(t *testing.T) { testClientTimeout(t, h1Mode) } 1213 func TestClientTimeout_h2(t *testing.T) { testClientTimeout(t, h2Mode) } 1214 1215 func testClientTimeout(t *testing.T, h2 bool) { 1216 setParallel(t) 1217 defer afterTest(t) 1218 testDone := make(chan struct{}) // closed in defer below 1219 1220 sawRoot := make(chan bool, 1) 1221 sawSlow := make(chan bool, 1) 1222 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1223 if r.URL.Path == "/" { 1224 sawRoot <- true 1225 Redirect(w, r, "/slow", StatusFound) 1226 return 1227 } 1228 if r.URL.Path == "/slow" { 1229 sawSlow <- true 1230 _, _ = w.Write([]byte("Hello")) 1231 w.(Flusher).Flush() 1232 <-testDone 1233 return 1234 } 1235 })) 1236 defer cst.close() 1237 defer close(testDone) // before cst.close, to unblock /slow handler 1238 1239 // 200ms should be long enough to get a normal request (the / 1240 // handler), but not so long that it makes the test slow. 1241 const timeout = 200 * time.Millisecond 1242 cst.c.Timeout = timeout 1243 1244 res, err := cst.c.Get(cst.ts.URL) 1245 if err != nil { 1246 if strings.Contains(err.Error(), "Client.Timeout") { 1247 t.Skipf("host too slow to get fast resource in %v", timeout) 1248 } 1249 t.Fatal(err) 1250 } 1251 1252 select { 1253 case <-sawRoot: 1254 // good. 1255 default: 1256 t.Fatal("handler never got / request") 1257 } 1258 1259 select { 1260 case <-sawSlow: 1261 // good. 1262 default: 1263 t.Fatal("handler never got /slow request") 1264 } 1265 1266 errc := make(chan error, 1) 1267 go func() { 1268 _, err := io.ReadAll(res.Body) 1269 errc <- err 1270 _ = res.Body.Close() 1271 }() 1272 1273 const failTime = 5 * time.Second 1274 select { 1275 case err := <-errc: 1276 if err == nil { 1277 t.Fatal("expected error from ReadAll") 1278 } 1279 ne, ok := err.(net.Error) 1280 if !ok { 1281 t.Errorf("error value from ReadAll was %T; expected some net.Error", err) 1282 } else if !ne.Timeout() { 1283 t.Errorf("net.Error.Timeout = false; want true") 1284 } 1285 if got := ne.Error(); !strings.Contains(got, "(Client.Timeout") { 1286 t.Errorf("error string = %q; missing timeout substring", got) 1287 } 1288 case <-time.After(failTime): 1289 t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout) 1290 } 1291 } 1292 1293 func TestClientTimeout_Headers_h1(t *testing.T) { testClientTimeout_Headers(t, h1Mode) } 1294 func TestClientTimeout_Headers_h2(t *testing.T) { testClientTimeout_Headers(t, h2Mode) } 1295 1296 // Client.Timeout firing before getting to the body 1297 //goland:noinspection GoSnakeCaseUsage 1298 func testClientTimeout_Headers(t *testing.T, h2 bool) { 1299 setParallel(t) 1300 defer afterTest(t) 1301 donec := make(chan bool, 1) 1302 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1303 <-donec 1304 }), optQuietLog) 1305 defer cst.close() 1306 // Note that we use a channel send here and not a close. 1307 // The race detector doesn't know that we're waiting for a timeout 1308 // and thinks that the waitgroup inside httptest.Server is added to concurrently 1309 // with us closing it. If we timed out immediately, we could close the testserver 1310 // before we entered the handler. We're not timing out immediately and there's 1311 // no way we would be done before we entered the handler, but the race detector 1312 // doesn't know this, so synchronize explicitly. 1313 defer func() { donec <- true }() 1314 1315 cst.c.Timeout = 5 * time.Millisecond 1316 res, err := cst.c.Get(cst.ts.URL) 1317 if err == nil { 1318 _ = res.Body.Close() 1319 t.Fatal("got response from Get; expected error") 1320 } 1321 if _, ok := err.(*url.Error); !ok { 1322 t.Fatalf("Got error of type %T; want *url.Error", err) 1323 } 1324 ne, ok := err.(net.Error) 1325 if !ok { 1326 t.Fatalf("Got error of type %T; want some net.Error", err) 1327 } 1328 if !ne.Timeout() { 1329 t.Error("net.Error.Timeout = false; want true") 1330 } 1331 if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") { 1332 t.Errorf("error string = %q; missing timeout substring", got) 1333 } 1334 } 1335 1336 // Issue 16094: if Client.Timeout is set but not hit, a Timeout error shouldn't be 1337 // returned. 1338 func TestClientTimeoutCancel(t *testing.T) { 1339 setParallel(t) 1340 defer afterTest(t) 1341 1342 testDone := make(chan struct{}) 1343 ctx, cancel := context.WithCancel(context.Background()) 1344 1345 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 1346 w.(Flusher).Flush() 1347 <-testDone 1348 })) 1349 defer cst.close() 1350 defer close(testDone) 1351 1352 cst.c.Timeout = 1 * time.Hour 1353 req, _ := NewRequest("GET", cst.ts.URL, nil) 1354 req.Cancel = ctx.Done() 1355 res, err := cst.c.Do(req) 1356 if err != nil { 1357 t.Fatal(err) 1358 } 1359 cancel() 1360 _, err = io.Copy(io.Discard, res.Body) 1361 if err != ExportErrRequestCanceled { 1362 t.Fatalf("error = %v; want errRequestCanceled", err) 1363 } 1364 } 1365 1366 func TestClientTimeoutDoesNotExpire_h1(t *testing.T) { testClientTimeoutDoesNotExpire(t, h1Mode) } 1367 func TestClientTimeoutDoesNotExpire_h2(t *testing.T) { testClientTimeoutDoesNotExpire(t, h2Mode) } 1368 1369 // Issue 49366: if Client.Timeout is set but not hit, no error should be returned. 1370 func testClientTimeoutDoesNotExpire(t *testing.T, h2 bool) { 1371 setParallel(t) 1372 defer afterTest(t) 1373 1374 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1375 _, _ = w.Write([]byte("body")) 1376 })) 1377 defer cst.close() 1378 1379 cst.c.Timeout = 1 * time.Hour 1380 req, _ := NewRequest("GET", cst.ts.URL, nil) 1381 res, err := cst.c.Do(req) 1382 if err != nil { 1383 t.Fatal(err) 1384 } 1385 if _, err = io.Copy(io.Discard, res.Body); err != nil { 1386 t.Fatalf("io.Copy(io.Discard, res.Body) = %v, want nil", err) 1387 } 1388 if err = res.Body.Close(); err != nil { 1389 t.Fatalf("res.Body.Close() = %v, want nil", err) 1390 } 1391 } 1392 1393 func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) } 1394 func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) } 1395 func testClientRedirectEatsBody(t *testing.T, h2 bool) { 1396 setParallel(t) 1397 defer afterTest(t) 1398 saw := make(chan string, 2) 1399 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1400 saw <- r.RemoteAddr 1401 if r.URL.Path == "/" { 1402 Redirect(w, r, "/foo", StatusFound) // which includes a body 1403 } 1404 })) 1405 defer cst.close() 1406 1407 res, err := cst.c.Get(cst.ts.URL) 1408 if err != nil { 1409 t.Fatal(err) 1410 } 1411 _, err = io.ReadAll(res.Body) 1412 _ = res.Body.Close() 1413 if err != nil { 1414 t.Fatal(err) 1415 } 1416 1417 var first string 1418 select { 1419 case first = <-saw: 1420 default: 1421 t.Fatal("server didn't see a request") 1422 } 1423 1424 var second string 1425 select { 1426 case second = <-saw: 1427 default: 1428 t.Fatal("server didn't see a second request") 1429 } 1430 1431 if first != second { 1432 t.Fatal("server saw different client ports before & after the redirect") 1433 } 1434 } 1435 1436 // eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF. 1437 type eofReaderFunc func() 1438 1439 //goland:noinspection GoUnusedParameter 1440 func (f eofReaderFunc) Read(p []byte) (n int, err error) { 1441 f() 1442 return 0, io.EOF 1443 } 1444 1445 func TestReferer(t *testing.T) { 1446 //goland:noinspection HttpUrlsUsage 1447 tests := []struct { 1448 lastReq, newReq string // from -> to URLs 1449 want string 1450 }{ 1451 // don't send user: 1452 {"http://gopher@test.com", "http://link.com", "http://test.com"}, 1453 {"https://gopher@test.com", "https://link.com", "https://test.com"}, 1454 1455 // don't send a user and password: 1456 {"http://gopher:go@test.com", "http://link.com", "http://test.com"}, 1457 {"https://gopher:go@test.com", "https://link.com", "https://test.com"}, 1458 1459 // nothing to do: 1460 {"http://test.com", "http://link.com", "http://test.com"}, 1461 {"https://test.com", "https://link.com", "https://test.com"}, 1462 1463 // https to http doesn't send a referer: 1464 {"https://test.com", "http://link.com", ""}, 1465 {"https://gopher:go@test.com", "http://link.com", ""}, 1466 } 1467 for _, tt := range tests { 1468 l, err := url.Parse(tt.lastReq) 1469 if err != nil { 1470 t.Fatal(err) 1471 } 1472 n, err := url.Parse(tt.newReq) 1473 if err != nil { 1474 t.Fatal(err) 1475 } 1476 r := ExportRefererForURL(l, n) 1477 if r != tt.want { 1478 t.Errorf("refererForURL(%q, %q) = %q; want %q", tt.lastReq, tt.newReq, r, tt.want) 1479 } 1480 } 1481 } 1482 1483 // issue15577Tripper returns a Response with a redirect response 1484 // header and doesn't populate its Response.Request field. 1485 type issue15577Tripper struct{} 1486 1487 func (issue15577Tripper) RoundTrip(*Request) (*Response, error) { 1488 //goland:noinspection HttpUrlsUsage 1489 resp := &Response{ 1490 StatusCode: 303, 1491 Header: map[string][]string{"Location": {"http://www.example.com/"}}, 1492 Body: io.NopCloser(strings.NewReader("")), 1493 } 1494 return resp, nil 1495 } 1496 1497 // Issue 15577: don't assume the roundtripper's response populates its Request field. 1498 func TestClientRedirectResponseWithoutRequest(t *testing.T) { 1499 c := &Client{ 1500 CheckRedirect: func(*Request, []*Request) error { 1501 //goland:noinspection GoErrorStringFormat 1502 return fmt.Errorf("no redirects!") 1503 }, 1504 Transport: issue15577Tripper{}, 1505 } 1506 // Check that this doesn't crash: 1507 _, _ = c.Get("http://dummy.tld") 1508 } 1509 1510 // Issue 4800: copy (some) headers when Client follows a redirect. 1511 func TestClientCopyHeadersOnRedirect(t *testing.T) { 1512 const ( 1513 ua = "some-agent/1.2" 1514 xfoo = "foo-val" 1515 ) 1516 var ts2URL string 1517 ts1 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1518 want := Header{ 1519 "User-Agent": []string{ua}, 1520 "X-Foo": []string{xfoo}, 1521 "Referer": []string{ts2URL}, 1522 "Accept-Encoding": []string{"gzip"}, 1523 } 1524 if !reflect.DeepEqual(r.Header, want) { 1525 t.Errorf("Request.Header = %#v; want %#v", r.Header, want) 1526 } 1527 if t.Failed() { 1528 w.Header().Set("Result", "got errors") 1529 } else { 1530 w.Header().Set("Result", "ok") 1531 } 1532 })) 1533 defer ts1.Close() 1534 ts2 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1535 Redirect(w, r, ts1.URL, StatusFound) 1536 })) 1537 defer ts2.Close() 1538 ts2URL = ts2.URL 1539 1540 c := ts1.Client() 1541 c.CheckRedirect = func(r *Request, via []*Request) error { 1542 want := Header{ 1543 "User-Agent": []string{ua}, 1544 "X-Foo": []string{xfoo}, 1545 "Referer": []string{ts2URL}, 1546 } 1547 if !reflect.DeepEqual(r.Header, want) { 1548 t.Errorf("CheckRedirect Request.Header = %#v; want %#v", r.Header, want) 1549 } 1550 return nil 1551 } 1552 1553 req, _ := NewRequest("GET", ts2.URL, nil) 1554 req.Header.Add("User-Agent", ua) 1555 req.Header.Add("X-Foo", xfoo) 1556 req.Header.Add("Cookie", "foo=bar") 1557 req.Header.Add("Authorization", "secretpassword") 1558 res, err := c.Do(req) 1559 if err != nil { 1560 t.Fatal(err) 1561 } 1562 defer func(Body io.ReadCloser) { 1563 _ = Body.Close() 1564 }(res.Body) 1565 if res.StatusCode != 200 { 1566 t.Fatal(res.Status) 1567 } 1568 if got := res.Header.Get("Result"); got != "ok" { 1569 t.Errorf("result = %q; want ok", got) 1570 } 1571 } 1572 1573 // Issue 22233: copy host when Client follows a relative redirect. 1574 func TestClientCopyHostOnRedirect(t *testing.T) { 1575 // Virtual hostname: should not receive any request. 1576 virtual := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1577 t.Errorf("Virtual host received request %v", r.URL) 1578 w.WriteHeader(403) 1579 _, _ = io.WriteString(w, "should not see this response") 1580 })) 1581 defer virtual.Close() 1582 //goland:noinspection HttpUrlsUsage 1583 virtualHost := strings.TrimPrefix(virtual.URL, "http://") 1584 t.Logf("Virtual host is %v", virtualHost) 1585 1586 // Actual hostname: should not receive any request. 1587 const wantBody = "response body" 1588 var tsURL string 1589 var tsHost string 1590 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1591 switch r.URL.Path { 1592 case "/": 1593 // Relative redirect. 1594 if r.Host != virtualHost { 1595 t.Errorf("Serving /: Request.Host = %#v; want %#v", r.Host, virtualHost) 1596 w.WriteHeader(404) 1597 return 1598 } 1599 w.Header().Set("Location", "/hop") 1600 w.WriteHeader(302) 1601 case "/hop": 1602 // Absolute redirect. 1603 if r.Host != virtualHost { 1604 t.Errorf("Serving /hop: Request.Host = %#v; want %#v", r.Host, virtualHost) 1605 w.WriteHeader(404) 1606 return 1607 } 1608 w.Header().Set("Location", tsURL+"/final") 1609 w.WriteHeader(302) 1610 case "/final": 1611 if r.Host != tsHost { 1612 t.Errorf("Serving /final: Request.Host = %#v; want %#v", r.Host, tsHost) 1613 w.WriteHeader(404) 1614 return 1615 } 1616 w.WriteHeader(200) 1617 _, _ = io.WriteString(w, wantBody) 1618 default: 1619 t.Errorf("Serving unexpected path %q", r.URL.Path) 1620 w.WriteHeader(404) 1621 } 1622 })) 1623 defer ts.Close() 1624 tsURL = ts.URL 1625 //goland:noinspection HttpUrlsUsage 1626 tsHost = strings.TrimPrefix(ts.URL, "http://") 1627 t.Logf("Server host is %v", tsHost) 1628 1629 c := ts.Client() 1630 req, _ := NewRequest("GET", ts.URL, nil) 1631 req.Host = virtualHost 1632 resp, err := c.Do(req) 1633 if err != nil { 1634 t.Fatal(err) 1635 } 1636 defer func(Body io.ReadCloser) { 1637 _ = Body.Close() 1638 }(resp.Body) 1639 if resp.StatusCode != 200 { 1640 t.Fatal(resp.Status) 1641 } 1642 if got, err := io.ReadAll(resp.Body); err != nil || string(got) != wantBody { 1643 t.Errorf("body = %q; want %q", got, wantBody) 1644 } 1645 } 1646 1647 // Issue 17494: cookies should be altered when Client follows redirects. 1648 func TestClientAltersCookiesOnRedirect(t *testing.T) { 1649 cookieMap := func(cs []*Cookie) map[string][]string { 1650 m := make(map[string][]string) 1651 for _, c := range cs { 1652 m[c.Name] = append(m[c.Name], c.Value) 1653 } 1654 return m 1655 } 1656 1657 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1658 var want map[string][]string 1659 got := cookieMap(r.Cookies()) 1660 1661 c, _ := r.Cookie("Cycle") 1662 switch c.Value { 1663 case "0": 1664 want = map[string][]string{ 1665 "Cookie1": {"OldValue1a", "OldValue1b"}, 1666 "Cookie2": {"OldValue2"}, 1667 "Cookie3": {"OldValue3a", "OldValue3b"}, 1668 "Cookie4": {"OldValue4"}, 1669 "Cycle": {"0"}, 1670 } 1671 SetCookie(w, &Cookie{Name: "Cycle", Value: "1", Path: "/"}) 1672 SetCookie(w, &Cookie{Name: "Cookie2", Path: "/", MaxAge: -1}) // Delete cookie from Header 1673 Redirect(w, r, "/", StatusFound) 1674 case "1": 1675 want = map[string][]string{ 1676 "Cookie1": {"OldValue1a", "OldValue1b"}, 1677 "Cookie3": {"OldValue3a", "OldValue3b"}, 1678 "Cookie4": {"OldValue4"}, 1679 "Cycle": {"1"}, 1680 } 1681 SetCookie(w, &Cookie{Name: "Cycle", Value: "2", Path: "/"}) 1682 SetCookie(w, &Cookie{Name: "Cookie3", Value: "NewValue3", Path: "/"}) // Modify cookie in Header 1683 SetCookie(w, &Cookie{Name: "Cookie4", Value: "NewValue4", Path: "/"}) // Modify cookie in Jar 1684 Redirect(w, r, "/", StatusFound) 1685 case "2": 1686 want = map[string][]string{ 1687 "Cookie1": {"OldValue1a", "OldValue1b"}, 1688 "Cookie3": {"NewValue3"}, 1689 "Cookie4": {"NewValue4"}, 1690 "Cycle": {"2"}, 1691 } 1692 SetCookie(w, &Cookie{Name: "Cycle", Value: "3", Path: "/"}) 1693 SetCookie(w, &Cookie{Name: "Cookie5", Value: "NewValue5", Path: "/"}) // Insert cookie into Jar 1694 Redirect(w, r, "/", StatusFound) 1695 case "3": 1696 want = map[string][]string{ 1697 "Cookie1": {"OldValue1a", "OldValue1b"}, 1698 "Cookie3": {"NewValue3"}, 1699 "Cookie4": {"NewValue4"}, 1700 "Cookie5": {"NewValue5"}, 1701 "Cycle": {"3"}, 1702 } 1703 // Don't redirect to ensure the loop ends. 1704 default: 1705 t.Errorf("unexpected redirect cycle") 1706 return 1707 } 1708 1709 if !reflect.DeepEqual(got, want) { 1710 t.Errorf("redirect %s, Cookie = %v, want %v", c.Value, got, want) 1711 } 1712 })) 1713 defer ts.Close() 1714 1715 jar, _ := cookiejar.New(nil) 1716 c := ts.Client() 1717 c.Jar = jar 1718 1719 u, _ := url.Parse(ts.URL) 1720 req, _ := NewRequest("GET", ts.URL, nil) 1721 req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1a"}) 1722 req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1b"}) 1723 req.AddCookie(&Cookie{Name: "Cookie2", Value: "OldValue2"}) 1724 req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3a"}) 1725 req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3b"}) 1726 jar.SetCookies(u, []*Cookie{{Name: "Cookie4", Value: "OldValue4", Path: "/"}}) 1727 jar.SetCookies(u, []*Cookie{{Name: "Cycle", Value: "0", Path: "/"}}) 1728 res, err := c.Do(req) 1729 if err != nil { 1730 t.Fatal(err) 1731 } 1732 defer func(Body io.ReadCloser) { 1733 _ = Body.Close() 1734 }(res.Body) 1735 if res.StatusCode != 200 { 1736 t.Fatal(res.Status) 1737 } 1738 } 1739 1740 // Part of Issue 4800 1741 func TestShouldCopyHeaderOnRedirect(t *testing.T) { 1742 //goland:noinspection HttpUrlsUsage 1743 tests := []struct { 1744 header string 1745 initialURL string 1746 destURL string 1747 want bool 1748 }{ 1749 {"User-Agent", "http://foo.com/", "http://bar.com/", true}, 1750 {"X-Foo", "http://foo.com/", "http://bar.com/", true}, 1751 1752 // Sensitive headers: 1753 {"cookie", "http://foo.com/", "http://bar.com/", false}, 1754 {"cookie2", "http://foo.com/", "http://bar.com/", false}, 1755 {"authorization", "http://foo.com/", "http://bar.com/", false}, 1756 {"www-authenticate", "http://foo.com/", "http://bar.com/", false}, 1757 1758 // But subdomains should work: 1759 {"www-authenticate", "http://foo.com/", "http://foo.com/", true}, 1760 {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true}, 1761 {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false}, 1762 {"www-authenticate", "http://foo.com/", "https://foo.com/", false}, 1763 {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true}, 1764 {"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true}, 1765 {"www-authenticate", "http://foo.com:443/", "https://foo.com/", true}, 1766 {"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true}, 1767 {"www-authenticate", "http://foo.com:1234/", "http://foo.com/", false}, 1768 } 1769 for i, tt := range tests { 1770 u0, err := url.Parse(tt.initialURL) 1771 if err != nil { 1772 t.Errorf("%d. initial URL %q parse error: %v", i, tt.initialURL, err) 1773 continue 1774 } 1775 u1, err := url.Parse(tt.destURL) 1776 if err != nil { 1777 t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err) 1778 continue 1779 } 1780 got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1) 1781 if got != tt.want { 1782 t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v", 1783 i, tt.header, tt.initialURL, tt.destURL, got, tt.want) 1784 } 1785 } 1786 } 1787 1788 func TestClientRedirectTypes(t *testing.T) { 1789 setParallel(t) 1790 defer afterTest(t) 1791 1792 tests := [...]struct { 1793 method string 1794 serverStatus int 1795 wantMethod string // desired subsequent client method 1796 }{ 1797 0: {method: "POST", serverStatus: 301, wantMethod: "GET"}, 1798 1: {method: "POST", serverStatus: 302, wantMethod: "GET"}, 1799 2: {method: "POST", serverStatus: 303, wantMethod: "GET"}, 1800 3: {method: "POST", serverStatus: 307, wantMethod: "POST"}, 1801 4: {method: "POST", serverStatus: 308, wantMethod: "POST"}, 1802 1803 5: {method: "HEAD", serverStatus: 301, wantMethod: "HEAD"}, 1804 6: {method: "HEAD", serverStatus: 302, wantMethod: "HEAD"}, 1805 7: {method: "HEAD", serverStatus: 303, wantMethod: "HEAD"}, 1806 8: {method: "HEAD", serverStatus: 307, wantMethod: "HEAD"}, 1807 9: {method: "HEAD", serverStatus: 308, wantMethod: "HEAD"}, 1808 1809 10: {method: "GET", serverStatus: 301, wantMethod: "GET"}, 1810 11: {method: "GET", serverStatus: 302, wantMethod: "GET"}, 1811 12: {method: "GET", serverStatus: 303, wantMethod: "GET"}, 1812 13: {method: "GET", serverStatus: 307, wantMethod: "GET"}, 1813 14: {method: "GET", serverStatus: 308, wantMethod: "GET"}, 1814 1815 15: {method: "DELETE", serverStatus: 301, wantMethod: "GET"}, 1816 16: {method: "DELETE", serverStatus: 302, wantMethod: "GET"}, 1817 17: {method: "DELETE", serverStatus: 303, wantMethod: "GET"}, 1818 18: {method: "DELETE", serverStatus: 307, wantMethod: "DELETE"}, 1819 19: {method: "DELETE", serverStatus: 308, wantMethod: "DELETE"}, 1820 1821 20: {method: "PUT", serverStatus: 301, wantMethod: "GET"}, 1822 21: {method: "PUT", serverStatus: 302, wantMethod: "GET"}, 1823 22: {method: "PUT", serverStatus: 303, wantMethod: "GET"}, 1824 23: {method: "PUT", serverStatus: 307, wantMethod: "PUT"}, 1825 24: {method: "PUT", serverStatus: 308, wantMethod: "PUT"}, 1826 1827 25: {method: "MADEUPMETHOD", serverStatus: 301, wantMethod: "GET"}, 1828 26: {method: "MADEUPMETHOD", serverStatus: 302, wantMethod: "GET"}, 1829 27: {method: "MADEUPMETHOD", serverStatus: 303, wantMethod: "GET"}, 1830 28: {method: "MADEUPMETHOD", serverStatus: 307, wantMethod: "MADEUPMETHOD"}, 1831 29: {method: "MADEUPMETHOD", serverStatus: 308, wantMethod: "MADEUPMETHOD"}, 1832 } 1833 1834 handlerc := make(chan HandlerFunc, 1) 1835 1836 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 1837 h := <-handlerc 1838 h(rw, req) 1839 })) 1840 defer ts.Close() 1841 1842 c := ts.Client() 1843 for i, tt := range tests { 1844 handlerc <- func(w ResponseWriter, r *Request) { 1845 w.Header().Set("Location", ts.URL) 1846 w.WriteHeader(tt.serverStatus) 1847 } 1848 1849 req, err := NewRequest(tt.method, ts.URL, nil) 1850 if err != nil { 1851 t.Errorf("#%d: NewRequest: %v", i, err) 1852 continue 1853 } 1854 1855 c.CheckRedirect = func(req *Request, via []*Request) error { 1856 if got, want := req.Method, tt.wantMethod; got != want { 1857 return fmt.Errorf("#%d: got next method %q; want %q", i, got, want) 1858 } 1859 handlerc <- func(rw ResponseWriter, req *Request) { 1860 // TODO: Check that the body is valid when we do 307 and 308 support 1861 } 1862 return nil 1863 } 1864 1865 res, err := c.Do(req) 1866 if err != nil { 1867 t.Errorf("#%d: Response: %v", i, err) 1868 continue 1869 } 1870 1871 _ = res.Body.Close() 1872 } 1873 } 1874 1875 // issue18239Body is an io.ReadCloser for TestTransportBodyReadError. 1876 // Its Read returns readErr and increments *readCalls atomically. 1877 // Its Close returns nil and increments *closeCalls atomically. 1878 type issue18239Body struct { 1879 readCalls *int32 1880 closeCalls *int32 1881 readErr error 1882 } 1883 1884 func (b issue18239Body) Read([]byte) (int, error) { 1885 atomic.AddInt32(b.readCalls, 1) 1886 return 0, b.readErr 1887 } 1888 1889 func (b issue18239Body) Close() error { 1890 atomic.AddInt32(b.closeCalls, 1) 1891 return nil 1892 } 1893 1894 // Issue 18239: make sure the Transport doesn't retry requests with bodies 1895 // if Request.GetBody is not defined. 1896 func TestTransportBodyReadError(t *testing.T) { 1897 setParallel(t) 1898 defer afterTest(t) 1899 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1900 if r.URL.Path == "/ping" { 1901 return 1902 } 1903 buf := make([]byte, 1) 1904 n, err := r.Body.Read(buf) 1905 w.Header().Set("X-Body-Read", fmt.Sprintf("%v, %v", n, err)) 1906 })) 1907 defer ts.Close() 1908 c := ts.Client() 1909 tr := c.Transport.(*Transport) 1910 1911 // Do one initial successful request to create an idle TCP connection 1912 // for the subsequent request to reuse. (The Transport only retries 1913 // requests on reused connections.) 1914 res, err := c.Get(ts.URL + "/ping") 1915 if err != nil { 1916 t.Fatal(err) 1917 } 1918 _ = res.Body.Close() 1919 1920 var readCallsAtomic int32 1921 var closeCallsAtomic int32 // atomic 1922 someErr := errors.New("some body read error") 1923 body := issue18239Body{&readCallsAtomic, &closeCallsAtomic, someErr} 1924 1925 req, err := NewRequest("POST", ts.URL, body) 1926 if err != nil { 1927 t.Fatal(err) 1928 } 1929 req = req.WithT(t) 1930 _, err = tr.RoundTrip(req) 1931 if err != someErr { 1932 t.Errorf("Got error: %v; want Request.Body read error: %v", err, someErr) 1933 } 1934 1935 // And verify that our Body wasn't used multiple times, which 1936 // would indicate retries. (as it buggily was during part of 1937 // Go 1.8's dev cycle) 1938 readCalls := atomic.LoadInt32(&readCallsAtomic) 1939 closeCalls := atomic.LoadInt32(&closeCallsAtomic) 1940 if readCalls != 1 { 1941 t.Errorf("read calls = %d; want 1", readCalls) 1942 } 1943 if closeCalls != 1 { 1944 t.Errorf("close calls = %d; want 1", closeCalls) 1945 } 1946 } 1947 1948 type roundTripperWithoutCloseIdle struct{} 1949 1950 func (roundTripperWithoutCloseIdle) RoundTrip(*Request) (*Response, error) { panic("unused") } 1951 1952 type roundTripperWithCloseIdle func() // underlying func is CloseIdleConnections func 1953 1954 func (roundTripperWithCloseIdle) RoundTrip(*Request) (*Response, error) { panic("unused") } 1955 func (f roundTripperWithCloseIdle) CloseIdleConnections() { f() } 1956 1957 func TestClientCloseIdleConnections(t *testing.T) { 1958 c := &Client{Transport: roundTripperWithoutCloseIdle{}} 1959 c.CloseIdleConnections() // verify we don't crash at least 1960 1961 closed := false 1962 var tr RoundTripper = roundTripperWithCloseIdle(func() { 1963 closed = true 1964 }) 1965 c = &Client{Transport: tr} 1966 c.CloseIdleConnections() 1967 if !closed { 1968 t.Error("not closed") 1969 } 1970 } 1971 1972 func TestClientPropagatesTimeoutToContext(t *testing.T) { 1973 errDial := errors.New("not actually dialing") 1974 c := &Client{ 1975 Timeout: 5 * time.Second, 1976 Transport: &Transport{ 1977 DialContext: func(ctx context.Context, netw, addr string) (net.Conn, error) { 1978 deadline, ok := ctx.Deadline() 1979 if !ok { 1980 t.Error("no deadline") 1981 } else { 1982 t.Logf("deadline in %v", deadline.Sub(time.Now()).Round(time.Second/10)) 1983 } 1984 return nil, errDial 1985 }, 1986 }, 1987 } 1988 _, _ = c.Get("https://example.tld/") 1989 } 1990 1991 func TestClientDoCanceledVsTimeout_h1(t *testing.T) { 1992 testClientDoCanceledVsTimeout(t, h1Mode) 1993 } 1994 1995 func TestClientDoCanceledVsTimeout_h2(t *testing.T) { 1996 testClientDoCanceledVsTimeout(t, h2Mode) 1997 } 1998 1999 // Issue 33545: lock-in the behavior promised by Client.Do's 2000 // docs about request cancellation vs timing out. 2001 func testClientDoCanceledVsTimeout(t *testing.T, h2 bool) { 2002 defer afterTest(t) 2003 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 2004 _, _ = w.Write([]byte("Hello, World!")) 2005 })) 2006 defer cst.close() 2007 2008 cases := []string{"timeout", "canceled"} 2009 2010 for _, name := range cases { 2011 t.Run(name, func(t *testing.T) { 2012 var ctx context.Context 2013 var cancel func() 2014 if name == "timeout" { 2015 ctx, cancel = context.WithTimeout(context.Background(), -time.Nanosecond) 2016 } else { 2017 ctx, cancel = context.WithCancel(context.Background()) 2018 cancel() 2019 } 2020 defer cancel() 2021 2022 req, _ := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil) 2023 _, err := cst.c.Do(req) 2024 if err == nil { 2025 t.Fatal("Unexpectedly got a nil error") 2026 } 2027 2028 ue := err.(*url.Error) 2029 2030 var wantIsTimeout bool 2031 var wantErr = context.Canceled 2032 if name == "timeout" { 2033 wantErr = context.DeadlineExceeded 2034 wantIsTimeout = true 2035 } 2036 if g, w := ue.Timeout(), wantIsTimeout; g != w { 2037 t.Fatalf("url.Timeout() = %t, want %t", g, w) 2038 } 2039 if g, w := ue.Err, wantErr; g != w { 2040 t.Errorf("url.Error.Err = %v; want %v", g, w) 2041 } 2042 }) 2043 } 2044 } 2045 2046 type nilBodyRoundTripper struct{} 2047 2048 func (nilBodyRoundTripper) RoundTrip(req *Request) (*Response, error) { 2049 return &Response{ 2050 StatusCode: StatusOK, 2051 Status: StatusText(StatusOK), 2052 Body: nil, 2053 Request: req, 2054 }, nil 2055 } 2056 2057 func TestClientPopulatesNilResponseBody(t *testing.T) { 2058 c := &Client{Transport: nilBodyRoundTripper{}} 2059 2060 resp, err := c.Get("http://localhost/anything") 2061 if err != nil { 2062 t.Fatalf("Client.Get rejected Response with nil Body: %v", err) 2063 } 2064 2065 if resp.Body == nil { 2066 t.Fatalf("Client failed to provide a non-nil Body as documented") 2067 } 2068 defer func() { 2069 if err := resp.Body.Close(); err != nil { 2070 t.Fatalf("error from Close on substitute Response.Body: %v", err) 2071 } 2072 }() 2073 2074 if b, err := io.ReadAll(resp.Body); err != nil { 2075 t.Errorf("read error from substitute Response.Body: %v", err) 2076 } else if len(b) != 0 { 2077 t.Errorf("substitute Response.Body was unexpectedly non-empty: %q", b) 2078 } 2079 } 2080 2081 // Issue 40382: Client calls Close multiple times on Request.Body. 2082 func TestClientCallsCloseOnlyOnce(t *testing.T) { 2083 setParallel(t) 2084 defer afterTest(t) 2085 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 2086 w.WriteHeader(StatusNoContent) 2087 })) 2088 defer cst.close() 2089 2090 // Issue occurred non-deterministically: needed to occur after a successful 2091 // write (into TCP buffer) but before end of body. 2092 for i := 0; i < 50 && !t.Failed(); i++ { 2093 body := &issue40382Body{t: t, n: 300000} 2094 req, err := NewRequest(MethodPost, cst.ts.URL, body) 2095 if err != nil { 2096 t.Fatal(err) 2097 } 2098 resp, err := cst.tr.RoundTrip(req) 2099 if err != nil { 2100 t.Fatal(err) 2101 } 2102 _ = resp.Body.Close() 2103 } 2104 } 2105 2106 // issue40382Body is an io.ReadCloser for TestClientCallsCloseOnlyOnce. 2107 // Its Read reads n bytes before returning io.EOF. 2108 // Its Close returns nil but fails the test if called more than once. 2109 type issue40382Body struct { 2110 t *testing.T 2111 n int 2112 closeCallsAtomic int32 2113 } 2114 2115 func (b *issue40382Body) Read(p []byte) (int, error) { 2116 switch { 2117 case b.n == 0: 2118 return 0, io.EOF 2119 case b.n < len(p): 2120 p = p[:b.n] 2121 fallthrough 2122 default: 2123 for i := range p { 2124 p[i] = 'x' 2125 } 2126 b.n -= len(p) 2127 return len(p), nil 2128 } 2129 } 2130 2131 func (b *issue40382Body) Close() error { 2132 if atomic.AddInt32(&b.closeCallsAtomic, 1) == 2 { 2133 b.t.Error("Body closed more than once") 2134 } 2135 return nil 2136 }