~chipaca/ubuntu-push/gsettings

« back to all changes in this revision

Viewing changes to http13client/response.go

  • Committer: Samuele Pedroni (Canonical Services Ltd.)
  • Date: 2014-03-19 20:20:19 UTC
  • mto: This revision was merged to the branch mainline in revision 82.
  • Revision ID: samuele.pedroni@canonical.com-20140319202019-p0w8krshj1098f82
grab go 1.3 dev net/http and massage it so that the test run on 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 Response reading and parsing.
 
6
 
 
7
package http
 
8
 
 
9
import (
 
10
        "bufio"
 
11
        "crypto/tls"
 
12
        "errors"
 
13
        "io"
 
14
        "net/textproto"
 
15
        "net/url"
 
16
        "strconv"
 
17
        "strings"
 
18
)
 
19
 
 
20
var respExcludeHeader = map[string]bool{
 
21
        "Content-Length":    true,
 
22
        "Transfer-Encoding": true,
 
23
        "Trailer":           true,
 
24
}
 
25
 
 
26
// Response represents the response from an HTTP request.
 
27
//
 
28
type Response struct {
 
29
        Status     string // e.g. "200 OK"
 
30
        StatusCode int    // e.g. 200
 
31
        Proto      string // e.g. "HTTP/1.0"
 
32
        ProtoMajor int    // e.g. 1
 
33
        ProtoMinor int    // e.g. 0
 
34
 
 
35
        // Header maps header keys to values.  If the response had multiple
 
36
        // headers with the same key, they may be concatenated, with comma
 
37
        // delimiters.  (Section 4.2 of RFC 2616 requires that multiple headers
 
38
        // be semantically equivalent to a comma-delimited sequence.) Values
 
39
        // duplicated by other fields in this struct (e.g., ContentLength) are
 
40
        // omitted from Header.
 
41
        //
 
42
        // Keys in the map are canonicalized (see CanonicalHeaderKey).
 
43
        Header Header
 
44
 
 
45
        // Body represents the response body.
 
46
        //
 
47
        // The http Client and Transport guarantee that Body is always
 
48
        // non-nil, even on responses without a body or responses with
 
49
        // a zero-lengthed body.
 
50
        //
 
51
        // The Body is automatically dechunked if the server replied
 
52
        // with a "chunked" Transfer-Encoding.
 
53
        Body io.ReadCloser
 
54
 
 
55
        // ContentLength records the length of the associated content.  The
 
56
        // value -1 indicates that the length is unknown.  Unless Request.Method
 
57
        // is "HEAD", values >= 0 indicate that the given number of bytes may
 
58
        // be read from Body.
 
59
        ContentLength int64
 
60
 
 
61
        // Contains transfer encodings from outer-most to inner-most. Value is
 
62
        // nil, means that "identity" encoding is used.
 
63
        TransferEncoding []string
 
64
 
 
65
        // Close records whether the header directed that the connection be
 
66
        // closed after reading Body.  The value is advice for clients: neither
 
67
        // ReadResponse nor Response.Write ever closes a connection.
 
68
        Close bool
 
69
 
 
70
        // Trailer maps trailer keys to values, in the same
 
71
        // format as the header.
 
72
        Trailer Header
 
73
 
 
74
        // The Request that was sent to obtain this Response.
 
75
        // Request's Body is nil (having already been consumed).
 
76
        // This is only populated for Client requests.
 
77
        Request *Request
 
78
 
 
79
        // TLS contains information about the TLS connection on which the
 
80
        // response was received. It is nil for unencrypted responses.
 
81
        // The pointer is shared between responses and should not be
 
82
        // modified.
 
83
        TLS *tls.ConnectionState
 
84
}
 
85
 
 
86
// Cookies parses and returns the cookies set in the Set-Cookie headers.
 
87
func (r *Response) Cookies() []*Cookie {
 
88
        return readSetCookies(r.Header)
 
89
}
 
90
 
 
91
var ErrNoLocation = errors.New("http: no Location header in response")
 
92
 
 
93
// Location returns the URL of the response's "Location" header,
 
94
// if present.  Relative redirects are resolved relative to
 
95
// the Response's Request.  ErrNoLocation is returned if no
 
96
// Location header is present.
 
97
func (r *Response) Location() (*url.URL, error) {
 
98
        lv := r.Header.Get("Location")
 
99
        if lv == "" {
 
100
                return nil, ErrNoLocation
 
101
        }
 
102
        if r.Request != nil && r.Request.URL != nil {
 
103
                return r.Request.URL.Parse(lv)
 
104
        }
 
105
        return url.Parse(lv)
 
106
}
 
107
 
 
108
// ReadResponse reads and returns an HTTP response from r.
 
109
// The req parameter optionally specifies the Request that corresponds
 
110
// to this Response. If nil, a GET request is assumed.
 
111
// Clients must call resp.Body.Close when finished reading resp.Body.
 
112
// After that call, clients can inspect resp.Trailer to find key/value
 
