github.com/dannin/go@v0.0.0-20161031215817-d35dfd405eaa/src/net/http/client.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 // HTTP client. See RFC 2616. 6 // 7 // This is the high-level Client interface. 8 // The low-level implementation is in transport.go. 9 10 package http 11 12 import ( 13 "crypto/tls" 14 "encoding/base64" 15 "errors" 16 "fmt" 17 "io" 18 "io/ioutil" 19 "log" 20 "net/url" 21 "sort" 22 "strings" 23 "sync" 24 "time" 25 ) 26 27 // A Client is an HTTP client. Its zero value (DefaultClient) is a 28 // usable client that uses DefaultTransport. 29 // 30 // The Client's Transport typically has internal state (cached TCP 31 // connections), so Clients should be reused instead of created as 32 // needed. Clients are safe for concurrent use by multiple goroutines. 33 // 34 // A Client is higher-level than a RoundTripper (such as Transport) 35 // and additionally handles HTTP details such as cookies and 36 // redirects. 37 type Client struct { 38 // Transport specifies the mechanism by which individual 39 // HTTP requests are made. 40 // If nil, DefaultTransport is used. 41 Transport RoundTripper 42 43 // CheckRedirect specifies the policy for handling redirects. 44 // If CheckRedirect is not nil, the client calls it before 45 // following an HTTP redirect. The arguments req and via are 46 // the upcoming request and the requests made already, oldest 47 // first. If CheckRedirect returns an error, the Client's Get 48 // method returns both the previous Response (with its Body 49 // closed) and CheckRedirect's error (wrapped in a url.Error) 50 // instead of issuing the Request req. 51 // As a special case, if CheckRedirect returns ErrUseLastResponse, 52 // then the most recent response is returned with its body 53 // unclosed, along with a nil error. 54 // 55 // If CheckRedirect is nil, the Client uses its default policy, 56 // which is to stop after 10 consecutive requests. 57 CheckRedirect func(req *Request, via []*Request) error 58 59 // Jar specifies the cookie jar. 60 // If Jar is nil, cookies are not sent in requests and ignored 61 // in responses. 62 Jar CookieJar 63 64 // Timeout specifies a time limit for requests made by this 65 // Client. The timeout includes connection time, any 66 // redirects, and reading the response body. The timer remains 67 // running after Get, Head, Post, or Do return and will 68 // interrupt reading of the Response.Body. 69 // 70 // A Timeout of zero means no timeout. 71 // 72 // The Client cancels requests to the underlying Transport 73 // using the Request.Cancel mechanism. Requests passed 74 // to Client.Do may still set Request.Cancel; both will 75 // cancel the request. 76 // 77 // For compatibility, the Client will also use the deprecated 78 // CancelRequest method on Transport if found. New 79 // RoundTripper implementations should use Request.Cancel 80 // instead of implementing CancelRequest. 81 Timeout time.Duration 82 } 83 84 // DefaultClient is the default Client and is used by Get, Head, and Post. 85 var DefaultClient = &Client{} 86 87 // RoundTripper is an interface representing the ability to execute a 88 // single HTTP transaction, obtaining the Response for a given Request. 89 // 90 // A RoundTripper must be safe for concurrent use by multiple 91 // goroutines. 92 type RoundTripper interface { 93 // RoundTrip executes a single HTTP transaction, returning 94 // a Response for the provided Request. 95 // 96 // RoundTrip should not attempt to interpret the response. In 97 // particular, RoundTrip must return err == nil if it obtained 98 // a response, regardless of the response's HTTP status code. 99 // A non-nil err should be reserved for failure to obtain a 100 // response. Similarly, RoundTrip should not attempt to 101 // handle higher-level protocol details such as redirects, 102 // authentication, or cookies. 103 // 104 // RoundTrip should not modify the request, except for 105 // consuming and closing the Request's Body. 106 // 107 // RoundTrip must always close the body, including on errors, 108 // but depending on the implementation may do so in a separate 109 // goroutine even after RoundTrip returns. This means that 110 // callers wanting to reuse the body for subsequent requests 111 // must arrange to wait for the Close call before doing so. 112 // 113 // The Request's URL and Header fields must be initialized. 114 RoundTrip(*Request) (*Response, error) 115 } 116 117 // refererForURL returns a referer without any authentication info or 118 // an empty string if lastReq scheme is https and newReq scheme is http. 119 func refererForURL(lastReq, newReq *url.URL) string { 120 // https://tools.ietf.org/html/rfc7231#section-5.5.2 121 // "Clients SHOULD NOT include a Referer header field in a 122 // (non-secure) HTTP request if the referring page was 123 // transferred with a secure protocol." 124 if lastReq.Scheme == "https" && newReq.Scheme == "http" { 125 return "" 126 } 127 referer := lastReq.String() 128 if lastReq.User != nil { 129 // This is not very efficient, but is the best we can 130 // do without: 131 // - introducing a new method on URL 132 // - creating a race condition 133 // - copying the URL struct manually, which would cause 134 // maintenance problems down the line 135 auth := lastReq.User.String() + "@" 136 referer = strings.Replace(referer, auth, "", 1) 137 } 138 return referer 139 } 140 141 func (c *Client) send(req *Request, deadline time.Time) (*Response, error) { 142 if c.Jar != nil { 143 for _, cookie := range c.Jar.Cookies(req.URL) { 144 req.AddCookie(cookie) 145 } 146 } 147 resp, err := send(req, c.transport(), deadline) 148 if err != nil { 149 return nil, err 150 } 151 if c.Jar != nil { 152 if rc := resp.Cookies(); len(rc) > 0 { 153 c.Jar.SetCookies(req.URL, rc) 154 } 155 } 156 return resp, nil 157 } 158 159 func (c *Client) deadline() time.Time { 160 if c.Timeout > 0 { 161 return time.Now().Add(c.Timeout) 162 } 163 return time.Time{} 164 } 165 166 func (c *Client) transport() RoundTripper { 167 if c.Transport != nil { 168 return c.Transport 169 } 170 return DefaultTransport 171 } 172 173 // send issues an HTTP request. 174 // Caller should close resp.Body when done reading from it. 175 func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error) { 176 req := ireq // req is either the original request, or a modified fork 177 178 if rt == nil { 179 req.closeBody() 180 return nil, errors.New("http: no Client.Transport or DefaultTransport") 181 } 182 183 if req.URL == nil { 184 req.closeBody() 185 return nil, errors.New("http: nil Request.URL") 186 } 187 188 if req.RequestURI != "" { 189 req.closeBody() 190 return nil, errors.New("http: Request.RequestURI can't be set in client requests.") 191 } 192 193 // forkReq forks req into a shallow clone of ireq the first 194 // time it's called. 195 forkReq := func() { 196 if ireq == req { 197 req = new(Request) 198 *req = *ireq // shallow clone 199 } 200 } 201 202 // Most the callers of send (Get, Post, et al) don't need 203 // Headers, leaving it uninitialized. We guarantee to the 204 // Transport that this has been initialized, though. 205 if req.Header == nil { 206 forkReq() 207 req.Header = make(Header) 208 } 209 210 if u := req.URL.User; u != nil && req.Header.Get("Authorization") == "" { 211 username := u.Username() 212 password, _ := u.Password() 213 forkReq() 214 req.Header = cloneHeader(ireq.Header) 215 req.Header.Set("Authorization", "Basic "+basicAuth(username, password)) 216 } 217 218 if !deadline.IsZero() { 219 forkReq() 220 } 221 stopTimer, wasCanceled := setRequestCancel(req, rt, deadline) 222 223 resp, err := rt.RoundTrip(req) 224 if err != nil { 225 stopTimer() 226 if resp != nil { 227 log.Printf("RoundTripper returned a response & error; ignoring response") 228 } 229 if tlsErr, ok := err.(tls.RecordHeaderError); ok { 230 // If we get a bad TLS record header, check to see if the 231 // response looks like HTTP and give a more helpful error. 232 // See golang.org/issue/11111. 233 if string(tlsErr.RecordHeader[:]) == "HTTP/" { 234 err = errors.New("http: server gave HTTP response to HTTPS client") 235 } 236 } 237 return nil, err 238 } 239 if !deadline.IsZero() { 240 resp.Body = &cancelTimerBody{ 241 stop: stopTimer, 242 rc: resp.Body, 243 reqWasCanceled: wasCanceled, 244 } 245 } 246 return resp, nil 247 } 248 249 // setRequestCancel sets the Cancel field of req, if deadline is 250 // non-zero. The RoundTripper's type is used to determine whether the legacy 251 // CancelRequest behavior should be used. 252 func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), wasCanceled func() bool) { 253 if deadline.IsZero() { 254 return nop, alwaysFalse 255 } 256 257 initialReqCancel := req.Cancel // the user's original Request.Cancel, if any 258 259 cancel := make(chan struct{}) 260 req.Cancel = cancel 261 262 wasCanceled = func() bool { 263 select { 264 case <-cancel: 265 return true 266 default: 267 return false 268 } 269 } 270 271 doCancel := func() { 272 // The new way: 273 close(cancel) 274 275 // The legacy compatibility way, used only 276 // for RoundTripper implementations written 277 // before Go 1.5 or Go 1.6. 278 type canceler interface { 279 CancelRequest(*Request) 280 } 281 switch v := rt.(type) { 282 case *Transport, *http2Transport: 283 // Do nothing. The net/http package's transports 284 // support the new Request.Cancel channel 285 case canceler: 286 v.CancelRequest(req) 287 } 288 } 289 290 stopTimerCh := make(chan struct{}) 291 var once sync.Once 292 stopTimer = func() { once.Do(func() { close(stopTimerCh) }) } 293 294 timer := time.NewTimer(time.Until(deadline)) 295 go func() { 296 select { 297 case <-initialReqCancel: 298 doCancel() 299 timer.Stop() 300 case <-timer.C: 301 doCancel() 302 case <-stopTimerCh: 303 timer.Stop() 304 } 305 }() 306 307 return stopTimer, wasCanceled 308 } 309 310 // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt 311 // "To receive authorization, the client sends the userid and password, 312 // separated by a single colon (":") character, within a base64 313 // encoded string in the credentials." 314 // It is not meant to be urlencoded. 315 func basicAuth(username, password string) string { 316 auth := username + ":" + password 317 return base64.StdEncoding.EncodeToString([]byte(auth)) 318 } 319 320 // Get issues a GET to the specified URL. If the response is one of 321 // the following redirect codes, Get follows the redirect, up to a 322 // maximum of 10 redirects: 323 // 324 // 301 (Moved Permanently) 325 // 302 (Found) 326 // 303 (See Other) 327 // 307 (Temporary Redirect) 328 // 308 (Permanent Redirect) 329 // 330 // An error is returned if there were too many redirects or if there 331 // was an HTTP protocol error. A non-2xx response doesn't cause an 332 // error. 333 // 334 // When err is nil, resp always contains a non-nil resp.Body. 335 // Caller should close resp.Body when done reading from it. 336 // 337 // Get is a wrapper around DefaultClient.Get. 338 // 339 // To make a request with custom headers, use NewRequest and 340 // DefaultClient.Do. 341 func Get(url string) (resp *Response, err error) { 342 return DefaultClient.Get(url) 343 } 344 345 // Get issues a GET to the specified URL. If the response is one of the 346 // following redirect codes, Get follows the redirect after calling the 347 // Client's CheckRedirect function: 348 // 349 // 301 (Moved Permanently) 350 // 302 (Found) 351 // 303 (See Other) 352 // 307 (Temporary Redirect) 353 // 308 (Permanent Redirect) 354 // 355 // An error is returned if the Client's CheckRedirect function fails 356 // or if there was an HTTP protocol error. A non-2xx response doesn't 357 // cause an error. 358 // 359 // When err is nil, resp always contains a non-nil resp.Body. 360 // Caller should close resp.Body when done reading from it. 361 // 362 // To make a request with custom headers, use NewRequest and Client.Do. 363 func (c *Client) Get(url string) (resp *Response, err error) { 364 req, err := NewRequest("GET", url, nil) 365 if err != nil { 366 return nil, err 367 } 368 return c.Do(req) 369 } 370 371 func alwaysFalse() bool { return false } 372 373 // ErrUseLastResponse can be returned by Client.CheckRedirect hooks to 374 // control how redirects are processed. If returned, the next request 375 // is not sent and the most recent response is returned with its body 376 // unclosed. 377 var ErrUseLastResponse = errors.New("net/http: use last response") 378 379 // checkRedirect calls either the user's configured CheckRedirect 380 // function, or the default. 381 func (c *Client) checkRedirect(req *Request, via []*Request) error { 382 fn := c.CheckRedirect 383 if fn == nil { 384 fn = defaultCheckRedirect 385 } 386 return fn(req, via) 387 } 388 389 // redirectBehavior describes what should happen when the 390 // client encounters a 3xx status code from the server 391 func redirectBehavior(reqMethod string, serverStatus int) (redirectMethod string, canRedirect bool) { 392 switch serverStatus { 393 case 301, 302, 303: 394 redirectMethod = "GET" 395 canRedirect = true 396 case 307, 308: 397 redirectMethod = reqMethod 398 canRedirect = true 399 } 400 401 return redirectMethod, canRedirect 402 } 403 404 // Do sends an HTTP request and returns an HTTP response, following 405 // policy (such as redirects, cookies, auth) as configured on the 406 // client. 407 // 408 // An error is returned if caused by client policy (such as 409 // CheckRedirect), or failure to speak HTTP (such as a network 410 // connectivity problem). A non-2xx status code doesn't cause an 411 // error. 412 // 413 // If the returned error is nil, the Response will contain a non-nil 414 // Body which the user is expected to close. If the Body is not 415 // closed, the Client's underlying RoundTripper (typically Transport) 416 // may not be able to re-use a persistent TCP connection to the server 417 // for a subsequent "keep-alive" request. 418 // 419 // The request Body, if non-nil, will be closed by the underlying 420 // Transport, even on errors. 421 // 422 // On error, any Response can be ignored. A non-nil Response with a 423 // non-nil error only occurs when CheckRedirect fails, and even then 424 // the returned Response.Body is already closed. 425 // 426 // Generally Get, Post, or PostForm will be used instead of Do. 427 func (c *Client) Do(req *Request) (*Response, error) { 428 if req.URL == nil { 429 req.closeBody() 430 return nil, errors.New("http: nil Request.URL") 431 } 432 433 var ( 434 deadline = c.deadline() 435 reqs []*Request 436 resp *Response 437 copyHeaders = c.makeHeadersCopier(req) 438 redirectMethod string 439 ) 440 uerr := func(err error) error { 441 req.closeBody() 442 method := valueOrDefault(reqs[0].Method, "GET") 443 var urlStr string 444 if resp != nil && resp.Request != nil { 445 urlStr = resp.Request.URL.String() 446 } else { 447 urlStr = req.URL.String() 448 } 449 return &url.Error{ 450 Op: method[:1] + strings.ToLower(method[1:]), 451 URL: urlStr, 452 Err: err, 453 } 454 } 455 for { 456 // For all but the first request, create the next 457 // request hop and replace req. 458 if len(reqs) > 0 { 459 loc := resp.Header.Get("Location") 460 if loc == "" { 461 return nil, uerr(fmt.Errorf("%d response missing Location header", resp.StatusCode)) 462 } 463 u, err := req.URL.Parse(loc) 464 if err != nil { 465 return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err)) 466 } 467 ireq := reqs[0] 468 req = &Request{ 469 Method: redirectMethod, 470 Response: resp, 471 URL: u, 472 Header: make(Header), 473 Cancel: ireq.Cancel, 474 ctx: ireq.ctx, 475 } 476 if ireq.GetBody != nil { 477 req.Body, err = ireq.GetBody() 478 if err != nil { 479 return nil, uerr(err) 480 } 481 req.ContentLength = ireq.ContentLength 482 } 483 484 // Copy original headers before setting the Referer, 485 // in case the user set Referer on their first request. 486 // If they really want to override, they can do it in 487 // their CheckRedirect func. 488 copyHeaders(req) 489 490 // Add the Referer header from the most recent 491 // request URL to the new one, if it's not https->http: 492 if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" { 493 req.Header.Set("Referer", ref) 494 } 495 err = c.checkRedirect(req, reqs) 496 497 // Sentinel error to let users select the 498 // previous response, without closing its 499 // body. See Issue 10069. 500 if err == ErrUseLastResponse { 501 return resp, nil 502 } 503 504 // Close the previous response's body. But 505 // read at least some of the body so if it's 506 // small the underlying TCP connection will be 507 // re-used. No need to check for errors: if it 508 // fails, the Transport won't reuse it anyway. 509 const maxBodySlurpSize = 2 << 10 510 if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize { 511 io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize) 512 } 513 resp.Body.Close() 514 515 if err != nil { 516 // Special case for Go 1 compatibility: return both the response 517 // and an error if the CheckRedirect function failed. 518 // See https://golang.org/issue/3795 519 // The resp.Body has already been closed. 520 ue := uerr(err) 521 ue.(*url.Error).URL = loc 522 return resp, ue 523 } 524 } 525 526 reqs = append(reqs, req) 527 var err error 528 if resp, err = c.send(req, deadline); err != nil { 529 if !deadline.IsZero() && !time.Now().Before(deadline) { 530 err = &httpError{ 531 err: err.Error() + " (Client.Timeout exceeded while awaiting headers)", 532 timeout: true, 533 } 534 } 535 return nil, uerr(err) 536 } 537 538 var shouldRedirect bool 539 redirectMethod, shouldRedirect = redirectBehavior(req.Method, resp.StatusCode) 540 if !shouldRedirect { 541 return resp, nil 542 } 543 544 req.closeBody() 545 } 546 } 547 548 // makeHeadersCopier makes a function that copies headers from the 549 // initial Request, ireq. For every redirect, this function must be called 550 // so that it can copy headers into the upcoming Request. 551 func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) { 552 // The headers to copy are from the very initial request. 553 // We use a closured callback to keep a reference to these original headers. 554 var ( 555 ireqhdr = ireq.Header.clone() 556 icookies map[string][]*Cookie 557 ) 558 if c.Jar != nil && ireq.Header.Get("Cookie") != "" { 559 icookies = make(map[string][]*Cookie) 560 for _, c := range ireq.Cookies() { 561 icookies[c.Name] = append(icookies[c.Name], c) 562 } 563 } 564 565 preq := ireq // The previous request 566 return func(req *Request) { 567 // If Jar is present and there was some initial cookies provided 568 // via the request header, then we may need to alter the initial 569 // cookies as we follow redirects since each redirect may end up 570 // modifying a pre-existing cookie. 571 // 572 // Since cookies already set in the request header do not contain 573 // information about the original domain and path, the logic below 574 // assumes any new set cookies override the original cookie 575 // regardless of domain or path. 576 // 577 // See https://golang.org/issue/17494 578 if c.Jar != nil && icookies != nil { 579 var changed bool 580 resp := req.Response // The response that caused the upcoming redirect 581 for _, c := range resp.Cookies() { 582 if _, ok := icookies[c.Name]; ok { 583 delete(icookies, c.Name) 584 changed = true 585 } 586 } 587 if changed { 588 ireqhdr.Del("Cookie") 589 var ss []string 590 for _, cs := range icookies { 591 for _, c := range cs { 592 ss = append(ss, c.Name+"="+c.Value) 593 } 594 } 595 sort.Strings(ss) // Ensure deterministic headers 596 ireqhdr.Set("Cookie", strings.Join(ss, "; ")) 597 } 598 } 599 600 // Copy the initial request's Header values 601 // (at least the safe ones). 602 for k, vv := range ireqhdr { 603 if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) { 604 req.Header[k] = vv 605 } 606 } 607 608 preq = req // Update previous Request with the current request 609 } 610 } 611 612 func defaultCheckRedirect(req *Request, via []*Request) error { 613 if len(via) >= 10 { 614 return errors.New("stopped after 10 redirects") 615 } 616 return nil 617 } 618 619 // Post issues a POST to the specified URL. 620 // 621 // Caller should close resp.Body when done reading from it. 622 // 623 // If the provided body is an io.Closer, it is closed after the 624 // request. 625 // 626 // Post is a wrapper around DefaultClient.Post. 627 // 628 // To set custom headers, use NewRequest and DefaultClient.Do. 629 func Post(url string, contentType string, body io.Reader) (resp *Response, err error) { 630 return DefaultClient.Post(url, contentType, body) 631 } 632 633 // Post issues a POST to the specified URL. 634 // 635 // Caller should close resp.Body when done reading from it. 636 // 637 // If the provided body is an io.Closer, it is closed after the 638 // request. 639 // 640 // To set custom headers, use NewRequest and Client.Do. 641 func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) { 642 req, err := NewRequest("POST", url, body) 643 if err != nil { 644 return nil, err 645 } 646 req.Header.Set("Content-Type", contentType) 647 return c.Do(req) 648 } 649 650 // PostForm issues a POST to the specified URL, with data's keys and 651 // values URL-encoded as the request body. 652 // 653 // The Content-Type header is set to application/x-www-form-urlencoded. 654 // To set other headers, use NewRequest and DefaultClient.Do. 655 // 656 // When err is nil, resp always contains a non-nil resp.Body. 657 // Caller should close resp.Body when done reading from it. 658 // 659 // PostForm is a wrapper around DefaultClient.PostForm. 660 func PostForm(url string, data url.Values) (resp *Response, err error) { 661 return DefaultClient.PostForm(url, data) 662 } 663 664 // PostForm issues a POST to the specified URL, 665 // with data's keys and values URL-encoded as the request body. 666 // 667 // The Content-Type header is set to application/x-www-form-urlencoded. 668 // To set other headers, use NewRequest and DefaultClient.Do. 669 // 670 // When err is nil, resp always contains a non-nil resp.Body. 671 // Caller should close resp.Body when done reading from it. 672 func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) { 673 return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) 674 } 675 676 // Head issues a HEAD to the specified URL. If the response is one of 677 // the following redirect codes, Head follows the redirect, up to a 678 // maximum of 10 redirects: 679 // 680 // 301 (Moved Permanently) 681 // 302 (Found) 682 // 303 (See Other) 683 // 307 (Temporary Redirect) 684 // 308 (Permanent Redirect) 685 // 686 // Head is a wrapper around DefaultClient.Head 687 func Head(url string) (resp *Response, err error) { 688 return DefaultClient.Head(url) 689 } 690 691 // Head issues a HEAD to the specified URL. If the response is one of the 692 // following redirect codes, Head follows the redirect after calling the 693 // Client's CheckRedirect function: 694 // 695 // 301 (Moved Permanently) 696 // 302 (Found) 697 // 303 (See Other) 698 // 307 (Temporary Redirect) 699 // 308 (Permanent Redirect) 700 func (c *Client) Head(url string) (resp *Response, err error) { 701 req, err := NewRequest("HEAD", url, nil) 702 if err != nil { 703 return nil, err 704 } 705 return c.Do(req) 706 } 707 708 // cancelTimerBody is an io.ReadCloser that wraps rc with two features: 709 // 1) on Read error or close, the stop func is called. 710 // 2) On Read failure, if reqWasCanceled is true, the error is wrapped and 711 // marked as net.Error that hit its timeout. 712 type cancelTimerBody struct { 713 stop func() // stops the time.Timer waiting to cancel the request 714 rc io.ReadCloser 715 reqWasCanceled func() bool 716 } 717 718 func (b *cancelTimerBody) Read(p []byte) (n int, err error) { 719 n, err = b.rc.Read(p) 720 if err == nil { 721 return n, nil 722 } 723 b.stop() 724 if err == io.EOF { 725 return n, err 726 } 727 if b.reqWasCanceled() { 728 err = &httpError{ 729 err: err.Error() + " (Client.Timeout exceeded while reading body)", 730 timeout: true, 731 } 732 } 733 return n, err 734 } 735 736 func (b *cancelTimerBody) Close() error { 737 err := b.rc.Close() 738 b.stop() 739 return err 740 } 741 742 func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool { 743 switch CanonicalHeaderKey(headerKey) { 744 case "Authorization", "Www-Authenticate", "Cookie", "Cookie2": 745 // Permit sending auth/cookie headers from "foo.com" 746 // to "sub.foo.com". 747 748 // Note that we don't send all cookies to subdomains 749 // automatically. This function is only used for 750 // Cookies set explicitly on the initial outgoing 751 // client request. Cookies automatically added via the 752 // CookieJar mechanism continue to follow each 753 // cookie's scope as set by Set-Cookie. But for 754 // outgoing requests with the Cookie header set 755 // directly, we don't know their scope, so we assume 756 // it's for *.domain.com. 757 758 // TODO(bradfitz): once issue 16142 is fixed, make 759 // this code use those URL accessors, and consider 760 // "http://foo.com" and "http://foo.com:80" as 761 // equivalent? 762 763 // TODO(bradfitz): better hostname canonicalization, 764 // at least once we figure out IDNA/Punycode (issue 765 // 13835). 766 ihost := strings.ToLower(initial.Host) 767 dhost := strings.ToLower(dest.Host) 768 return isDomainOrSubdomain(dhost, ihost) 769 } 770 // All other headers are copied: 771 return true 772 } 773 774 // isDomainOrSubdomain reports whether sub is a subdomain (or exact 775 // match) of the parent domain. 776 // 777 // Both domains must already be in canonical form. 778 func isDomainOrSubdomain(sub, parent string) bool { 779 if sub == parent { 780 return true 781 } 782 // If sub is "foo.example.com" and parent is "example.com", 783 // that means sub must end in "."+parent. 784 // Do it without allocating. 785 if !strings.HasSuffix(sub, parent) { 786 return false 787 } 788 return sub[len(sub)-len(parent)-1] == '.' 789 }