2009-06-09 10:58:58 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
2018-02-13 22:03:05 +01:00
|
|
|
// HTTP client. See RFC 7230 through 7235.
|
2012-10-29 17:56:31 +01:00
|
|
|
//
|
2011-10-19 08:48:26 -07:00
|
|
|
// This is the high-level Client interface.
|
|
|
|
|
// The low-level implementation is in transport.go.
|
2009-06-09 10:58:58 -07:00
|
|
|
|
|
|
|
|
package http
|
|
|
|
|
|
|
|
|
|
import (
|
2019-05-07 16:25:05 -07:00
|
|
|
"context"
|
2015-10-20 00:35:42 -07:00
|
|
|
"crypto/tls"
|
2009-12-15 16:27:45 -08:00
|
|
|
"encoding/base64"
|
2011-11-01 22:04:37 -04:00
|
|
|
"errors"
|
2009-12-15 15:35:38 -08:00
|
|
|
"fmt"
|
|
|
|
|
"io"
|
2014-03-03 11:25:57 -08:00
|
|
|
"io/ioutil"
|
2012-06-19 09:10:14 -07:00
|
|
|
"log"
|
2011-11-08 15:41:54 -08:00
|
|
|
"net/url"
|
2019-05-07 16:25:05 -07:00
|
|
|
"reflect"
|
2016-10-18 14:56:19 -07:00
|
|
|
"sort"
|
2009-12-15 15:35:38 -08:00
|
|
|
"strings"
|
2014-03-02 20:39:20 -08:00
|
|
|
"sync"
|
|
|
|
|
"time"
|
2009-06-09 10:58:58 -07:00
|
|
|
)
|
|
|
|
|
|
2013-03-11 18:51:01 -07:00
|
|
|
// A Client is an HTTP client. Its zero value (DefaultClient) is a
|
|
|
|
|
// usable client that uses DefaultTransport.
|
2011-06-16 15:02:47 -07:00
|
|
|
//
|
2013-03-11 18:51:01 -07:00
|
|
|
// The Client's Transport typically has internal state (cached TCP
|
|
|
|
|
// connections), so Clients should be reused instead of created as
|
2011-06-16 15:02:47 -07:00
|
|
|
// needed. Clients are safe for concurrent use by multiple goroutines.
|
2013-03-11 18:51:01 -07:00
|
|
|
//
|
|
|
|
|
// A Client is higher-level than a RoundTripper (such as Transport)
|
|
|
|
|
// and additionally handles HTTP details such as cookies and
|
|
|
|
|
// redirects.
|
2016-11-29 14:42:22 -08:00
|
|
|
//
|
|
|
|
|
// When following redirects, the Client will forward all headers set on the
|
|
|
|
|
// initial Request except:
|
|
|
|
|
//
|
2017-04-20 13:01:59 +01:00
|
|
|
// • when forwarding sensitive headers like "Authorization",
|
|
|
|
|
// "WWW-Authenticate", and "Cookie" to untrusted targets.
|
|
|
|
|
// These headers will be ignored when following a redirect to a domain
|
|
|
|
|
// that is not a subdomain match or exact match of the initial domain.
|
|
|
|
|
// For example, a redirect from "foo.com" to either "foo.com" or "sub.foo.com"
|
|
|
|
|
// will forward the sensitive headers, but a redirect to "bar.com" will not.
|
2016-11-29 14:42:22 -08:00
|
|
|
//
|
2017-04-20 13:01:59 +01:00
|
|
|
// • when forwarding the "Cookie" header with a non-nil cookie Jar.
|
|
|
|
|
// Since each redirect may mutate the state of the cookie jar,
|
|
|
|
|
// a redirect may possibly alter a cookie set in the initial request.
|
|
|
|
|
// When forwarding the "Cookie" header, any mutated cookies will be omitted,
|
|
|
|
|
// with the expectation that the Jar will insert those mutated cookies
|
|
|
|
|
// with the updated values (assuming the origin matches).
|
|
|
|
|
// If Jar is nil, the initial cookies are forwarded without change.
|
2016-11-29 14:42:22 -08:00
|
|
|
//
|
2011-02-23 12:20:50 -08:00
|
|
|
type Client struct {
|
2012-01-18 19:05:53 -08:00
|
|
|
// Transport specifies the mechanism by which individual
|
|
|
|
|
// HTTP requests are made.
|
|
|
|
|
// If nil, DefaultTransport is used.
|
|
|
|
|
Transport RoundTripper
|
2011-04-25 22:41:50 -07:00
|
|
|
|
2012-01-18 19:05:53 -08:00
|
|
|
// CheckRedirect specifies the policy for handling redirects.
|
2011-04-25 22:41:50 -07:00
|
|
|
// If CheckRedirect is not nil, the client calls it before
|
2012-07-18 13:48:39 -07:00
|
|
|
// following an HTTP redirect. The arguments req and via are
|
|
|
|
|
// the upcoming request and the requests made already, oldest
|
|
|
|
|
// first. If CheckRedirect returns an error, the Client's Get
|
2016-03-31 05:36:20 -07:00
|
|
|
// method returns both the previous Response (with its Body
|
|
|
|
|
// closed) and CheckRedirect's error (wrapped in a url.Error)
|
|
|
|
|
// instead of issuing the Request req.
|
2016-05-18 15:42:54 +00:00
|
|
|
// As a special case, if CheckRedirect returns ErrUseLastResponse,
|
|
|
|
|
// then the most recent response is returned with its body
|
|
|
|
|
// unclosed, along with a nil error.
|
2011-04-25 22:41:50 -07:00
|
|
|
//
|
|
|
|
|
// If CheckRedirect is nil, the Client uses its default policy,
|
|
|
|
|
// which is to stop after 10 consecutive requests.
|
2011-11-01 22:04:37 -04:00
|
|
|
CheckRedirect func(req *Request, via []*Request) error
|
2011-12-16 10:48:41 -05:00
|
|
|
|
2012-10-29 17:56:31 +01:00
|
|
|
// Jar specifies the cookie jar.
|
2016-11-29 14:42:22 -08:00
|
|
|
//
|
|
|
|
|
// The Jar is used to insert relevant cookies into every
|
|
|
|
|
// outbound Request and is updated with the cookie values
|
|
|
|
|
// of every inbound Response. The Jar is consulted for every
|
|
|
|
|
// redirect that the Client follows.
|
|
|
|
|
//
|
|
|
|
|
// If Jar is nil, cookies are only sent if they are explicitly
|
|
|
|
|
// set on the Request.
|
2011-12-16 10:48:41 -05:00
|
|
|
Jar CookieJar
|
2014-03-02 20:39:20 -08:00
|
|
|
|
2014-03-04 13:41:05 -08:00
|
|
|
// Timeout specifies a time limit for requests made by this
|
|
|
|
|
// Client. The timeout includes connection time, any
|
|
|
|
|
// redirects, and reading the response body. The timer remains
|
|
|
|
|
// running after Get, Head, Post, or Do return and will
|
|
|
|
|
// interrupt reading of the Response.Body.
|
2014-03-02 20:39:20 -08:00
|
|
|
//
|
|
|
|
|
// A Timeout of zero means no timeout.
|
|
|
|
|
//
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
// The Client cancels requests to the underlying Transport
|
2018-08-13 16:00:34 +00:00
|
|
|
// as if the Request's Context ended.
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
//
|
|
|
|
|
// For compatibility, the Client will also use the deprecated
|
|
|
|
|
// CancelRequest method on Transport if found. New
|
2018-08-13 16:00:34 +00:00
|
|
|
// RoundTripper implementations should use the Request's Context
|
2019-03-28 16:15:14 -07:00
|
|
|
// for cancellation instead of implementing CancelRequest.
|
2014-03-02 20:39:20 -08:00
|
|
|
Timeout time.Duration
|
2011-02-23 12:20:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultClient is the default Client and is used by Get, Head, and Post.
|
|
|
|
|
var DefaultClient = &Client{}
|
|
|
|
|
|
2011-03-11 11:32:33 -08:00
|
|
|
// RoundTripper is an interface representing the ability to execute a
|
2011-02-23 12:20:50 -08:00
|
|
|
// single HTTP transaction, obtaining the Response for a given Request.
|
2011-06-16 15:02:47 -07:00
|
|
|
//
|
|
|
|
|
// A RoundTripper must be safe for concurrent use by multiple
|
|
|
|
|
// goroutines.
|
2011-03-11 11:32:33 -08:00
|
|
|
type RoundTripper interface {
|
|
|
|
|
// RoundTrip executes a single HTTP transaction, returning
|
2015-12-09 17:07:44 +00:00
|
|
|
// a Response for the provided Request.
|
|
|
|
|
//
|
|
|
|
|
// RoundTrip should not attempt to interpret the response. In
|
|
|
|
|
// particular, RoundTrip must return err == nil if it obtained
|
|
|
|
|
// a response, regardless of the response's HTTP status code.
|
|
|
|
|
// A non-nil err should be reserved for failure to obtain a
|
|
|
|
|
// response. Similarly, RoundTrip should not attempt to
|
|
|
|
|
// handle higher-level protocol details such as redirects,
|
2011-02-23 12:20:50 -08:00
|
|
|
// authentication, or cookies.
|
2011-03-02 10:21:56 -08:00
|
|
|
//
|
2011-10-14 14:16:43 -07:00
|
|
|
// RoundTrip should not modify the request, except for
|
2017-11-02 15:41:10 -07:00
|
|
|
// consuming and closing the Request's Body. RoundTrip may
|
|
|
|
|
// read fields of the request in a separate goroutine. Callers
|
2018-07-09 22:05:34 +00:00
|
|
|
// should not mutate or reuse the request until the Response's
|
|
|
|
|
// Body has been closed.
|
2015-12-09 17:07:44 +00:00
|
|
|
//
|
|
|
|
|
// RoundTrip must always close the body, including on errors,
|
|
|
|
|
// but depending on the implementation may do so in a separate
|
|
|
|
|
// goroutine even after RoundTrip returns. This means that
|
|
|
|
|
// callers wanting to reuse the body for subsequent requests
|
|
|
|
|
// must arrange to wait for the Close call before doing so.
|
|
|
|
|
//
|
|
|
|
|
// The Request's URL and Header fields must be initialized.
|
2011-11-01 22:04:37 -04:00
|
|
|
RoundTrip(*Request) (*Response, error)
|
2011-02-23 12:20:50 -08:00
|
|
|
}
|
|
|
|
|
|
2014-10-07 07:13:42 -07:00
|
|
|
// refererForURL returns a referer without any authentication info or
|
|
|
|
|
// an empty string if lastReq scheme is https and newReq scheme is http.
|
|
|
|
|
func refererForURL(lastReq, newReq *url.URL) string {
|
|
|
|
|
// https://tools.ietf.org/html/rfc7231#section-5.5.2
|
|
|
|
|
// "Clients SHOULD NOT include a Referer header field in a
|
|
|
|
|
// (non-secure) HTTP request if the referring page was
|
|
|
|
|
// transferred with a secure protocol."
|
|
|
|
|
if lastReq.Scheme == "https" && newReq.Scheme == "http" {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
referer := lastReq.String()
|
|
|
|
|
if lastReq.User != nil {
|
|
|
|
|
// This is not very efficient, but is the best we can
|
|
|
|
|
// do without:
|
|
|
|
|
// - introducing a new method on URL
|
|
|
|
|
// - creating a race condition
|
|
|
|
|
// - copying the URL struct manually, which would cause
|
|
|
|
|
// maintenance problems down the line
|
|
|
|
|
auth := lastReq.User.String() + "@"
|
|
|
|
|
referer = strings.Replace(referer, auth, "", 1)
|
|
|
|
|
}
|
|
|
|
|
return referer
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-14 18:57:13 +00:00
|
|
|
// didTimeout is non-nil only if err != nil.
|
|
|
|
|
func (c *Client) send(req *Request, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
|
2012-10-29 17:56:31 +01:00
|
|
|
if c.Jar != nil {
|
|
|
|
|
for _, cookie := range c.Jar.Cookies(req.URL) {
|
|
|
|
|
req.AddCookie(cookie)
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-14 18:57:13 +00:00
|
|
|
resp, didTimeout, err = send(req, c.transport(), deadline)
|
2012-10-29 17:56:31 +01:00
|
|
|
if err != nil {
|
2016-12-14 18:57:13 +00:00
|
|
|
return nil, didTimeout, err
|
2012-10-29 17:56:31 +01:00
|
|
|
}
|
|
|
|
|
if c.Jar != nil {
|
2012-12-19 16:24:38 -08:00
|
|
|
if rc := resp.Cookies(); len(rc) > 0 {
|
|
|
|
|
c.Jar.SetCookies(req.URL, rc)
|
|
|
|
|
}
|
2012-10-29 17:56:31 +01:00
|
|
|
}
|
2016-12-14 18:57:13 +00:00
|
|
|
return resp, nil, nil
|
2012-10-29 17:56:31 +01:00
|
|
|
}
|
|
|
|
|
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
func (c *Client) deadline() time.Time {
|
|
|
|
|
if c.Timeout > 0 {
|
|
|
|
|
return time.Now().Add(c.Timeout)
|
|
|
|
|
}
|
|
|
|
|
return time.Time{}
|
2011-02-23 12:20:50 -08:00
|
|
|
}
|
|
|
|
|
|
2014-03-02 20:39:20 -08:00
|
|
|
func (c *Client) transport() RoundTripper {
|
|
|
|
|
if c.Transport != nil {
|
|
|
|
|
return c.Transport
|
|
|
|
|
}
|
|
|
|
|
return DefaultTransport
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-19 09:10:14 -07:00
|
|
|
// send issues an HTTP request.
|
|
|
|
|
// Caller should close resp.Body when done reading from it.
|
2016-12-14 18:57:13 +00:00
|
|
|
func send(ireq *Request, rt RoundTripper, deadline time.Time) (resp *Response, didTimeout func() bool, err error) {
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
req := ireq // req is either the original request, or a modified fork
|
|
|
|
|
|
|
|
|
|
if rt == nil {
|
2014-04-14 08:06:13 -07:00
|
|
|
req.closeBody()
|
2016-12-14 18:57:13 +00:00
|
|
|
return nil, alwaysFalse, errors.New("http: no Client.Transport or DefaultTransport")
|
2009-06-09 10:58:58 -07:00
|
|
|
}
|
2011-03-02 10:21:56 -08:00
|
|
|
|
2011-10-14 14:16:43 -07:00
|
|
|
if req.URL == nil {
|
2014-04-14 08:06:13 -07:00
|
|
|
req.closeBody()
|
2016-12-14 18:57:13 +00:00
|
|
|
return nil, alwaysFalse, errors.New("http: nil Request.URL")
|
2011-10-14 14:16:43 -07:00
|
|
|
}
|
|
|
|
|
|
2012-01-26 14:37:14 -08:00
|
|
|
if req.RequestURI != "" {
|
2014-04-14 08:06:13 -07:00
|
|
|
req.closeBody()
|
2016-12-14 18:57:13 +00:00
|
|
|
return nil, alwaysFalse, errors.New("http: Request.RequestURI can't be set in client requests.")
|
2012-01-26 14:37:14 -08:00
|
|
|
}
|
|
|
|
|
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
// forkReq forks req into a shallow clone of ireq the first
|
|
|
|
|
// time it's called.
|
|
|
|
|
forkReq := func() {
|
|
|
|
|
if ireq == req {
|
|
|
|
|
req = new(Request)
|
|
|
|
|
*req = *ireq // shallow clone
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-02 10:21:56 -08:00
|
|
|
// Most the callers of send (Get, Post, et al) don't need
|
2016-03-01 23:21:55 +00:00
|
|
|
// Headers, leaving it uninitialized. We guarantee to the
|
2011-03-04 11:41:57 -08:00
|
|
|
// Transport that this has been initialized, though.
|
2011-03-02 10:21:56 -08:00
|
|
|
if req.Header == nil {
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
forkReq()
|
2011-03-06 23:02:29 -05:00
|
|
|
req.Header = make(Header)
|
2011-03-02 10:21:56 -08:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 16:52:51 +01:00
|
|
|
if u := req.URL.User; u != nil && req.Header.Get("Authorization") == "" {
|
2013-08-07 11:58:59 -07:00
|
|
|
username := u.Username()
|
|
|
|
|
password, _ := u.Password()
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
forkReq()
|
2019-10-13 15:07:06 -07:00
|
|
|
req.Header = cloneOrMakeHeader(ireq.Header)
|
2013-08-07 11:58:59 -07:00
|
|
|
req.Header.Set("Authorization", "Basic "+basicAuth(username, password))
|
2009-12-15 16:27:45 -08:00
|
|
|
}
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
|
|
|
|
|
if !deadline.IsZero() {
|
|
|
|
|
forkReq()
|
|
|
|
|
}
|
2016-11-01 00:44:48 -07:00
|
|
|
stopTimer, didTimeout := setRequestCancel(req, rt, deadline)
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
|
2016-12-14 18:57:13 +00:00
|
|
|
resp, err = rt.RoundTrip(req)
|
2012-06-19 09:10:14 -07:00
|
|
|
if err != nil {
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
stopTimer()
|
2012-06-19 09:10:14 -07:00
|
|
|
if resp != nil {
|
|
|
|
|
log.Printf("RoundTripper returned a response & error; ignoring response")
|
|
|
|
|
}
|
2015-10-20 00:35:42 -07:00
|
|
|
if tlsErr, ok := err.(tls.RecordHeaderError); ok {
|
|
|
|
|
// If we get a bad TLS record header, check to see if the
|
|
|
|
|
// response looks like HTTP and give a more helpful error.
|
|
|
|
|
// See golang.org/issue/11111.
|
|
|
|
|
if string(tlsErr.RecordHeader[:]) == "HTTP/" {
|
|
|
|
|
err = errors.New("http: server gave HTTP response to HTTPS client")
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-12-14 18:57:13 +00:00
|
|
|
return nil, didTimeout, err
|
2012-06-19 09:10:14 -07:00
|
|
|
}
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
if !deadline.IsZero() {
|
|
|
|
|
resp.Body = &cancelTimerBody{
|
2016-11-01 00:44:48 -07:00
|
|
|
stop: stopTimer,
|
|
|
|
|
rc: resp.Body,
|
|
|
|
|
reqDidTimeout: didTimeout,
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-12-14 18:57:13 +00:00
|
|
|
return resp, nil, nil
|
2009-06-09 10:58:58 -07:00
|
|
|
}
|
|
|
|
|
|
2019-05-07 16:25:05 -07:00
|
|
|
// timeBeforeContextDeadline reports whether the non-zero Time t is
|
|
|
|
|
// before ctx's deadline, if any. If ctx does not have a deadline, it
|
|
|
|
|
// always reports true (the deadline is considered infinite).
|
|
|
|
|
func timeBeforeContextDeadline(t time.Time, ctx context.Context) bool {
|
|
|
|
|
d, ok := ctx.Deadline()
|
|
|
|
|
if !ok {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return t.Before(d)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// knownRoundTripperImpl reports whether rt is a RoundTripper that's
|
|
|
|
|
// maintained by the Go team and known to implement the latest
|
|
|
|
|
// optional semantics (notably contexts).
|
|
|
|
|
func knownRoundTripperImpl(rt RoundTripper) bool {
|
|
|
|
|
switch rt.(type) {
|
|
|
|
|
case *Transport, *http2Transport:
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
// There's a very minor chance of a false positive with this.
|
|
|
|
|
// Insted of detecting our golang.org/x/net/http2.Transport,
|
|
|
|
|
// it might detect a Transport type in a different http2
|
|
|
|
|
// package. But I know of none, and the only problem would be
|
|
|
|
|
// some temporarily leaked goroutines if the transport didn't
|
|
|
|
|
// support contexts. So this is a good enough heuristic:
|
|
|
|
|
if reflect.TypeOf(rt).String() == "*http2.Transport" {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// setRequestCancel sets req.Cancel and adds a deadline context to req
|
|
|
|
|
// if deadline is non-zero. The RoundTripper's type is used to
|
|
|
|
|
// determine whether the legacy CancelRequest behavior should be used.
|
2016-12-13 00:12:19 +00:00
|
|
|
//
|
|
|
|
|
// As background, there are three ways to cancel a request:
|
|
|
|
|
// First was Transport.CancelRequest. (deprecated)
|
2019-05-07 16:25:05 -07:00
|
|
|
// Second was Request.Cancel.
|
2016-12-13 00:12:19 +00:00
|
|
|
// Third was Request.Context.
|
2019-05-07 16:25:05 -07:00
|
|
|
// This function populates the second and third, and uses the first if it really needs to.
|
2016-11-01 00:44:48 -07:00
|
|
|
func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTimer func(), didTimeout func() bool) {
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
if deadline.IsZero() {
|
|
|
|
|
return nop, alwaysFalse
|
|
|
|
|
}
|
2019-05-07 16:25:05 -07:00
|
|
|
knownTransport := knownRoundTripperImpl(rt)
|
|
|
|
|
oldCtx := req.Context()
|
|
|
|
|
|
|
|
|
|
if req.Cancel == nil && knownTransport {
|
|
|
|
|
// If they already had a Request.Context that's
|
|
|
|
|
// expiring sooner, do nothing:
|
|
|
|
|
if !timeBeforeContextDeadline(deadline, oldCtx) {
|
|
|
|
|
return nop, alwaysFalse
|
|
|
|
|
}
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
|
2019-05-07 16:25:05 -07:00
|
|
|
var cancelCtx func()
|
|
|
|
|
req.ctx, cancelCtx = context.WithDeadline(oldCtx, deadline)
|
|
|
|
|
return cancelCtx, func() bool { return time.Now().After(deadline) }
|
|
|
|
|
}
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
initialReqCancel := req.Cancel // the user's original Request.Cancel, if any
|
|
|
|
|
|
2019-05-07 16:25:05 -07:00
|
|
|
var cancelCtx func()
|
|
|
|
|
if oldCtx := req.Context(); timeBeforeContextDeadline(deadline, oldCtx) {
|
|
|
|
|
req.ctx, cancelCtx = context.WithDeadline(oldCtx, deadline)
|
|
|
|
|
}
|
|
|
|
|
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
cancel := make(chan struct{})
|
|
|
|
|
req.Cancel = cancel
|
|
|
|
|
|
|
|
|
|
doCancel := func() {
|
2019-05-07 16:25:05 -07:00
|
|
|
// The second way in the func comment above:
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
close(cancel)
|
2019-05-07 16:25:05 -07:00
|
|
|
// The first way, used only for RoundTripper
|
|
|
|
|
// implementations written before Go 1.5 or Go 1.6.
|
|
|
|
|
type canceler interface{ CancelRequest(*Request) }
|
|
|
|
|
if v, ok := rt.(canceler); ok {
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
v.CancelRequest(req)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stopTimerCh := make(chan struct{})
|
|
|
|
|
var once sync.Once
|
2019-05-07 16:25:05 -07:00
|
|
|
stopTimer = func() {
|
|
|
|
|
once.Do(func() {
|
|
|
|
|
close(stopTimerCh)
|
|
|
|
|
if cancelCtx != nil {
|
|
|
|
|
cancelCtx()
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
|
2016-08-30 01:05:18 +00:00
|
|
|
timer := time.NewTimer(time.Until(deadline))
|
2016-11-01 00:44:48 -07:00
|
|
|
var timedOut atomicBool
|
|
|
|
|
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
go func() {
|
|
|
|
|
select {
|
|
|
|
|
case <-initialReqCancel:
|
|
|
|
|
doCancel()
|
2016-08-30 01:09:32 +00:00
|
|
|
timer.Stop()
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
case <-timer.C:
|
2016-11-01 00:44:48 -07:00
|
|
|
timedOut.setTrue()
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
doCancel()
|
|
|
|
|
case <-stopTimerCh:
|
|
|
|
|
timer.Stop()
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
2016-11-01 00:44:48 -07:00
|
|
|
return stopTimer, timedOut.isSet
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
}
|
|
|
|
|
|
2018-06-01 17:29:59 -03:00
|
|
|
// See 2 (end of page 4) https://www.ietf.org/rfc/rfc2617.txt
|
2013-08-07 11:58:59 -07:00
|
|
|
// "To receive authorization, the client sends the userid and password,
|
|
|
|
|
// separated by a single colon (":") character, within a base64
|
|
|
|
|
// encoded string in the credentials."
|
|
|
|
|
// It is not meant to be urlencoded.
|
|
|
|
|
func basicAuth(username, password string) string {
|
|
|
|
|
auth := username + ":" + password
|
|
|
|
|
return base64.StdEncoding.EncodeToString([]byte(auth))
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-27 18:55:21 -07:00
|
|
|
// Get issues a GET to the specified URL. If the response is one of
|
|
|
|
|
// the following redirect codes, Get follows the redirect, up to a
|
|
|
|
|
// maximum of 10 redirects:
|
2009-06-09 10:58:58 -07:00
|
|
|
//
|
|
|
|
|
// 301 (Moved Permanently)
|
|
|
|
|
// 302 (Found)
|
|
|
|
|
// 303 (See Other)
|
|
|
|
|
// 307 (Temporary Redirect)
|
2016-09-26 20:38:57 -07:00
|
|
|
// 308 (Permanent Redirect)
|
2009-06-09 10:58:58 -07:00
|
|
|
//
|
2012-06-19 09:10:14 -07:00
|
|
|
// An error is returned if there were too many redirects or if there
|
|
|
|
|
// was an HTTP protocol error. A non-2xx response doesn't cause an
|
2018-07-24 00:24:49 +00:00
|
|
|
// error. Any returned error will be of type *url.Error. The url.Error
|
|
|
|
|
// value's Timeout method will report true if request timed out or was
|
|
|
|
|
// canceled.
|
2012-06-19 09:10:14 -07:00
|
|
|
//
|
|
|
|
|
// When err is nil, resp always contains a non-nil resp.Body.
|
|
|
|
|
// Caller should close resp.Body when done reading from it.
|
2011-02-23 12:20:50 -08:00
|
|
|
//
|
2011-11-03 20:37:02 -07:00
|
|
|
// Get is a wrapper around DefaultClient.Get.
|
2015-04-27 18:55:21 -07:00
|
|
|
//
|
|
|
|
|
// To make a request with custom headers, use NewRequest and
|
|
|
|
|
// DefaultClient.Do.
|
2012-06-19 09:10:14 -07:00
|
|
|
func Get(url string) (resp *Response, err error) {
|
2011-02-23 12:20:50 -08:00
|
|
|
return DefaultClient.Get(url)
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-27 18:55:21 -07:00
|
|
|
// Get issues a GET to the specified URL. If the response is one of the
|
2011-04-25 22:41:50 -07:00
|
|
|
// following redirect codes, Get follows the redirect after calling the
|
2015-06-23 11:36:57 -07:00
|
|
|
// Client's CheckRedirect function:
|
2011-02-23 12:20:50 -08:00
|
|
|
//
|
|
|
|
|
// 301 (Moved Permanently)
|
|
|
|
|
// 302 (Found)
|
|
|
|
|
// 303 (See Other)
|
|
|
|
|
// 307 (Temporary Redirect)
|
2016-09-26 20:38:57 -07:00
|
|
|
// 308 (Permanent Redirect)
|
2011-02-23 12:20:50 -08:00
|
|
|
//
|
2012-06-19 09:10:14 -07:00
|
|
|
// An error is returned if the Client's CheckRedirect function fails
|
|
|
|
|
// or if there was an HTTP protocol error. A non-2xx response doesn't
|
2018-07-24 00:24:49 +00:00
|
|
|
// cause an error. Any returned error will be of type *url.Error. The
|
2019-10-11 20:27:33 -04:00
|
|
|
// url.Error value's Timeout method will report true if the request
|
|
|
|
|
// timed out.
|
2012-06-19 09:10:14 -07:00
|
|
|
//
|
|
|
|
|
// When err is nil, resp always contains a non-nil resp.Body.
|
|
|
|
|
// Caller should close resp.Body when done reading from it.
|
2015-04-27 18:55:21 -07:00
|
|
|
//
|
|
|
|
|
// To make a request with custom headers, use NewRequest and Client.Do.
|
2012-06-19 09:10:14 -07:00
|
|
|
func (c *Client) Get(url string) (resp *Response, err error) {
|
2011-05-18 17:17:26 -07:00
|
|
|
req, err := NewRequest("GET", url, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2016-09-26 20:38:57 -07:00
|
|
|
return c.Do(req)
|
2011-05-13 08:17:59 -07:00
|
|
|
}
|
|
|
|
|
|
2014-12-20 15:46:09 +11:00
|
|
|
func alwaysFalse() bool { return false }
|
|
|
|
|
|
2016-05-18 15:42:54 +00:00
|
|
|
// ErrUseLastResponse can be returned by Client.CheckRedirect hooks to
|
|
|
|
|
// control how redirects are processed. If returned, the next request
|
|
|
|
|
// is not sent and the most recent response is returned with its body
|
|
|
|
|
// unclosed.
|
|
|
|
|
var ErrUseLastResponse = errors.New("net/http: use last response")
|
|
|
|
|
|
2016-03-31 05:36:20 -07:00
|
|
|
// checkRedirect calls either the user's configured CheckRedirect
|
|
|
|
|
// function, or the default.
|
|
|
|
|
func (c *Client) checkRedirect(req *Request, via []*Request) error {
|
|
|
|
|
fn := c.CheckRedirect
|
|
|
|
|
if fn == nil {
|
|
|
|
|
fn = defaultCheckRedirect
|
2011-04-25 22:41:50 -07:00
|
|
|
}
|
2016-03-31 05:36:20 -07:00
|
|
|
return fn(req, via)
|
|
|
|
|
}
|
2009-06-09 10:58:58 -07:00
|
|
|
|
2016-09-26 20:38:57 -07:00
|
|
|
// redirectBehavior describes what should happen when the
|
|
|
|
|
// client encounters a 3xx status code from the server
|
2017-01-24 17:52:54 +00:00
|
|
|
func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirectMethod string, shouldRedirect, includeBody bool) {
|
2016-11-03 21:17:45 -07:00
|
|
|
switch resp.StatusCode {
|
2016-09-26 20:38:57 -07:00
|
|
|
case 301, 302, 303:
|
2017-01-09 01:00:36 -08:00
|
|
|
redirectMethod = reqMethod
|
2016-11-03 21:17:45 -07:00
|
|
|
shouldRedirect = true
|
2017-01-24 17:52:54 +00:00
|
|
|
includeBody = false
|
2017-01-09 01:00:36 -08:00
|
|
|
|
|
|
|
|
// RFC 2616 allowed automatic redirection only with GET and
|
|
|
|
|
// HEAD requests. RFC 7231 lifts this restriction, but we still
|
|
|
|
|
// restrict other methods to GET to maintain compatibility.
|
|
|
|
|
// See Issue 18570.
|
|
|
|
|
if reqMethod != "GET" && reqMethod != "HEAD" {
|
|
|
|
|
redirectMethod = "GET"
|
|
|
|
|
}
|
2016-09-26 20:38:57 -07:00
|
|
|
case 307, 308:
|
|
|
|
|
redirectMethod = reqMethod
|
2016-11-03 21:17:45 -07:00
|
|
|
shouldRedirect = true
|
2017-01-24 17:52:54 +00:00
|
|
|
includeBody = true
|
2016-11-03 21:17:45 -07:00
|
|
|
|
|
|
|
|
// Treat 307 and 308 specially, since they're new in
|
|
|
|
|
// Go 1.8, and they also require re-sending the request body.
|
2017-01-09 01:00:36 -08:00
|
|
|
if resp.Header.Get("Location") == "" {
|
2016-11-03 21:17:45 -07:00
|
|
|
// 308s have been observed in the wild being served
|
|
|
|
|
// without Location headers. Since Go 1.7 and earlier
|
|
|
|
|
// didn't follow these codes, just stop here instead
|
|
|
|
|
// of returning an error.
|
|
|
|
|
// See Issue 17773.
|
|
|
|
|
shouldRedirect = false
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
|
|
|
|
|
// We had a request body, and 307/308 require
|
|
|
|
|
// re-sending it, but GetBody is not defined. So just
|
|
|
|
|
// return this response to the user instead of an
|
|
|
|
|
// error, like we did in Go 1.7 and earlier.
|
|
|
|
|
shouldRedirect = false
|
|
|
|
|
}
|
2016-09-26 20:38:57 -07:00
|
|
|
}
|
2017-01-24 17:52:54 +00:00
|
|
|
return redirectMethod, shouldRedirect, includeBody
|
2016-09-26 20:38:57 -07:00
|
|
|
}
|
|
|
|
|
|
2018-07-24 00:24:49 +00:00
|
|
|
// urlErrorOp returns the (*url.Error).Op value to use for the
|
|
|
|
|
// provided (*Request).Method value.
|
|
|
|
|
func urlErrorOp(method string) string {
|
|
|
|
|
if method == "" {
|
|
|
|
|
return "Get"
|
|
|
|
|
}
|
|
|
|
|
return method[:1] + strings.ToLower(method[1:])
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 20:38:57 -07:00
|
|
|
// Do sends an HTTP request and returns an HTTP response, following
|
|
|
|
|
// policy (such as redirects, cookies, auth) as configured on the
|
|
|
|
|
// client.
|
|
|
|
|
//
|
|
|
|
|
// An error is returned if caused by client policy (such as
|
|
|
|
|
// CheckRedirect), or failure to speak HTTP (such as a network
|
|
|
|
|
// connectivity problem). A non-2xx status code doesn't cause an
|
|
|
|
|
// error.
|
|
|
|
|
//
|
|
|
|
|
// If the returned error is nil, the Response will contain a non-nil
|
2019-01-17 15:22:47 -08:00
|
|
|
// Body which the user is expected to close. If the Body is not both
|
|
|
|
|
// read to EOF and closed, the Client's underlying RoundTripper
|
|
|
|
|
// (typically Transport) may not be able to re-use a persistent TCP
|
|
|
|
|
// connection to the server for a subsequent "keep-alive" request.
|
2016-09-26 20:38:57 -07:00
|
|
|
//
|
|
|
|
|
// The request Body, if non-nil, will be closed by the underlying
|
|
|
|
|
// Transport, even on errors.
|
|
|
|
|
//
|
|
|
|
|
// On error, any Response can be ignored. A non-nil Response with a
|
|
|
|
|
// non-nil error only occurs when CheckRedirect fails, and even then
|
|
|
|
|
// the returned Response.Body is already closed.
|
|
|
|
|
//
|
|
|
|
|
// Generally Get, Post, or PostForm will be used instead of Do.
|
2016-12-20 17:59:37 +00:00
|
|
|
//
|
|
|
|
|
// If the server replies with a redirect, the Client first uses the
|
|
|
|
|
// CheckRedirect function to determine whether the redirect should be
|
|
|
|
|
// followed. If permitted, a 301, 302, or 303 redirect causes
|
2017-01-09 01:00:36 -08:00
|
|
|
// subsequent requests to use HTTP method GET
|
|
|
|
|
// (or HEAD if the original request was HEAD), with no body.
|
2016-12-20 17:59:37 +00:00
|
|
|
// A 307 or 308 redirect preserves the original HTTP method and body,
|
|
|
|
|
// provided that the Request.GetBody function is defined.
|
|
|
|
|
// The NewRequest function automatically sets GetBody for common
|
|
|
|
|
// standard library body types.
|
2018-07-24 00:24:49 +00:00
|
|
|
//
|
|
|
|
|
// Any returned error will be of type *url.Error. The url.Error
|
|
|
|
|
// value's Timeout method will report true if request timed out or was
|
|
|
|
|
// canceled.
|
2016-09-26 20:38:57 -07:00
|
|
|
func (c *Client) Do(req *Request) (*Response, error) {
|
2018-07-24 00:24:49 +00:00
|
|
|
return c.do(req)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var testHookClientDoResult func(retres *Response, reterr error)
|
|
|
|
|
|
|
|
|
|
func (c *Client) do(req *Request) (retres *Response, reterr error) {
|
|
|
|
|
if testHookClientDoResult != nil {
|
|
|
|
|
defer func() { testHookClientDoResult(retres, reterr) }()
|
|
|
|
|
}
|
2016-03-31 05:36:20 -07:00
|
|
|
if req.URL == nil {
|
|
|
|
|
req.closeBody()
|
2018-07-24 00:24:49 +00:00
|
|
|
return nil, &url.Error{
|
|
|
|
|
Op: urlErrorOp(req.Method),
|
|
|
|
|
Err: errors.New("http: nil Request.URL"),
|
|
|
|
|
}
|
2011-10-14 17:09:38 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 05:36:20 -07:00
|
|
|
var (
|
2017-02-20 20:07:44 -08:00
|
|
|
deadline = c.deadline()
|
|
|
|
|
reqs []*Request
|
|
|
|
|
resp *Response
|
|
|
|
|
copyHeaders = c.makeHeadersCopier(req)
|
|
|
|
|
reqBodyClosed = false // have we closed the current req.Body?
|
2017-01-24 17:52:54 +00:00
|
|
|
|
|
|
|
|
// Redirect behavior:
|
2016-09-26 20:38:57 -07:00
|
|
|
redirectMethod string
|
2017-01-24 17:52:54 +00:00
|
|
|
includeBody bool
|
2016-03-31 05:36:20 -07:00
|
|
|
)
|
|
|
|
|
uerr := func(err error) error {
|
2017-02-20 20:07:44 -08:00
|
|
|
// the body may have been closed already by c.send()
|
|
|
|
|
if !reqBodyClosed {
|
|
|
|
|
req.closeBody()
|
|
|
|
|
}
|
2016-03-31 05:36:20 -07:00
|
|
|
var urlStr string
|
2016-05-06 18:11:38 +00:00
|
|
|
if resp != nil && resp.Request != nil {
|
2018-03-28 11:44:10 +03:00
|
|
|
urlStr = stripPassword(resp.Request.URL)
|
2016-03-31 05:36:20 -07:00
|
|
|
} else {
|
2018-03-28 11:44:10 +03:00
|
|
|
urlStr = stripPassword(req.URL)
|
2016-03-31 05:36:20 -07:00
|
|
|
}
|
|
|
|
|
return &url.Error{
|
2018-07-24 00:24:49 +00:00
|
|
|
Op: urlErrorOp(reqs[0].Method),
|
2016-03-31 05:36:20 -07:00
|
|
|
URL: urlStr,
|
|
|
|
|
Err: err,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for {
|
|
|
|
|
// For all but the first request, create the next
|
|
|
|
|
// request hop and replace req.
|
|
|
|
|
if len(reqs) > 0 {
|
|
|
|
|
loc := resp.Header.Get("Location")
|
|
|
|
|
if loc == "" {
|
2017-04-18 10:57:12 +08:00
|
|
|
resp.closeBody()
|
2016-03-31 05:36:20 -07:00
|
|
|
return nil, uerr(fmt.Errorf("%d response missing Location header", resp.StatusCode))
|
2012-12-12 11:09:55 -08:00
|
|
|
}
|
2016-03-31 05:36:20 -07:00
|
|
|
u, err := req.URL.Parse(loc)
|
2011-04-25 22:41:50 -07:00
|
|
|
if err != nil {
|
2017-04-18 10:57:12 +08:00
|
|
|
resp.closeBody()
|
2016-03-31 05:36:20 -07:00
|
|
|
return nil, uerr(fmt.Errorf("failed to parse Location header %q: %v", loc, err))
|
2011-04-25 22:41:50 -07:00
|
|
|
}
|
2017-10-13 15:56:37 -07:00
|
|
|
host := ""
|
|
|
|
|
if req.Host != "" && req.Host != req.URL.Host {
|
|
|
|
|
// If the caller specified a custom Host header and the
|
|
|
|
|
// redirect location is relative, preserve the Host header
|
|
|
|
|
// through the redirect. See issue #22233.
|
|
|
|
|
if u, _ := url.Parse(loc); u != nil && !u.IsAbs() {
|
|
|
|
|
host = req.Host
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-31 05:36:20 -07:00
|
|
|
ireq := reqs[0]
|
|
|
|
|
req = &Request{
|
2016-09-26 20:38:57 -07:00
|
|
|
Method: redirectMethod,
|
2016-05-18 15:42:54 +00:00
|
|
|
Response: resp,
|
|
|
|
|
URL: u,
|
|
|
|
|
Header: make(Header),
|
2017-10-13 15:56:37 -07:00
|
|
|
Host: host,
|
2016-05-18 15:42:54 +00:00
|
|
|
Cancel: ireq.Cancel,
|
|
|
|
|
ctx: ireq.ctx,
|
2016-03-31 05:36:20 -07:00
|
|
|
}
|
2017-01-24 17:52:54 +00:00
|
|
|
if includeBody && ireq.GetBody != nil {
|
2016-10-21 12:03:41 +01:00
|
|
|
req.Body, err = ireq.GetBody()
|
|
|
|
|
if err != nil {
|
2017-04-18 10:57:12 +08:00
|
|
|
resp.closeBody()
|
2016-10-21 12:03:41 +01:00
|
|
|
return nil, uerr(err)
|
|
|
|
|
}
|
2016-09-26 20:38:57 -07:00
|
|
|
req.ContentLength = ireq.ContentLength
|
2016-03-31 05:36:20 -07:00
|
|
|
}
|
2016-10-18 14:56:19 -07:00
|
|
|
|
|
|
|
|
// Copy original headers before setting the Referer,
|
|
|
|
|
// in case the user set Referer on their first request.
|
|
|
|
|
// If they really want to override, they can do it in
|
2016-09-09 18:06:56 +00:00
|
|
|
// their CheckRedirect func.
|
2016-10-18 14:56:19 -07:00
|
|
|
copyHeaders(req)
|
|
|
|
|
|
2016-03-31 05:36:20 -07:00
|
|
|
// Add the Referer header from the most recent
|
|
|
|
|
// request URL to the new one, if it's not https->http:
|
|
|
|
|
if ref := refererForURL(reqs[len(reqs)-1].URL, req.URL); ref != "" {
|
|
|
|
|
req.Header.Set("Referer", ref)
|
|
|
|
|
}
|
2016-05-18 15:42:54 +00:00
|
|
|
err = c.checkRedirect(req, reqs)
|
|
|
|
|
|
|
|
|
|
// Sentinel error to let users select the
|
|
|
|
|
// previous response, without closing its
|
|
|
|
|
// body. See Issue 10069.
|
|
|
|
|
if err == ErrUseLastResponse {
|
|
|
|
|
return resp, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close the previous response's body. But
|
|
|
|
|
// read at least some of the body so if it's
|
|
|
|
|
// small the underlying TCP connection will be
|
|
|
|
|
// re-used. No need to check for errors: if it
|
|
|
|
|
// fails, the Transport won't reuse it anyway.
|
|
|
|
|
const maxBodySlurpSize = 2 << 10
|
|
|
|
|
if resp.ContentLength == -1 || resp.ContentLength <= maxBodySlurpSize {
|
|
|
|
|
io.CopyN(ioutil.Discard, resp.Body, maxBodySlurpSize)
|
|
|
|
|
}
|
|
|
|
|
resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if err != nil {
|
2016-03-31 05:36:20 -07:00
|
|
|
// Special case for Go 1 compatibility: return both the response
|
|
|
|
|
// and an error if the CheckRedirect function failed.
|
|
|
|
|
// See https://golang.org/issue/3795
|
|
|
|
|
// The resp.Body has already been closed.
|
|
|
|
|
ue := uerr(err)
|
|
|
|
|
ue.(*url.Error).URL = loc
|
|
|
|
|
return resp, ue
|
2011-05-18 17:17:26 -07:00
|
|
|
}
|
2011-04-25 22:41:50 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-31 05:36:20 -07:00
|
|
|
reqs = append(reqs, req)
|
|
|
|
|
var err error
|
2016-12-14 18:57:13 +00:00
|
|
|
var didTimeout func() bool
|
|
|
|
|
if resp, didTimeout, err = c.send(req, deadline); err != nil {
|
2017-02-20 20:07:44 -08:00
|
|
|
// c.send() always closes req.Body
|
|
|
|
|
reqBodyClosed = true
|
2016-12-14 18:57:13 +00:00
|
|
|
if !deadline.IsZero() && didTimeout() {
|
2014-12-20 15:46:09 +11:00
|
|
|
err = &httpError{
|
2019-03-28 16:15:14 -07:00
|
|
|
// TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancellation/
|
2014-12-20 15:46:09 +11:00
|
|
|
err: err.Error() + " (Client.Timeout exceeded while awaiting headers)",
|
|
|
|
|
timeout: true,
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-03-31 05:36:20 -07:00
|
|
|
return nil, uerr(err)
|
2009-06-09 10:58:58 -07:00
|
|
|
}
|
2011-12-16 10:48:41 -05:00
|
|
|
|
2016-09-26 20:38:57 -07:00
|
|
|
var shouldRedirect bool
|
2017-01-24 17:52:54 +00:00
|
|
|
redirectMethod, shouldRedirect, includeBody = redirectBehavior(req.Method, resp, reqs[0])
|
2016-09-26 20:38:57 -07:00
|
|
|
if !shouldRedirect {
|
2016-03-31 05:36:20 -07:00
|
|
|
return resp, nil
|
2009-06-09 10:58:58 -07:00
|
|
|
}
|
2016-09-26 20:38:57 -07:00
|
|
|
|
|
|
|
|
req.closeBody()
|
2012-07-18 13:48:39 -07:00
|
|
|
}
|
2009-06-09 10:58:58 -07:00
|
|
|
}
|
|
|
|
|
|
2016-10-18 14:56:19 -07:00
|
|
|
// makeHeadersCopier makes a function that copies headers from the
|
|
|
|
|
// initial Request, ireq. For every redirect, this function must be called
|
|
|
|
|
// so that it can copy headers into the upcoming Request.
|
|
|
|
|
func (c *Client) makeHeadersCopier(ireq *Request) func(*Request) {
|
|
|
|
|
// The headers to copy are from the very initial request.
|
|
|
|
|
// We use a closured callback to keep a reference to these original headers.
|
|
|
|
|
var (
|
2019-10-13 15:07:06 -07:00
|
|
|
ireqhdr = cloneOrMakeHeader(ireq.Header)
|
2016-10-18 14:56:19 -07:00
|
|
|
icookies map[string][]*Cookie
|
|
|
|
|
)
|
|
|
|
|
if c.Jar != nil && ireq.Header.Get("Cookie") != "" {
|
|
|
|
|
icookies = make(map[string][]*Cookie)
|
|
|
|
|
for _, c := range ireq.Cookies() {
|
|
|
|
|
icookies[c.Name] = append(icookies[c.Name], c)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
preq := ireq // The previous request
|
|
|
|
|
return func(req *Request) {
|
|
|
|
|
// If Jar is present and there was some initial cookies provided
|
|
|
|
|
// via the request header, then we may need to alter the initial
|
|
|
|
|
// cookies as we follow redirects since each redirect may end up
|
|
|
|
|
// modifying a pre-existing cookie.
|
|
|
|
|
//
|
|
|
|
|
// Since cookies already set in the request header do not contain
|
|
|
|
|
// information about the original domain and path, the logic below
|
|
|
|
|
// assumes any new set cookies override the original cookie
|
|
|
|
|
// regardless of domain or path.
|
|
|
|
|
//
|
|
|
|
|
// See https://golang.org/issue/17494
|
|
|
|
|
if c.Jar != nil && icookies != nil {
|
|
|
|
|
var changed bool
|
|
|
|
|
resp := req.Response // The response that caused the upcoming redirect
|
|
|
|
|
for _, c := range resp.Cookies() {
|
|
|
|
|
if _, ok := icookies[c.Name]; ok {
|
|
|
|
|
delete(icookies, c.Name)
|
|
|
|
|
changed = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if changed {
|
|
|
|
|
ireqhdr.Del("Cookie")
|
|
|
|
|
var ss []string
|
|
|
|
|
for _, cs := range icookies {
|
|
|
|
|
for _, c := range cs {
|
|
|
|
|
ss = append(ss, c.Name+"="+c.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(ss) // Ensure deterministic headers
|
|
|
|
|
ireqhdr.Set("Cookie", strings.Join(ss, "; "))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy the initial request's Header values
|
|
|
|
|
// (at least the safe ones).
|
|
|
|
|
for k, vv := range ireqhdr {
|
|
|
|
|
if shouldCopyHeaderOnRedirect(k, preq.URL, req.URL) {
|
|
|
|
|
req.Header[k] = vv
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
preq = req // Update previous Request with the current request
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-01 22:04:37 -04:00
|
|
|
func defaultCheckRedirect(req *Request, via []*Request) error {
|
2011-04-25 22:41:50 -07:00
|
|
|
if len(via) >= 10 {
|
2011-11-01 22:04:37 -04:00
|
|
|
return errors.New("stopped after 10 redirects")
|
2011-04-25 22:41:50 -07:00
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-09 10:58:58 -07:00
|
|
|
// Post issues a POST to the specified URL.
|
|
|
|
|
//
|
2012-06-19 09:10:14 -07:00
|
|
|
// Caller should close resp.Body when done reading from it.
|
2011-02-23 12:20:50 -08:00
|
|
|
//
|
2015-04-27 18:55:21 -07:00
|
|
|
// If the provided body is an io.Closer, it is closed after the
|
|
|
|
|
// request.
|
|
|
|
|
//
|
|
|
|
|
// Post is a wrapper around DefaultClient.Post.
|
|
|
|
|
//
|
|
|
|
|
// To set custom headers, use NewRequest and DefaultClient.Do.
|
2016-12-20 17:59:37 +00:00
|
|
|
//
|
|
|
|
|
// See the Client.Do method documentation for details on how redirects
|
|
|
|
|
// are handled.
|
2018-04-21 16:46:27 +00:00
|
|
|
func Post(url, contentType string, body io.Reader) (resp *Response, err error) {
|
2016-09-16 15:25:07 -07:00
|
|
|
return DefaultClient.Post(url, contentType, body)
|
2011-02-23 12:20:50 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Post issues a POST to the specified URL.
|
|
|
|
|
//
|
2012-06-19 09:10:14 -07:00
|
|
|
// Caller should close resp.Body when done reading from it.
|
2013-07-19 12:02:54 +10:00
|
|
|
//
|
2015-04-27 18:55:21 -07:00
|
|
|
// If the provided body is an io.Closer, it is closed after the
|
2014-04-14 08:06:13 -07:00
|
|
|
// request.
|
2015-04-27 18:55:21 -07:00
|
|
|
//
|
|
|
|
|
// To set custom headers, use NewRequest and Client.Do.
|
2016-12-20 17:59:37 +00:00
|
|
|
//
|
|
|
|
|
// See the Client.Do method documentation for details on how redirects
|
|
|
|
|
// are handled.
|
2018-04-21 16:46:27 +00:00
|
|
|
func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response, err error) {
|
2011-05-31 08:47:03 -07:00
|
|
|
req, err := NewRequest("POST", url, body)
|
2009-06-09 10:58:58 -07:00
|
|
|
if err != nil {
|
2009-11-09 12:07:39 -08:00
|
|
|
return nil, err
|
2009-06-09 10:58:58 -07:00
|
|
|
}
|
2016-09-16 15:25:07 -07:00
|
|
|
req.Header.Set("Content-Type", contentType)
|
2016-09-26 20:38:57 -07:00
|
|
|
return c.Do(req)
|
2009-06-09 10:58:58 -07:00
|
|
|
}
|
2010-01-25 18:49:08 -08:00
|
|
|
|
2012-06-19 09:10:14 -07:00
|
|
|
// PostForm issues a POST to the specified URL, with data's keys and
|
|
|
|
|
// values URL-encoded as the request body.
|
2010-09-02 10:01:34 +10:00
|
|
|
//
|
2015-04-27 18:55:21 -07:00
|
|
|
// The Content-Type header is set to application/x-www-form-urlencoded.
|
|
|
|
|
// To set other headers, use NewRequest and DefaultClient.Do.
|
|
|
|
|
//
|
2012-06-19 09:10:14 -07:00
|
|
|
// When err is nil, resp always contains a non-nil resp.Body.
|
|
|
|
|
// Caller should close resp.Body when done reading from it.
|
2011-02-23 12:20:50 -08:00
|
|
|
//
|
2015-04-27 18:55:21 -07:00
|
|
|
// PostForm is a wrapper around DefaultClient.PostForm.
|
2016-12-20 17:59:37 +00:00
|
|
|
//
|
|
|
|
|
// See the Client.Do method documentation for details on how redirects
|
|
|
|
|
// are handled.
|
2012-06-19 09:10:14 -07:00
|
|
|
func PostForm(url string, data url.Values) (resp *Response, err error) {
|
2011-02-23 12:20:50 -08:00
|
|
|
return DefaultClient.PostForm(url, data)
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-29 17:56:31 +01:00
|
|
|
// PostForm issues a POST to the specified URL,
|
2015-04-27 18:55:21 -07:00
|
|
|
// with data's keys and values URL-encoded as the request body.
|
|
|
|
|
//
|
|
|
|
|
// The Content-Type header is set to application/x-www-form-urlencoded.
|
2017-10-31 09:24:44 +00:00
|
|
|
// To set other headers, use NewRequest and Client.Do.
|
2011-02-23 12:20:50 -08:00
|
|
|
//
|
2012-06-19 09:10:14 -07:00
|
|
|
// When err is nil, resp always contains a non-nil resp.Body.
|
|
|
|
|
// Caller should close resp.Body when done reading from it.
|
2016-12-20 17:59:37 +00:00
|
|
|
//
|
|
|
|
|
// See the Client.Do method documentation for details on how redirects
|
|
|
|
|
// are handled.
|
2012-06-19 09:10:14 -07:00
|
|
|
func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
|
2011-06-08 13:38:20 -07:00
|
|
|
return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
2010-09-02 10:01:34 +10:00
|
|
|
}
|
|
|
|
|
|
2016-10-18 14:56:19 -07:00
|
|
|
// Head issues a HEAD to the specified URL. If the response is one of
|
2015-06-23 11:36:57 -07:00
|
|
|
// the following redirect codes, Head follows the redirect, up to a
|
|
|
|
|
// maximum of 10 redirects:
|
2011-05-13 08:17:59 -07:00
|
|
|
//
|
|
|
|
|
// 301 (Moved Permanently)
|
|
|
|
|
// 302 (Found)
|
|
|
|
|
// 303 (See Other)
|
|
|
|
|
// 307 (Temporary Redirect)
|
2016-09-26 20:38:57 -07:00
|
|
|
// 308 (Permanent Redirect)
|
2011-02-23 12:20:50 -08:00
|
|
|
//
|
|
|
|
|
// Head is a wrapper around DefaultClient.Head
|
2012-06-19 09:10:14 -07:00
|
|
|
func Head(url string) (resp *Response, err error) {
|
2011-02-23 12:20:50 -08:00
|
|
|
return DefaultClient.Head(url)
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 14:56:19 -07:00
|
|
|
// Head issues a HEAD to the specified URL. If the response is one of the
|
2011-05-13 08:17:59 -07:00
|
|
|
// following redirect codes, Head follows the redirect after calling the
|
2015-06-23 11:36:57 -07:00
|
|
|
// Client's CheckRedirect function:
|
2011-05-13 08:17:59 -07:00
|
|
|
//
|
|
|
|
|
// 301 (Moved Permanently)
|
|
|
|
|
// 302 (Found)
|
|
|
|
|
// 303 (See Other)
|
|
|
|
|
// 307 (Temporary Redirect)
|
2016-09-26 20:38:57 -07:00
|
|
|
// 308 (Permanent Redirect)
|
2012-06-19 09:10:14 -07:00
|
|
|
func (c *Client) Head(url string) (resp *Response, err error) {
|
2011-05-18 17:17:26 -07:00
|
|
|
req, err := NewRequest("HEAD", url, nil)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
2016-09-26 20:38:57 -07:00
|
|
|
return c.Do(req)
|
2010-06-08 01:28:40 +02:00
|
|
|
}
|
2014-03-02 20:39:20 -08:00
|
|
|
|
2018-08-20 21:04:15 +00:00
|
|
|
// CloseIdleConnections closes any connections on its Transport which
|
|
|
|
|
// were previously connected from previous requests but are now
|
|
|
|
|
// sitting idle in a "keep-alive" state. It does not interrupt any
|
|
|
|
|
// connections currently in use.
|
|
|
|
|
//
|
|
|
|
|
// If the Client's Transport does not have a CloseIdleConnections method
|
|
|
|
|
// then this method does nothing.
|
|
|
|
|
func (c *Client) CloseIdleConnections() {
|
|
|
|
|
type closeIdler interface {
|
|
|
|
|
CloseIdleConnections()
|
|
|
|
|
}
|
|
|
|
|
if tr, ok := c.transport().(closeIdler); ok {
|
|
|
|
|
tr.CloseIdleConnections()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-20 15:46:09 +11:00
|
|
|
// cancelTimerBody is an io.ReadCloser that wraps rc with two features:
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
// 1) on Read error or close, the stop func is called.
|
2016-11-01 00:44:48 -07:00
|
|
|
// 2) On Read failure, if reqDidTimeout is true, the error is wrapped and
|
2014-12-20 15:46:09 +11:00
|
|
|
// marked as net.Error that hit its timeout.
|
2014-03-02 20:39:20 -08:00
|
|
|
type cancelTimerBody struct {
|
2016-11-01 00:44:48 -07:00
|
|
|
stop func() // stops the time.Timer waiting to cancel the request
|
|
|
|
|
rc io.ReadCloser
|
|
|
|
|
reqDidTimeout func() bool
|
2014-03-02 20:39:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
|
|
|
|
|
n, err = b.rc.Read(p)
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
if err == nil {
|
|
|
|
|
return n, nil
|
|
|
|
|
}
|
|
|
|
|
b.stop()
|
2014-03-02 20:39:20 -08:00
|
|
|
if err == io.EOF {
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
return n, err
|
|
|
|
|
}
|
2016-11-01 00:44:48 -07:00
|
|
|
if b.reqDidTimeout() {
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
err = &httpError{
|
2019-05-07 16:25:05 -07:00
|
|
|
err: err.Error() + " (Client.Timeout or context cancellation while reading body)",
|
2014-12-20 15:46:09 +11:00
|
|
|
timeout: true,
|
|
|
|
|
}
|
2014-03-02 20:39:20 -08:00
|
|
|
}
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
return n, err
|
2014-03-02 20:39:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (b *cancelTimerBody) Close() error {
|
|
|
|
|
err := b.rc.Close()
|
net/http: make Client use Request.Cancel for timeouts instead of CancelRequest
In the beginning, there was no way to cancel an HTTP request.
We later added Transport.CancelRequest to cancel an in-flight HTTP
request by breaking its underlying TCP connection, but it was hard to
use correctly and didn't work in all cases. And its error messages
were terrible. Some of those issues were fixed over time, but the most
unfixable problem was that it didn't compose well. All RoundTripper
implementations had to choose to whether to implement CancelRequest
and both decisions had negative consequences.
In Go 1.5 we added Request.Cancel, which composed well, worked in all
phases, had nice error messages, etc. But we forgot to use it in the
implementation of Client.Timeout (a timeout which spans multiple
requests and reading request bodies).
In Go 1.6 (upcoming), we added HTTP/2 support, but now Client.Timeout
didn't work because the http2.Transport didn't have a CancelRequest
method.
Rather than add a CancelRequest method to http2, officially deprecate
it and update the only caller (Client, for Client.Cancel) to use
Request.Cancel instead.
The http2 Client timeout tests are enabled now.
For compatibility, we still use CancelRequest in Client if we don't
recognize the RoundTripper type. But documentation has been updated to
tell people that CancelRequest is deprecated.
Fixes #13540
Change-Id: I15546b90825bb8b54905e17563eca55ea2642075
Reviewed-on: https://go-review.googlesource.com/18260
Reviewed-by: Andrew Gerrand <adg@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-01-04 20:59:05 -08:00
|
|
|
b.stop()
|
2014-03-02 20:39:20 -08:00
|
|
|
return err
|
|
|
|
|
}
|
2016-09-09 18:06:56 +00:00
|
|
|
|
|
|
|
|
func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool {
|
|
|
|
|
switch CanonicalHeaderKey(headerKey) {
|
|
|
|
|
case "Authorization", "Www-Authenticate", "Cookie", "Cookie2":
|
|
|
|
|
// Permit sending auth/cookie headers from "foo.com"
|
|
|
|
|
// to "sub.foo.com".
|
|
|
|
|
|
|
|
|
|
// Note that we don't send all cookies to subdomains
|
|
|
|
|
// automatically. This function is only used for
|
|
|
|
|
// Cookies set explicitly on the initial outgoing
|
|
|
|
|
// client request. Cookies automatically added via the
|
|
|
|
|
// CookieJar mechanism continue to follow each
|
|
|
|
|
// cookie's scope as set by Set-Cookie. But for
|
|
|
|
|
// outgoing requests with the Cookie header set
|
|
|
|
|
// directly, we don't know their scope, so we assume
|
|
|
|
|
// it's for *.domain.com.
|
|
|
|
|
|
2017-09-04 09:28:27 -03:00
|
|
|
ihost := canonicalAddr(initial)
|
|
|
|
|
dhost := canonicalAddr(dest)
|
2016-09-09 18:06:56 +00:00
|
|
|
return isDomainOrSubdomain(dhost, ihost)
|
|
|
|
|
}
|
|
|
|
|
// All other headers are copied:
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// isDomainOrSubdomain reports whether sub is a subdomain (or exact
|
|
|
|
|
// match) of the parent domain.
|
|
|
|
|
//
|
|
|
|
|
// Both domains must already be in canonical form.
|
|
|
|
|
func isDomainOrSubdomain(sub, parent string) bool {
|
|
|
|
|
if sub == parent {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
// If sub is "foo.example.com" and parent is "example.com",
|
|
|
|
|
// that means sub must end in "."+parent.
|
|
|
|
|
// Do it without allocating.
|
|
|
|
|
if !strings.HasSuffix(sub, parent) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return sub[len(sub)-len(parent)-1] == '.'
|
|
|
|
|
}
|
2018-03-28 11:44:10 +03:00
|
|
|
|
|
|
|
|
func stripPassword(u *url.URL) string {
|
2019-05-03 11:41:54 +07:00
|
|
|
_, passSet := u.User.Password()
|
2018-03-28 11:44:10 +03:00
|
|
|
if passSet {
|
2019-05-03 11:41:54 +07:00
|
|
|
return strings.Replace(u.String(), u.User.String()+"@", u.User.Username()+":***@", 1)
|
2018-03-28 11:44:10 +03:00
|
|
|
}
|
|
|
|
|
return u.String()
|
|
|
|
|
}
|