diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-10-31 00:59:47 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2015-10-31 00:59:47 +0000 |
commit | af146490bb04205107cb23e301ec7a8ff927b5fc (patch) | |
tree | 13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/net/http/request.go | |
parent | 725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff) | |
download | gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.zip gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.gz gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.bz2 |
runtime: Remove now unnecessary pad field from ParFor.
It is not needed due to the removal of the ctx field.
Reviewed-on: https://go-review.googlesource.com/16525
From-SVN: r229616
Diffstat (limited to 'libgo/go/net/http/request.go')
-rw-r--r-- | libgo/go/net/http/request.go | 139 |
1 files changed, 113 insertions, 26 deletions
diff --git a/libgo/go/net/http/request.go b/libgo/go/net/http/request.go index 487eebc..31fe45a 100644 --- a/libgo/go/net/http/request.go +++ b/libgo/go/net/http/request.go @@ -25,9 +25,6 @@ import ( ) const ( - maxValueLength = 4096 - maxHeaderLines = 1024 - chunkSize = 4 << 10 // 4 KB chunks defaultMaxMemory = 32 << 20 // 32 MB ) @@ -172,8 +169,9 @@ type Request struct { // The HTTP client ignores Form and uses Body instead. Form url.Values - // PostForm contains the parsed form data from POST or PUT - // body parameters. + // PostForm contains the parsed form data from POST, PATCH, + // or PUT body parameters. + // // This field is only available after ParseForm is called. // The HTTP client ignores PostForm and uses Body instead. PostForm url.Values @@ -226,6 +224,13 @@ type Request struct { // otherwise it leaves the field nil. // This field is ignored by the HTTP client. TLS *tls.ConnectionState + + // Cancel is an optional channel whose closure indicates that the client + // request should be regarded as canceled. Not all implementations of + // RoundTripper may support Cancel. + // + // For server requests, this field is not applicable. + Cancel <-chan struct{} } // ProtoAtLeast reports whether the HTTP protocol used @@ -245,6 +250,7 @@ func (r *Request) Cookies() []*Cookie { return readCookies(r.Header, "") } +// ErrNoCookie is returned by Request's Cookie method when a cookie is not found. var ErrNoCookie = errors.New("http: named cookie not present") // Cookie returns the named cookie provided in the request or @@ -329,13 +335,12 @@ func valueOrDefault(value, def string) string { } // NOTE: This is not intended to reflect the actual Go version being used. -// It was changed from "Go http package" to "Go 1.1 package http" at the -// time of the Go 1.1 release because the former User-Agent had ended up -// on a blacklist for some intrusion detection systems. +// It was changed at the time of Go 1.1 release because the former User-Agent +// had ended up on a blacklist for some intrusion detection systems. // See https://codereview.appspot.com/7532043. -const defaultUserAgent = "Go 1.1 package http" +const defaultUserAgent = "Go-http-client/1.1" -// Write writes an HTTP/1.1 request -- header and body -- in wire format. +// Write writes an HTTP/1.1 request, which is the header and body, in wire format. // This method consults the following fields of the request: // Host // URL @@ -364,14 +369,23 @@ func (r *Request) WriteProxy(w io.Writer) error { // extraHeaders may be nil func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error { - host := req.Host + // Find the target host. Prefer the Host: header, but if that + // is not given, use the host from the request URL. + // + // Clean the host, in case it arrives with unexpected stuff in it. + host := cleanHost(req.Host) if host == "" { if req.URL == nil { return errors.New("http: Request.Write on Request with no Host or URL set") } - host = req.URL.Host + host = cleanHost(req.URL.Host) } + // According to RFC 6874, an HTTP client, proxy, or other + // intermediary must remove any IPv6 zone identifier attached + // to an outgoing URI. + host = removeZone(host) + ruri := req.URL.RequestURI() if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" { ruri = req.URL.Scheme + "://" + host + ruri @@ -456,6 +470,39 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err return nil } +// cleanHost strips anything after '/' or ' '. +// Ideally we'd clean the Host header according to the spec: +// https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]") +// https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host) +// https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host) +// But practically, what we are trying to avoid is the situation in +// issue 11206, where a malformed Host header used in the proxy context +// would create a bad request. So it is enough to just truncate at the +// first offending character. +func cleanHost(in string) string { + if i := strings.IndexAny(in, " /"); i != -1 { + return in[:i] + } + return in +} + +// removeZone removes IPv6 zone identifer from host. +// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080" +func removeZone(host string) string { + if !strings.HasPrefix(host, "[") { + return host + } + i := strings.LastIndex(host, "]") + if i < 0 { + return host + } + j := strings.LastIndex(host[:i], "%") + if j < 0 { + return host + } + return host[:j] + host[i:] +} + // ParseHTTPVersion parses a HTTP version string. // "HTTP/1.0" returns (1, 0, true). func ParseHTTPVersion(vers string) (major, minor int, ok bool) { @@ -489,6 +536,13 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) { // If the provided body is also an io.Closer, the returned // Request.Body is set to body and will be closed by the Client // methods Do, Post, and PostForm, and Transport.RoundTrip. +// +// NewRequest returns a Request suitable for use with Client.Do or +// Transport.RoundTrip. +// To create a request for use with testing a Server Handler use either +// ReadRequest or manually update the Request fields. See the Request +// type's documentation for the difference between inbound and outbound +// request fields. func NewRequest(method, urlStr string, body io.Reader) (*Request, error) { u, err := url.Parse(urlStr) if err != nil { @@ -536,10 +590,11 @@ func (r *Request) BasicAuth() (username, password string, ok bool) { // parseBasicAuth parses an HTTP Basic Authentication string. // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true). func parseBasicAuth(auth string) (username, password string, ok bool) { - if !strings.HasPrefix(auth, "Basic ") { + const prefix = "Basic " + if !strings.HasPrefix(auth, prefix) { return } - c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic ")) + c, err := base64.StdEncoding.DecodeString(auth[len(prefix):]) if err != nil { return } @@ -587,7 +642,7 @@ func putTextprotoReader(r *textproto.Reader) { textprotoReaderPool.Put(r) } -// ReadRequest reads and parses a request from b. +// ReadRequest reads and parses an incoming request from b. func ReadRequest(b *bufio.Reader) (req *Request, err error) { tp := newTextprotoReader(b) @@ -660,19 +715,20 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) { fixPragmaCacheControl(req.Header) + req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false) + err = readTransfer(req, b) if err != nil { return nil, err } - req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false) return req, nil } // MaxBytesReader is similar to io.LimitReader but is intended for // limiting the size of incoming request bodies. In contrast to // io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a -// non-EOF error for a Read beyond the limit, and Closes the +// non-EOF error for a Read beyond the limit, and closes the // underlying reader when its Close method is called. // // MaxBytesReader prevents clients from accidentally or maliciously @@ -686,23 +742,52 @@ type maxBytesReader struct { r io.ReadCloser // underlying reader n int64 // max bytes remaining stopped bool + sawEOF bool +} + +func (l *maxBytesReader) tooLarge() (n int, err error) { + if !l.stopped { + l.stopped = true + if res, ok := l.w.(*response); ok { + res.requestTooLarge() + } + } + return 0, errors.New("http: request body too large") } func (l *maxBytesReader) Read(p []byte) (n int, err error) { - if l.n <= 0 { - if !l.stopped { - l.stopped = true - if res, ok := l.w.(*response); ok { - res.requestTooLarge() - } + toRead := l.n + if l.n == 0 { + if l.sawEOF { + return l.tooLarge() } - return 0, errors.New("http: request body too large") + // The underlying io.Reader may not return (0, io.EOF) + // at EOF if the requested size is 0, so read 1 byte + // instead. The io.Reader docs are a bit ambiguous + // about the return value of Read when 0 bytes are + // requested, and {bytes,strings}.Reader gets it wrong + // too (it returns (0, nil) even at EOF). + toRead = 1 } - if int64(len(p)) > l.n { - p = p[:l.n] + if int64(len(p)) > toRead { + p = p[:toRead] } n, err = l.r.Read(p) + if err == io.EOF { + l.sawEOF = true + } + if l.n == 0 { + // If we had zero bytes to read remaining (but hadn't seen EOF) + // and we get a byte here, that means we went over our limit. + if n > 0 { + return l.tooLarge() + } + return 0, err + } l.n -= int64(n) + if l.n < 0 { + l.n = 0 + } return } @@ -852,6 +937,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error { // POST and PUT body parameters take precedence over URL query string values. // FormValue calls ParseMultipartForm and ParseForm if necessary and ignores // any errors returned by these functions. +// If key is not present, FormValue returns the empty string. // To access multiple values of the same key, call ParseForm and // then inspect Request.Form directly. func (r *Request) FormValue(key string) string { @@ -868,6 +954,7 @@ func (r *Request) FormValue(key string) string { // or PUT request body. URL query parameters are ignored. // PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores // any errors returned by these functions. +// If key is not present, PostFormValue returns the empty string. func (r *Request) PostFormValue(key string) string { if r.PostForm == nil { r.ParseMultipartForm(defaultMaxMemory) |