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