Skip to content

Commit

Permalink
[release-branch.go1.7] http2: don't sniff first Request.Body byte in …
Browse files Browse the repository at this point in the history
…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 <glebstepanov1992@gmail.com>
Reviewed-by: Chris Broadfoot <cbro@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-on: https://go-review.googlesource.com/29081
  • Loading branch information
bradfitz committed Sep 13, 2016
1 parent 917f3d5 commit 8d4d01f
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 3 deletions.
6 changes: 3 additions & 3 deletions http2/transport.go
Original file line number Diff line number Diff line change
Expand Up @@ -651,16 +651,16 @@ func (cc *ClientConn) RoundTrip(req *http.Request) (*http.Response, error) {
}
hasTrailers := trailers != ""

body, contentLen := bodyAndLength(req)
hasBody := body != nil

cc.mu.Lock()
cc.lastActive = time.Now()
if cc.closed || !cc.canTakeNewRequestLocked() {
cc.mu.Unlock()
return nil, errClientConnUnusable
}

body, contentLen := bodyAndLength(req)
hasBody := body != nil

// TODO(bradfitz): this is a copy of the logic in net/http. Unify somewhere?
var requestedGzip bool
if !cc.t.disableCompression() &&
Expand Down
21 changes: 21 additions & 0 deletions http2/transport_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2468,3 +2468,24 @@ func TestTransportBodyDoubleEndStream(t *testing.T) {
defer res.Body.Close()
}
}

// golang.org/issue/17071 -- don't sniff the first byte of the request body
// before we've determined that the ClientConn is usable.
func TestRoundTripDoesntConsumeRequestBodyEarly(t *testing.T) {
const body = "foo"
req, _ := http.NewRequest("POST", "http://foo.com/", ioutil.NopCloser(strings.NewReader(body)))
cc := &ClientConn{
closed: true,
}
_, err := cc.RoundTrip(req)
if err != errClientConnUnusable {
t.Fatalf("RoundTrip = %v; want errClientConnUnusable", err)
}
slurp, err := ioutil.ReadAll(req.Body)
if err != nil {
t.Errorf("ReadAll = %v", err)
}
if string(slurp) != body {
t.Errorf("Body = %q; want %q", slurp, body)
}
}

0 comments on commit 8d4d01f

Please sign in to comment.