diff options
Diffstat (limited to 'libgo/go/net/http/transfer.go')
-rw-r--r-- | libgo/go/net/http/transfer.go | 87 |
1 files changed, 62 insertions, 25 deletions
diff --git a/libgo/go/net/http/transfer.go b/libgo/go/net/http/transfer.go index a8736b28e16..6e59af8f6f4 100644 --- a/libgo/go/net/http/transfer.go +++ b/libgo/go/net/http/transfer.go @@ -56,7 +56,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) { if rr.ContentLength != 0 && rr.Body == nil { return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength) } - t.Method = rr.Method + t.Method = valueOrDefault(rr.Method, "GET") t.Body = rr.Body t.BodyCloser = rr.Body t.ContentLength = rr.ContentLength @@ -271,6 +271,10 @@ type transferReader struct { Trailer Header } +func (t *transferReader) protoAtLeast(m, n int) bool { + return t.ProtoMajor > m || (t.ProtoMajor == m && t.ProtoMinor >= n) +} + // bodyAllowedForStatus reports whether a given response status code // permits a body. See RFC2616, section 4.4. func bodyAllowedForStatus(status int) bool { @@ -337,7 +341,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) { } // Transfer encoding, content length - t.TransferEncoding, err = fixTransferEncoding(isResponse, t.RequestMethod, t.Header) + err = t.fixTransferEncoding() if err != nil { return err } @@ -424,13 +428,18 @@ func chunked(te []string) bool { return len(te) > 0 && te[0] == "chunked" } // Checks whether the encoding is explicitly "identity". func isIdentity(te []string) bool { return len(te) == 1 && te[0] == "identity" } -// Sanitize transfer encoding -func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ([]string, error) { - raw, present := header["Transfer-Encoding"] +// fixTransferEncoding sanitizes t.TransferEncoding, if needed. +func (t *transferReader) fixTransferEncoding() error { + raw, present := t.Header["Transfer-Encoding"] if !present { - return nil, nil + return nil + } + delete(t.Header, "Transfer-Encoding") + + // Issue 12785; ignore Transfer-Encoding on HTTP/1.0 requests. + if !t.protoAtLeast(1, 1) { + return nil } - delete(header, "Transfer-Encoding") encodings := strings.Split(raw[0], ",") te := make([]string, 0, len(encodings)) @@ -445,13 +454,13 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ( break } if encoding != "chunked" { - return nil, &badStringError{"unsupported transfer encoding", encoding} + return &badStringError{"unsupported transfer encoding", encoding} } te = te[0 : len(te)+1] te[len(te)-1] = encoding } if len(te) > 1 { - return nil, &badStringError{"too many transfer encodings", strings.Join(te, ",")} + return &badStringError{"too many transfer encodings", strings.Join(te, ",")} } if len(te) > 0 { // RFC 7230 3.3.2 says "A sender MUST NOT send a @@ -470,11 +479,12 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) ( // such a message downstream." // // Reportedly, these appear in the wild. - delete(header, "Content-Length") - return te, nil + delete(t.Header, "Content-Length") + t.TransferEncoding = te + return nil } - return nil, nil + return nil } // Determine the expected body length, using RFC 2616 Section 4.4. This @@ -567,21 +577,29 @@ func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool { // Parse the trailer header func fixTrailer(header Header, te []string) (Header, error) { - raw := header.get("Trailer") - if raw == "" { + vv, ok := header["Trailer"] + if !ok { return nil, nil } - header.Del("Trailer") + trailer := make(Header) - keys := strings.Split(raw, ",") - for _, key := range keys { - key = CanonicalHeaderKey(strings.TrimSpace(key)) - switch key { - case "Transfer-Encoding", "Trailer", "Content-Length": - return nil, &badStringError{"bad trailer key", key} - } - trailer[key] = nil + var err error + for _, v := range vv { + foreachHeaderElement(v, func(key string) { + key = CanonicalHeaderKey(key) + switch key { + case "Transfer-Encoding", "Trailer", "Content-Length": + if err == nil { + err = &badStringError{"bad trailer key", key} + return + } + } + trailer[key] = nil + }) + } + if err != nil { + return nil, err } if len(trailer) == 0 { return nil, nil @@ -603,10 +621,11 @@ type body struct { closing bool // is the connection to be closed after reading body? doEarlyClose bool // whether Close should stop early - mu sync.Mutex // guards closed, and calls to Read and Close + mu sync.Mutex // guards following, and calls to Read and Close sawEOF bool closed bool - earlyClose bool // Close called and we didn't read to the end of src + earlyClose bool // Close called and we didn't read to the end of src + onHitEOF func() // if non-nil, func to call when EOF is Read } // ErrBodyReadAfterClose is returned when reading a Request or Response @@ -666,6 +685,10 @@ func (b *body) readLocked(p []byte) (n int, err error) { } } + if b.sawEOF && b.onHitEOF != nil { + b.onHitEOF() + } + return n, err } @@ -800,6 +823,20 @@ func (b *body) didEarlyClose() bool { return b.earlyClose } +// bodyRemains reports whether future Read calls might +// yield data. +func (b *body) bodyRemains() bool { + b.mu.Lock() + defer b.mu.Unlock() + return !b.sawEOF +} + +func (b *body) registerOnHitEOF(fn func()) { + b.mu.Lock() + defer b.mu.Unlock() + b.onHitEOF = fn +} + // bodyLocked is a io.Reader reading from a *body when its mutex is // already held. type bodyLocked struct { |