github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/net/http/response.go (about) 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 "bytes" 12 "crypto/tls" 13 "errors" 14 "fmt" 15 "io" 16 "net/textproto" 17 "net/url" 18 "strconv" 19 "strings" 20 ) 21 22 var respExcludeHeader = map[string]bool{ 23 "Content-Length": true, 24 "Transfer-Encoding": true, 25 "Trailer": true, 26 } 27 28 // Response represents the response from an HTTP request. 29 // 30 type Response struct { 31 Status string // e.g. "200 OK" 32 StatusCode int // e.g. 200 33 Proto string // e.g. "HTTP/1.0" 34 ProtoMajor int // e.g. 1 35 ProtoMinor int // e.g. 0 36 37 // Header maps header keys to values. If the response had multiple 38 // headers with the same key, they may be concatenated, with comma 39 // delimiters. (Section 4.2 of RFC 2616 requires that multiple headers 40 // be semantically equivalent to a comma-delimited sequence.) Values 41 // duplicated by other fields in this struct (e.g., ContentLength) are 42 // omitted from Header. 43 // 44 // Keys in the map are canonicalized (see CanonicalHeaderKey). 45 Header Header 46 47 // Body represents the response body. 48 // 49 // The http Client and Transport guarantee that Body is always 50 // non-nil, even on responses without a body or responses with 51 // a zero-length body. It is the caller's responsibility to 52 // close Body. The default HTTP client's Transport does not 53 // attempt to reuse HTTP/1.0 or HTTP/1.1 TCP connections 54 // ("keep-alive") unless the Body is read to completion and is 55 // closed. 56 // 57 // The Body is automatically dechunked if the server replied 58 // with a "chunked" Transfer-Encoding. 59 Body io.ReadCloser 60 61 // ContentLength records the length of the associated content. The 62 // value -1 indicates that the length is unknown. Unless Request.Method 63 // is "HEAD", values >= 0 indicate that the given number of bytes may 64 // be read from Body. 65 ContentLength int64 66 67 // Contains transfer encodings from outer-most to inner-most. Value is 68 // nil, means that "identity" encoding is used. 69 TransferEncoding []string 70 71 // Close records whether the header directed that the connection be 72 // closed after reading Body. The value is advice for clients: neither 73 // ReadResponse nor Response.Write ever closes a connection. 74 Close bool 75 76 // Trailer maps trailer keys to values in the same 77 // format as Header. 78 // 79 // The Trailer initially contains only nil values, one for 80 // each key specified in the server's "Trailer" header 81 // value. Those values are not added to Header. 82 // 83 // Trailer must not be accessed concurrently with Read calls 84 // on the Body. 85 // 86 // After Body.Read has returned io.EOF, Trailer will contain 87 // any trailer values sent by the server. 88 Trailer Header 89 90 // The Request that was sent to obtain this Response. 91 // Request's Body is nil (having already been consumed). 92 // This is only populated for Client requests. 93 Request *Request 94 95 // TLS contains information about the TLS connection on which the 96 // response was received. It is nil for unencrypted responses. 97 // The pointer is shared between responses and should not be 98 // modified. 99 TLS *tls.ConnectionState 100 } 101 102 // Cookies parses and returns the cookies set in the Set-Cookie headers. 103 func (r *Response) Cookies() []*Cookie { 104 return readSetCookies(r.Header) 105 } 106 107 // ErrNoLocation is returned by Response's Location method 108 // when no Location header is present. 109 var ErrNoLocation = errors.New("http: no Location header in response") 110 111 // Location returns the URL of the response's "Location" header, 112 // if present. Relative redirects are resolved relative to 113 // the Response's Request. ErrNoLocation is returned if no 114 // Location header is present. 115 func (r *Response) Location() (*url.URL, error) { 116 lv := r.Header.Get("Location") 117 if lv == "" { 118 return nil, ErrNoLocation 119 } 120 if r.Request != nil && r.Request.URL != nil { 121 return r.Request.URL.Parse(lv) 122 } 123 return url.Parse(lv) 124 } 125 126 // ReadResponse reads and returns an HTTP response from r. 127 // The req parameter optionally specifies the Request that corresponds 128 // to this Response. If nil, a GET request is assumed. 129 // Clients must call resp.Body.Close when finished reading resp.Body. 130 // After that call, clients can inspect resp.Trailer to find key/value 131 // pairs included in the response trailer. 132 func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) { 133 tp := textproto.NewReader(r) 134 resp := &Response{ 135 Request: req, 136 } 137 138 // Parse the first line of the response. 139 line, err := tp.ReadLine() 140 if err != nil { 141 if err == io.EOF { 142 err = io.ErrUnexpectedEOF 143 } 144 return nil, err 145 } 146 f := strings.SplitN(line, " ", 3) 147 if len(f) < 2 { 148 return nil, &badStringError{"malformed HTTP response", line} 149 } 150 reasonPhrase := "" 151 if len(f) > 2 { 152 reasonPhrase = f[2] 153 } 154 if len(f[1]) != 3 { 155 return nil, &badStringError{"malformed HTTP status code", f[1]} 156 } 157 resp.StatusCode, err = strconv.Atoi(f[1]) 158 if err != nil || resp.StatusCode < 0 { 159 return nil, &badStringError{"malformed HTTP status code", f[1]} 160 } 161 resp.Status = f[1] + " " + reasonPhrase 162 resp.Proto = f[0] 163 var ok bool 164 if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok { 165 return nil, &badStringError{"malformed HTTP version", resp.Proto} 166 } 167 168 // Parse the response headers. 169 mimeHeader, err := tp.ReadMIMEHeader() 170 if err != nil { 171 if err == io.EOF { 172 err = io.ErrUnexpectedEOF 173 } 174 return nil, err 175 } 176 resp.Header = Header(mimeHeader) 177 178 fixPragmaCacheControl(resp.Header) 179 180 err = readTransfer(resp, r) 181 if err != nil { 182 return nil, err 183 } 184 185 return resp, nil 186 } 187 188 // RFC2616: Should treat 189 // Pragma: no-cache 190 // like 191 // Cache-Control: no-cache 192 func fixPragmaCacheControl(header Header) { 193 if hp, ok := header["Pragma"]; ok && len(hp) > 0 && hp[0] == "no-cache" { 194 if _, presentcc := header["Cache-Control"]; !presentcc { 195 header["Cache-Control"] = []string{"no-cache"} 196 } 197 } 198 } 199 200 // ProtoAtLeast reports whether the HTTP protocol used 201 // in the response is at least major.minor. 202 func (r *Response) ProtoAtLeast(major, minor int) bool { 203 return r.ProtoMajor > major || 204 r.ProtoMajor == major && r.ProtoMinor >= minor 205 } 206 207 // Write writes r to w in the HTTP/1.n server response format, 208 // including the status line, headers, body, and optional trailer. 209 // 210 // This method consults the following fields of the response r: 211 // 212 // StatusCode 213 // ProtoMajor 214 // ProtoMinor 215 // Request.Method 216 // TransferEncoding 217 // Trailer 218 // Body 219 // ContentLength 220 // Header, values for non-canonical keys will have unpredictable behavior 221 // 222 // The Response Body is closed after it is sent. 223 func (r *Response) Write(w io.Writer) error { 224 // Status line 225 text := r.Status 226 if text == "" { 227 var ok bool 228 text, ok = statusText[r.StatusCode] 229 if !ok { 230 text = "status code " + strconv.Itoa(r.StatusCode) 231 } 232 } else { 233 // Just to reduce stutter, if user set r.Status to "200 OK" and StatusCode to 200. 234 // Not important. 235 text = strings.TrimPrefix(text, strconv.Itoa(r.StatusCode)+" ") 236 } 237 238 if _, err := fmt.Fprintf(w, "HTTP/%d.%d %03d %s\r\n", r.ProtoMajor, r.ProtoMinor, r.StatusCode, text); err != nil { 239 return err 240 } 241 242 // Clone it, so we can modify r1 as needed. 243 r1 := new(Response) 244 *r1 = *r 245 if r1.ContentLength == 0 && r1.Body != nil { 246 // Is it actually 0 length? Or just unknown? 247 var buf [1]byte 248 n, err := r1.Body.Read(buf[:]) 249 if err != nil && err != io.EOF { 250 return err 251 } 252 if n == 0 { 253 // Reset it to a known zero reader, in case underlying one 254 // is unhappy being read repeatedly. 255 r1.Body = eofReader 256 } else { 257 r1.ContentLength = -1 258 r1.Body = struct { 259 io.Reader 260 io.Closer 261 }{ 262 io.MultiReader(bytes.NewReader(buf[:1]), r.Body), 263 r.Body, 264 } 265 } 266 } 267 // If we're sending a non-chunked HTTP/1.1 response without a 268 // content-length, the only way to do that is the old HTTP/1.0 269 // way, by noting the EOF with a connection close, so we need 270 // to set Close. 271 if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) { 272 r1.Close = true 273 } 274 275 // Process Body,ContentLength,Close,Trailer 276 tw, err := newTransferWriter(r1) 277 if err != nil { 278 return err 279 } 280 err = tw.WriteHeader(w) 281 if err != nil { 282 return err 283 } 284 285 // Rest of header 286 err = r.Header.WriteSubset(w, respExcludeHeader) 287 if err != nil { 288 return err 289 } 290 291 // contentLengthAlreadySent may have been already sent for 292 // POST/PUT requests, even if zero length. See Issue 8180. 293 contentLengthAlreadySent := tw.shouldSendContentLength() 294 if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent { 295 if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil { 296 return err 297 } 298 } 299 300 // End-of-header 301 if _, err := io.WriteString(w, "\r\n"); err != nil { 302 return err 303 } 304 305 // Write body and trailer 306 err = tw.WriteBody(w) 307 if err != nil { 308 return err 309 } 310 311 // Success 312 return nil 313 }