Skip to content

Commit 9491e7d

Browse files
committed
net/http: refactor testing of Request.Body on 0 ContentLength
Code movement only, to look more like the equivalent http2 code, and to make an upcoming fix look more obvious. Updates #16002 (to be fixed once this code is in) Change-Id: Iaa4f965be14e98f9996e7c4624afe6e19bed1a80 Reviewed-on: https://go-review.googlesource.com/30087 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Joe Tsai <[email protected]>
1 parent ab6ba99 commit 9491e7d

File tree

2 files changed

+46
-27
lines changed

2 files changed

+46
-27
lines changed

src/net/http/request.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,3 +1215,42 @@ func (r *Request) isReplayable() bool {
12151215
}
12161216
return false
12171217
}
1218+
1219+
// bodyAndLength reports the request's body and content length, with
1220+
// the difference from r.ContentLength being that 0 means actually
1221+
// zero, and -1 means unknown.
1222+
func (r *Request) bodyAndLength() (body io.Reader, contentLen int64) {
1223+
body = r.Body
1224+
if body == nil {
1225+
return nil, 0
1226+
}
1227+
if r.ContentLength != 0 {
1228+
return body, r.ContentLength
1229+
}
1230+
// Don't try to sniff the bytes if they're using a custom
1231+
// transfer encoding (or specified chunked themselves), and
1232+
// don't sniff if they're not using HTTP/1.1 and can't chunk
1233+
// anyway.
1234+
if len(r.TransferEncoding) != 0 || !r.ProtoAtLeast(1, 1) {
1235+
return body, -1
1236+
}
1237+
1238+
// Test to see if it's actually zero or just unset.
1239+
var buf [1]byte
1240+
n, err := io.ReadFull(body, buf[:])
1241+
if err != nil && err != io.EOF {
1242+
return errorReader{err}, -1
1243+
}
1244+
1245+
if n == 1 {
1246+
// Oh, guess there is data in this Body Reader after all.
1247+
// The ContentLength field just wasn't set.
1248+
// Stich the Body back together again, re-attaching our
1249+
// consumed byte.
1250+
// TODO(bradfitz): switch to stitchByteAndReader
1251+
return io.MultiReader(bytes.NewReader(buf[:]), body), -1
1252+
}
1253+
1254+
// Body is actually empty.
1255+
return nil, 0
1256+
}

src/net/http/transfer.go

Lines changed: 7 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,37 +59,17 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
5959
return nil, fmt.Errorf("http: Request.ContentLength=%d with nil Body", rr.ContentLength)
6060
}
6161
t.Method = valueOrDefault(rr.Method, "GET")
62-
t.Body = rr.Body
63-
t.BodyCloser = rr.Body
64-
t.ContentLength = rr.ContentLength
6562
t.Close = rr.Close
6663
t.TransferEncoding = rr.TransferEncoding
6764
t.Trailer = rr.Trailer
6865
atLeastHTTP11 = rr.ProtoAtLeast(1, 1)
69-
if t.Body != nil && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
70-
if t.ContentLength == 0 {
71-
// Test to see if it's actually zero or just unset.
72-
var buf [1]byte
73-
n, rerr := io.ReadFull(t.Body, buf[:])
74-
if rerr != nil && rerr != io.EOF {
75-
t.ContentLength = -1
76-
t.Body = errorReader{rerr}
77-
} else if n == 1 {
78-
// Oh, guess there is data in this Body Reader after all.
79-
// The ContentLength field just wasn't set.
80-
// Stich the Body back together again, re-attaching our
81-
// consumed byte.
82-
t.ContentLength = -1
83-
t.Body = io.MultiReader(bytes.NewReader(buf[:]), t.Body)
84-
} else {
85-
// Body is actually empty.
86-
t.Body = nil
87-
t.BodyCloser = nil
88-
}
89-
}
90-
if t.ContentLength < 0 {
91-
t.TransferEncoding = []string{"chunked"}
92-
}
66+
67+
t.Body, t.ContentLength = rr.bodyAndLength()
68+
if t.Body != nil {
69+
t.BodyCloser = rr.Body
70+
}
71+
if t.ContentLength < 0 && len(t.TransferEncoding) == 0 && atLeastHTTP11 {
72+
t.TransferEncoding = []string{"chunked"}
9373
}
9474
case *Response:
9575
t.IsResponse = true

0 commit comments

Comments
 (0)