LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Primitive HTTP client. See RFC 2616. | 5 // Primitive HTTP client. See RFC 2616. |
6 | 6 |
7 package http | 7 package http |
8 | 8 |
9 import ( | 9 import ( |
10 "bytes" | 10 "bytes" |
11 "encoding/base64" | 11 "encoding/base64" |
12 "fmt" | 12 "fmt" |
13 "io" | 13 "io" |
14 "os" | 14 "os" |
15 "strconv" | 15 "strconv" |
16 "strings" | 16 "strings" |
17 ) | 17 ) |
18 | 18 |
19 // A Client is an HTTP client. | 19 // A Client is an HTTP client. Its zero value (DefaultClient) is a usable client |
20 // It is not yet possible to create custom Clients; use DefaultClient. | 20 // that uses DefaultTransport. |
| 21 // Client is not yet very configurable. |
21 type Client struct { | 22 type Client struct { |
22 Transport ClientTransport // if nil, DefaultTransport is used | 23 Transport ClientTransport // if nil, DefaultTransport is used |
23 | |
24 unused int // prevent instantiation; there will likely be internal state
in the future | |
25 } | 24 } |
26 | 25 |
27 // DefaultClient is the default Client and is used by Get, Head, and Post. | 26 // DefaultClient is the default Client and is used by Get, Head, and Post. |
28 var DefaultClient = &Client{} | 27 var DefaultClient = &Client{} |
29 | |
30 // NewClient returns a new Client which you can then initialize as needed. | |
31 func NewClient() *Client { | |
32 return &Client{} | |
33 } | |
34 | 28 |
35 // ClientTransport is an interface representing the ability to execute a | 29 // ClientTransport is an interface representing the ability to execute a |
36 // single HTTP transaction, obtaining the Response for a given Request. | 30 // single HTTP transaction, obtaining the Response for a given Request. |
37 type ClientTransport interface { | 31 type ClientTransport interface { |
38 // Do executes a single HTTP transaction, returning the Response for the | 32 // Do executes a single HTTP transaction, returning the Response for the |
39 // request req. Do should not attempt to interpret the response. | 33 // request req. Do should not attempt to interpret the response. |
40 // In particular, Do must return err == nil if it obtained a response, | 34 // In particular, Do must return err == nil if it obtained a response, |
41 // regardless of the response's HTTP status code. A non-nil err should | 35 // regardless of the response's HTTP status code. A non-nil err should |
42 // be reserved for failure to obtain a response. Similarly, Do should | 36 // be reserved for failure to obtain a response. Similarly, Do should |
43 // not attempt to handle higher-level protocol details such as redirects
, | 37 // not attempt to handle higher-level protocol details such as redirects
, |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 if addr == p || (p[0] == '.' && (strings.HasSuffix(addr, p) || a
ddr == p[1:])) { | 81 if addr == p || (p[0] == '.' && (strings.HasSuffix(addr, p) || a
ddr == p[1:])) { |
88 return true | 82 return true |
89 } | 83 } |
90 } | 84 } |
91 return false | 85 return false |
92 } | 86 } |
93 | 87 |
94 // Do sends an HTTP request and returns an HTTP response, following | 88 // Do sends an HTTP request and returns an HTTP response, following |
95 // policy (e.g. redirects, cookies, auth) as configured on the client. | 89 // policy (e.g. redirects, cookies, auth) as configured on the client. |
96 // | 90 // |
97 // Callers should close resp.Body when done reading it. | 91 // Callers should close resp.Body when done reading from it. |
98 // | 92 // |
99 // Generally Get, Post, or PostForm will be used instead of Do. | 93 // Generally Get, Post, or PostForm will be used instead of Do. |
100 func (c *Client) Do(req *Request) (resp *Response, err os.Error) { | 94 func (c *Client) Do(req *Request) (resp *Response, err os.Error) { |
101 return send(req, c.Transport) | 95 return send(req, c.Transport) |
102 } | 96 } |
103 | 97 |
104 | 98 |
105 // send issues an HTTP request. Caller should close resp.Body when done reading
it. | 99 // send issues an HTTP request. Caller should close resp.Body when done reading
from it. |
106 // | 100 // |
107 // TODO: support persistent connections (multiple requests on a single connectio
n). | 101 // TODO: support persistent connections (multiple requests on a single connectio
n). |
108 // send() method is nonpublic because, when we refactor the code for persistent | 102 // send() method is nonpublic because, when we refactor the code for persistent |
109 // connections, it may no longer make sense to have a method with this signature
. | 103 // connections, it may no longer make sense to have a method with this signature
. |
110 func send(req *Request, t ClientTransport) (resp *Response, err os.Error) { | 104 func send(req *Request, t ClientTransport) (resp *Response, err os.Error) { |
111 if t == nil { | 105 if t == nil { |
112 t = DefaultTransport | 106 t = DefaultTransport |
113 if t == nil { | 107 if t == nil { |
114 err = os.NewError("no http.Client.Transport or http.Defa
ultTransport") | 108 err = os.NewError("no http.Client.Transport or http.Defa
ultTransport") |
115 return | 109 return |
(...skipping 26 matching lines...) Expand all Loading... |
142 // redirect codes, it follows the redirect, up to a maximum of 10 redirects: | 136 // redirect codes, it follows the redirect, up to a maximum of 10 redirects: |
143 // | 137 // |
144 // 301 (Moved Permanently) | 138 // 301 (Moved Permanently) |
145 // 302 (Found) | 139 // 302 (Found) |
146 // 303 (See Other) | 140 // 303 (See Other) |
147 // 307 (Temporary Redirect) | 141 // 307 (Temporary Redirect) |
148 // | 142 // |
149 // finalURL is the URL from which the response was fetched -- identical to the | 143 // finalURL is the URL from which the response was fetched -- identical to the |
150 // input URL unless redirects were followed. | 144 // input URL unless redirects were followed. |
151 // | 145 // |
152 // Caller should close r.Body when done reading it. | 146 // Caller should close r.Body when done reading from it. |
153 // | 147 // |
154 // Get is a convenience wrapper around DefaultClient.Get. | 148 // Get is a convenience wrapper around DefaultClient.Get. |
155 func Get(url string) (r *Response, finalURL string, err os.Error) { | 149 func Get(url string) (r *Response, finalURL string, err os.Error) { |
156 return DefaultClient.Get(url) | 150 return DefaultClient.Get(url) |
157 } | 151 } |
158 | 152 |
159 // Get issues a GET to the specified URL. If the response is one of the followi
ng | 153 // Get issues a GET to the specified URL. If the response is one of the followi
ng |
160 // redirect codes, it follows the redirect, up to a maximum of 10 redirects: | 154 // redirect codes, it follows the redirect, up to a maximum of 10 redirects: |
161 // | 155 // |
162 // 301 (Moved Permanently) | 156 // 301 (Moved Permanently) |
163 // 302 (Found) | 157 // 302 (Found) |
164 // 303 (See Other) | 158 // 303 (See Other) |
165 // 307 (Temporary Redirect) | 159 // 307 (Temporary Redirect) |
166 // | 160 // |
167 // finalURL is the URL from which the response was fetched -- identical to the | 161 // finalURL is the URL from which the response was fetched -- identical to the |
168 // input URL unless redirects were followed. | 162 // input URL unless redirects were followed. |
169 // | 163 // |
170 // Caller should close r.Body when done reading it. | 164 // Caller should close r.Body when done reading from it. |
171 func (c *Client) Get(url string) (r *Response, finalURL string, err os.Error) { | 165 func (c *Client) Get(url string) (r *Response, finalURL string, err os.Error) { |
172 // TODO: if/when we add cookie support, the redirected request shouldn't | 166 // TODO: if/when we add cookie support, the redirected request shouldn't |
173 // necessarily supply the same cookies as the original. | 167 // necessarily supply the same cookies as the original. |
174 // TODO: set referrer header on redirects. | 168 // TODO: set referrer header on redirects. |
175 var base *URL | 169 var base *URL |
176 // TODO: remove this hard-coded 10 and use the Client's policy | 170 // TODO: remove this hard-coded 10 and use the Client's policy |
177 // (ClientConfig) instead. | 171 // (ClientConfig) instead. |
178 for redirect := 0; ; redirect++ { | 172 for redirect := 0; ; redirect++ { |
179 if redirect >= 10 { | 173 if redirect >= 10 { |
180 err = os.ErrorString("stopped after 10 redirects") | 174 err = os.ErrorString("stopped after 10 redirects") |
(...skipping 28 matching lines...) Expand all Loading... |
209 finalURL = url | 203 finalURL = url |
210 return | 204 return |
211 } | 205 } |
212 | 206 |
213 err = &URLError{"Get", url, err} | 207 err = &URLError{"Get", url, err} |
214 return | 208 return |
215 } | 209 } |
216 | 210 |
217 // Post issues a POST to the specified URL. | 211 // Post issues a POST to the specified URL. |
218 // | 212 // |
219 // Caller should close r.Body when done reading it. | 213 // Caller should close r.Body when done reading from it. |
220 // | 214 // |
221 // Post is a wrapper around DefaultClient.Post | 215 // Post is a wrapper around DefaultClient.Post |
222 func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Erro
r) { | 216 func Post(url string, bodyType string, body io.Reader) (r *Response, err os.Erro
r) { |
223 return DefaultClient.Post(url, bodyType, body) | 217 return DefaultClient.Post(url, bodyType, body) |
224 } | 218 } |
225 | 219 |
226 // Post issues a POST to the specified URL. | 220 // Post issues a POST to the specified URL. |
227 // | 221 // |
228 // Caller should close r.Body when done reading it. | 222 // Caller should close r.Body when done reading from it. |
229 func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response,
err os.Error) { | 223 func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response,
err os.Error) { |
230 var req Request | 224 var req Request |
231 req.Method = "POST" | 225 req.Method = "POST" |
232 req.ProtoMajor = 1 | 226 req.ProtoMajor = 1 |
233 req.ProtoMinor = 1 | 227 req.ProtoMinor = 1 |
234 req.Close = true | 228 req.Close = true |
235 req.Body = nopCloser{body} | 229 req.Body = nopCloser{body} |
236 req.Header = Header{ | 230 req.Header = Header{ |
237 "Content-Type": {bodyType}, | 231 "Content-Type": {bodyType}, |
238 } | 232 } |
239 req.TransferEncoding = []string{"chunked"} | 233 req.TransferEncoding = []string{"chunked"} |
240 | 234 |
241 req.URL, err = ParseURL(url) | 235 req.URL, err = ParseURL(url) |
242 if err != nil { | 236 if err != nil { |
243 return nil, err | 237 return nil, err |
244 } | 238 } |
245 | 239 |
246 return send(&req, c.Transport) | 240 return send(&req, c.Transport) |
247 } | 241 } |
248 | 242 |
249 // PostForm issues a POST to the specified URL,· | 243 // PostForm issues a POST to the specified URL,· |
250 // with data's keys and values urlencoded as the request body. | 244 // with data's keys and values urlencoded as the request body. |
251 // | 245 // |
252 // Caller should close r.Body when done reading it. | 246 // Caller should close r.Body when done reading from it. |
253 // | 247 // |
254 // PostForm is a wrapper around DefaultClient.PostForm | 248 // PostForm is a wrapper around DefaultClient.PostForm |
255 func PostForm(url string, data map[string]string) (r *Response, err os.Error) { | 249 func PostForm(url string, data map[string]string) (r *Response, err os.Error) { |
256 return DefaultClient.PostForm(url, data) | 250 return DefaultClient.PostForm(url, data) |
257 } | 251 } |
258 | 252 |
259 // PostForm issues a POST to the specified URL,· | 253 // PostForm issues a POST to the specified URL,· |
260 // with data's keys and values urlencoded as the request body. | 254 // with data's keys and values urlencoded as the request body. |
261 // | 255 // |
262 // Caller should close r.Body when done reading it. | 256 // Caller should close r.Body when done reading from it. |
263 func (c *Client) PostForm(url string, data map[string]string) (r *Response, err
os.Error) { | 257 func (c *Client) PostForm(url string, data map[string]string) (r *Response, err
os.Error) { |
264 var req Request | 258 var req Request |
265 req.Method = "POST" | 259 req.Method = "POST" |
266 req.ProtoMajor = 1 | 260 req.ProtoMajor = 1 |
267 req.ProtoMinor = 1 | 261 req.ProtoMinor = 1 |
268 req.Close = true | 262 req.Close = true |
269 body := urlencode(data) | 263 body := urlencode(data) |
270 req.Body = nopCloser{body} | 264 req.Body = nopCloser{body} |
271 req.Header = Header{ | 265 req.Header = Header{ |
272 "Content-Type": {"application/x-www-form-urlencoded"}, | 266 "Content-Type": {"application/x-www-form-urlencoded"}, |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
306 return | 300 return |
307 } | 301 } |
308 return send(&req, c.Transport) | 302 return send(&req, c.Transport) |
309 } | 303 } |
310 | 304 |
311 type nopCloser struct { | 305 type nopCloser struct { |
312 io.Reader | 306 io.Reader |
313 } | 307 } |
314 | 308 |
315 func (nopCloser) Close() os.Error { return nil } | 309 func (nopCloser) Close() os.Error { return nil } |
LEFT | RIGHT |