Skip to content

Commit a625e39

Browse files
committed
http2: never Read from Request.Body in Transport to determine ContentLength
Updates golang/go#17480 (fixes after vendor to std) Updates golang/go#17071 (a better fix than the original one) Change-Id: Ibb49d2cb825e28518e688b5c3e0952956a305050 Reviewed-on: https://go-review.googlesource.com/31326 Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Chris Broadfoot <[email protected]>
1 parent 8b4af36 commit a625e39

File tree

2 files changed

+44
-33
lines changed

2 files changed

+44
-33
lines changed

http2/transport.go

Lines changed: 10 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -635,39 +635,17 @@ func checkConnHeaders(req *http.Request) error {
635635
return nil
636636
}
637637

638-
func bodyAndLength(req *http.Request) (body io.Reader, contentLen int64) {
639-
body = req.Body
640-
if body == nil {
641-
return nil, 0
638+
// actualContentLength returns a sanitized version of
639+
// req.ContentLength, where 0 actually means zero (not unknown) and -1
640+
// means unknown.
641+
func actualContentLength(req *http.Request) int64 {
642+
if req.Body == nil {
643+
return 0
642644
}
643645
if req.ContentLength != 0 {
644-
return req.Body, req.ContentLength
645-
}
646-
// Don't try to sniff the size if they're doing an expect
647-
// request (Issue 16002):
648-
if req.Header.Get("Expect") == "100-continue" {
649-
return req.Body, -1
650-
}
651-
652-
// We have a body but a zero content length. Test to see if
653-
// it's actually zero or just unset.
654-
var buf [1]byte
655-
n, rerr := body.Read(buf[:])
656-
if rerr != nil && rerr != io.EOF {
657-
return errorReader{rerr}, -1
658-
}
659-
if n == 1 {
660-
// Oh, guess there is data in this Body Reader after all.
661-
// The ContentLength field just wasn't set.
662-
// Stitch the Body back together again, re-attaching our
663-
// consumed byte.
664-
if rerr == io.EOF {
665-
return bytes.NewReader(buf[:]), 1
666-
}
667-
return io.MultiReader(bytes.NewReader(buf[:]), body), -1
646+
return req.ContentLength
668647
}
669-
// Body is actually zero bytes.
670-
return nil, 0
648+
return -1
671649
}
672650

673651
func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
@@ -691,8 +669,9 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
691669
return nil, errClientConnUnusable
692670
}
693671

694-
body, contentLen := bodyAndLength(req)
672+
body := req.Body
695673
hasBody := body != nil
674+
contentLen := actualContentLength(req)
696675

697676
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
698677
var requestedGzip bool

http2/transport_test.go

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -391,15 +391,47 @@ func randString(n int) string {
391391
return string(b)
392392
}
393393

394+
type panicReader struct{}
395+
396+
func (panicReader) Read([]byte) (int, error) { panic("unexpected Read") }
397+
func (panicReader) Close() error { panic("unexpected Close") }
398+
399+
func TestActualContentLength(t *testing.T) {
400+
tests := []struct {
401+
req *http.Request
402+
want int64
403+
}{
404+
// Verify we don't read from Body:
405+
0: {
406+
req: &http.Request{Body: panicReader{}},
407+
want: -1,
408+
},
409+
// nil Body means 0, regardless of ContentLength:
410+
1: {
411+
req: &http.Request{Body: nil, ContentLength: 5},
412+
want: 0,
413+
},
414+
// ContentLength is used if set.
415+
2: {
416+
req: &http.Request{Body: panicReader{}, ContentLength: 5},
417+
want: 5,
418+
},
419+
}
420+
for i, tt := range tests {
421+
got := actualContentLength(tt.req)
422+
if got != tt.want {
423+
t.Errorf("test[%d]: got %d; want %d", i, got, tt.want)
424+
}
425+
}
426+
}
427+
394428
func TestTransportBody(t *testing.T) {
395429
bodyTests := []struct {
396430
body string
397431
noContentLen bool
398432
}{
399433
{body: "some message"},
400434
{body: "some message", noContentLen: true},
401-
{body: ""},
402-
{body: "", noContentLen: true},
403435
{body: strings.Repeat("a", 1<<20), noContentLen: true},
404436
{body: strings.Repeat("a", 1<<20)},
405437
{body: randString(16<<10 - 1)},

0 commit comments

Comments
 (0)