gitee.com/ks-custle/core-gm@v0.0.0-20230922171213-b83bdd97b62c/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/ks-custle/core-gm/gmhttp" 28 "gitee.com/ks-custle/core-gm/gmhttp/cookiejar" 29 "gitee.com/ks-custle/core-gm/gmhttp/httptest" 30 tls "gitee.com/ks-custle/core-gm/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 // 1298 //goland:noinspection GoSnakeCaseUsage 1299 func testClientTimeout_Headers(t *testing.T, h2 bool) { 1300 setParallel(t) 1301 defer afterTest(t) 1302 donec := make(chan bool, 1) 1303 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1304 <-donec 1305 }), optQuietLog) 1306 defer cst.close() 1307 // Note that we use a channel send here and not a close. 1308 // The race detector doesn't know that we're waiting for a timeout 1309 // and thinks that the waitgroup inside httptest.Server is added to concurrently 1310 // with us closing it. If we timed out immediately, we could close the testserver 1311 // before we entered the handler. We're not timing out immediately and there's 1312 // no way we would be done before we entered the handler, but the race detector 1313 // doesn't know this, so synchronize explicitly. 1314 defer func() { donec <- true }() 1315 1316 cst.c.Timeout = 5 * time.Millisecond 1317 res, err := cst.c.Get(cst.ts.URL) 1318 if err == nil { 1319 _ = res.Body.Close() 1320 t.Fatal("got response from Get; expected error") 1321 } 1322 if _, ok := err.(*url.Error); !ok { 1323 t.Fatalf("Got error of type %T; want *url.Error", err) 1324 } 1325 ne, ok := err.(net.Error) 1326 if !ok { 1327 t.Fatalf("Got error of type %T; want some net.Error", err) 1328 } 1329 if !ne.Timeout() { 1330 t.Error("net.Error.Timeout = false; want true") 1331 } 1332 if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") { 1333 t.Errorf("error string = %q; missing timeout substring", got) 1334 } 1335 } 1336 1337 // Issue 16094: if Client.Timeout is set but not hit, a Timeout error shouldn't be 1338 // returned. 1339 func TestClientTimeoutCancel(t *testing.T) { 1340 setParallel(t) 1341 defer afterTest(t) 1342 1343 testDone := make(chan struct{}) 1344 ctx, cancel := context.WithCancel(context.Background()) 1345 1346 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 1347 w.(Flusher).Flush() 1348 <-testDone 1349 })) 1350 defer cst.close() 1351 defer close(testDone) 1352 1353 cst.c.Timeout = 1 * time.Hour 1354 req, _ := NewRequest("GET", cst.ts.URL, nil) 1355 req.Cancel = ctx.Done() 1356 res, err := cst.c.Do(req) 1357 if err != nil { 1358 t.Fatal(err) 1359 } 1360 cancel() 1361 _, err = io.Copy(io.Discard, res.Body) 1362 if err != ExportErrRequestCanceled { 1363 t.Fatalf("error = %v; want errRequestCanceled", err) 1364 } 1365 } 1366 1367 func TestClientTimeoutDoesNotExpire_h1(t *testing.T) { testClientTimeoutDoesNotExpire(t, h1Mode) } 1368 func TestClientTimeoutDoesNotExpire_h2(t *testing.T) { testClientTimeoutDoesNotExpire(t, h2Mode) } 1369 1370 // Issue 49366: if Client.Timeout is set but not hit, no error should be returned. 1371 func testClientTimeoutDoesNotExpire(t *testing.T, h2 bool) { 1372 setParallel(t) 1373 defer afterTest(t) 1374 1375 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1376 _, _ = w.Write([]byte("body")) 1377 })) 1378 defer cst.close() 1379 1380 cst.c.Timeout = 1 * time.Hour 1381 req, _ := NewRequest("GET", cst.ts.URL, nil) 1382 res, err := cst.c.Do(req) 1383 if err != nil { 1384 t.Fatal(err) 1385 } 1386 if _, err = io.Copy(io.Discard, res.Body); err != nil { 1387 t.Fatalf("io.Copy(io.Discard, res.Body) = %v, want nil", err) 1388 } 1389 if err = res.Body.Close(); err != nil { 1390 t.Fatalf("res.Body.Close() = %v, want nil", err) 1391 } 1392 } 1393 1394 func TestClientRedirectEatsBody_h1(t *testing.T) { testClientRedirectEatsBody(t, h1Mode) } 1395 func TestClientRedirectEatsBody_h2(t *testing.T) { testClientRedirectEatsBody(t, h2Mode) } 1396 func testClientRedirectEatsBody(t *testing.T, h2 bool) { 1397 setParallel(t) 1398 defer afterTest(t) 1399 saw := make(chan string, 2) 1400 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 1401 saw <- r.RemoteAddr 1402 if r.URL.Path == "/" { 1403 Redirect(w, r, "/foo", StatusFound) // which includes a body 1404 } 1405 })) 1406 defer cst.close() 1407 1408 res, err := cst.c.Get(cst.ts.URL) 1409 if err != nil { 1410 t.Fatal(err) 1411 } 1412 _, err = io.ReadAll(res.Body) 1413 _ = res.Body.Close() 1414 if err != nil { 1415 t.Fatal(err) 1416 } 1417 1418 var first string 1419 select { 1420 case first = <-saw: 1421 default: 1422 t.Fatal("server didn't see a request") 1423 } 1424 1425 var second string 1426 select { 1427 case second = <-saw: 1428 default: 1429 t.Fatal("server didn't see a second request") 1430 } 1431 1432 if first != second { 1433 t.Fatal("server saw different client ports before & after the redirect") 1434 } 1435 } 1436 1437 // eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF. 1438 type eofReaderFunc func() 1439 1440 //goland:noinspection GoUnusedParameter 1441 func (f eofReaderFunc) Read(p []byte) (n int, err error) { 1442 f() 1443 return 0, io.EOF 1444 } 1445 1446 func TestReferer(t *testing.T) { 1447 //goland:noinspection HttpUrlsUsage 1448 tests := []struct { 1449 lastReq, newReq string // from -> to URLs 1450 want string 1451 }{ 1452 // don't send user: 1453 {"http://gopher@test.com", "http://link.com", "http://test.com"}, 1454 {"https://gopher@test.com", "https://link.com", "https://test.com"}, 1455 1456 // don't send a user and password: 1457 {"http://gopher:go@test.com", "http://link.com", "http://test.com"}, 1458 {"https://gopher:go@test.com", "https://link.com", "https://test.com"}, 1459 1460 // nothing to do: 1461 {"http://test.com", "http://link.com", "http://test.com"}, 1462 {"https://test.com", "https://link.com", "https://test.com"}, 1463 1464 // https to http doesn't send a referer: 1465 {"https://test.com", "http://link.com", ""}, 1466 {"https://gopher:go@test.com", "http://link.com", ""}, 1467 } 1468 for _, tt := range tests { 1469 l, err := url.Parse(tt.lastReq) 1470 if err != nil { 1471 t.Fatal(err) 1472 } 1473 n, err := url.Parse(tt.newReq) 1474 if err != nil { 1475 t.Fatal(err) 1476 } 1477 r := ExportRefererForURL(l, n) 1478 if r != tt.want { 1479 t.Errorf("refererForURL(%q, %q) = %q; want %q", tt.lastReq, tt.newReq, r, tt.want) 1480 } 1481 } 1482 } 1483 1484 // issue15577Tripper returns a Response with a redirect response 1485 // header and doesn't populate its Response.Request field. 1486 type issue15577Tripper struct{} 1487 1488 func (issue15577Tripper) RoundTrip(*Request) (*Response, error) { 1489 //goland:noinspection HttpUrlsUsage 1490 resp := &Response{ 1491 StatusCode: 303, 1492 Header: map[string][]string{"Location": {"http://www.example.com/"}}, 1493 Body: io.NopCloser(strings.NewReader("")), 1494 } 1495 return resp, nil 1496 } 1497 1498 // Issue 15577: don't assume the roundtripper's response populates its Request field. 1499 func TestClientRedirectResponseWithoutRequest(t *testing.T) { 1500 c := &Client{ 1501 CheckRedirect: func(*Request, []*Request) error { 1502 //goland:noinspection GoErrorStringFormat 1503 return fmt.Errorf("no redirects!") 1504 }, 1505 Transport: issue15577Tripper{}, 1506 } 1507 // Check that this doesn't crash: 1508 _, _ = c.Get("http://dummy.tld") 1509 } 1510 1511 // Issue 4800: copy (some) headers when Client follows a redirect. 1512 func TestClientCopyHeadersOnRedirect(t *testing.T) { 1513 const ( 1514 ua = "some-agent/1.2" 1515 xfoo = "foo-val" 1516 ) 1517 var ts2URL string 1518 ts1 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1519 want := Header{ 1520 "User-Agent": []string{ua}, 1521 "X-Foo": []string{xfoo}, 1522 "Referer": []string{ts2URL}, 1523 "Accept-Encoding": []string{"gzip"}, 1524 } 1525 if !reflect.DeepEqual(r.Header, want) { 1526 t.Errorf("Request.Header = %#v; want %#v", r.Header, want) 1527 } 1528 if t.Failed() { 1529 w.Header().Set("Result", "got errors") 1530 } else { 1531 w.Header().Set("Result", "ok") 1532 } 1533 })) 1534 defer ts1.Close() 1535 ts2 := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1536 Redirect(w, r, ts1.URL, StatusFound) 1537 })) 1538 defer ts2.Close() 1539 ts2URL = ts2.URL 1540 1541 c := ts1.Client() 1542 c.CheckRedirect = func(r *Request, via []*Request) error { 1543 want := Header{ 1544 "User-Agent": []string{ua}, 1545 "X-Foo": []string{xfoo}, 1546 "Referer": []string{ts2URL}, 1547 } 1548 if !reflect.DeepEqual(r.Header, want) { 1549 t.Errorf("CheckRedirect Request.Header = %#v; want %#v", r.Header, want) 1550 } 1551 return nil 1552 } 1553 1554 req, _ := NewRequest("GET", ts2.URL, nil) 1555 req.Header.Add("User-Agent", ua) 1556 req.Header.Add("X-Foo", xfoo) 1557 req.Header.Add("Cookie", "foo=bar") 1558 req.Header.Add("Authorization", "secretpassword") 1559 res, err := c.Do(req) 1560 if err != nil { 1561 t.Fatal(err) 1562 } 1563 defer func(Body io.ReadCloser) { 1564 _ = Body.Close() 1565 }(res.Body) 1566 if res.StatusCode != 200 { 1567 t.Fatal(res.Status) 1568 } 1569 if got := res.Header.Get("Result"); got != "ok" { 1570 t.Errorf("result = %q; want ok", got) 1571 } 1572 } 1573 1574 // Issue 22233: copy host when Client follows a relative redirect. 1575 func TestClientCopyHostOnRedirect(t *testing.T) { 1576 // Virtual hostname: should not receive any request. 1577 virtual := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1578 t.Errorf("Virtual host received request %v", r.URL) 1579 w.WriteHeader(403) 1580 _, _ = io.WriteString(w, "should not see this response") 1581 })) 1582 defer virtual.Close() 1583 //goland:noinspection HttpUrlsUsage 1584 virtualHost := strings.TrimPrefix(virtual.URL, "http://") 1585 t.Logf("Virtual host is %v", virtualHost) 1586 1587 // Actual hostname: should not receive any request. 1588 const wantBody = "response body" 1589 var tsURL string 1590 var tsHost string 1591 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1592 switch r.URL.Path { 1593 case "/": 1594 // Relative redirect. 1595 if r.Host != virtualHost { 1596 t.Errorf("Serving /: Request.Host = %#v; want %#v", r.Host, virtualHost) 1597 w.WriteHeader(404) 1598 return 1599 } 1600 w.Header().Set("Location", "/hop") 1601 w.WriteHeader(302) 1602 case "/hop": 1603 // Absolute redirect. 1604 if r.Host != virtualHost { 1605 t.Errorf("Serving /hop: Request.Host = %#v; want %#v", r.Host, virtualHost) 1606 w.WriteHeader(404) 1607 return 1608 } 1609 w.Header().Set("Location", tsURL+"/final") 1610 w.WriteHeader(302) 1611 case "/final": 1612 if r.Host != tsHost { 1613 t.Errorf("Serving /final: Request.Host = %#v; want %#v", r.Host, tsHost) 1614 w.WriteHeader(404) 1615 return 1616 } 1617 w.WriteHeader(200) 1618 _, _ = io.WriteString(w, wantBody) 1619 default: 1620 t.Errorf("Serving unexpected path %q", r.URL.Path) 1621 w.WriteHeader(404) 1622 } 1623 })) 1624 defer ts.Close() 1625 tsURL = ts.URL 1626 //goland:noinspection HttpUrlsUsage 1627 tsHost = strings.TrimPrefix(ts.URL, "http://") 1628 t.Logf("Server host is %v", tsHost) 1629 1630 c := ts.Client() 1631 req, _ := NewRequest("GET", ts.URL, nil) 1632 req.Host = virtualHost 1633 resp, err := c.Do(req) 1634 if err != nil { 1635 t.Fatal(err) 1636 } 1637 defer func(Body io.ReadCloser) { 1638 _ = Body.Close() 1639 }(resp.Body) 1640 if resp.StatusCode != 200 { 1641 t.Fatal(resp.Status) 1642 } 1643 if got, err := io.ReadAll(resp.Body); err != nil || string(got) != wantBody { 1644 t.Errorf("body = %q; want %q", got, wantBody) 1645 } 1646 } 1647 1648 // Issue 17494: cookies should be altered when Client follows redirects. 1649 func TestClientAltersCookiesOnRedirect(t *testing.T) { 1650 cookieMap := func(cs []*Cookie) map[string][]string { 1651 m := make(map[string][]string) 1652 for _, c := range cs { 1653 m[c.Name] = append(m[c.Name], c.Value) 1654 } 1655 return m 1656 } 1657 1658 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1659 var want map[string][]string 1660 got := cookieMap(r.Cookies()) 1661 1662 c, _ := r.Cookie("Cycle") 1663 switch c.Value { 1664 case "0": 1665 want = map[string][]string{ 1666 "Cookie1": {"OldValue1a", "OldValue1b"}, 1667 "Cookie2": {"OldValue2"}, 1668 "Cookie3": {"OldValue3a", "OldValue3b"}, 1669 "Cookie4": {"OldValue4"}, 1670 "Cycle": {"0"}, 1671 } 1672 SetCookie(w, &Cookie{Name: "Cycle", Value: "1", Path: "/"}) 1673 SetCookie(w, &Cookie{Name: "Cookie2", Path: "/", MaxAge: -1}) // Delete cookie from Header 1674 Redirect(w, r, "/", StatusFound) 1675 case "1": 1676 want = map[string][]string{ 1677 "Cookie1": {"OldValue1a", "OldValue1b"}, 1678 "Cookie3": {"OldValue3a", "OldValue3b"}, 1679 "Cookie4": {"OldValue4"}, 1680 "Cycle": {"1"}, 1681 } 1682 SetCookie(w, &Cookie{Name: "Cycle", Value: "2", Path: "/"}) 1683 SetCookie(w, &Cookie{Name: "Cookie3", Value: "NewValue3", Path: "/"}) // Modify cookie in Header 1684 SetCookie(w, &Cookie{Name: "Cookie4", Value: "NewValue4", Path: "/"}) // Modify cookie in Jar 1685 Redirect(w, r, "/", StatusFound) 1686 case "2": 1687 want = map[string][]string{ 1688 "Cookie1": {"OldValue1a", "OldValue1b"}, 1689 "Cookie3": {"NewValue3"}, 1690 "Cookie4": {"NewValue4"}, 1691 "Cycle": {"2"}, 1692 } 1693 SetCookie(w, &Cookie{Name: "Cycle", Value: "3", Path: "/"}) 1694 SetCookie(w, &Cookie{Name: "Cookie5", Value: "NewValue5", Path: "/"}) // Insert cookie into Jar 1695 Redirect(w, r, "/", StatusFound) 1696 case "3": 1697 want = map[string][]string{ 1698 "Cookie1": {"OldValue1a", "OldValue1b"}, 1699 "Cookie3": {"NewValue3"}, 1700 "Cookie4": {"NewValue4"}, 1701 "Cookie5": {"NewValue5"}, 1702 "Cycle": {"3"}, 1703 } 1704 // Don't redirect to ensure the loop ends. 1705 default: 1706 t.Errorf("unexpected redirect cycle") 1707 return 1708 } 1709 1710 if !reflect.DeepEqual(got, want) { 1711 t.Errorf("redirect %s, Cookie = %v, want %v", c.Value, got, want) 1712 } 1713 })) 1714 defer ts.Close() 1715 1716 jar, _ := cookiejar.New(nil) 1717 c := ts.Client() 1718 c.Jar = jar 1719 1720 u, _ := url.Parse(ts.URL) 1721 req, _ := NewRequest("GET", ts.URL, nil) 1722 req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1a"}) 1723 req.AddCookie(&Cookie{Name: "Cookie1", Value: "OldValue1b"}) 1724 req.AddCookie(&Cookie{Name: "Cookie2", Value: "OldValue2"}) 1725 req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3a"}) 1726 req.AddCookie(&Cookie{Name: "Cookie3", Value: "OldValue3b"}) 1727 jar.SetCookies(u, []*Cookie{{Name: "Cookie4", Value: "OldValue4", Path: "/"}}) 1728 jar.SetCookies(u, []*Cookie{{Name: "Cycle", Value: "0", Path: "/"}}) 1729 res, err := c.Do(req) 1730 if err != nil { 1731 t.Fatal(err) 1732 } 1733 defer func(Body io.ReadCloser) { 1734 _ = Body.Close() 1735 }(res.Body) 1736 if res.StatusCode != 200 { 1737 t.Fatal(res.Status) 1738 } 1739 } 1740 1741 // Part of Issue 4800 1742 func TestShouldCopyHeaderOnRedirect(t *testing.T) { 1743 //goland:noinspection HttpUrlsUsage 1744 tests := []struct { 1745 header string 1746 initialURL string 1747 destURL string 1748 want bool 1749 }{ 1750 {"User-Agent", "http://foo.com/", "http://bar.com/", true}, 1751 {"X-Foo", "http://foo.com/", "http://bar.com/", true}, 1752 1753 // Sensitive headers: 1754 {"cookie", "http://foo.com/", "http://bar.com/", false}, 1755 {"cookie2", "http://foo.com/", "http://bar.com/", false}, 1756 {"authorization", "http://foo.com/", "http://bar.com/", false}, 1757 {"www-authenticate", "http://foo.com/", "http://bar.com/", false}, 1758 1759 // But subdomains should work: 1760 {"www-authenticate", "http://foo.com/", "http://foo.com/", true}, 1761 {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true}, 1762 {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false}, 1763 {"www-authenticate", "http://foo.com/", "https://foo.com/", false}, 1764 {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true}, 1765 {"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true}, 1766 {"www-authenticate", "http://foo.com:443/", "https://foo.com/", true}, 1767 {"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true}, 1768 {"www-authenticate", "http://foo.com:1234/", "http://foo.com/", false}, 1769 } 1770 for i, tt := range tests { 1771 u0, err := url.Parse(tt.initialURL) 1772 if err != nil { 1773 t.Errorf("%d. initial URL %q parse error: %v", i, tt.initialURL, err) 1774 continue 1775 } 1776 u1, err := url.Parse(tt.destURL) 1777 if err != nil { 1778 t.Errorf("%d. dest URL %q parse error: %v", i, tt.destURL, err) 1779 continue 1780 } 1781 got := Export_shouldCopyHeaderOnRedirect(tt.header, u0, u1) 1782 if got != tt.want { 1783 t.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v", 1784 i, tt.header, tt.initialURL, tt.destURL, got, tt.want) 1785 } 1786 } 1787 } 1788 1789 func TestClientRedirectTypes(t *testing.T) { 1790 setParallel(t) 1791 defer afterTest(t) 1792 1793 tests := [...]struct { 1794 method string 1795 serverStatus int 1796 wantMethod string // desired subsequent client method 1797 }{ 1798 0: {method: "POST", serverStatus: 301, wantMethod: "GET"}, 1799 1: {method: "POST", serverStatus: 302, wantMethod: "GET"}, 1800 2: {method: "POST", serverStatus: 303, wantMethod: "GET"}, 1801 3: {method: "POST", serverStatus: 307, wantMethod: "POST"}, 1802 4: {method: "POST", serverStatus: 308, wantMethod: "POST"}, 1803 1804 5: {method: "HEAD", serverStatus: 301, wantMethod: "HEAD"}, 1805 6: {method: "HEAD", serverStatus: 302, wantMethod: "HEAD"}, 1806 7: {method: "HEAD", serverStatus: 303, wantMethod: "HEAD"}, 1807 8: {method: "HEAD", serverStatus: 307, wantMethod: "HEAD"}, 1808 9: {method: "HEAD", serverStatus: 308, wantMethod: "HEAD"}, 1809 1810 10: {method: "GET", serverStatus: 301, wantMethod: "GET"}, 1811 11: {method: "GET", serverStatus: 302, wantMethod: "GET"}, 1812 12: {method: "GET", serverStatus: 303, wantMethod: "GET"}, 1813 13: {method: "GET", serverStatus: 307, wantMethod: "GET"}, 1814 14: {method: "GET", serverStatus: 308, wantMethod: "GET"}, 1815 1816 15: {method: "DELETE", serverStatus: 301, wantMethod: "GET"}, 1817 16: {method: "DELETE", serverStatus: 302, wantMethod: "GET"}, 1818 17: {method: "DELETE", serverStatus: 303, wantMethod: "GET"}, 1819 18: {method: "DELETE", serverStatus: 307, wantMethod: "DELETE"}, 1820 19: {method: "DELETE", serverStatus: 308, wantMethod: "DELETE"}, 1821 1822 20: {method: "PUT", serverStatus: 301, wantMethod: "GET"}, 1823 21: {method: "PUT", serverStatus: 302, wantMethod: "GET"}, 1824 22: {method: "PUT", serverStatus: 303, wantMethod: "GET"}, 1825 23: {method: "PUT", serverStatus: 307, wantMethod: "PUT"}, 1826 24: {method: "PUT", serverStatus: 308, wantMethod: "PUT"}, 1827 1828 25: {method: "MADEUPMETHOD", serverStatus: 301, wantMethod: "GET"}, 1829 26: {method: "MADEUPMETHOD", serverStatus: 302, wantMethod: "GET"}, 1830 27: {method: "MADEUPMETHOD", serverStatus: 303, wantMethod: "GET"}, 1831 28: {method: "MADEUPMETHOD", serverStatus: 307, wantMethod: "MADEUPMETHOD"}, 1832 29: {method: "MADEUPMETHOD", serverStatus: 308, wantMethod: "MADEUPMETHOD"}, 1833 } 1834 1835 handlerc := make(chan HandlerFunc, 1) 1836 1837 ts := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) { 1838 h := <-handlerc 1839 h(rw, req) 1840 })) 1841 defer ts.Close() 1842 1843 c := ts.Client() 1844 for i, tt := range tests { 1845 handlerc <- func(w ResponseWriter, r *Request) { 1846 w.Header().Set("Location", ts.URL) 1847 w.WriteHeader(tt.serverStatus) 1848 } 1849 1850 req, err := NewRequest(tt.method, ts.URL, nil) 1851 if err != nil { 1852 t.Errorf("#%d: NewRequest: %v", i, err) 1853 continue 1854 } 1855 1856 c.CheckRedirect = func(req *Request, via []*Request) error { 1857 if got, want := req.Method, tt.wantMethod; got != want { 1858 return fmt.Errorf("#%d: got next method %q; want %q", i, got, want) 1859 } 1860 handlerc <- func(rw ResponseWriter, req *Request) { 1861 // TODO: Check that the body is valid when we do 307 and 308 support 1862 } 1863 return nil 1864 } 1865 1866 res, err := c.Do(req) 1867 if err != nil { 1868 t.Errorf("#%d: Response: %v", i, err) 1869 continue 1870 } 1871 1872 _ = res.Body.Close() 1873 } 1874 } 1875 1876 // issue18239Body is an io.ReadCloser for TestTransportBodyReadError. 1877 // Its Read returns readErr and increments *readCalls atomically. 1878 // Its Close returns nil and increments *closeCalls atomically. 1879 type issue18239Body struct { 1880 readCalls *int32 1881 closeCalls *int32 1882 readErr error 1883 } 1884 1885 func (b issue18239Body) Read([]byte) (int, error) { 1886 atomic.AddInt32(b.readCalls, 1) 1887 return 0, b.readErr 1888 } 1889 1890 func (b issue18239Body) Close() error { 1891 atomic.AddInt32(b.closeCalls, 1) 1892 return nil 1893 } 1894 1895 // Issue 18239: make sure the Transport doesn't retry requests with bodies 1896 // if Request.GetBody is not defined. 1897 func TestTransportBodyReadError(t *testing.T) { 1898 setParallel(t) 1899 defer afterTest(t) 1900 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) { 1901 if r.URL.Path == "/ping" { 1902 return 1903 } 1904 buf := make([]byte, 1) 1905 n, err := r.Body.Read(buf) 1906 w.Header().Set("X-Body-Read", fmt.Sprintf("%v, %v", n, err)) 1907 })) 1908 defer ts.Close() 1909 c := ts.Client() 1910 tr := c.Transport.(*Transport) 1911 1912 // Do one initial successful request to create an idle TCP connection 1913 // for the subsequent request to reuse. (The Transport only retries 1914 // requests on reused connections.) 1915 res, err := c.Get(ts.URL + "/ping") 1916 if err != nil { 1917 t.Fatal(err) 1918 } 1919 _ = res.Body.Close() 1920 1921 var readCallsAtomic int32 1922 var closeCallsAtomic int32 // atomic 1923 someErr := errors.New("some body read error") 1924 body := issue18239Body{&readCallsAtomic, &closeCallsAtomic, someErr} 1925 1926 req, err := NewRequest("POST", ts.URL, body) 1927 if err != nil { 1928 t.Fatal(err) 1929 } 1930 req = req.WithT(t) 1931 _, err = tr.RoundTrip(req) 1932 if err != someErr { 1933 t.Errorf("Got error: %v; want Request.Body read error: %v", err, someErr) 1934 } 1935 1936 // And verify that our Body wasn't used multiple times, which 1937 // would indicate retries. (as it buggily was during part of 1938 // Go 1.8's dev cycle) 1939 readCalls := atomic.LoadInt32(&readCallsAtomic) 1940 closeCalls := atomic.LoadInt32(&closeCallsAtomic) 1941 if readCalls != 1 { 1942 t.Errorf("read calls = %d; want 1", readCalls) 1943 } 1944 if closeCalls != 1 { 1945 t.Errorf("close calls = %d; want 1", closeCalls) 1946 } 1947 } 1948 1949 type roundTripperWithoutCloseIdle struct{} 1950 1951 func (roundTripperWithoutCloseIdle) RoundTrip(*Request) (*Response, error) { panic("unused") } 1952 1953 type roundTripperWithCloseIdle func() // underlying func is CloseIdleConnections func 1954 1955 func (roundTripperWithCloseIdle) RoundTrip(*Request) (*Response, error) { panic("unused") } 1956 func (f roundTripperWithCloseIdle) CloseIdleConnections() { f() } 1957 1958 func TestClientCloseIdleConnections(t *testing.T) { 1959 c := &Client{Transport: roundTripperWithoutCloseIdle{}} 1960 c.CloseIdleConnections() // verify we don't crash at least 1961 1962 closed := false 1963 var tr RoundTripper = roundTripperWithCloseIdle(func() { 1964 closed = true 1965 }) 1966 c = &Client{Transport: tr} 1967 c.CloseIdleConnections() 1968 if !closed { 1969 t.Error("not closed") 1970 } 1971 } 1972 1973 func TestClientPropagatesTimeoutToContext(t *testing.T) { 1974 errDial := errors.New("not actually dialing") 1975 c := &Client{ 1976 Timeout: 5 * time.Second, 1977 Transport: &Transport{ 1978 DialContext: func(ctx context.Context, netw, addr string) (net.Conn, error) { 1979 deadline, ok := ctx.Deadline() 1980 if !ok { 1981 t.Error("no deadline") 1982 } else { 1983 t.Logf("deadline in %v", deadline.Sub(time.Now()).Round(time.Second/10)) 1984 } 1985 return nil, errDial 1986 }, 1987 }, 1988 } 1989 _, _ = c.Get("https://example.tld/") 1990 } 1991 1992 func TestClientDoCanceledVsTimeout_h1(t *testing.T) { 1993 testClientDoCanceledVsTimeout(t, h1Mode) 1994 } 1995 1996 func TestClientDoCanceledVsTimeout_h2(t *testing.T) { 1997 testClientDoCanceledVsTimeout(t, h2Mode) 1998 } 1999 2000 // Issue 33545: lock-in the behavior promised by Client.Do's 2001 // docs about request cancellation vs timing out. 2002 func testClientDoCanceledVsTimeout(t *testing.T, h2 bool) { 2003 defer afterTest(t) 2004 cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) { 2005 _, _ = w.Write([]byte("Hello, World!")) 2006 })) 2007 defer cst.close() 2008 2009 cases := []string{"timeout", "canceled"} 2010 2011 for _, name := range cases { 2012 t.Run(name, func(t *testing.T) { 2013 var ctx context.Context 2014 var cancel func() 2015 if name == "timeout" { 2016 ctx, cancel = context.WithTimeout(context.Background(), -time.Nanosecond) 2017 } else { 2018 ctx, cancel = context.WithCancel(context.Background()) 2019 cancel() 2020 } 2021 defer cancel() 2022 2023 req, _ := NewRequestWithContext(ctx, "GET", cst.ts.URL, nil) 2024 _, err := cst.c.Do(req) 2025 if err == nil { 2026 t.Fatal("Unexpectedly got a nil error") 2027 } 2028 2029 ue := err.(*url.Error) 2030 2031 var wantIsTimeout bool 2032 var wantErr = context.Canceled 2033 if name == "timeout" { 2034 wantErr = context.DeadlineExceeded 2035 wantIsTimeout = true 2036 } 2037 if g, w := ue.Timeout(), wantIsTimeout; g != w { 2038 t.Fatalf("url.Timeout() = %t, want %t", g, w) 2039 } 2040 if g, w := ue.Err, wantErr; g != w { 2041 t.Errorf("url.Error.Err = %v; want %v", g, w) 2042 } 2043 }) 2044 } 2045 } 2046 2047 type nilBodyRoundTripper struct{} 2048 2049 func (nilBodyRoundTripper) RoundTrip(req *Request) (*Response, error) { 2050 return &Response{ 2051 StatusCode: StatusOK, 2052 Status: StatusText(StatusOK), 2053 Body: nil, 2054 Request: req, 2055 }, nil 2056 } 2057 2058 func TestClientPopulatesNilResponseBody(t *testing.T) { 2059 c := &Client{Transport: nilBodyRoundTripper{}} 2060 2061 resp, err := c.Get("http://localhost/anything") 2062 if err != nil { 2063 t.Fatalf("Client.Get rejected Response with nil Body: %v", err) 2064 } 2065 2066 if resp.Body == nil { 2067 t.Fatalf("Client failed to provide a non-nil Body as documented") 2068 } 2069 defer func() { 2070 if err := resp.Body.Close(); err != nil { 2071 t.Fatalf("error from Close on substitute Response.Body: %v", err) 2072 } 2073 }() 2074 2075 if b, err := io.ReadAll(resp.Body); err != nil { 2076 t.Errorf("read error from substitute Response.Body: %v", err) 2077 } else if len(b) != 0 { 2078 t.Errorf("substitute Response.Body was unexpectedly non-empty: %q", b) 2079 } 2080 } 2081 2082 // Issue 40382: Client calls Close multiple times on Request.Body. 2083 func TestClientCallsCloseOnlyOnce(t *testing.T) { 2084 setParallel(t) 2085 defer afterTest(t) 2086 cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) { 2087 w.WriteHeader(StatusNoContent) 2088 })) 2089 defer cst.close() 2090 2091 // Issue occurred non-deterministically: needed to occur after a successful 2092 // write (into TCP buffer) but before end of body. 2093 for i := 0; i < 50 && !t.Failed(); i++ { 2094 body := &issue40382Body{t: t, n: 300000} 2095 req, err := NewRequest(MethodPost, cst.ts.URL, body) 2096 if err != nil { 2097 t.Fatal(err) 2098 } 2099 resp, err := cst.tr.RoundTrip(req) 2100 if err != nil { 2101 t.Fatal(err) 2102 } 2103 _ = resp.Body.Close() 2104 } 2105 } 2106 2107 // issue40382Body is an io.ReadCloser for TestClientCallsCloseOnlyOnce. 2108 // Its Read reads n bytes before returning io.EOF. 2109 // Its Close returns nil but fails the test if called more than once. 2110 type issue40382Body struct { 2111 t *testing.T 2112 n int 2113 closeCallsAtomic int32 2114 } 2115 2116 func (b *issue40382Body) Read(p []byte) (int, error) { 2117 switch { 2118 case b.n == 0: 2119 return 0, io.EOF 2120 case b.n < len(p): 2121 p = p[:b.n] 2122 fallthrough 2123 default: 2124 for i := range p { 2125 p[i] = 'x' 2126 } 2127 b.n -= len(p) 2128 return len(p), nil 2129 } 2130 } 2131 2132 func (b *issue40382Body) Close() error { 2133 if atomic.AddInt32(&b.closeCallsAtomic, 1) == 2 { 2134 b.t.Error("Body closed more than once") 2135 } 2136 return nil 2137 }