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 and closing the Body. The request's URL and
    78		// Header fields 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			username := u.Username()
   165			password, _ := u.Password()
   166			req.Header.Set("Authorization", "Basic "+basicAuth(username, password))
   167		}
   168		resp, err = t.RoundTrip(req)
   169		if err != nil {
   170			if resp != nil {
   171				log.Printf("RoundTripper returned a response & error; ignoring response")
   172			}
   173			return nil, err
   174		}
   175		return resp, nil
   176	}
   177	
   178	// See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
   179	// "To receive authorization, the client sends the userid and password,
   180	// separated by a single colon (":") character, within a base64
   181	// encoded string in the credentials."
   182	// It is not meant to be urlencoded.
   183	func basicAuth(username, password string) string {
   184		auth := username + ":" + password
   185		return base64.StdEncoding.EncodeToString([]byte(auth))
   186	}
   187	
   188	// True if the specified HTTP status code is one for which the Get utility should
   189	// automatically redirect.
   190	func shouldRedirectGet(statusCode int) bool {
   191		switch statusCode {
   192		case StatusMovedPermanently, StatusFound, StatusSeeOther, StatusTemporaryRedirect:
   193			return true
   194		}
   195		return false
   196	}
   197	
   198	// True if the specified HTTP status code is one for which the Post utility should
   199	// automatically redirect.
   200	func shouldRedirectPost(statusCode int) bool {
   201		switch statusCode {
   202		case StatusFound, StatusSeeOther:
   203			return true
   204		}
   205		return false
   206	}
   207	
   208	// Get issues a GET to the specified URL.  If the response is one of the following
   209	// redirect codes, Get follows the redirect, up to a maximum of 10 redirects:
   210	//
   211	//    301 (Moved Permanently)
   212	//    302 (Found)
   213	//    303 (See Other)
   214	//    307 (Temporary Redirect)
   215	//
   216	// An error is returned if there were too many redirects or if there
   217	// was an HTTP protocol error. A non-2xx response doesn't cause an
   218	// error.
   219	//
   220	// When err is nil, resp always contains a non-nil resp.Body.
   221	// Caller should close resp.Body when done reading from it.
   222	//
   223	// Get is a wrapper around DefaultClient.Get.
   224	func Get(url string) (resp *Response, err error) {
   225		return DefaultClient.Get(url)
   226	}
   227	
   228	// Get issues a GET to the specified URL.  If the response is one of the
   229	// following redirect codes, Get follows the redirect after calling the
   230	// Client's CheckRedirect function.
   231	//
   232	//    301 (Moved Permanently)
   233	//    302 (Found)
   234	//    303 (See Other)
   235	//    307 (Temporary Redirect)
   236	//
   237	// An error is returned if the Client's CheckRedirect function fails
   238	// or if there was an HTTP protocol error. A non-2xx response doesn't
   239	// cause an error.
   240	//
   241	// When err is nil, resp always contains a non-nil resp.Body.
   242	// Caller should close resp.Body when done reading from it.
   243	func (c *Client) Get(url string) (resp *Response, err error) {
   244		req, err := NewRequest("GET", url, nil)
   245		if err != nil {
   246			return nil, err
   247		}
   248		return c.doFollowingRedirects(req, shouldRedirectGet)
   249	}
   250	
   251	func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bool) (resp *Response, err error) {
   252		var base *url.URL
   253		redirectChecker := c.CheckRedirect
   254		if redirectChecker == nil {
   255			redirectChecker = defaultCheckRedirect
   256		}
   257		var via []*Request
   258	
   259		if ireq.URL == nil {
   260			return nil, errors.New("http: nil Request.URL")
   261		}
   262	
   263		req := ireq
   264		urlStr := "" // next relative or absolute URL to fetch (after first request)
   265		redirectFailed := false
   266		for redirect := 0; ; redirect++ {
   267			if redirect != 0 {
   268				req = new(Request)
   269				req.Method = ireq.Method
   270				if ireq.Method == "POST" || ireq.Method == "PUT" {
   271					req.Method = "GET"
   272				}
   273				req.Header = make(Header)
   274				req.URL, err = base.Parse(urlStr)
   275				if err != nil {
   276					break
   277				}
   278				if len(via) > 0 {
   279					// Add the Referer header.
   280					lastReq := via[len(via)-1]
   281					if lastReq.URL.Scheme != "https" {
   282						req.Header.Set("Referer", lastReq.URL.String())
   283					}
   284	
   285					err = redirectChecker(req, via)
   286					if err != nil {
   287						redirectFailed = true
   288						break
   289					}
   290				}
   291			}
   292	
   293			urlStr = req.URL.String()
   294			if resp, err = c.send(req); err != nil {
   295				break
   296			}
   297	
   298			if shouldRedirect(resp.StatusCode) {
   299				resp.Body.Close()
   300				if urlStr = resp.Header.Get("Location"); urlStr == "" {
   301					err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
   302					break
   303				}
   304				base = req.URL
   305				via = append(via, req)
   306				continue
   307			}
   308			return
   309		}
   310	
   311		method := ireq.Method
   312		urlErr := &url.Error{
   313			Op:  method[0:1] + strings.ToLower(method[1:]),
   314			URL: urlStr,
   315			Err: err,
   316		}
   317	
   318		if redirectFailed {
   319			// Special case for Go 1 compatibility: return both the response
   320			// and an error if the CheckRedirect function failed.
   321			// See http://golang.org/issue/3795
   322			return resp, urlErr
   323		}
   324	
   325		if resp != nil {
   326			resp.Body.Close()
   327		}
   328		return nil, urlErr
   329	}
   330	
   331	func defaultCheckRedirect(req *Request, via []*Request) error {
   332		if len(via) >= 10 {
   333			return errors.New("stopped after 10 redirects")
   334		}
   335		return nil
   336	}
   337	
   338	// Post issues a POST to the specified URL.
   339	//
   340	// Caller should close resp.Body when done reading from it.
   341	//
   342	// Post is a wrapper around DefaultClient.Post
   343	func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
   344		return DefaultClient.Post(url, bodyType, body)
   345	}
   346	
   347	// Post issues a POST to the specified URL.
   348	//
   349	// Caller should close resp.Body when done reading from it.
   350	//
   351	// If the provided body is also an io.Closer, it is closed after the
   352	// body is successfully written to the server.
   353	func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
   354		req, err := NewRequest("POST", url, body)
   355		if err != nil {
   356			return nil, err
   357		}
   358		req.Header.Set("Content-Type", bodyType)
   359		return c.doFollowingRedirects(req, shouldRedirectPost)
   360	}
   361	
   362	// PostForm issues a POST to the specified URL, with data's keys and
   363	// values URL-encoded as the request body.
   364	//
   365	// When err is nil, resp always contains a non-nil resp.Body.
   366	// Caller should close resp.Body when done reading from it.
   367	//
   368	// PostForm is a wrapper around DefaultClient.PostForm
   369	func PostForm(url string, data url.Values) (resp *Response, err error) {
   370		return DefaultClient.PostForm(url, data)
   371	}
   372	
   373	// PostForm issues a POST to the specified URL,
   374	// with data's keys and values urlencoded as the request body.
   375	//
   376	// When err is nil, resp always contains a non-nil resp.Body.
   377	// Caller should close resp.Body when done reading from it.
   378	func (c *Client) PostForm(url string, data url.Values) (resp *Response, err error) {
   379		return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
   380	}
   381	
   382	// Head issues a HEAD to the specified URL.  If the response is one of the
   383	// following redirect codes, Head follows the redirect after calling the
   384	// Client's CheckRedirect function.
   385	//
   386	//    301 (Moved Permanently)
   387	//    302 (Found)
   388	//    303 (See Other)
   389	//    307 (Temporary Redirect)
   390	//
   391	// Head is a wrapper around DefaultClient.Head
   392	func Head(url string) (resp *Response, err error) {
   393		return DefaultClient.Head(url)
   394	}
   395	
   396	// Head issues a HEAD to the specified URL.  If the response is one of the
   397	// following redirect codes, Head follows the redirect after calling the
   398	// Client's CheckRedirect function.
   399	//
   400	//    301 (Moved Permanently)
   401	//    302 (Found)
   402	//    303 (See Other)
   403	//    307 (Temporary Redirect)
   404	func (c *Client) Head(url string) (resp *Response, err error) {
   405		req, err := NewRequest("HEAD", url, nil)
   406		if err != nil {
   407			return nil, err
   408		}
   409		return c.doFollowingRedirects(req, shouldRedirectGet)
   410	}

View as plain text