From 26ea8175a156eecf99974b64a6906b0fa4c76532 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 10 Oct 2023 15:32:20 +0200 Subject: [PATCH] http2: unconditionally recycle responseWriterState CL 46008 fixed golang/go#20704 by not recycling the responseWriterState if any previous Write call failed, as there could be outstanding goroutines referencing the responseWriterState memory. More recently, CL 467355 fixed a variant of the same issue by not referencing that memory after exiting the Write call. This fix supersedes the fix in CL 46008, as it is more general and does not require the caller to know whether any previous Write calls failed. This CL partially reverts CL 46008 just leaving the test case to ensure that golang/go#20704 does not regress. Change-Id: I18ea4d27420265a94cc7af21f1dffa3f7dc3bd34 Reviewed-on: https://go-review.googlesource.com/c/net/+/534315 TryBot-Result: Gopher Robot Auto-Submit: Damien Neil Reviewed-by: Damien Neil LUCI-TryBot-Result: Go LUCI Run-TryBot: Quim Muntal Commit-Queue: Damien Neil Reviewed-by: Bryan Mills Reviewed-by: Dmitri Shuralyov --- http2/server.go | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/http2/server.go b/http2/server.go index 7f3bed9261..ae94c6408d 100644 --- a/http2/server.go +++ b/http2/server.go @@ -2549,7 +2549,6 @@ type responseWriterState struct { wroteHeader bool // WriteHeader called (explicitly or implicitly). Not necessarily sent to user yet. sentHeader bool // have we sent the header frame? handlerDone bool // handler has finished - dirty bool // a Write failed; don't reuse this responseWriterState sentContentLen int64 // non-zero if handler set a Content-Length header wroteBytes int64 @@ -2669,7 +2668,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { date: date, }) if err != nil { - rws.dirty = true return 0, err } if endStream { @@ -2690,7 +2688,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { if len(p) > 0 || endStream { // only send a 0 byte DATA frame if we're ending the stream. if err := rws.conn.writeDataFromHandler(rws.stream, p, endStream); err != nil { - rws.dirty = true return 0, err } } @@ -2702,9 +2699,6 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { trailers: rws.trailers, endStream: true, }) - if err != nil { - rws.dirty = true - } return len(p), err } return len(p), nil @@ -2920,14 +2914,12 @@ func (rws *responseWriterState) writeHeader(code int) { h.Del("Transfer-Encoding") } - if rws.conn.writeHeaders(rws.stream, &writeResHeaders{ + rws.conn.writeHeaders(rws.stream, &writeResHeaders{ streamID: rws.stream.id, httpResCode: code, h: h, endStream: rws.handlerDone && !rws.hasTrailers(), - }) != nil { - rws.dirty = true - } + }) return } @@ -2992,19 +2984,10 @@ func (w *responseWriter) write(lenData int, dataB []byte, dataS string) (n int, func (w *responseWriter) handlerDone() { rws := w.rws - dirty := rws.dirty rws.handlerDone = true w.Flush() w.rws = nil - if !dirty { - // Only recycle the pool if all prior Write calls to - // the serverConn goroutine completed successfully. If - // they returned earlier due to resets from the peer - // there might still be write goroutines outstanding - // from the serverConn referencing the rws memory. See - // issue 20704. - responseWriterStatePool.Put(rws) - } + responseWriterStatePool.Put(rws) } // Push errors.