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