Left: | ||
Right: |
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 | 7 package http |
8 | 8 |
9 import ( | 9 import ( |
10 "bufio" | 10 "bufio" |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
63 var reqWriteExcludeHeader = map[string]bool{ | 63 var reqWriteExcludeHeader = map[string]bool{ |
64 "Host": true, // not in Header map anyway | 64 "Host": true, // not in Header map anyway |
65 "User-Agent": true, | 65 "User-Agent": true, |
66 "Content-Length": true, | 66 "Content-Length": true, |
67 "Transfer-Encoding": true, | 67 "Transfer-Encoding": true, |
68 "Trailer": true, | 68 "Trailer": true, |
69 } | 69 } |
70 | 70 |
71 // A Request represents an HTTP request received by a server | 71 // A Request represents an HTTP request received by a server |
72 // or to be sent by a client. | 72 // or to be sent by a client. |
73 // | |
74 // The field semantics differ slightly between client and server | |
75 // usage. In addition to the notes on the fields below, see the | |
76 // documentation for Request.Write and RoundTripper. | |
73 type Request struct { | 77 type Request struct { |
74 » Method string // GET, POST, PUT, etc. | 78 » // Method specifies the HTTP method (GET, POST, PUT, etc.). |
75 | 79 » // For client requests an empty string means GET. |
76 » // URL is created from the URI supplied on the Request-Line | 80 » Method string |
77 » // as stored in RequestURI. | 81 |
78 » // | 82 » // URL specifies either the URI being requested (for server |
79 » // For most requests, fields other than Path and RawQuery | 83 » // requests) or the URL to access (for client requests). |
80 » // will be empty. (See RFC 2616, Section 5.1.2) | 84 » // |
85 » // For server requests the URL is parsed from the URI | |
86 » // supplied on the Request-Line as stored in RequestURI. For | |
87 » // most requests, fields other than Path and RawQuery will be | |
88 » // empty. (See RFC 2616, Section 5.1.2) | |
89 » // | |
90 » // For client requests, the URL's Host specifies the server to | |
91 » // connect to, while the Request's Host field optionally | |
92 » // specifies the Host header value to send in the HTTP | |
93 » // request. | |
81 URL *url.URL | 94 URL *url.URL |
82 | 95 |
83 // The protocol version for incoming requests. | 96 // The protocol version for incoming requests. |
84 » // Outgoing requests always use HTTP/1.1. | 97 » // Client requests always use HTTP/1.1. |
85 Proto string // "HTTP/1.0" | 98 Proto string // "HTTP/1.0" |
86 ProtoMajor int // 1 | 99 ProtoMajor int // 1 |
87 ProtoMinor int // 0 | 100 ProtoMinor int // 0 |
88 | 101 |
89 // A header maps request lines to their values. | 102 // A header maps request lines to their values. |
90 // If the header says | 103 // If the header says |
91 // | 104 // |
92 // accept-encoding: gzip, deflate | 105 // accept-encoding: gzip, deflate |
93 // Accept-Language: en-us | 106 // Accept-Language: en-us |
94 // Connection: keep-alive | 107 // Connection: keep-alive |
95 // | 108 // |
96 // then | 109 // then |
97 // | 110 // |
98 // Header = map[string][]string{ | 111 // Header = map[string][]string{ |
99 // "Accept-Encoding": {"gzip, deflate"}, | 112 // "Accept-Encoding": {"gzip, deflate"}, |
100 // "Accept-Language": {"en-us"}, | 113 // "Accept-Language": {"en-us"}, |
101 // "Connection": {"keep-alive"}, | 114 // "Connection": {"keep-alive"}, |
102 // } | 115 // } |
103 // | 116 // |
104 // HTTP defines that header names are case-insensitive. | 117 // HTTP defines that header names are case-insensitive. |
105 // The request parser implements this by canonicalizing the | 118 // The request parser implements this by canonicalizing the |
106 // name, making the first character and any characters | 119 // name, making the first character and any characters |
107 // following a hyphen uppercase and the rest lowercase. | 120 // following a hyphen uppercase and the rest lowercase. |
121 // | |
122 // For client requests certain headers are automatically | |
123 // added and may override values in Header. | |
124 // | |
125 // See the documentation for the Request.Write method. | |
108 Header Header | 126 Header Header |
109 | 127 |
110 // Body is the request's body. | 128 // Body is the request's body. |
111 // | 129 // |
112 » // For client requests, a nil body means the request has no | 130 » // For client requests a nil body means the request has no |
113 // body, such as a GET request. The HTTP Client's Transport | 131 // body, such as a GET request. The HTTP Client's Transport |
114 // is responsible for calling the Close method. | 132 // is responsible for calling the Close method. |
115 // | 133 // |
116 » // For server requests, the Request Body is always non-nil | 134 » // For server requests the Request Body is always non-nil |
117 // but will return EOF immediately when no body is present. | 135 // but will return EOF immediately when no body is present. |
118 // The Server will close the request body. The ServeHTTP | 136 // The Server will close the request body. The ServeHTTP |
119 // Handler does not need to. | 137 // Handler does not need to. |
120 Body io.ReadCloser | 138 Body io.ReadCloser |
121 | 139 |
122 // ContentLength records the length of the associated content. | 140 // ContentLength records the length of the associated content. |
123 // The value -1 indicates that the length is unknown. | 141 // The value -1 indicates that the length is unknown. |
124 // Values >= 0 indicate that the given number of bytes may | 142 // Values >= 0 indicate that the given number of bytes may |
125 // be read from Body. | 143 // be read from Body. |
126 » // For outgoing requests, a value of 0 means unknown if Body is not nil. | 144 » // For client requests, a value of 0 means unknown if Body is not nil. |
127 ContentLength int64 | 145 ContentLength int64 |
128 | 146 |
129 // TransferEncoding lists the transfer encodings from outermost to | 147 // TransferEncoding lists the transfer encodings from outermost to |
130 // innermost. An empty list denotes the "identity" encoding. | 148 // innermost. An empty list denotes the "identity" encoding. |
131 // TransferEncoding can usually be ignored; chunked encoding is | 149 // TransferEncoding can usually be ignored; chunked encoding is |
132 // automatically added and removed as necessary when sending and | 150 // automatically added and removed as necessary when sending and |
133 // receiving requests. | 151 // receiving requests. |
134 TransferEncoding []string | 152 TransferEncoding []string |
135 | 153 |
136 // Close indicates whether to close the connection after | 154 // Close indicates whether to close the connection after |
137 » // replying to this request. | 155 » // replying to this request (for servers) or after sending |
156 » // the request (for clients). | |
138 Close bool | 157 Close bool |
139 | 158 |
140 » // The host on which the URL is sought. | 159 » // For server requests Host specifies the host on which the |
141 » // Per RFC 2616, this is either the value of the Host: header | 160 » // URL is sought. Per RFC 2616, this is either the value of |
142 » // or the host name given in the URL itself. | 161 » // the "Host" header or the host name given in the URL itself. |
143 // It may be of the form "host:port". | 162 // It may be of the form "host:port". |
163 // | |
164 // For client requests Host optionally overrides the Host | |
165 // header to send. If empty, the Request.Write method uses | |
166 // the value of URL.Host. | |
144 Host string | 167 Host string |
145 | 168 |
146 // Form contains the parsed form data, including both the URL | 169 // Form contains the parsed form data, including both the URL |
147 // field's query parameters and the POST or PUT form data. | 170 // field's query parameters and the POST or PUT form data. |
148 // This field is only available after ParseForm is called. | 171 // This field is only available after ParseForm is called. |
149 // The HTTP client ignores Form and uses Body instead. | 172 // The HTTP client ignores Form and uses Body instead. |
150 Form url.Values | 173 Form url.Values |
151 | 174 |
152 // PostForm contains the parsed form data from POST or PUT | 175 // PostForm contains the parsed form data from POST or PUT |
153 // body parameters. | 176 // body parameters. |
154 // This field is only available after ParseForm is called. | 177 // This field is only available after ParseForm is called. |
155 // The HTTP client ignores PostForm and uses Body instead. | 178 // The HTTP client ignores PostForm and uses Body instead. |
156 PostForm url.Values | 179 PostForm url.Values |
157 | 180 |
158 // MultipartForm is the parsed multipart form, including file uploads. | 181 // MultipartForm is the parsed multipart form, including file uploads. |
159 // This field is only available after ParseMultipartForm is called. | 182 // This field is only available after ParseMultipartForm is called. |
160 // The HTTP client ignores MultipartForm and uses Body instead. | 183 // The HTTP client ignores MultipartForm and uses Body instead. |
161 MultipartForm *multipart.Form | 184 MultipartForm *multipart.Form |
162 | 185 |
163 » // Trailer maps trailer keys to values. Like for Header, if the | 186 » // Trailer specifies additional headers that are sent after the request |
164 » // response has multiple trailer lines with the same key, they will be | 187 » // body. |
165 » // concatenated, delimited by commas. | 188 » // |
166 » // For server requests, Trailer is only populated after Body has been | 189 » // For server requests the Trailer map initially contains only the |
167 » // closed or fully consumed. | 190 » // trailer keys, with nil values. (The client declares which trailers it |
168 » // Trailer support is only partially complete. | 191 » // will later send.) While the handler is reading from Body, it must |
192 » // not reference Trailer. After reading from Body returns EOF, Trailer | |
193 » // can be read again and will contain non-nil values, if they were sent | |
194 » // by the client. | |
195 » // | |
196 » // For client requests Trailer must be initialized to a map containing | |
197 » // the trailer keys to later send. The values may be nil or their final | |
198 » // values. The ContentLength must be 0 or -1, to send a chunked request. | |
199 » // After the HTTP request is sent the map values can be updated while | |
200 » // the request body is read. Once the body returns EOF, the caller must | |
201 » // not mutate Trailer. | |
202 » // | |
203 » // Few HTTP clients, servers, or proxies support HTTP trailers. | |
169 Trailer Header | 204 Trailer Header |
170 | 205 |
171 // RemoteAddr allows HTTP servers and other software to record | 206 // RemoteAddr allows HTTP servers and other software to record |
172 // the network address that sent the request, usually for | 207 // the network address that sent the request, usually for |
173 // logging. This field is not filled in by ReadRequest and | 208 // logging. This field is not filled in by ReadRequest and |
174 // has no defined format. The HTTP server in this package | 209 // has no defined format. The HTTP server in this package |
175 // sets RemoteAddr to an "IP:port" address before invoking a | 210 // sets RemoteAddr to an "IP:port" address before invoking a |
176 // handler. | 211 // handler. |
177 // This field is ignored by the HTTP client. | 212 // This field is ignored by the HTTP client. |
178 RemoteAddr string | 213 RemoteAddr string |
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 // Wrap the writer in a bufio Writer if it's not already buffered. | 384 // Wrap the writer in a bufio Writer if it's not already buffered. |
350 // Don't always call NewWriter, as that forces a bytes.Buffer | 385 // Don't always call NewWriter, as that forces a bytes.Buffer |
351 // and other small bufio Writers to have a minimum 4k buffer | 386 // and other small bufio Writers to have a minimum 4k buffer |
352 // size. | 387 // size. |
353 var bw *bufio.Writer | 388 var bw *bufio.Writer |
354 if _, ok := w.(io.ByteWriter); !ok { | 389 if _, ok := w.(io.ByteWriter); !ok { |
355 bw = bufio.NewWriter(w) | 390 bw = bufio.NewWriter(w) |
356 w = bw | 391 w = bw |
357 } | 392 } |
358 | 393 |
359 » fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method, "GET"), ruri) | 394 » _, err := fmt.Fprintf(w, "%s %s HTTP/1.1\r\n", valueOrDefault(req.Method , "GET"), ruri) |
395 » if err != nil { | |
396 » » return err | |
397 » } | |
360 | 398 |
361 // Header lines | 399 // Header lines |
362 » fmt.Fprintf(w, "Host: %s\r\n", host) | 400 » _, err = fmt.Fprintf(w, "Host: %s\r\n", host) |
401 » if err != nil { | |
402 » » return err | |
403 » } | |
363 | 404 |
364 // Use the defaultUserAgent unless the Header contains one, which | 405 // Use the defaultUserAgent unless the Header contains one, which |
365 // may be blank to not send the header. | 406 // may be blank to not send the header. |
366 userAgent := defaultUserAgent | 407 userAgent := defaultUserAgent |
367 if req.Header != nil { | 408 if req.Header != nil { |
368 if ua := req.Header["User-Agent"]; len(ua) > 0 { | 409 if ua := req.Header["User-Agent"]; len(ua) > 0 { |
369 userAgent = ua[0] | 410 userAgent = ua[0] |
370 } | 411 } |
371 } | 412 } |
372 if userAgent != "" { | 413 if userAgent != "" { |
373 » » fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent) | 414 » » _, err = fmt.Fprintf(w, "User-Agent: %s\r\n", userAgent) |
415 » » if err != nil { | |
416 » » » return err | |
417 » » } | |
374 } | 418 } |
375 | 419 |
376 // Process Body,ContentLength,Close,Trailer | 420 // Process Body,ContentLength,Close,Trailer |
377 tw, err := newTransferWriter(req) | 421 tw, err := newTransferWriter(req) |
378 if err != nil { | 422 if err != nil { |
379 return err | 423 return err |
380 } | 424 } |
381 err = tw.WriteHeader(w) | 425 err = tw.WriteHeader(w) |
382 if err != nil { | 426 if err != nil { |
383 return err | 427 return err |
384 } | 428 } |
385 | 429 |
386 // TODO: split long values? (If so, should share code with Conn.Write) | |
387 err = req.Header.WriteSubset(w, reqWriteExcludeHeader) | 430 err = req.Header.WriteSubset(w, reqWriteExcludeHeader) |
388 if err != nil { | 431 if err != nil { |
389 return err | 432 return err |
390 } | 433 } |
391 | 434 |
392 if extraHeaders != nil { | 435 if extraHeaders != nil { |
393 err = extraHeaders.Write(w) | 436 err = extraHeaders.Write(w) |
394 if err != nil { | 437 if err != nil { |
395 return err | 438 return err |
396 } | 439 } |
397 } | 440 } |
398 | 441 |
399 » io.WriteString(w, "\r\n") | 442 » _, err = io.WriteString(w, "\r\n") |
443 » if err != nil { | |
444 » » return err | |
445 » } | |
400 | 446 |
401 // Write body and trailer | 447 // Write body and trailer |
402 err = tw.WriteBody(w) | 448 err = tw.WriteBody(w) |
403 if err != nil { | 449 if err != nil { |
404 return err | 450 return err |
405 } | 451 } |
406 | 452 |
407 if bw != nil { | 453 if bw != nil { |
408 return bw.Flush() | 454 return bw.Flush() |
409 } | 455 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
469 case *bytes.Reader: | 515 case *bytes.Reader: |
470 req.ContentLength = int64(v.Len()) | 516 req.ContentLength = int64(v.Len()) |
471 case *strings.Reader: | 517 case *strings.Reader: |
472 req.ContentLength = int64(v.Len()) | 518 req.ContentLength = int64(v.Len()) |
473 } | 519 } |
474 } | 520 } |
475 | 521 |
476 return req, nil | 522 return req, nil |
477 } | 523 } |
478 | 524 |
479 // BasicAuth returns the request's username and password if this is | 525 // BasicAuth returns the username and password provided in the request's |
josharian
2014/03/16 18:51:16
Maybe something like:
// BasicAuth returns the us
| |
480 // an authenticated request using the basic authentication scheme. | 526 // Authorization header, if the request uses HTTP Basic Authentication. |
481 // (See RFC 2617, Section 2) | 527 // See RFC 2617, Section 2. |
482 func (r *Request) BasicAuth() (username, password string, ok bool) { | 528 func (r *Request) BasicAuth() (username, password string, ok bool) { |
josharian
2014/03/16 18:51:16
The RFC uses "userid" instead of "username" in sec
| |
483 » return parseBasicAuth(r.Header.Get("Authorization")) | 529 » auth := r.Header.Get("Authorization") |
josharian
2014/03/16 18:51:16
Why the indirection? I assumed that it was for eas
| |
484 } | 530 » if auth == "" { |
485 | 531 » » return |
486 // parseBasicAuth parses a HTTP Basic Authentication string. | 532 » } |
josharian
2014/03/16 18:51:16
s/a/an/
| |
533 » return parseBasicAuth(auth) | |
534 } | |
535 | |
536 // parseBasicAuth parses an HTTP Basic Authentication string. | |
487 // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true) . | 537 // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true) . |
488 func parseBasicAuth(auth string) (username, password string, ok bool) { | 538 func parseBasicAuth(auth string) (username, password string, ok bool) { |
489 » s1 := strings.SplitN(auth, " ", 2) | 539 » if !strings.HasPrefix(auth, "Basic ") { |
490 » if len(s1) != 2 || s1[0] != "Basic" { | 540 » » return |
491 » » return "", "", false | 541 » } |
492 » } | 542 » c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basi c ")) |
493 » b, err := base64.StdEncoding.DecodeString(s1[1]) | 543 » if err != nil { |
494 » if err != nil { | 544 » » return |
495 » » return "", "", false | 545 » } |
496 » } | 546 » cs := string(c) |
497 » s2 := strings.SplitN(string(b), ":", 2) | 547 » s := strings.IndexByte(cs, ':') |
498 » if len(s2) != 2 { | 548 » if s < 0 { |
josharian
2014/03/16 18:51:16
What if the password contains ":"? The RFC only sp
| |
499 » » return "", "", false | 549 » » return |
500 » } | 550 » } |
501 » return s2[0], s2[1], true | 551 » return cs[:s], cs[s+1:], true |
josharian
2014/03/16 18:51:16
I find the numbered local variables here impede re
| |
502 } | 552 } |
503 | 553 |
504 // SetBasicAuth sets the request's Authorization header to use HTTP | 554 // SetBasicAuth sets the request's Authorization header to use HTTP |
505 // Basic Authentication with the provided username and password. | 555 // Basic Authentication with the provided username and password. |
506 // | 556 // |
507 // With HTTP Basic Authentication the provided username and password | 557 // With HTTP Basic Authentication the provided username and password |
508 // are not encrypted. | 558 // are not encrypted. |
509 func (r *Request) SetBasicAuth(username, password string) { | 559 func (r *Request) SetBasicAuth(username, password string) { |
510 r.Header.Set("Authorization", "Basic "+basicAuth(username, password)) | 560 r.Header.Set("Authorization", "Basic "+basicAuth(username, password)) |
511 } | 561 } |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
603 // Host: doesntmatter | 653 // Host: doesntmatter |
604 // the same. In the second case, any Host line is ignored. | 654 // the same. In the second case, any Host line is ignored. |
605 req.Host = req.URL.Host | 655 req.Host = req.URL.Host |
606 if req.Host == "" { | 656 if req.Host == "" { |
607 req.Host = req.Header.get("Host") | 657 req.Host = req.Header.get("Host") |
608 } | 658 } |
609 delete(req.Header, "Host") | 659 delete(req.Header, "Host") |
610 | 660 |
611 fixPragmaCacheControl(req.Header) | 661 fixPragmaCacheControl(req.Header) |
612 | 662 |
613 // TODO: Parse specific header values: | |
614 // Accept | |
615 // Accept-Encoding | |
616 // Accept-Language | |
617 // Authorization | |
618 // Cache-Control | |
619 // Connection | |
620 // Date | |
621 // Expect | |
622 // From | |
623 // If-Match | |
624 // If-Modified-Since | |
625 // If-None-Match | |
626 // If-Range | |
627 // If-Unmodified-Since | |
628 // Max-Forwards | |
629 // Proxy-Authorization | |
630 // Referer [sic] | |
631 // TE (transfer-codings) | |
632 // Trailer | |
633 // Transfer-Encoding | |
634 // Upgrade | |
635 // User-Agent | |
636 // Via | |
637 // Warning | |
638 | |
639 err = readTransfer(req, b) | 663 err = readTransfer(req, b) |
640 if err != nil { | 664 if err != nil { |
641 return nil, err | 665 return nil, err |
642 } | 666 } |
643 | 667 |
668 req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, fals e) | |
644 return req, nil | 669 return req, nil |
645 } | 670 } |
646 | 671 |
647 // MaxBytesReader is similar to io.LimitReader but is intended for | 672 // MaxBytesReader is similar to io.LimitReader but is intended for |
648 // limiting the size of incoming request bodies. In contrast to | 673 // limiting the size of incoming request bodies. In contrast to |
649 // io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a | 674 // io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a |
650 // non-EOF error for a Read beyond the limit, and Closes the | 675 // non-EOF error for a Read beyond the limit, and Closes the |
651 // underlying reader when its Close method is called. | 676 // underlying reader when its Close method is called. |
652 // | 677 // |
653 // MaxBytesReader prevents clients from accidentally or maliciously | 678 // MaxBytesReader prevents clients from accidentally or maliciously |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
800 err := r.ParseForm() | 825 err := r.ParseForm() |
801 if err != nil { | 826 if err != nil { |
802 return err | 827 return err |
803 } | 828 } |
804 } | 829 } |
805 if r.MultipartForm != nil { | 830 if r.MultipartForm != nil { |
806 return nil | 831 return nil |
807 } | 832 } |
808 | 833 |
809 mr, err := r.multipartReader() | 834 mr, err := r.multipartReader() |
810 » if err == ErrNotMultipart { | 835 » if err != nil { |
811 » » return nil | |
812 » } else if err != nil { | |
813 return err | 836 return err |
814 } | 837 } |
815 | 838 |
816 f, err := mr.ReadForm(maxMemory) | 839 f, err := mr.ReadForm(maxMemory) |
817 if err != nil { | 840 if err != nil { |
818 return err | 841 return err |
819 } | 842 } |
820 for k, v := range f.Value { | 843 for k, v := range f.Value { |
821 r.Form[k] = append(r.Form[k], v...) | 844 r.Form[k] = append(r.Form[k], v...) |
822 } | 845 } |
823 r.MultipartForm = f | 846 r.MultipartForm = f |
824 | 847 |
825 return nil | 848 return nil |
826 } | 849 } |
827 | 850 |
828 // FormValue returns the first value for the named component of the query. | 851 // FormValue returns the first value for the named component of the query. |
829 // POST and PUT body parameters take precedence over URL query string values. | 852 // POST and PUT body parameters take precedence over URL query string values. |
830 // FormValue calls ParseMultipartForm and ParseForm if necessary. | 853 // FormValue calls ParseMultipartForm and ParseForm if necessary and ignores |
854 // any errors returned by these functions. | |
831 // To access multiple values of the same key use ParseForm. | 855 // To access multiple values of the same key use ParseForm. |
832 func (r *Request) FormValue(key string) string { | 856 func (r *Request) FormValue(key string) string { |
833 if r.Form == nil { | 857 if r.Form == nil { |
834 r.ParseMultipartForm(defaultMaxMemory) | 858 r.ParseMultipartForm(defaultMaxMemory) |
835 } | 859 } |
836 if vs := r.Form[key]; len(vs) > 0 { | 860 if vs := r.Form[key]; len(vs) > 0 { |
837 return vs[0] | 861 return vs[0] |
838 } | 862 } |
839 return "" | 863 return "" |
840 } | 864 } |
841 | 865 |
842 // PostFormValue returns the first value for the named component of the POST | 866 // PostFormValue returns the first value for the named component of the POST |
843 // or PUT request body. URL query parameters are ignored. | 867 // or PUT request body. URL query parameters are ignored. |
844 // PostFormValue calls ParseMultipartForm and ParseForm if necessary. | 868 // PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores |
869 // any errors returned by these functions. | |
845 func (r *Request) PostFormValue(key string) string { | 870 func (r *Request) PostFormValue(key string) string { |
846 if r.PostForm == nil { | 871 if r.PostForm == nil { |
847 r.ParseMultipartForm(defaultMaxMemory) | 872 r.ParseMultipartForm(defaultMaxMemory) |
848 } | 873 } |
849 if vs := r.PostForm[key]; len(vs) > 0 { | 874 if vs := r.PostForm[key]; len(vs) > 0 { |
850 return vs[0] | 875 return vs[0] |
851 } | 876 } |
852 return "" | 877 return "" |
853 } | 878 } |
854 | 879 |
(...skipping 25 matching lines...) Expand all Loading... | |
880 func (r *Request) wantsHttp10KeepAlive() bool { | 905 func (r *Request) wantsHttp10KeepAlive() bool { |
881 if r.ProtoMajor != 1 || r.ProtoMinor != 0 { | 906 if r.ProtoMajor != 1 || r.ProtoMinor != 0 { |
882 return false | 907 return false |
883 } | 908 } |
884 return hasToken(r.Header.get("Connection"), "keep-alive") | 909 return hasToken(r.Header.get("Connection"), "keep-alive") |
885 } | 910 } |
886 | 911 |
887 func (r *Request) wantsClose() bool { | 912 func (r *Request) wantsClose() bool { |
888 return hasToken(r.Header.get("Connection"), "close") | 913 return hasToken(r.Header.get("Connection"), "close") |
889 } | 914 } |
915 | |
916 func (r *Request) closeBody() { | |
917 if r.Body != nil { | |
918 r.Body.Close() | |
919 } | |
920 } | |
LEFT | RIGHT |