Run Format

Source file src/pkg/net/http/client.go

     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		"encoding/base64"
    14		"errors"
    15		"fmt"
    16		"io"
    17		"log"
    18		"net/url"
    19		"strings"
    20	)
    21	
    22	// A Client is an HTTP client. Its zero value (DefaultClient) is a
    23	// usable client that uses DefaultTransport.
    24	//
    25	// The Client's Transport typically has internal state (cached TCP
    26	// connections), so Clients should be reused instead of created as
    27	// needed. Clients are safe for concurrent use by multiple goroutines.
    28	//
    29	// A Client is higher-level than a RoundTripper (such as Transport)
    30	// and additionally handles HTTP details such as cookies and
    31	// redirects.
    32	type Client struct {
    33		// Transport specifies the mechanism by which individual
    34		// HTTP requests are made.
    35		// If nil, DefaultTransport is used.
    36		Transport RoundTripper
    37	
    38		// CheckRedirect specifies the policy for handling redirects.
    39		// If CheckRedirect is not nil, the client calls it before
    40		// following an HTTP redirect. The arguments req and via are
    41		// the upcoming request and the requests made already, oldest
    42		// first. If CheckRedirect returns an error, the Client's Get
    43		// method returns both the previous Response and
    44		// CheckRedirect's error (wrapped in a url.Error) instead of
    45		// issuing the Request req.
    46		//
    47		// If CheckRedirect is nil, the Client uses its default policy,
    48		// which is to stop after 10 consecutive requests.
    49		CheckRedirect func(req *Request, via []*Request) error
    50	
    51		// Jar specifies the cookie jar.
    52		// If Jar is nil, cookies are not sent in requests and ignored
    53		// in responses.
    54		Jar CookieJar
    55	}
    56	
    57	// DefaultClient is the default Client and is used by Get, Head, and Post.
    58	var DefaultClient = &Client{}
    59	
    60	// RoundTripper is an interface representing the ability to execute a
    61	// single HTTP transaction, obtaining the Response for a given Request.
    62	//
    63	// A RoundTripper must be safe for concurrent use by multiple
    64	// goroutines.
    65	type RoundTripper interface {
    66		// RoundTrip executes a single HTTP transaction, returning
    67		// the Response for the request req.  RoundTrip should not
    68		// attempt to interpret the response.  In particular,
    69		// RoundTrip must return err == nil if it obtained a response,
    70		// regardless of the response's HTTP status code.  A non-nil
    71		// err should be reserved for failure to obtain a response.
    72		// Similarly, RoundTrip should not attempt to handle
    73		// higher-level protocol details such as redirects,
    74		// authentication, or cookies.
    75		//
    76		// RoundTrip should not modify the request, except for
    77		// consuming the Body.  The request's URL and Header fields
    78		// are guaranteed to be initialized.
    79		RoundTrip(*Request) (*Response, error)
    80	}
    81	
    82	// Given a string of the form "host", "host:port", or "[ipv6::address]:port",
    83	// return true if the string includes a port.
    84	func hasPort(s string) bool { return strings.LastIndex(s, ":") > strings.LastIndex(s, "]") }
    85	
    86	// Used in Send to implement io.ReadCloser by bundling together the
    87	// bufio.Reader through which we read the response, and the underlying
    88	// network connection.
    89	type readClose struct {
    90		io.Reader
    91		io.Closer
    92	}
    93	
    94	func (c *Client) send(req *Request) (*Response, error) {
    95		if c.Jar != nil {
    96			for _, cookie := range c.Jar.Cookies(req.URL) {
    97				req.AddCookie(cookie)
    98			}
    99		}
   100		resp, err := send(req, c.Transport)
   101		if err != nil {
   102			return nil, err
   103		}
   104		if c.Jar != nil {
   105			if rc := resp.Cookies(); len(rc) > 0 {
   106				c.Jar.SetCookies(req.URL, rc)
   107			}
   108		}
   109		return resp, err
   110	}
   111	
   112	// Do sends an HTTP request and returns an HTTP response, following
   113	// policy (e.g. redirects, cookies, auth) as configured on the client.
   114	//
   115	// An error is returned if caused by client policy (such as
   116	// CheckRedirect), or if there was an HTTP protocol error.
   117	// A non-2xx response doesn't cause an error.
   118	//
   119	// When err is nil, resp always contains a non-nil resp.Body.
   120	//
   121	// Callers should close resp.Body when done reading from it. If
   122	// resp.Body is not closed, the Client's underlying RoundTripper
   123	// (typically Transport) may not be able to re-use a persistent TCP
   124	// connection to the server for a subsequent "keep-alive" request.
   125	//
   126	// Generally Get, Post, or PostForm will be used instead of Do.
   127	func (c *Client) Do(req *Request) (resp *Response, err error) {
   128		if req.Method == "GET" || req.Method == "HEAD" {
   129			return c.doFollowingRedirects(req, shouldRedirectGet)
   130		}
   131		if req.Method == "POST" || req.Method == "PUT" {
   132			return c.doFollowingRedirects(req, shouldRedirectPost)
   133		}
   134		return c.send(req)
   135	}
   136	
   137	// send issues an HTTP request.
   138	// Caller should close resp.Body when done reading from it.
   139	func send(req *Request, t RoundTripper) (resp *Response, err error) {
   140		if t == nil {
   141			t = DefaultTransport
   142			if t == nil {
   143				err = errors.New("http: no Client.Transport or DefaultTransport")
   144				return
   145			}
   146		}
   147	
   148		if req.URL == nil {
   149			return nil, errors.New("http: nil Request.URL")
   150		}
   151	
   152		if req.RequestURI != "" {
   153			return nil, errors.New("http: Request.RequestURI can't be set in client requests.")
   154		}
   155	
   156		// Most the callers of send (Get, Post, et al) don't need
   157		// Headers, leaving it uninitialized.  We guarantee to the
   158		// Transport that this has been initialized, though.
   159		if req.Header == nil {
   160			req.Header = make(Header)
   161		}
   162	
   163		if u := req.URL.User; u != nil {
   164			req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(u.String())))
   165		}
   166		resp, err = t.RoundTrip(req)
   167		if err != nil {
   168			if resp != nil {
   169				log.Printf("RoundTripper returned a response & error; ignoring response")
   170			}
   171			return nil, err
   172		}
   173		return resp, nil
   174	}
   175	
   176	// True if the specified HTTP status code is one for which the Get utility should
   177	// automatically redirect.
   178	func shouldRedirectGet(statusCode int) bool {
   179		switch statusCode {
   180		case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
   181			return true
   182		}
   183		return false
   184	}
   185	
   186	// True if the specified HTTP status code is one for which the Post utility should
   187	// automatically redirect.
   188	func shouldRedirectPost(statusCode int) bool {
   189		switch statusCode {
   190		case StatusFound, StatusSeeOther:
   191			return true
   192		}
   193		return false
   194	}
   195	
   196	// Get issues a GET to the specified URL.  If the response is one of the following
   197	// redirect codes, Get follows the redirect, up to a maximum of 10 redirects:
   198	//
   199	//    301 (Moved Permanently)
   200	//    302 (Found)
   201	//    303 (See Other)
   202	//    307 (Temporary Redirect)
   203	//
   204	// An error is returned if there were too many redirects or if there
   205	// was an HTTP protocol error. A non-2xx response doesn't cause an
   206	// error.
   207	//
   208	// When err is nil, resp always contains a non-nil resp.Body.
   209	// Caller should close resp.Body when done reading from it.
   210	//
   211	// Get is a wrapper around DefaultClient.Get.
   212	func Get(url string) (resp *Response, err error) {
   213		return DefaultClient.Get(url)
   214	}
   215	
   216	// Get issues a GET to the specified URL.  If the response is one of the
   217	// following redirect codes, Get follows the redirect after calling the
   218	// Client's CheckRedirect function.
   219	//
   220	//    301 (Moved Permanently)
   221	//    302 (Found)
   222	//    303 (See Other)
   223	//    307 (Temporary Redirect)
   224	//
   225	// An error is returned if the Client's CheckRedirect function fails
   226	// or if there was an HTTP protocol error. A non-2xx response doesn't
   227	// cause an error.
   228	//
   229	// When err is nil, resp always contains a non-nil resp.Body.
   230	// Caller should close resp.Body when done reading from it.
   231	func (c *Client) Get(url string) (resp *Response, err error) {
   232		req, err := NewRequest("GET", url, nil)
   233		if err != nil {
   234			return nil, err
   235		}
   236		return c.doFollowingRedirects(req, shouldRedirectGet)
   237	}
   238	
   239	func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bool) (resp *Response, err error) {
   240		var base *url.URL
   241		redirectChecker := c.CheckRedirect
   242		if redirectChecker == nil {
   243			redirectChecker = defaultCheckRedirect
   244		}
   245		var via []*Request
   246	
   247		if ireq.URL == nil {
   248			return nil, errors.New("http: nil Request.URL")
   249		}
   250	
   251		req := ireq
   252		urlStr := "" // next relative or absolute URL to fetch (after first request)
   253		redirectFailed := false
   254		for redirect := 0; ; redirect++ {
   255			if redirect != 0 {
   256				req = new(Request)
   257				req.Method = ireq.Method
   258				if ireq.Method == "POST" || ireq.Method == "PUT" {
   259					req.Method = "GET"
   260				}
   261				req.Header = make(Header)
   262				req.URL, err = base.Parse(urlStr)
   263				if err != nil {
   264					break
   265				}
   266				if len(via) > 0 {
   267					// Add the Referer header.
   268					lastReq := via[len(via)-1]
   269					if lastReq.URL.Scheme != "https" {
   270						req.Header.Set("Referer", lastReq.URL.String())
   271					}
   272	
   273					err = redirectChecker(req, via)
   274					if err != nil {
   275						redirectFailed = true
   276						break
   277					}
   278				}
   279			}
   280	
   281			urlStr = req.URL.String()
   282			if resp, err = c.send(req); err != nil {
   283				break
   284			}
   285	
   286			if shouldRedirect(resp.StatusCode) {
   287				resp.Body.Close()
   288				if urlStr = resp.Header.Get("Location"); urlStr == "" {
   289					err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
   290					break
   291				}
   292				base = req.URL
   293				via = append(via, req)
   294				continue
   295			}
   296			return
   297		}
   298	
   299		method := ireq.Method
   300		urlErr := &url.Error{
   301			Op:  method[0:1] + strings.ToLower(method[1:]),
   302			URL: urlStr,
   303			Err: err,
   304		}
   305	
   306		if redirectFailed {
   307			// Special case for Go 1 compatibility: return both the response
   308			// and an error if the CheckRedirect function failed.
   309			// See http://golang.org/issue/3795
   310			return resp, urlErr
   311		}
   312	
   313		if resp != nil {
   314			resp.Body.Close()
   315		}
   316		return nil, urlErr
   317	}
   318	
   319	func defaultCheckRedirect(req *Request, via []*Request) error {
   320		if len(via) >= 10 {
   321			return errors.New("stopped after 10 redirects")
   322		}
   323		return nil
   324	}
   325	
   326	// Post issues a POST to the specified URL.
   327	//
   328	// Caller should close resp.Body when done reading from it.
   329	//
   330	// Post is a wrapper around DefaultClient.Post
   331	func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
   332		return DefaultClient.Post(url, bodyType, body)
   333	}
   334	
   335	// Post issues a POST to the specified URL.
   336	//
   337	// Caller should close resp.Body when done reading from it.
   338	func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
   339		req, err := NewRequest("POST", url, body)
   340		if err != nil {
   341			return nil, err
   342		}
   343		req.Header.Set("Content-Type", bodyType)
   344		return c.doFollowingRedirects(req, shouldRedirectPost)
   345	}
   346	
   347	// PostForm issues a POST to the specified URL, with data's keys and
   348	// values URL-encoded as the request body.
   349	//
   350	// When err is nil, resp always contains a non-nil resp.Body.
   351	// Caller should close resp.Body when done reading from it.
   352	//
   353	// PostForm is a wrapper around DefaultClient.PostForm
   354	func PostForm(url string, data url.Values) (resp *Response, err error) {
   355		return DefaultClient.PostForm(url, data)
   356	}
   357	
   358	// PostForm issues a POST to the specified URL,
   359	// with data's keys and values urlencoded as the request body.
   360	//
   361	// When err is nil, resp always contains a non-nil resp.Body.
   362	// Caller should close resp.Body when done reading from it.
   363	func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
   364		return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
   365	}
   366	
   367	// Head issues a HEAD to the specified URL.  If the response is one of the
   368	// following redirect codes, Head follows the redirect after calling the
   369	// Client's CheckRedirect function.
   370	//
   371	//    301 (Moved Permanently)
   372	//    302 (Found)
   373	//    303 (See Other)
   374	//    307 (Temporary Redirect)
   375	//
   376	// Head is a wrapper around DefaultClient.Head
   377	func Head(url string) (resp *Response, err error) {
   378		return DefaultClient.Head(url)
   379	}
   380	
   381	// Head issues a HEAD to the specified URL.  If the response is one of the
   382	// following redirect codes, Head follows the redirect after calling the
   383	// Client's CheckRedirect function.
   384	//
   385	//    301 (Moved Permanently)
   386	//    302 (Found)
   387	//    303 (See Other)
   388	//    307 (Temporary Redirect)
   389	func (c *Client) Head(url string) (resp *Response, err error) {
   390		req, err := NewRequest("HEAD", url, nil)
   391		if err != nil {
   392			return nil, err
   393		}
   394		return c.doFollowingRedirects(req, shouldRedirectGet)
   395	}

View as plain text