@@ -14,6 +14,7 @@ import (
14
14
"errors"
15
15
"fmt"
16
16
"io"
17
+ "log"
17
18
"net/url"
18
19
"strings"
19
20
)
@@ -87,9 +88,13 @@ type readClose struct {
87
88
// Do sends an HTTP request and returns an HTTP response, following
88
89
// policy (e.g. redirects, cookies, auth) as configured on the client.
89
90
//
90
- // A non-nil response always contains a non-nil resp.Body.
91
+ // An error is returned if caused by client policy (such as
92
+ // CheckRedirect), or if there was an HTTP protocol error.
93
+ // A non-2xx response doesn't cause an error.
91
94
//
92
- // Callers should close resp.Body when done reading from it. If
95
+ // When err is nil, resp always contains a non-nil resp.Body.
96
+ //
97
+ // Callers should close res.Body when done reading from it. If
93
98
// resp.Body is not closed, the Client's underlying RoundTripper
94
99
// (typically Transport) may not be able to re-use a persistent TCP
95
100
// connection to the server for a subsequent "keep-alive" request.
@@ -102,7 +107,8 @@ func (c *Client) Do(req *Request) (resp *Response, err error) {
102
107
return send (req , c .Transport )
103
108
}
104
109
105
- // send issues an HTTP request. Caller should close resp.Body when done reading from it.
110
+ // send issues an HTTP request.
111
+ // Caller should close resp.Body when done reading from it.
106
112
func send (req * Request , t RoundTripper ) (resp * Response , err error ) {
107
113
if t == nil {
108
114
t = DefaultTransport
@@ -130,7 +136,14 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) {
130
136
if u := req .URL .User ; u != nil {
131
137
req .Header .Set ("Authorization" , "Basic " + base64 .URLEncoding .EncodeToString ([]byte (u .String ())))
132
138
}
133
- return t .RoundTrip (req )
139
+ resp , err = t .RoundTrip (req )
140
+ if err != nil {
141
+ if resp != nil {
142
+ log .Printf ("RoundTripper returned a response & error; ignoring response" )
143
+ }
144
+ return nil , err
145
+ }
146
+ return resp , nil
134
147
}
135
148
136
149
// True if the specified HTTP status code is one for which the Get utility should
@@ -151,10 +164,15 @@ func shouldRedirect(statusCode int) bool {
151
164
// 303 (See Other)
152
165
// 307 (Temporary Redirect)
153
166
//
154
- // Caller should close r.Body when done reading from it.
167
+ // An error is returned if there were too many redirects or if there
168
+ // was an HTTP protocol error. A non-2xx response doesn't cause an
169
+ // error.
170
+ //
171
+ // When err is nil, resp always contains a non-nil resp.Body.
172
+ // Caller should close resp.Body when done reading from it.
155
173
//
156
174
// Get is a wrapper around DefaultClient.Get.
157
- func Get (url string ) (r * Response , err error ) {
175
+ func Get (url string ) (resp * Response , err error ) {
158
176
return DefaultClient .Get (url )
159
177
}
160
178
@@ -167,16 +185,21 @@ func Get(url string) (r *Response, err error) {
167
185
// 303 (See Other)
168
186
// 307 (Temporary Redirect)
169
187
//
170
- // Caller should close r.Body when done reading from it.
171
- func (c * Client ) Get (url string ) (r * Response , err error ) {
188
+ // An error is returned if the Client's CheckRedirect function fails
189
+ // or if there was an HTTP protocol error. A non-2xx response doesn't
190
+ // cause an error.
191
+ //
192
+ // When err is nil, resp always contains a non-nil resp.Body.
193
+ // Caller should close resp.Body when done reading from it.
194
+ func (c * Client ) Get (url string ) (resp * Response , err error ) {
172
195
req , err := NewRequest ("GET" , url , nil )
173
196
if err != nil {
174
197
return nil , err
175
198
}
176
199
return c .doFollowingRedirects (req )
177
200
}
178
201
179
- func (c * Client ) doFollowingRedirects (ireq * Request ) (r * Response , err error ) {
202
+ func (c * Client ) doFollowingRedirects (ireq * Request ) (resp * Response , err error ) {
180
203
// TODO: if/when we add cookie support, the redirected request shouldn't
181
204
// necessarily supply the same cookies as the original.
182
205
var base * url.URL
@@ -224,17 +247,17 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
224
247
req .AddCookie (cookie )
225
248
}
226
249
urlStr = req .URL .String ()
227
- if r , err = send (req , c .Transport ); err != nil {
250
+ if resp , err = send (req , c .Transport ); err != nil {
228
251
break
229
252
}
230
- if c := r .Cookies (); len (c ) > 0 {
253
+ if c := resp .Cookies (); len (c ) > 0 {
231
254
jar .SetCookies (req .URL , c )
232
255
}
233
256
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 ))
257
+ if shouldRedirect (resp .StatusCode ) {
258
+ resp .Body .Close ()
259
+ if urlStr = resp .Header .Get ("Location" ); urlStr == "" {
260
+ err = errors .New (fmt .Sprintf ("%d response missing Location header" , resp .StatusCode ))
238
261
break
239
262
}
240
263
base = req .URL
@@ -244,13 +267,16 @@ func (c *Client) doFollowingRedirects(ireq *Request) (r *Response, err error) {
244
267
return
245
268
}
246
269
270
+ if resp != nil {
271
+ resp .Body .Close ()
272
+ }
273
+
247
274
method := ireq .Method
248
- err = & url.Error {
275
+ return nil , & url.Error {
249
276
Op : method [0 :1 ] + strings .ToLower (method [1 :]),
250
277
URL : urlStr ,
251
278
Err : err ,
252
279
}
253
- return
254
280
}
255
281
256
282
func defaultCheckRedirect (req * Request , via []* Request ) error {
@@ -262,17 +288,17 @@ func defaultCheckRedirect(req *Request, via []*Request) error {
262
288
263
289
// Post issues a POST to the specified URL.
264
290
//
265
- // Caller should close r .Body when done reading from it.
291
+ // Caller should close resp .Body when done reading from it.
266
292
//
267
293
// Post is a wrapper around DefaultClient.Post
268
- func Post (url string , bodyType string , body io.Reader ) (r * Response , err error ) {
294
+ func Post (url string , bodyType string , body io.Reader ) (resp * Response , err error ) {
269
295
return DefaultClient .Post (url , bodyType , body )
270
296
}
271
297
272
298
// Post issues a POST to the specified URL.
273
299
//
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 ) {
300
+ // Caller should close resp .Body when done reading from it.
301
+ func (c * Client ) Post (url string , bodyType string , body io.Reader ) (resp * Response , err error ) {
276
302
req , err := NewRequest ("POST" , url , body )
277
303
if err != nil {
278
304
return nil , err
@@ -283,28 +309,30 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (r *Response,
283
309
req .AddCookie (cookie )
284
310
}
285
311
}
286
- r , err = send (req , c .Transport )
312
+ resp , err = send (req , c .Transport )
287
313
if err == nil && c .Jar != nil {
288
- c .Jar .SetCookies (req .URL , r .Cookies ())
314
+ c .Jar .SetCookies (req .URL , resp .Cookies ())
289
315
}
290
- return r , err
316
+ return
291
317
}
292
318
293
- // PostForm issues a POST to the specified URL,
294
- // with data's keys and values urlencoded as the request body.
319
+ // PostForm issues a POST to the specified URL, with data's keys and
320
+ // values URL-encoded as the request body.
295
321
//
296
- // Caller should close r.Body when done reading from it.
322
+ // When err is nil, resp always contains a non-nil resp.Body.
323
+ // Caller should close resp.Body when done reading from it.
297
324
//
298
325
// PostForm is a wrapper around DefaultClient.PostForm
299
- func PostForm (url string , data url.Values ) (r * Response , err error ) {
326
+ func PostForm (url string , data url.Values ) (resp * Response , err error ) {
300
327
return DefaultClient .PostForm (url , data )
301
328
}
302
329
303
330
// PostForm issues a POST to the specified URL,
304
331
// with data's keys and values urlencoded as the request body.
305
332
//
306
- // Caller should close r.Body when done reading from it.
307
- func (c * Client ) PostForm (url string , data url.Values ) (r * Response , err error ) {
333
+ // When err is nil, resp always contains a non-nil resp.Body.
334
+ // Caller should close resp.Body when done reading from it.
335
+ func (c * Client ) PostForm (url string , data url.Values ) (resp * Response , err error ) {
308
336
return c .Post (url , "application/x-www-form-urlencoded" , strings .NewReader (data .Encode ()))
309
337
}
310
338
@@ -318,7 +346,7 @@ func (c *Client) PostForm(url string, data url.Values) (r *Response, err error)
318
346
// 307 (Temporary Redirect)
319
347
//
320
348
// Head is a wrapper around DefaultClient.Head
321
- func Head (url string ) (r * Response , err error ) {
349
+ func Head (url string ) (resp * Response , err error ) {
322
350
return DefaultClient .Head (url )
323
351
}
324
352
@@ -330,7 +358,7 @@ func Head(url string) (r *Response, err error) {
330
358
// 302 (Found)
331
359
// 303 (See Other)
332
360
// 307 (Temporary Redirect)
333
- func (c * Client ) Head (url string ) (r * Response , err error ) {
361
+ func (c * Client ) Head (url string ) (resp * Response , err error ) {
334
362
req , err := NewRequest ("HEAD" , url , nil )
335
363
if err != nil {
336
364
return nil , err
0 commit comments