Source file src/net/http/response.go

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

View as plain text