Skip to content

Commit 7594919

Browse files
committed
http2: avoid race between processing END_STREAM and closing Response.Body
When the client gets an END_STREAM from the peer, it causes the response body to return io.EOF and closes cs.peerClosed. It is possible for the caller of RoundTrip to read io.EOF from the response body and end the request by calling Response.Body.Close before we close cs.peerClosed. In this case, we send a spurious RST_STREAM to the peer. Closing cs.peerClosed first reverses the race: This can cause the response body to return "request canceled" rather than io.EOF. Close both streams with the connection mutex held. Fixes golang/go#49314 Change-Id: I75557670497c96dd6ed1b566bb4f0f3106a0c9f9 Reviewed-on: https://go-review.googlesource.com/c/net/+/361267 Trust: Damien Neil <[email protected]> Run-TryBot: Damien Neil <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 4a448f8 commit 7594919

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

http2/transport.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2576,6 +2576,12 @@ func (rl *clientConnReadLoop) endStream(cs *clientStream) {
25762576
// server.go's (*stream).endStream method.
25772577
if !cs.readClosed {
25782578
cs.readClosed = true
2579+
// Close cs.bufPipe and cs.peerClosed with cc.mu held to avoid a
2580+
// race condition: The caller can read io.EOF from Response.Body
2581+
// and close the body before we close cs.peerClosed, causing
2582+
// cleanupWriteRequest to send a RST_STREAM.
2583+
rl.cc.mu.Lock()
2584+
defer rl.cc.mu.Unlock()
25792585
cs.bufPipe.closeWithErrorAndCode(io.EOF, cs.copyTrailers)
25802586
close(cs.peerClosed)
25812587
}

0 commit comments

Comments
 (0)