diff options
Diffstat (limited to 'libgo/go/net/http/client.go')
-rw-r--r-- | libgo/go/net/http/client.go | 73 |
1 files changed, 55 insertions, 18 deletions
diff --git a/libgo/go/net/http/client.go b/libgo/go/net/http/client.go index 6f6024e..8f69a29 100644 --- a/libgo/go/net/http/client.go +++ b/libgo/go/net/http/client.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// HTTP client. See RFC 2616. +// HTTP client. See RFC 7230 through 7235. // // This is the high-level Client interface. // The low-level implementation is in transport.go. @@ -95,14 +95,12 @@ type Client struct { // A Timeout of zero means no timeout. // // The Client cancels requests to the underlying Transport - // using the Request.Cancel mechanism. Requests passed - // to Client.Do may still set Request.Cancel; both will - // cancel the request. + // as if the Request's Context ended. // // For compatibility, the Client will also use the deprecated // CancelRequest method on Transport if found. New - // RoundTripper implementations should use Request.Cancel - // instead of implementing CancelRequest. + // RoundTripper implementations should use the Request's Context + // for cancelation instead of implementing CancelRequest. Timeout time.Duration } @@ -129,8 +127,8 @@ type RoundTripper interface { // RoundTrip should not modify the request, except for // consuming and closing the Request's Body. RoundTrip may // read fields of the request in a separate goroutine. Callers - // should not mutate the request until the Response's Body has - // been closed. + // should not mutate or reuse the request until the Response's + // Body has been closed. // // RoundTrip must always close the body, including on errors, // but depending on the implementation may do so in a separate @@ -335,7 +333,7 @@ func setRequestCancel(req *Request, rt RoundTripper, deadline time.Time) (stopTi return stopTimer, timedOut.isSet } -// See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt +// See 2 (end of page 4) https://www.ietf.org/rfc/rfc2617.txt // "To receive authorization, the client sends the userid and password, // separated by a single colon (":") character, within a base64 // encoded string in the credentials." @@ -357,7 +355,9 @@ func basicAuth(username, password string) string { // // 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 -// error. +// 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. // // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. @@ -382,7 +382,9 @@ func Get(url string) (resp *Response, err error) { // // 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 -// cause an error. +// cause an 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. // // When err is nil, resp always contains a non-nil resp.Body. // Caller should close resp.Body when done reading from it. @@ -457,6 +459,15 @@ func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirect return redirectMethod, shouldRedirect, includeBody } +// 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:]) +} + // Do sends an HTTP request and returns an HTTP response, following // policy (such as redirects, cookies, auth) as configured on the // client. @@ -490,10 +501,26 @@ func redirectBehavior(reqMethod string, resp *Response, ireq *Request) (redirect // provided that the Request.GetBody function is defined. // The NewRequest function automatically sets GetBody for common // standard library body types. +// +// 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. func (c *Client) Do(req *Request) (*Response, error) { + 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) }() + } if req.URL == nil { req.closeBody() - return nil, errors.New("http: nil Request.URL") + return nil, &url.Error{ + Op: urlErrorOp(req.Method), + Err: errors.New("http: nil Request.URL"), + } } var ( @@ -512,15 +539,14 @@ func (c *Client) Do(req *Request) (*Response, error) { if !reqBodyClosed { req.closeBody() } - method := valueOrDefault(reqs[0].Method, "GET") var urlStr string if resp != nil && resp.Request != nil { - urlStr = resp.Request.URL.String() + urlStr = stripPassword(resp.Request.URL) } else { - urlStr = req.URL.String() + urlStr = stripPassword(req.URL) } return &url.Error{ - Op: method[:1] + strings.ToLower(method[1:]), + Op: urlErrorOp(reqs[0].Method), URL: urlStr, Err: err, } @@ -617,6 +643,7 @@ func (c *Client) Do(req *Request) (*Response, error) { reqBodyClosed = true if !deadline.IsZero() && didTimeout() { err = &httpError{ + // TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancelation/ err: err.Error() + " (Client.Timeout exceeded while awaiting headers)", timeout: true, } @@ -718,7 +745,7 @@ func defaultCheckRedirect(req *Request, via []*Request) error { // // See the Client.Do method documentation for details on how redirects // are handled. -func Post(url string, contentType string, body io.Reader) (resp *Response, err error) { +func Post(url, contentType string, body io.Reader) (resp *Response, err error) { return DefaultClient.Post(url, contentType, body) } @@ -733,7 +760,7 @@ func Post(url string, contentType string, body io.Reader) (resp *Response, err e // // See the Client.Do method documentation for details on how redirects // are handled. -func (c *Client) Post(url string, contentType string, body io.Reader) (resp *Response, err error) { +func (c *Client) Post(url, contentType string, body io.Reader) (resp *Response, err error) { req, err := NewRequest("POST", url, body) if err != nil { return nil, err @@ -827,6 +854,7 @@ func (b *cancelTimerBody) Read(p []byte) (n int, err error) { } if b.reqDidTimeout() { err = &httpError{ + // TODO: early in cycle: s/Client.Timeout exceeded/timeout or context cancelation/ err: err.Error() + " (Client.Timeout exceeded while reading body)", timeout: true, } @@ -880,3 +908,12 @@ func isDomainOrSubdomain(sub, parent string) bool { } return sub[len(sub)-len(parent)-1] == '.' } + +func stripPassword(u *url.URL) string { + pass, passSet := u.User.Password() + if passSet { + return strings.Replace(u.String(), pass+"@", "***@", 1) + } + + return u.String() +} |