Skip to content

Commit 749a502

Browse files
committed
http2: don't sniff first Request.Body byte in Transport until we have a conn
bodyAndLength mutates Request.Body if Request.ContentLength == 0, reading the first byte to determine whether it's actually empty or just undeclared. But we did that before we checked whether our connection was overloaded, which meant the caller could retry the request on an new or lesser-loaded connection, but then lose the first byte of the request. Updates golang/go#17071 (needs bundle into std before fixed) Change-Id: I996a92ad037b45bc49e7cf0801a2027bbbb3c920 Reviewed-on: https://go-review.googlesource.com/29074 Reviewed-by: Gleb Stepanov <[email protected]> Reviewed-by: Chris Broadfoot <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 57c7820 commit 749a502

File tree

2 files changed

+24
-3
lines changed

2 files changed

+24
-3
lines changed

http2/transport.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -656,16 +656,16 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
656656
}
657657
hasTrailers := trailers != ""
658658

659-
body, contentLen := bodyAndLength(req)
660-
hasBody := body != nil
661-
662659
cc.mu.Lock()
663660
cc.lastActive = time.Now()
664661
if cc.closed || !cc.canTakeNewRequestLocked() {
665662
cc.mu.Unlock()
666663
return nil, errClientConnUnusable
667664
}
668665

666+
body, contentLen := bodyAndLength(req)
667+
hasBody := body != nil
668+
669669
// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
670670
var requestedGzip bool
671671
if !cc.t.disableCompression() &&

http2/transport_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2597,3 +2597,24 @@ func TestTransportRequestPathPseudo(t *testing.T) {
25972597
}
25982598

25992599
}
2600+
2601+
// golang.org/issue/17071 -- don't sniff the first byte of the request body
2602+
// before we've determined that the ClientConn is usable.
2603+
func TestRoundTripDoesntConsumeRequestBodyEarly(t *testing.T) {
2604+
const body = "foo"
2605+
req, _ := http.NewRequest("POST", "http://foo.com/", ioutil.NopCloser(strings.NewReader(body)))
2606+
cc := &ClientConn{
2607+
closed: true,
2608+
}
2609+
_, err := cc.RoundTrip(req)
2610+
if err != errClientConnUnusable {
2611+
t.Fatalf("RoundTrip = %v; want errClientConnUnusable", err)
2612+
}
2613+
slurp, err := ioutil.ReadAll(req.Body)
2614+
if err != nil {
2615+
t.Errorf("ReadAll = %v", err)
2616+
}
2617+
if string(slurp) != body {
2618+
t.Errorf("Body = %q; want %q", slurp, body)
2619+
}
2620+
}

0 commit comments

Comments
 (0)