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  }