LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // HTTP Request reading and parsing. | 5 // HTTP Request reading and parsing. |
6 | 6 |
7 // Package http implements parsing of HTTP requests, replies, and URLs and | 7 // Package http implements parsing of HTTP requests, replies, and URLs and |
8 // provides an extensible HTTP server and a basic HTTP client. | 8 // provides an extensible HTTP server and a basic HTTP client. |
9 package http | 9 package http |
10 | 10 |
(...skipping 21 matching lines...) Expand all Loading... |
32 chunkSize = 4 << 10 // 4 KB chunks | 32 chunkSize = 4 << 10 // 4 KB chunks |
33 defaultMaxMemory = 32 << 20 // 32 MB | 33 defaultMaxMemory = 32 << 20 // 32 MB |
34 ) | 34 ) |
35 | 35 |
36 // ErrMissingFile is returned by FormFile when the provided file field name | 36 // ErrMissingFile is returned by FormFile when the provided file field name |
37 // is either not present in the request or not a file field. | 37 // is either not present in the request or not a file field. |
38 var ErrMissingFile = os.NewError("http: no such file") | 38 var ErrMissingFile = os.NewError("http: no such file") |
39 | 39 |
40 // HTTP request parsing errors. | 40 // HTTP request parsing errors. |
41 type ProtocolError struct { | 41 type ProtocolError struct { |
42 » os.Error | 42 » ErrorString string |
43 } | 43 } |
| 44 |
| 45 func (err *ProtocolError) String() string { return err.ErrorString } |
44 | 46 |
45 var ( | 47 var ( |
46 » ErrLineTooLong = &ProtocolError{os.NewError("header line too lo
ng")} | 48 » ErrLineTooLong = &ProtocolError{"header line too long"} |
47 » ErrHeaderTooLong = &ProtocolError{os.NewError("header too long")} | 49 » ErrHeaderTooLong = &ProtocolError{"header too long"} |
48 » ErrShortBody = &ProtocolError{os.NewError("entity body too sh
ort")} | 50 » ErrShortBody = &ProtocolError{"entity body too short"} |
49 » ErrNotSupported = &ProtocolError{os.NewError("feature not suppor
ted")} | 51 » ErrNotSupported = &ProtocolError{"feature not supported"} |
50 » ErrUnexpectedTrailer = &ProtocolError{os.NewError("trailer header wit
hout chunked transfer encoding")} | 52 » ErrUnexpectedTrailer = &ProtocolError{"trailer header without chunked
transfer encoding"} |
51 » ErrMissingContentLength = &ProtocolError{os.NewError("missing ContentLen
gth in HEAD response")} | 53 » ErrMissingContentLength = &ProtocolError{"missing ContentLength in HEAD
response"} |
52 » ErrNotMultipart = &ProtocolError{os.NewError("request Content-Ty
pe isn't multipart/form-data")} | 54 » ErrNotMultipart = &ProtocolError{"request Content-Type isn't mul
tipart/form-data"} |
53 » ErrMissingBoundary = &ProtocolError{os.NewError("no multipart bound
ary param Content-Type")} | 55 » ErrMissingBoundary = &ProtocolError{"no multipart boundary param Co
ntent-Type"} |
54 ) | 56 ) |
55 | 57 |
56 type badStringError struct { | 58 type badStringError struct { |
57 what string | 59 what string |
58 str string | 60 str string |
59 } | 61 } |
60 | 62 |
61 func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e
.str) } | 63 func (e *badStringError) String() string { return fmt.Sprintf("%s %q", e.what, e
.str) } |
62 | 64 |
63 var reqExcludeHeader = map[string]bool{ | 65 // Headers that Request.Write handles itself and should be skipped. |
| 66 var reqWriteExcludeHeader = map[string]bool{ |
64 "Host": true, | 67 "Host": true, |
65 "User-Agent": true, | 68 "User-Agent": true, |
66 "Referer": true, | |
67 "Content-Length": true, | 69 "Content-Length": true, |
68 "Transfer-Encoding": true, | 70 "Transfer-Encoding": true, |
69 "Trailer": true, | 71 "Trailer": true, |
70 } | 72 } |
71 | 73 |
72 // A Request represents a parsed HTTP request header. | 74 // A Request represents a parsed HTTP request header. |
73 type Request struct { | 75 type Request struct { |
74 Method string // GET, POST, PUT, etc. | 76 Method string // GET, POST, PUT, etc. |
75 RawURL string // The raw URL given in the request. | 77 RawURL string // The raw URL given in the request. |
76 URL *URL // Parsed URL. | 78 URL *URL // Parsed URL. |
(...skipping 18 matching lines...) Expand all Loading... |
95 // "Accept-Language": {"en-us"}, | 97 // "Accept-Language": {"en-us"}, |
96 // "Connection": {"keep-alive"}, | 98 // "Connection": {"keep-alive"}, |
97 // } | 99 // } |
98 // | 100 // |
99 // HTTP defines that header names are case-insensitive. | 101 // HTTP defines that header names are case-insensitive. |
100 // The request parser implements this by canonicalizing the | 102 // The request parser implements this by canonicalizing the |
101 // name, making the first character and any characters | 103 // name, making the first character and any characters |
102 // following a hyphen uppercase and the rest lowercase. | 104 // following a hyphen uppercase and the rest lowercase. |
103 Header Header | 105 Header Header |
104 | 106 |
105 // Cookie records the HTTP cookies sent with the request. | |
106 Cookie []*Cookie | |
107 | |
108 // The message body. | 107 // The message body. |
109 Body io.ReadCloser | 108 Body io.ReadCloser |
110 | 109 |
111 // ContentLength records the length of the associated content. | 110 // ContentLength records the length of the associated content. |
112 // The value -1 indicates that the length is unknown. | 111 // The value -1 indicates that the length is unknown. |
113 // Values >= 0 indicate that the given number of bytes may be read from
Body. | 112 // Values >= 0 indicate that the given number of bytes may be read from
Body. |
114 ContentLength int64 | 113 ContentLength int64 |
115 | 114 |
116 // TransferEncoding lists the transfer encodings from outermost to inner
most. | 115 // TransferEncoding lists the transfer encodings from outermost to inner
most. |
117 // An empty list denotes the "identity" encoding. | 116 // An empty list denotes the "identity" encoding. |
118 TransferEncoding []string | 117 TransferEncoding []string |
119 | 118 |
120 // Whether to close the connection after replying to this request. | 119 // Whether to close the connection after replying to this request. |
121 Close bool | 120 Close bool |
122 | 121 |
123 // The host on which the URL is sought. | 122 // The host on which the URL is sought. |
124 // Per RFC 2616, this is either the value of the Host: header | 123 // Per RFC 2616, this is either the value of the Host: header |
125 // or the host name given in the URL itself. | 124 // or the host name given in the URL itself. |
126 Host string | 125 Host string |
127 | |
128 // The referring URL, if sent in the request. | |
129 // | |
130 // Referer is misspelled as in the request itself, | |
131 // a mistake from the earliest days of HTTP. | |
132 // This value can also be fetched from the Header map | |
133 // as Header["Referer"]; the benefit of making it | |
134 // available as a structure field is that the compiler | |
135 // can diagnose programs that use the alternate | |
136 // (correct English) spelling req.Referrer but cannot | |
137 // diagnose programs that use Header["Referrer"]. | |
138 Referer string | |
139 | |
140 // The User-Agent: header string, if sent in the request. | |
141 UserAgent string | |
142 | 126 |
143 // The parsed form. Only available after ParseForm is called. | 127 // The parsed form. Only available after ParseForm is called. |
144 Form Values | 128 Form Values |
145 | 129 |
146 // The parsed multipart form, including file uploads. | 130 // The parsed multipart form, including file uploads. |
147 // Only available after ParseMultipartForm is called. | 131 // Only available after ParseMultipartForm is called. |
148 MultipartForm *multipart.Form | 132 MultipartForm *multipart.Form |
149 | 133 |
150 // Trailer maps trailer keys to values. Like for Header, if the | 134 // Trailer maps trailer keys to values. Like for Header, if the |
151 // response has multiple trailer lines with the same key, they will be | 135 // response has multiple trailer lines with the same key, they will be |
(...skipping 17 matching lines...) Expand all Loading... |
169 TLS *tls.ConnectionState | 153 TLS *tls.ConnectionState |
170 } | 154 } |
171 | 155 |
172 // ProtoAtLeast returns whether the HTTP protocol used | 156 // ProtoAtLeast returns whether the HTTP protocol used |
173 // in the request is at least major.minor. | 157 // in the request is at least major.minor. |
174 func (r *Request) ProtoAtLeast(major, minor int) bool { | 158 func (r *Request) ProtoAtLeast(major, minor int) bool { |
175 return r.ProtoMajor > major || | 159 return r.ProtoMajor > major || |
176 r.ProtoMajor == major && r.ProtoMinor >= minor | 160 r.ProtoMajor == major && r.ProtoMinor >= minor |
177 } | 161 } |
178 | 162 |
| 163 // UserAgent returns the client's User-Agent, if sent in the request. |
| 164 func (r *Request) UserAgent() string { |
| 165 return r.Header.Get("User-Agent") |
| 166 } |
| 167 |
| 168 // Cookies parses and returns the HTTP cookies sent with the request. |
| 169 func (r *Request) Cookies() []*Cookie { |
| 170 return readCookies(r.Header, "") |
| 171 } |
| 172 |
| 173 var ErrNoCookie = os.NewError("http: named cookied not present") |
| 174 |
| 175 // Cookie returns the named cookie provided in the request or |
| 176 // ErrNoCookie if not found. |
| 177 func (r *Request) Cookie(name string) (*Cookie, os.Error) { |
| 178 for _, c := range readCookies(r.Header, name) { |
| 179 return c, nil |
| 180 } |
| 181 return nil, ErrNoCookie |
| 182 } |
| 183 |
| 184 // AddCookie adds a cookie to the request. Per RFC 6265 section 5.4, |
| 185 // AddCookie does not attach more than one Cookie header field. That |
| 186 // means all cookies, if any, are written into the same line, |
| 187 // separated by semicolon. |
| 188 func (r *Request) AddCookie(c *Cookie) { |
| 189 s := fmt.Sprintf("%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value)) |
| 190 if c := r.Header.Get("Cookie"); c != "" { |
| 191 r.Header.Set("Cookie", c+"; "+s) |
| 192 } else { |
| 193 r.Header.Set("Cookie", s) |
| 194 } |
| 195 } |
| 196 |
| 197 // Referer returns the referring URL, if sent in the request. |
| 198 // |
| 199 // Referer is misspelled as in the request itself, a mistake from the |
| 200 // earliest days of HTTP. This value can also be fetched from the |
| 201 // Header map as Header["Referer"]; the benefit of making it available |
| 202 // as a method is that the compiler can diagnose programs that use the |
| 203 // alternate (correct English) spelling req.Referrer() but cannot |
| 204 // diagnose programs that use Header["Referrer"]. |
| 205 func (r *Request) Referer() string { |
| 206 return r.Header.Get("Referer") |
| 207 } |
| 208 |
179 // multipartByReader is a sentinel value. | 209 // multipartByReader is a sentinel value. |
180 // Its presence in Request.MultipartForm indicates that parsing of the request | 210 // Its presence in Request.MultipartForm indicates that parsing of the request |
181 // body has been handed off to a MultipartReader instead of ParseMultipartFrom. | 211 // body has been handed off to a MultipartReader instead of ParseMultipartFrom. |
182 var multipartByReader = &multipart.Form{ | 212 var multipartByReader = &multipart.Form{ |
183 Value: make(map[string][]string), | 213 Value: make(map[string][]string), |
184 File: make(map[string][]*multipart.FileHeader), | 214 File: make(map[string][]*multipart.FileHeader), |
185 } | 215 } |
186 | 216 |
187 // MultipartReader returns a MIME multipart reader if this is a | 217 // MultipartReader returns a MIME multipart reader if this is a |
188 // multipart/form-data POST request, else returns nil and an error. | 218 // multipart/form-data POST request, else returns nil and an error. |
189 // Use this function instead of ParseMultipartForm to | 219 // Use this function instead of ParseMultipartForm to |
190 // process the request body as a stream. | 220 // process the request body as a stream. |
191 func (r *Request) MultipartReader() (multipart.Reader, os.Error) { | 221 func (r *Request) MultipartReader() (*multipart.Reader, os.Error) { |
192 if r.MultipartForm == multipartByReader { | 222 if r.MultipartForm == multipartByReader { |
193 return nil, os.NewError("http: MultipartReader called twice") | 223 return nil, os.NewError("http: MultipartReader called twice") |
194 } | 224 } |
195 if r.MultipartForm != nil { | 225 if r.MultipartForm != nil { |
196 return nil, os.NewError("http: multipart handled by ParseMultipa
rtForm") | 226 return nil, os.NewError("http: multipart handled by ParseMultipa
rtForm") |
197 } | 227 } |
198 r.MultipartForm = multipartByReader | 228 r.MultipartForm = multipartByReader |
199 return r.multipartReader() | 229 return r.multipartReader() |
200 } | 230 } |
201 | 231 |
202 func (r *Request) multipartReader() (multipart.Reader, os.Error) { | 232 func (r *Request) multipartReader() (*multipart.Reader, os.Error) { |
203 v := r.Header.Get("Content-Type") | 233 v := r.Header.Get("Content-Type") |
204 if v == "" { | 234 if v == "" { |
205 return nil, ErrNotMultipart | 235 return nil, ErrNotMultipart |
206 } | 236 } |
207 d, params := mime.ParseMediaType(v) | 237 d, params := mime.ParseMediaType(v) |
208 if d != "multipart/form-data" { | 238 if d != "multipart/form-data" { |
209 return nil, ErrNotMultipart | 239 return nil, ErrNotMultipart |
210 } | 240 } |
211 boundary, ok := params["boundary"] | 241 boundary, ok := params["boundary"] |
212 if !ok { | 242 if !ok { |
(...skipping 10 matching lines...) Expand all Loading... |
223 return def | 253 return def |
224 } | 254 } |
225 | 255 |
226 const defaultUserAgent = "Go http package" | 256 const defaultUserAgent = "Go http package" |
227 | 257 |
228 // Write writes an HTTP/1.1 request -- header and body -- in wire format. | 258 // Write writes an HTTP/1.1 request -- header and body -- in wire format. |
229 // This method consults the following fields of req: | 259 // This method consults the following fields of req: |
230 // Host | 260 // Host |
231 // RawURL, if non-empty, or else URL | 261 // RawURL, if non-empty, or else URL |
232 // Method (defaults to "GET") | 262 // Method (defaults to "GET") |
233 //» UserAgent (defaults to defaultUserAgent) | 263 //» Header |
234 //» Referer | |
235 //» Header (only keys not already in this list) | |
236 //» Cookie | |
237 // ContentLength | 264 // ContentLength |
238 // TransferEncoding | 265 // TransferEncoding |
239 // Body | 266 // Body |
240 // | 267 // |
241 // If Body is present, Content-Length is <= 0 and TransferEncoding | 268 // If Body is present, Content-Length is <= 0 and TransferEncoding |
242 // hasn't been set to "identity", Write adds "Transfer-Encoding: | 269 // hasn't been set to "identity", Write adds "Transfer-Encoding: |
243 // chunked" to the header. Body is closed after it is sent. | 270 // chunked" to the header. Body is closed after it is sent. |
244 func (req *Request) Write(w io.Writer) os.Error { | 271 func (req *Request) Write(w io.Writer) os.Error { |
245 return req.write(w, false) | 272 return req.write(w, false) |
246 } | 273 } |
(...skipping 27 matching lines...) Expand all Loading... |
274 uri = "/" + uri | 301 uri = "/" + uri |
275 } | 302 } |
276 uri = req.URL.Scheme + "://" + host + uri | 303 uri = req.URL.Scheme + "://" + host + uri |
277 } | 304 } |
278 } | 305 } |
279 | 306 |
280 fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"),
uri) | 307 fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"),
uri) |
281 | 308 |
282 // Header lines | 309 // Header lines |
283 fmt.Fprintf(w, "Host: %s\r\n", host) | 310 fmt.Fprintf(w, "Host: %s\r\n", host) |
284 » fmt.Fprintf(w, "User-Agent: %s\r\n", valueOrDefault(req.UserAgent, defau
ltUserAgent)) | 311 |
285 » if req.Referer != "" { | 312 » // Use the defaultUserAgent unless the Header contains one, which |
286 » » fmt.Fprintf(w, "Referer: %s\r\n", req.Referer) | 313 » // may be blank to not send the header. |
| 314 » userAgent := defaultUserAgent |
| 315 » if req.Header != nil { |
| 316 » » if ua := req.Header["User-Agent"]; len(ua) > 0 { |
| 317 » » » userAgent = ua[0] |
| 318 » » } |
| 319 » } |
| 320 » if userAgent != "" { |
| 321 » » fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent) |
287 } | 322 } |
288 | 323 |
289 // Process Body,ContentLength,Close,Trailer | 324 // Process Body,ContentLength,Close,Trailer |
290 tw, err := newTransferWriter(req) | 325 tw, err := newTransferWriter(req) |
291 if err != nil { | 326 if err != nil { |
292 return err | 327 return err |
293 } | 328 } |
294 err = tw.WriteHeader(w) | 329 err = tw.WriteHeader(w) |
295 if err != nil { | 330 if err != nil { |
296 return err | 331 return err |
297 } | 332 } |
298 | 333 |
299 // TODO: split long values? (If so, should share code with Conn.Write) | 334 // TODO: split long values? (If so, should share code with Conn.Write) |
300 » // TODO: if Header includes values for Host, User-Agent, or Referer, thi
s | 335 » err = req.Header.WriteSubset(w, reqWriteExcludeHeader) |
301 » // may conflict with the User-Agent or Referer headers we add manually. | |
302 » // One solution would be to remove the Host, UserAgent, and Referer fiel
ds | |
303 » // from Request, and introduce Request methods along the lines of | |
304 » // Response.{GetHeader,AddHeader} and string constants for "Host", | |
305 » // "User-Agent" and "Referer". | |
306 » err = req.Header.WriteSubset(w, reqExcludeHeader) | |
307 if err != nil { | 336 if err != nil { |
308 return err | |
309 } | |
310 | |
311 if err = writeCookies(w, req.Cookie); err != nil { | |
312 return err | 337 return err |
313 } | 338 } |
314 | 339 |
315 io.WriteString(w, "\r\n") | 340 io.WriteString(w, "\r\n") |
316 | 341 |
317 // Write body and trailer | 342 // Write body and trailer |
318 err = tw.WriteBody(w) | 343 err = tw.WriteBody(w) |
319 if err != nil { | 344 if err != nil { |
320 return err | 345 return err |
321 } | 346 } |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 // GET http://www.google.com/index.html HTTP/1.1 | 576 // GET http://www.google.com/index.html HTTP/1.1 |
552 // Host: doesntmatter | 577 // Host: doesntmatter |
553 // the same. In the second case, any Host line is ignored. | 578 // the same. In the second case, any Host line is ignored. |
554 req.Host = req.URL.Host | 579 req.Host = req.URL.Host |
555 if req.Host == "" { | 580 if req.Host == "" { |
556 req.Host = req.Header.Get("Host") | 581 req.Host = req.Header.Get("Host") |
557 } | 582 } |
558 req.Header.Del("Host") | 583 req.Header.Del("Host") |
559 | 584 |
560 fixPragmaCacheControl(req.Header) | 585 fixPragmaCacheControl(req.Header) |
561 | |
562 // Pull out useful fields as a convenience to clients. | |
563 req.Referer = req.Header.Get("Referer") | |
564 req.Header.Del("Referer") | |
565 | |
566 req.UserAgent = req.Header.Get("User-Agent") | |
567 req.Header.Del("User-Agent") | |
568 | 586 |
569 // TODO: Parse specific header values: | 587 // TODO: Parse specific header values: |
570 // Accept | 588 // Accept |
571 // Accept-Encoding | 589 // Accept-Encoding |
572 // Accept-Language | 590 // Accept-Language |
573 // Authorization | 591 // Authorization |
574 // Cache-Control | 592 // Cache-Control |
575 // Connection | 593 // Connection |
576 // Date | 594 // Date |
577 // Expect | 595 // Expect |
(...skipping 12 matching lines...) Expand all Loading... |
590 // Upgrade | 608 // Upgrade |
591 // User-Agent | 609 // User-Agent |
592 // Via | 610 // Via |
593 // Warning | 611 // Warning |
594 | 612 |
595 err = readTransfer(req, b) | 613 err = readTransfer(req, b) |
596 if err != nil { | 614 if err != nil { |
597 return nil, err | 615 return nil, err |
598 } | 616 } |
599 | 617 |
600 req.Cookie = readCookies(req.Header) | |
601 | |
602 return req, nil | 618 return req, nil |
603 } | 619 } |
604 | 620 |
605 // Values maps a string key to a list of values. | 621 // Values maps a string key to a list of values. |
606 // It is typically used for query parameters and form values. | 622 // It is typically used for query parameters and form values. |
607 // Unlike in the Header map, the keys in a Values map | 623 // Unlike in the Header map, the keys in a Values map |
608 // are case-sensitive. | 624 // are case-sensitive. |
609 type Values map[string][]string | 625 type Values map[string][]string |
610 | 626 |
611 // Get gets the first value associated with the given key. | 627 // Get gets the first value associated with the given key. |
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
794 func (r *Request) expectsContinue() bool { | 810 func (r *Request) expectsContinue() bool { |
795 return strings.ToLower(r.Header.Get("Expect")) == "100-continue" | 811 return strings.ToLower(r.Header.Get("Expect")) == "100-continue" |
796 } | 812 } |
797 | 813 |
798 func (r *Request) wantsHttp10KeepAlive() bool { | 814 func (r *Request) wantsHttp10KeepAlive() bool { |
799 if r.ProtoMajor != 1 || r.ProtoMinor != 0 { | 815 if r.ProtoMajor != 1 || r.ProtoMinor != 0 { |
800 return false | 816 return false |
801 } | 817 } |
802 return strings.Contains(strings.ToLower(r.Header.Get("Connection")), "ke
ep-alive") | 818 return strings.Contains(strings.ToLower(r.Header.Get("Connection")), "ke
ep-alive") |
803 } | 819 } |
LEFT | RIGHT |