113
// pairs included in the response trailer.
 
114
func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) {
 
115
        tp := textproto.NewReader(r)
 
116
        resp := &Response{
 
117
                Request: req,
 
118
        }
 
119
 
 
120
        // Parse the first line of the response.
 
121
        line, err := tp.ReadLine()
 
122
        if err != nil {
 
123
                if err == io.EOF {
 
124
                        err = io.ErrUnexpectedEOF
 
125
                }
 
126
                return nil, err
 
127
        }
 
128
        f := strings.SplitN(line, " ", 3)
 
129
        if len(f) < 2 {
 
130
                return nil, &badStringError{"malformed HTTP response", line}
 
131
        }
 
132
        reasonPhrase := ""
 
133
        if len(f) > 2 {
 
134
                reasonPhrase = f[2]
 
135
        }
 
136
        resp.Status = f[1] + " " + reasonPhrase
 
137
        resp.StatusCode, err = strconv.Atoi(f[1])
 
138
        if err != nil {
 
139
                return nil, &badStringError{"malformed HTTP status code", f[1]}
 
140
        }
 
141
 
 
142
        resp.Proto = f[0]
 
143
        var ok bool
 
144
        if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok {
 
145
                return nil, &badStringError{"malformed HTTP version", resp.Proto}
 
146
        }
 
147
 
 
148
        // Parse the response headers.
 
149
        mimeHeader, err := tp.ReadMIMEHeader()
 
150
        if err != nil {
 
151
                if err == io.EOF {
 
152
                        err = io.ErrUnexpectedEOF
 
153
                }
 
154
                return nil, err
 
155
        }
 
156
        resp.Header = Header(mimeHeader)
 
157
 
 
158
        fixPragmaCacheControl(resp.Header)
 
159
 
 
160
        err = readTransfer(resp, r)
 
161
        if err != nil {
 
162
                return nil, err
 
163
        }
 
164
 
 
165
        return resp, nil
 
166
}
 
167
 
 
168
// RFC2616: Should treat
 
169
//      Pragma: no-cache
 
170
// like
 
171
//      Cache-Control: no-cache
 
172
func fixPragmaCacheControl(header Header) {
 
173
        if hp, ok := header["Pragma"]; ok && len(hp) > 0 && hp[0] == "no-cache" {
 
174
                if _, presentcc := header["Cache-Control"]; !presentcc {
 
175
                        header["Cache-Control"] = []string{"no-cache"}
 
176
                }
 
177
        }
 
178
}
 
179
 
 
180
// ProtoAtLeast reports whether the HTTP protocol used
 
181
// in the response is at least major.minor.
 
182
func (r *Response) ProtoAtLeast(major, minor int) bool {
 
183
        return r.ProtoMajor > major ||
 
184
                r.ProtoMajor == major && r.ProtoMinor >= minor
 
185
}
 
186
 
 
187
// Writes the response (header, body and trailer) in wire format. This method
 
188
// consults the following fields of the response:
 
189
//
 
190
//  StatusCode
 
191
//  ProtoMajor
 
192
//  ProtoMinor
 
193
//  Request.Method
 
194
//  TransferEncoding
 
195
//  Trailer
 
196
//  Body
 
197
//  ContentLength
 
198
//  Header, values for non-canonical keys will have unpredictable behavior
 
199
//
 
200
// Body is closed after it is sent.
 
201
func (r *Response) Write(w io.Writer) error {
 
202
 
 
203
        // Status line
 
204
        text := r.Status
 
205
        if text == "" {
 
206
                var ok bool
 
207
                text, ok = statusText[r.StatusCode]
 
208
                if !ok {
 
209
                        text = "status code " + strconv.Itoa(r.StatusCode)
 
210
                }
 
211
        }
 
212
        protoMajor, protoMinor := strconv.Itoa(r.ProtoMajor), strconv.Itoa(r.ProtoMinor)
 
213
        statusCode := strconv.Itoa(r.StatusCode) + " "
 
214
        text = strings.TrimPrefix(text, statusCode)
 
215
        io.WriteString(w, "HTTP/"+protoMajor+"."+protoMinor+" "+statusCode+text+"\r\n")
 
216
 
 
217
        // Process Body,ContentLength,Close,Trailer
 
218
        tw, err := newTransferWriter(r)
 
219
        if err != nil {
 
220
                return err
 
221
        }
 
222
        err = tw.WriteHeader(w)
 
223
        if err != nil {
 
224
                return err
 
225
        }
 
226
 
 
227
        // Rest of header
 
228
        err = r.Header.WriteSubset(w, respExcludeHeader)
 
229
        if err != nil {
 
230
                return err
 
231
        }
 
232
 
 
233
        // End-of-header
 
234
        io.WriteString(w, "\r\n")
 
235
 
 
236
        // Write body and trailer
 
237
        err = tw.WriteBody(w)
 
238
        if err != nil {
 
239
                return err
 
240
        }
 
241
 
 
242
        // Success
 
243
        return nil
 
244
}