OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [client.go] - Blame information for rev 858

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.