github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 "strings" 22 "sync" 23 "time" 24 ) 25 26 // A Client is an HTTP client. Its zero value (DefaultClient) is a 27 // usable client that uses DefaultTransport. 28 // 29 // The Client's Transport typically has internal state (cached TCP 30 // connections), so Clients should be reused instead of created as 31 // needed. Clients are safe for concurrent use by multiple goroutines. 32 // 33 // A Client is higher-level than a RoundTripper (such as Transport) 34 // and additionally handles HTTP details such as cookies and 35 // redirects. 36 type Client struct { 37 // Transport specifies the mechanism by which individual 38 // HTTP requests are made. 39 // If nil, DefaultTransport is used. 40 Transport RoundTripper 41 42 // CheckRedirect specifies the policy for handling redirects. 43 // If CheckRedirect is not nil, the client calls it before 44 // following an HTTP redirect. The arguments req and via are 45 // the upcoming request and the requests made already, oldest 46 // first. If CheckRedirect returns an error, the Client's Get 47 // method returns both the previous Response (with its Body 48 // closed) and CheckRedirect's error (wrapped in a url.Error) 49 // instead of issuing the Request req. 50 // 51 // If CheckRedirect is nil, the Client uses its default policy, 52 // which is to stop after 10 consecutive requests. 53 CheckRedirect func(req *Request, via []*Request) error 54 55 // Jar specifies the cookie jar. 56 // If Jar is nil, cookies are not sent in requests and ignored 57 // in responses. 58 Jar CookieJar 59 60 // Timeout specifies a time limit for requests made by this 61 // Client. The timeout includes connection time, any 62 // redirects, and reading the response body. The timer remains 63 // running after Get, Head, Post, or Do return and will 64 // interrupt reading of the Response.Body. 65 // 66 // A Timeout of zero means no timeout. 67 // 68 // The Client cancels requests to the underlying Transport 69 // using the Request.Cancel mechanism. Requests passed 70 // to Client.Do may still set Request.Cancel; both will 71 // cancel the request. 72 // 73 // For compatibility, the Client will also use the deprecated 74 // CancelRequest method on Transport if found. New 75 // RoundTripper implementations should use Request.Cancel 76 // instead of implementing CancelRequest. 77 Timeout time.Duration 78 } 79 80 // DefaultClient is the default Client and is used by Get, Head, and Post. 81 var DefaultClient = &Client{} 82 83 // RoundTripper is an interface representing the ability to execute a 84 // single HTTP transaction, obtaining the Response for a given Request. 85 // 86 // A RoundTripper must be safe for concurrent use by multiple 87 // goroutines. 88 type RoundTripper interface { 89 // RoundTrip executes a single HTTP transaction, returning 90 // a Response for the provided Request. 91 // 92 // RoundTrip should not attempt to interpret the response. In 93 // particular, RoundTrip must return err == nil if it obtained 94 // a response, regardless of the response's HTTP status code. 95 // A non-nil err should be reserved for failure to obtain a 96 // response. Similarly, RoundTrip should not attempt to 97 // handle higher-level protocol details such as redirects, 98 // authentication, or cookies. 99 // 100 // RoundTrip should not modify the request, except for 101 // consuming and closing the Request's Body. 102 // 103 // RoundTrip must always close the body, including on errors, 104 // but depending on the implementation may do so in a separate 105 // goroutine even after RoundTrip returns. This means that 106 // callers wanting to reuse the body for subsequent requests 107 // must arrange to wait for the Close call before doing so. 108 // 109 // The Request's URL and Header fields must be initialized. 110 RoundTrip(*Request) (*Response, error) 111 } 112 113 // Given a string of the form "host", "host:port", or "[ipv6::address]:port", 114 // return true if the string includes a port. 115 func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") } 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 // Do sends an HTTP request and returns an HTTP response, following 160 // policy (such as redirects, cookies, auth) as configured on the 161 // client. 162 // 163 // An error is returned if caused by client policy (such as 164 // CheckRedirect), or failure to speak HTTP (such as a network 165 // connectivity problem). A non-2xx status code doesn't cause an 166 // error. 167 // 168 // If the returned error is nil, the Response will contain a non-nil 169 // Body which the user is expected to close. If the Body is not 170 // closed, the Client's underlying RoundTripper (typically Transport) 171 // may not be able to re-use a persistent TCP connection to the server 172 // for a subsequent "keep-alive" request. 173 // 174 // The request Body, if non-nil, will be closed by the underlying 175 // Transport, even on errors. 176 // 177 // On error, any Response can be ignored. A non-nil Response with a 178 // non-nil error only occurs when CheckRedirect fails, and even then 179 // the returned Response.Body is already closed. 180 // 181 // Generally Get, Post, or PostForm will be used instead of Do. 182 func (c *Client) Do(req *Request) (*Response, error) { 183 method := valueOrDefault(req.Method, "GET") 184 if method == "GET" || method == "HEAD" { 185 return c.doFollowingRedirects(req, shouldRedirectGet) 186 } 187 if method == "POST" || method == "PUT" { 188 return c.doFollowingRedirects(req, shouldRedirectPost) 189 } 190 return c.send(req, c.deadline()) 191 } 192 193 func (c *Client) deadline() time.Time { 194 if c.Timeout > 0 { 195 return time.Now().Add(c.Timeout) 196 } 197 return time.Time{} 198 } 199 200 func (c *Client) transport() RoundTripper { 201 if c.Transport != nil { 202 return c.Transport 203 } 204 return DefaultTransport 205 } 206 207 // send issues an HTTP request. 208 // Caller should close resp.Body when done reading from it. 209 func send(ireq *Request, rt RoundTripper, deadline time.Time) (*Response, error) { 210 req := ireq // req is either the original request, or a modified fork 211 212 if rt == nil { 213 req.closeBody() 214 return nil, errors.New("http: no Client.Transport or DefaultTransport") 215 } 216 217 if req.URL == nil { 218 req.closeBody() 219 return nil, errors.New("http: nil Request.URL") 220 } 221 222 if req.RequestURI != "" { 223 req.closeBody() 224 return nil, errors.New("http: Request.RequestURI can't be set in client requests.") 225 } 226 227 // forkReq forks req into a shallow clone of ireq the first 228 // time it's called. 229 forkReq := func() { 230 if ireq == req { 231 req = new(Request) 232 *req = *ireq // shallow clone 233 } 234 } 235 236 // Most the callers of send (Get, Post, et al) don't need 237 // Headers, leaving it uninitialized. We guarantee to the 238 // Transport that this has been initialized, though. 239 if req.Header == nil { 240 forkReq() 241 req.Header = make(Header) 242 } 243 244 if u := req.URL.User; u != nil && req.Header.Get("Authorization") == "" { 245 username := u.Username() 246 password, _ := u.Password() 247 forkReq() 248 req.Header = cloneHeader(ireq.Header) 249 req.Header.Set("Authorization", "Basic "+basicAuth(username, password)) 250 } 251 252 if !deadline.IsZero() { 253 forkReq() 254 } 255 stopTimer, wasCanceled := setRequestCancel(req, rt, deadline) 256 257 resp, err := rt.RoundTrip(req) 258 if err != nil { 259 stopTimer() 260 if resp != nil { 261 log.Printf("RoundTripper returned a response & error; ignoring response") 262 } 263 if tlsErr, ok := err.(tls.RecordHeaderError); ok { 264 // If we get a bad TLS record header, check to see if the 265 // response looks like HTTP and give a more helpful error. 266 // See golang.org/issue/11111. 267 if string(tlsErr.RecordHeader[:]) == "HTTP/" { 268 err = errors.New("http: server gave HTTP response to HTTPS client") 269 } 270 } 271 return nil, err 272 } 273 if !deadline.IsZero() { 274 resp.Body = &cancelTimerBody{ 275 stop: stopTimer, 276 rc: resp.Body, 277 reqWasCanceled: wasCanceled, 278 } 279 } 280 return resp, nil 281 } 282 283 // setRequestCancel sets the Cancel field of req, if deadline is 284 // non-zero. The RoundTripper's type is used to determine whether the legacy 285 // CancelRequest behavior should be used. 286 func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), wasCanceled func() bool) { 287 if deadline.IsZero() { 288 return nop, alwaysFalse 289 } 290 291 initialReqCancel := req.Cancel // the user's original Request.Cancel, if any 292 293 cancel := make(chan struct{}) 294 req.Cancel = cancel 295 296 wasCanceled = func() bool { 297 select { 298 case <-cancel: 299 return true 300 default: 301 return false 302 } 303 } 304 305 doCancel := func() { 306 // The new way: 307 close(cancel) 308 309 // The legacy compatibility way, used only 310 // for RoundTripper implementations written 311 // before Go 1.5 or Go 1.6. 312 type canceler interface { 313 CancelRequest(*Request) 314 } 315 switch v := rt.(type) { 316 case *Transport, *http2Transport: 317 // Do nothing. The net/http package's transports 318 // support the new Request.Cancel channel 319 case canceler: 320 v.CancelRequest(req) 321 } 322 } 323 324 stopTimerCh := make(chan struct{}) 325 var once sync.Once 326 stopTimer = func() { once.Do(func() { close(stopTimerCh) }) } 327 328 timer := time.NewTimer(deadline.Sub(time.Now())) 329 go func() { 330 select { 331 case <-initialReqCancel: 332 doCancel() 333 case <-timer.C: 334 doCancel() 335 case <-stopTimerCh: 336 timer.Stop() 337 } 338 }() 339 340 return stopTimer, wasCanceled 341 } 342 343 // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt 344 // "To receive authorization, the client sends the userid and password, 345 // separated by a single colon (":") character, within a base64 346 // encoded string in the credentials." 347 // It is not meant to be urlencoded. 348 func basicAuth(username, password string) string { 349 auth := username + ":" + password 350 return base64.StdEncoding.EncodeToString([]byte(auth)) 351 } 352 353 // True if the specified HTTP status code is one for which the Get utility should 354 // automatically redirect. 355 func shouldRedirectGet(statusCode int) bool { 356 switch statusCode { 357 case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect: 358 return true 359 } 360 return false 361 } 362 363 // True if the specified HTTP status code is one for which the Post utility should 364 // automatically redirect. 365 func shouldRedirectPost(statusCode int) bool { 366 switch statusCode { 367 case StatusFound, StatusSeeOther: 368 return true 369 } 370 return false 371 } 372 373 // Get issues a GET to the specified URL. If the response is one of 374 // the following redirect codes, Get follows the redirect, up to a 375 // maximum of 10 redirects: 376 // 377 // 301 (Moved Permanently) 378 // 302 (Found) 379 // 303 (See Other) 380 // 307 (Temporary Redirect) 381 // 382 // An error is returned if there were too many redirects or if there 383 // was an HTTP protocol error. A non-2xx response doesn't cause an 384 // error. 385 // 386 // When err is nil, resp always contains a non-nil resp.Body. 387 // Caller should close resp.Body when done reading from it. 388 // 389 // Get is a wrapper around DefaultClient.Get. 390 // 391 // To make a request with custom headers, use NewRequest and 392 // DefaultClient.Do. 393 func Get(url string) (resp *Response, err error) { 394 return DefaultClient.Get(url) 395 } 396 397 // Get issues a GET to the specified URL. If the response is one of the 398 // following redirect codes, Get follows the redirect after calling the 399 // Client's CheckRedirect function: 400 // 401 // 301 (Moved Permanently) 402 // 302 (Found) 403 // 303 (See Other) 404 // 307 (Temporary Redirect) 405 // 406 // An error is returned if the Client's CheckRedirect function fails 407 // or if there was an HTTP protocol error. A non-2xx response doesn't 408 // cause an error. 409 // 410 // When err is nil, resp always contains a non-nil resp.Body. 411 // Caller should close resp.Body when done reading from it. 412 // 413 // To make a request with custom headers, use NewRequest and Client.Do. 414 func (c *Client) Get(url string) (resp *Response, err error) { 415 req, err := NewRequest("GET", url, nil) 416 if err != nil { 417 return nil, err 418 } 419 return c.doFollowingRedirects(req, shouldRedirectGet) 420 } 421 422 func alwaysFalse() bool { return false } 423 424 // checkRedirect calls either the user's configured CheckRedirect 425 // function, or the default. 426 func (c *Client) checkRedirect(req *Request, via []*Request) error { 427 fn := c.CheckRedirect 428 if fn == nil { 429 fn = defaultCheckRedirect 430 } 431 return fn(req, via) 432 } 433 434 func (c *Client) doFollowingRedirects(req *Request, shouldRedirect func(int) bool) (*Response, error) { 435 if req.URL == nil { 436 req.closeBody() 437 return nil, errors.New("http: nil Request.URL") 438 } 439 440 var ( 441 deadline = c.deadline() 442 reqs []*Request 443 resp *Response 444 ) 445 uerr := func(err error) error { 446 req.closeBody() 447 method := valueOrDefault(reqs[0].Method, "GET") 448 var urlStr string 449 if resp != nil { 450 urlStr = resp.Request.URL.String() 451 } else { 452 urlStr = req.URL.String() 453 } 454 return &url.Error{ 455 Op: method[:1] + strings.ToLower(method[1:]), 456 URL: urlStr, 457 Err: err, 458 } 459 } 460 for { 461 // For all but the first request, create the next 462 // request hop and replace req. 463 if len(reqs) > 0 { 464 loc := resp.Header.Get("Location") 465 if loc == "" { 466 return nil, uerr(fmt.Errorf("%d response missing Location header", resp.StatusCode)) 467 } 468 u, err := req.URL.Parse(loc) 469 if err != nil { 470 return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err)) 471 } 472 ireq := reqs[0] 473 req = &Request{ 474 Method: ireq.Method, 475 URL: u, 476 Header: make(Header), 477 Cancel: ireq.Cancel, 478 } 479 if ireq.Method == "POST" || ireq.Method == "PUT" { 480 req.Method = "GET" 481 } 482 // Add the Referer header from the most recent 483 // request URL to the new one, if it's not https->http: 484 if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" { 485 req.Header.Set("Referer", ref) 486 } 487 if err := c.checkRedirect(req, reqs); err != nil { 488 // Special case for Go 1 compatibility: return both the response 489 // and an error if the CheckRedirect function failed. 490 // See https://golang.org/issue/3795 491 // The resp.Body has already been closed. 492 ue := uerr(err) 493 ue.(*url.Error).URL = loc 494 return resp, ue 495 } 496 } 497 498 reqs = append(reqs, req) 499 500 var err error 501 if resp, err = c.send(req, deadline); err != nil { 502 if !deadline.IsZero() && !time.Now().Before(deadline) { 503 err = &httpError{ 504 err: err.Error() + " (Client.Timeout exceeded while awaiting headers)", 505 timeout: true, 506 } 507 } 508 return nil, uerr(err) 509 } 510 511 if !shouldRedirect(resp.StatusCode) { 512 return resp, nil 513 } 514 515 // Read the body if small so underlying TCP connection will be re-used. 516 // No need to check for errors: if it fails, Transport won't reuse it anyway. 517 const maxBodySlurpSize = 2 << 10 518 if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize { 519 io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize) 520 } 521 resp.Body.Close() 522 } 523 } 524 525 func defaultCheckRedirect(req *Request, via []*Request) error { 526 if len(via) >= 10 { 527 return errors.New("stopped after 10 redirects") 528 } 529 return nil 530 } 531 532 // Post issues a POST to the specified URL. 533 // 534 // Caller should close resp.Body when done reading from it. 535 // 536 // If the provided body is an io.Closer, it is closed after the 537 // request. 538 // 539 // Post is a wrapper around DefaultClient.Post. 540 // 541 // To set custom headers, use NewRequest and DefaultClient.Do. 542 func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) { 543 return DefaultClient.Post(url, bodyType, body) 544 } 545 546 // Post issues a POST to the specified URL. 547 // 548 // Caller should close resp.Body when done reading from it. 549 // 550 // If the provided body is an io.Closer, it is closed after the 551 // request. 552 // 553 // To set custom headers, use NewRequest and Client.Do. 554 func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) { 555 req, err := NewRequest("POST", url, body) 556 if err != nil { 557 return nil, err 558 } 559 req.Header.Set("Content-Type", bodyType) 560 return c.doFollowingRedirects(req, shouldRedirectPost) 561 } 562 563 // PostForm issues a POST to the specified URL, with data's keys and 564 // values URL-encoded as the request body. 565 // 566 // The Content-Type header is set to application/x-www-form-urlencoded. 567 // To set other headers, use NewRequest and DefaultClient.Do. 568 // 569 // When err is nil, resp always contains a non-nil resp.Body. 570 // Caller should close resp.Body when done reading from it. 571 // 572 // PostForm is a wrapper around DefaultClient.PostForm. 573 func PostForm(url string, data url.Values) (resp *Response, err error) { 574 return DefaultClient.PostForm(url, data) 575 } 576 577 // PostForm issues a POST to the specified URL, 578 // with data's keys and values URL-encoded as the request body. 579 // 580 // The Content-Type header is set to application/x-www-form-urlencoded. 581 // To set other headers, use NewRequest and DefaultClient.Do. 582 // 583 // When err is nil, resp always contains a non-nil resp.Body. 584 // Caller should close resp.Body when done reading from it. 585 func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) { 586 return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode())) 587 } 588 589 // Head issues a HEAD to the specified URL. If the response is one of 590 // the following redirect codes, Head follows the redirect, up to a 591 // maximum of 10 redirects: 592 // 593 // 301 (Moved Permanently) 594 // 302 (Found) 595 // 303 (See Other) 596 // 307 (Temporary Redirect) 597 // 598 // Head is a wrapper around DefaultClient.Head 599 func Head(url string) (resp *Response, err error) { 600 return DefaultClient.Head(url) 601 } 602 603 // Head issues a HEAD to the specified URL. If the response is one of the 604 // following redirect codes, Head follows the redirect after calling the 605 // Client's CheckRedirect function: 606 // 607 // 301 (Moved Permanently) 608 // 302 (Found) 609 // 303 (See Other) 610 // 307 (Temporary Redirect) 611 func (c *Client) Head(url string) (resp *Response, err error) { 612 req, err := NewRequest("HEAD", url, nil) 613 if err != nil { 614 return nil, err 615 } 616 return c.doFollowingRedirects(req, shouldRedirectGet) 617 } 618 619 // cancelTimerBody is an io.ReadCloser that wraps rc with two features: 620 // 1) on Read error or close, the stop func is called. 621 // 2) On Read failure, if reqWasCanceled is true, the error is wrapped and 622 // marked as net.Error that hit its timeout. 623 type cancelTimerBody struct { 624 stop func() // stops the time.Timer waiting to cancel the request 625 rc io.ReadCloser 626 reqWasCanceled func() bool 627 } 628 629 func (b *cancelTimerBody) Read(p []byte) (n int, err error) { 630 n, err = b.rc.Read(p) 631 if err == nil { 632 return n, nil 633 } 634 b.stop() 635 if err == io.EOF { 636 return n, err 637 } 638 if b.reqWasCanceled() { 639 err = &httpError{ 640 err: err.Error() + " (Client.Timeout exceeded while reading body)", 641 timeout: true, 642 } 643 } 644 return n, err 645 } 646 647 func (b *cancelTimerBody) Close() error { 648 err := b.rc.Close() 649 b.stop() 650 return err 651 }