net/http: Errors from persistConn.readLoop not returned to client still writing a request #62447
Labels
NeedsInvestigation
Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
Consider a HTTP server facing a client which is slow to upload a request body, and the HTTP server times out and closes the socket.
https://go.dev/play/p/zu0cZuiGxDZ
What did you expect to see?
On the client side, a real error cause of some kind; such as the one in https://go.dev/play/p/fKwUQwOjTDW (with
s/if false/if true
):contains a useful “connection reset by peer” error.
What did you see instead?
contains
net.ErrClosed
, with no indication of the actual underlying root cause. And I think it's possibly controversial but plausible point thatnet.ErrClosed
is considered an indication of a programming bug.The reports in #4373 obliquely hint at net/http encountering this issue, but never quite spell it out, hence this report.
The underlying cause, at least for this specific reproducer, is that
persistConn.readLoop
andpersistConn.writeLoop
are quite independent; in this case,readLoop
encounters a socket read error, terminates, and closespersistConn.conn
. Meanwhile,writeLoop
is deep intransferWriter.doBodyCopy
, continuing to issue writes and flushes topersistConn.conn
, and that triggersnet.ErrClosed
on the write side. Arguably that’s the primary bug, issuing a write on a closed connection.And then,
persistConn.roundTrip
actually sees the read-side error first (re := <-resc:
); but it proceeds tomapRoundTripError
, and seesreq.err
set, and returns that value. Alternatively, if issuing a write on a closed connection is considered fine (or the performance cost to avoid that would be too great), the logic inmapRoundTripError
could see that there is both a read-side and write-side error, and decide thatnet.ErrClosed
is not the one that should be returned.There also seems to be a dual of this issue, where
persistConn.writeLoop
can encounter an error and close the connection, causingreadLoop
to fail withnet.ErrClosed
instead, and in that case, again, an error with the “use of closed network connection” text is returned. I’m afraid I lost the reproducer I had for that one.The text was updated successfully, but these errors were encountered: