aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/net/http/transfer.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/http/transfer.go')
-rw-r--r--libgo/go/net/http/transfer.go87
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 {