|  | // Copyright 2009 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | // HTTP Response reading and parsing. | 
|  |  | 
|  | package http | 
|  |  | 
|  | import ( | 
|  | "bufio" | 
|  | "bytes" | 
|  | "crypto/tls" | 
|  | "errors" | 
|  | "fmt" | 
|  | "io" | 
|  | "net/textproto" | 
|  | "net/url" | 
|  | "strconv" | 
|  | "strings" | 
|  |  | 
|  | "golang.org/x/net/http/httpguts" | 
|  | ) | 
|  |  | 
|  | var respExcludeHeader = map[string]bool{ | 
|  | "Content-Length":    true, | 
|  | "Transfer-Encoding": true, | 
|  | "Trailer":           true, | 
|  | } | 
|  |  | 
|  | // Response represents the response from an HTTP request. | 
|  | // | 
|  | // The Client and Transport return Responses from servers once | 
|  | // the response headers have been received. The response body | 
|  | // is streamed on demand as the Body field is read. | 
|  | type Response struct { | 
|  | Status     string // e.g. "200 OK" | 
|  | StatusCode int    // e.g. 200 | 
|  | Proto      string // e.g. "HTTP/1.0" | 
|  | ProtoMajor int    // e.g. 1 | 
|  | ProtoMinor int    // e.g. 0 | 
|  |  | 
|  | // Header maps header keys to values. If the response had multiple | 
|  | // headers with the same key, they may be concatenated, with comma | 
|  | // delimiters.  (RFC 7230, section 3.2.2 requires that multiple headers | 
|  | // be semantically equivalent to a comma-delimited sequence.) When | 
|  | // Header values are duplicated by other fields in this struct (e.g., | 
|  | // ContentLength, TransferEncoding, Trailer), the field values are | 
|  | // authoritative. | 
|  | // | 
|  | // Keys in the map are canonicalized (see CanonicalHeaderKey). | 
|  | Header Header | 
|  |  | 
|  | // Body represents the response body. | 
|  | // | 
|  | // The response body is streamed on demand as the Body field | 
|  | // is read. If the network connection fails or the server | 
|  | // terminates the response, Body.Read calls return an error. | 
|  | // | 
|  | // The http Client and Transport guarantee that Body is always | 
|  | // non-nil, even on responses without a body or responses with | 
|  | // a zero-length body. It is the caller's responsibility to | 
|  | // close Body. The default HTTP client's Transport may not | 
|  | // reuse HTTP/1.x "keep-alive" TCP connections if the Body is | 
|  | // not read to completion and closed. | 
|  | // | 
|  | // The Body is automatically dechunked if the server replied | 
|  | // with a "chunked" Transfer-Encoding. | 
|  | // | 
|  | // As of Go 1.12, the Body will be also implement io.Writer | 
|  | // on a successful "101 Switching Protocols" response, | 
|  | // as used by WebSockets and HTTP/2's "h2c" mode. | 
|  | Body io.ReadCloser | 
|  |  | 
|  | // ContentLength records the length of the associated content. The | 
|  | // value -1 indicates that the length is unknown. Unless Request.Method | 
|  | // is "HEAD", values >= 0 indicate that the given number of bytes may | 
|  | // be read from Body. | 
|  | ContentLength int64 | 
|  |  | 
|  | // Contains transfer encodings from outer-most to inner-most. Value is | 
|  | // nil, means that "identity" encoding is used. | 
|  | TransferEncoding []string | 
|  |  | 
|  | // Close records whether the header directed that the connection be | 
|  | // closed after reading Body. The value is advice for clients: neither | 
|  | // ReadResponse nor Response.Write ever closes a connection. | 
|  | Close bool | 
|  |  | 
|  | // Uncompressed reports whether the response was sent compressed but | 
|  | // was decompressed by the http package. When true, reading from | 
|  | // Body yields the uncompressed content instead of the compressed | 
|  | // content actually set from the server, ContentLength is set to -1, | 
|  | // and the "Content-Length" and "Content-Encoding" fields are deleted | 
|  | // from the responseHeader. To get the original response from | 
|  | // the server, set Transport.DisableCompression to true. | 
|  | Uncompressed bool | 
|  |  | 
|  | // Trailer maps trailer keys to values in the same | 
|  | // format as Header. | 
|  | // | 
|  | // The Trailer initially contains only nil values, one for | 
|  | // each key specified in the server's "Trailer" header | 
|  | // value. Those values are not added to Header. | 
|  | // | 
|  | // Trailer must not be accessed concurrently with Read calls | 
|  | // on the Body. | 
|  | // | 
|  | // After Body.Read has returned io.EOF, Trailer will contain | 
|  | // any trailer values sent by the server. | 
|  | Trailer Header | 
|  |  | 
|  | // Request is the request that was sent to obtain this Response. | 
|  | // Request's Body is nil (having already been consumed). | 
|  | // This is only populated for Client requests. | 
|  | Request *Request | 
|  |  | 
|  | // TLS contains information about the TLS connection on which the | 
|  | // response was received. It is nil for unencrypted responses. | 
|  | // The pointer is shared between responses and should not be | 
|  | // modified. | 
|  | TLS *tls.ConnectionState | 
|  | } | 
|  |  | 
|  | // Cookies parses and returns the cookies set in the Set-Cookie headers. | 
|  | func (r *Response) Cookies() []*Cookie { | 
|  | return readSetCookies(r.Header) | 
|  | } | 
|  |  | 
|  | // ErrNoLocation is returned by Response's Location method | 
|  | // when no Location header is present. | 
|  | var ErrNoLocation = errors.New("http: no Location header in response") | 
|  |  | 
|  | // Location returns the URL of the response's "Location" header, | 
|  | // if present. Relative redirects are resolved relative to | 
|  | // the Response's Request. ErrNoLocation is returned if no | 
|  | // Location header is present. | 
|  | func (r *Response) Location() (*url.URL, error) { | 
|  | lv := r.Header.Get("Location") | 
|  | if lv == "" { | 
|  | return nil, ErrNoLocation | 
|  | } | 
|  | if r.Request != nil && r.Request.URL != nil { | 
|  | return r.Request.URL.Parse(lv) | 
|  | } | 
|  | return url.Parse(lv) | 
|  | } | 
|  |  | 
|  | // ReadResponse reads and returns an HTTP response from r. | 
|  | // The req parameter optionally specifies the Request that corresponds | 
|  | // to this Response. If nil, a GET request is assumed. | 
|  | // Clients must call resp.Body.Close when finished reading resp.Body. | 
|  | // After that call, clients can inspect resp.Trailer to find key/value | 
|  | // pairs included in the response trailer. | 
|  | func ReadResponse(r *bufio.Reader, req *Request) (*Response, error) { | 
|  | tp := textproto.NewReader(r) | 
|  | resp := &Response{ | 
|  | Request: req, | 
|  | } | 
|  |  | 
|  | // Parse the first line of the response. | 
|  | line, err := tp.ReadLine() | 
|  | if err != nil { | 
|  | if err == io.EOF { | 
|  | err = io.ErrUnexpectedEOF | 
|  | } | 
|  | return nil, err | 
|  | } | 
|  | if i := strings.IndexByte(line, ' '); i == -1 { | 
|  | return nil, &badStringError{"malformed HTTP response", line} | 
|  | } else { | 
|  | resp.Proto = line[:i] | 
|  | resp.Status = strings.TrimLeft(line[i+1:], " ") | 
|  | } | 
|  | statusCode := resp.Status | 
|  | if i := strings.IndexByte(resp.Status, ' '); i != -1 { | 
|  | statusCode = resp.Status[:i] | 
|  | } | 
|  | if len(statusCode) != 3 { | 
|  | return nil, &badStringError{"malformed HTTP status code", statusCode} | 
|  | } | 
|  | resp.StatusCode, err = strconv.Atoi(statusCode) | 
|  | if err != nil || resp.StatusCode < 0 { | 
|  | return nil, &badStringError{"malformed HTTP status code", statusCode} | 
|  | } | 
|  | var ok bool | 
|  | if resp.ProtoMajor, resp.ProtoMinor, ok = ParseHTTPVersion(resp.Proto); !ok { | 
|  | return nil, &badStringError{"malformed HTTP version", resp.Proto} | 
|  | } | 
|  |  | 
|  | // Parse the response headers. | 
|  | mimeHeader, err := tp.ReadMIMEHeader() | 
|  | if err != nil { | 
|  | if err == io.EOF { | 
|  | err = io.ErrUnexpectedEOF | 
|  | } | 
|  | return nil, err | 
|  | } | 
|  | resp.Header = Header(mimeHeader) | 
|  |  | 
|  | fixPragmaCacheControl(resp.Header) | 
|  |  | 
|  | err = readTransfer(resp, r) | 
|  | if err != nil { | 
|  | return nil, err | 
|  | } | 
|  |  | 
|  | return resp, nil | 
|  | } | 
|  |  | 
|  | // RFC 7234, section 5.4: Should treat | 
|  | //	Pragma: no-cache | 
|  | // like | 
|  | //	Cache-Control: no-cache | 
|  | func fixPragmaCacheControl(header Header) { | 
|  | if hp, ok := header["Pragma"]; ok && len(hp) > 0 && hp[0] == "no-cache" { | 
|  | if _, presentcc := header["Cache-Control"]; !presentcc { | 
|  | header["Cache-Control"] = []string{"no-cache"} | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | // ProtoAtLeast reports whether the HTTP protocol used | 
|  | // in the response is at least major.minor. | 
|  | func (r *Response) ProtoAtLeast(major, minor int) bool { | 
|  | return r.ProtoMajor > major || | 
|  | r.ProtoMajor == major && r.ProtoMinor >= minor | 
|  | } | 
|  |  | 
|  | // Write writes r to w in the HTTP/1.x server response format, | 
|  | // including the status line, headers, body, and optional trailer. | 
|  | // | 
|  | // This method consults the following fields of the response r: | 
|  | // | 
|  | //  StatusCode | 
|  | //  ProtoMajor | 
|  | //  ProtoMinor | 
|  | //  Request.Method | 
|  | //  TransferEncoding | 
|  | //  Trailer | 
|  | //  Body | 
|  | //  ContentLength | 
|  | //  Header, values for non-canonical keys will have unpredictable behavior | 
|  | // | 
|  | // The Response Body is closed after it is sent. | 
|  | func (r *Response) Write(w io.Writer) error { | 
|  | // Status line | 
|  | text := r.Status | 
|  | if text == "" { | 
|  | var ok bool | 
|  | text, ok = statusText[r.StatusCode] | 
|  | if !ok { | 
|  | text = "status code " + strconv.Itoa(r.StatusCode) | 
|  | } | 
|  | } else { | 
|  | // Just to reduce stutter, if user set r.Status to "200 OK" and StatusCode to 200. | 
|  | // Not important. | 
|  | text = strings.TrimPrefix(text, strconv.Itoa(r.StatusCode)+" ") | 
|  | } | 
|  |  | 
|  | if _, err := fmt.Fprintf(w, "HTTP/%d.%d %03d %s\r\n", r.ProtoMajor, r.ProtoMinor, r.StatusCode, text); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Clone it, so we can modify r1 as needed. | 
|  | r1 := new(Response) | 
|  | *r1 = *r | 
|  | if r1.ContentLength == 0 && r1.Body != nil { | 
|  | // Is it actually 0 length? Or just unknown? | 
|  | var buf [1]byte | 
|  | n, err := r1.Body.Read(buf[:]) | 
|  | if err != nil && err != io.EOF { | 
|  | return err | 
|  | } | 
|  | if n == 0 { | 
|  | // Reset it to a known zero reader, in case underlying one | 
|  | // is unhappy being read repeatedly. | 
|  | r1.Body = NoBody | 
|  | } else { | 
|  | r1.ContentLength = -1 | 
|  | r1.Body = struct { | 
|  | io.Reader | 
|  | io.Closer | 
|  | }{ | 
|  | io.MultiReader(bytes.NewReader(buf[:1]), r.Body), | 
|  | r.Body, | 
|  | } | 
|  | } | 
|  | } | 
|  | // If we're sending a non-chunked HTTP/1.1 response without a | 
|  | // content-length, the only way to do that is the old HTTP/1.0 | 
|  | // way, by noting the EOF with a connection close, so we need | 
|  | // to set Close. | 
|  | if r1.ContentLength == -1 && !r1.Close && r1.ProtoAtLeast(1, 1) && !chunked(r1.TransferEncoding) && !r1.Uncompressed { | 
|  | r1.Close = true | 
|  | } | 
|  |  | 
|  | // Process Body,ContentLength,Close,Trailer | 
|  | tw, err := newTransferWriter(r1) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | err = tw.writeHeader(w, nil) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Rest of header | 
|  | err = r.Header.WriteSubset(w, respExcludeHeader) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // contentLengthAlreadySent may have been already sent for | 
|  | // POST/PUT requests, even if zero length. See Issue 8180. | 
|  | contentLengthAlreadySent := tw.shouldSendContentLength() | 
|  | if r1.ContentLength == 0 && !chunked(r1.TransferEncoding) && !contentLengthAlreadySent && bodyAllowedForStatus(r.StatusCode) { | 
|  | if _, err := io.WriteString(w, "Content-Length: 0\r\n"); err != nil { | 
|  | return err | 
|  | } | 
|  | } | 
|  |  | 
|  | // End-of-header | 
|  | if _, err := io.WriteString(w, "\r\n"); err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Write body and trailer | 
|  | err = tw.writeBody(w) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  |  | 
|  | // Success | 
|  | return nil | 
|  | } | 
|  |  | 
|  | func (r *Response) closeBody() { | 
|  | if r.Body != nil { | 
|  | r.Body.Close() | 
|  | } | 
|  | } | 
|  |  | 
|  | // bodyIsWritable reports whether the Body supports writing. The | 
|  | // Transport returns Writable bodies for 101 Switching Protocols | 
|  | // responses. | 
|  | // The Transport uses this method to determine whether a persistent | 
|  | // connection is done being managed from its perspective. Once we | 
|  | // return a writable response body to a user, the net/http package is | 
|  | // done managing that connection. | 
|  | func (r *Response) bodyIsWritable() bool { | 
|  | _, ok := r.Body.(io.Writer) | 
|  | return ok | 
|  | } | 
|  |  | 
|  | // isProtocolSwitch reports whether r is a response to a successful | 
|  | // protocol upgrade. | 
|  | func (r *Response) isProtocolSwitch() bool { | 
|  | return r.StatusCode == StatusSwitchingProtocols && | 
|  | r.Header.Get("Upgrade") != "" && | 
|  | httpguts.HeaderValuesContainsToken(r.Header["Connection"], "Upgrade") | 
|  | } |