github.com/aloncn/graphics-go@v0.0.1/src/net/http/client.go (about)

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