github.com/sbinet/go@v0.0.0-20160827155028-54d7de7dd62b/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 // Uncompressed reports whether the response was sent compressed but 77 // was decompressed by the http package. When true, reading from 78 // Body yields the uncompressed content instead of the compressed 79 // content actually set from the server, ContentLength is set to -1, 80 // and the "Content-Length" and "Content-Encoding" fields are deleted 81 // from the responseHeader. To get the original response from 82 // the server, set Transport.DisableCompression to true. 83 Uncompressed bool 84 85 // Trailer maps trailer keys to values in the same 86 // format as Header. 87 // 88 // The Trailer initially contains only nil values, one for 89 // each key specified in the server's "Trailer" header 90 // value. Those values are not added to Header. 91 // 92 // Trailer must not be accessed concurrently with Read calls 93 // on the Body. 94 // 95 // After Body.Read has returned io.EOF, Trailer will contain 96 // any trailer values sent by the server. 97 Trailer Header 98 99 // Request is the request that was sent to obtain this Response. 100 // Request's Body is nil (having already been consumed). 101 // This is only populated for Client requests. 102 Request *Request 103 104 // TLS contains information about the TLS connection on which the 105 // response was received. It is nil for unencrypted responses. 106 // The pointer is shared between responses and should not be 107 // modified. 108 TLS *tls.ConnectionState 109 } 110 111 // Cookies parses and returns the cookies set in the Set-Cookie headers. 112 func (r *Response) Cookies() []*Cookie { 113 return readSetCookies(r.Header) 114 } 115 116 // ErrNoLocation is returned by Response's Location method 117 // when no Location header is present. 118 var ErrNoLocation = errors.New("http: no Location header in response") 119 120 // Location returns the URL of the response's "Location" header, 121 // if present. Relative redirects are resolved relative to 122 // the Response's Request. ErrNoLocation is returned if no 123 // Location header is present. 124 func (r *Response) Location() (*url.URL, error) { 125 lv := r.Header.Get("Location") 126 if lv == "" { 127 return nil, ErrNoLocation 128 } 129 if r.Request != nil && r.Request.URL != nil { 130 return r.Request.URL.Parse(lv) 131 } 132 return url.Parse(lv) 133 } 134 135 // ReadResponse reads and returns an HTTP response from r. 136 // The req parameter optionally specifies the Request that corresponds 137 // to this Response. If nil, a GET request is assumed. 138 // Clients must call resp.Body.Close when finished reading resp.Body. 139 // After that call, clients can inspect resp.Trailer to find key/value 140 // pairs included in the response trailer. 141 func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) { 142 tp := textproto.NewReader(r) 143 resp := &Response{ 144 Request: req, 145 } 146 147 // Parse the first line of the response. 148 line, err := tp.ReadLine() 149 if err != nil { 150 if err == io.EOF { 151 err = io.ErrUnexpectedEOF 152 } 153 return nil, err 154 } 155 f := strings.SplitN(line, " ", 3) 156 if len(f) < 2 { 157 return nil, &badStringError{"malformed HTTP response", line} 158 } 159 reasonPhrase := "" 160 if len(f) > 2 { 161 reasonPhrase = f[2] 162 } 163 if len(f[1]) != 3 { 164 return nil, &badStringError{"malformed HTTP status code", f[1]} 165 } 166 resp.StatusCode, err = strconv.Atoi(f[1]) 167 if err != nil || resp.StatusCode < 0 { 168 return nil, &badStringError{"malformed HTTP status code", f[1]} 169 } 170 resp.Status = f[1] + " " + reasonPhrase 171 resp.Proto = f[0] 172 var ok bool 173 if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok { 174 return nil, &badStringError{"malformed HTTP version", resp.Proto} 175 } 176 177 // Parse the response headers. 178 mimeHeader, err := tp.ReadMIMEHeader() 179 if err != nil { 180 if err == io.EOF { 181 err = io.ErrUnexpectedEOF 182 } 183 return nil, err 184 } 185 resp.Header = Header(mimeHeader) 186 187 fixPragmaCacheControl(resp.Header) 188 189 err = readTransfer(resp, r) 190 if err != nil { 191 return nil, err 192 } 193 194 return resp, nil 195 } 196 197 // RFC 2616: Should treat 198 // Pragma: no-cache 199 // like 200 // Cache-Control: no-cache 201 func fixPragmaCacheControl(header Header) { 202 if hp, ok := header["Pragma"]; ok && len(hp) > 0 && hp[0] == "no-cache" { 203 if _, presentcc := header["Cache-Control"]; !presentcc { 204 header["Cache-Control"] = []string{"no-cache"} 205 } 206 } 207 } 208 209 // ProtoAtLeast reports whether the HTTP protocol used 210 // in the response is at least major.minor. 211 func (r *Response) ProtoAtLeast(major, minor int) bool { 212 return r.ProtoMajor > major || 213 r.ProtoMajor == major && r.ProtoMinor >= minor 214 } 215 216 // Write writes r to w in the HTTP/1.x server response format, 217 // including the status line, headers, body, and optional trailer. 218 // 219 // This method consults the following fields of the response r: 220 // 221 // StatusCode 222 // ProtoMajor 223 // ProtoMinor 224 // Request.Method 225 // TransferEncoding 226 // Trailer 227 // Body 228 // ContentLength 229 // Header, values for non-canonical keys will have unpredictable behavior 230 // 231 // The Response Body is closed after it is sent. 232 func (r *Response) Write(w io.Writer) error { 233 // Status line 234 text := r.Status 235 if text == "" { 236 var ok bool 237 text, ok = statusText[r.StatusCode] 238 if !ok { 239 text = "status code " + strconv.Itoa(r.StatusCode) 240 } 241 } else { 242 // Just to reduce stutter, if user set r.Status to "200 OK" and StatusCode to 200. 243 // Not important. 244 text = strings.TrimPrefix(text, strconv.Itoa(r.StatusCode)+" ") 245 } 246 247 if _, err := fmt.Fprintf(w, "HTTP/%d.%d %03d %s\r\n", r.ProtoMajor, r.ProtoMinor, r.StatusCode, text); err != nil { 248 return err 249 } 250 251 // Clone it, so we can modify r1 as needed. 252 r1 := new(Response) 253 *r1 = *r 254 if r1.ContentLength == 0 && r1.Body != nil { 255 // Is it actually 0 length? Or just unknown? 256 var buf [1]byte 257 n, err := r1.Body.Read(buf[:]) 258 if err != nil && err != io.EOF { 259 return err 260 } 261 if n == 0 { 262 // Reset it to a known zero reader, in case underlying one 263 // is unhappy being read repeatedly. 264 r1.Body = eofReader 265 } else { 266 r1.ContentLength = -1 267 r1.Body = struct { 268 io.Reader 269 io.Closer 270 }{ 271 io.MultiReader(bytes.NewReader(buf[:1]), r.Body), 272 r.Body, 273 } 274 } 275 } 276 // If we're sending a non-chunked HTTP/1.1 response without a 277 // content-length, the only way to do that is the old HTTP/1.0 278 // way, by noting the EOF with a connection close, so we need 279 // to set Close. 280 if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) && !r1.Uncompressed { 281 r1.Close = true 282 } 283 284 // Process Body,ContentLength,Close,Trailer 285 tw, err := newTransferWriter(r1) 286 if err != nil { 287 return err 288 } 289 err = tw.WriteHeader(w) 290 if err != nil { 291 return err 292 } 293 294 // Rest of header 295 err = r.Header.WriteSubset(w, respExcludeHeader) 296 if err != nil { 297 return err 298 } 299 300 // contentLengthAlreadySent may have been already sent for 301 // POST/PUT requests, even if zero length. See Issue 8180. 302 contentLengthAlreadySent := tw.shouldSendContentLength() 303 if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent { 304 if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil { 305 return err 306 } 307 } 308 309 // End-of-header 310 if _, err := io.WriteString(w, "\r\n"); err != nil { 311 return err 312 } 313 314 // Write body and trailer 315 err = tw.WriteBody(w) 316 if err != nil { 317 return err 318 } 319 320 // Success 321 return nil 322 }