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