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
7package http
8
9import (
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
22var 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//
30type 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.
113func (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.
119var 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.
125func (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.
142func 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
202func 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.
212func (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.
233func (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
325func (r *Response) closeBody() {
326	if r.Body != nil {
327		r.Body.Close()
328	}
329}
330