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