Skip to content

Commit efda1ce

Browse files
committed
http2: return os.ErrDeadlineExceeded from timed-out response body writes
When a server handler writes to a response body after Server.WriteTimeout has expired, return an error matching os.ErrDeadlineExceeded rather than "http2: stream closed". Tested by net/http CL 446255. For golang/go#56478 Change-Id: I94494cc7e7f8f9a01a663de09fd5b73acc8ea4e4 Reviewed-on: https://go-review.googlesource.com/c/net/+/446257 Run-TryBot: Damien Neil <[email protected]> TryBot-Result: Gopher Robot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]> Reviewed-by: Bryan Mills <[email protected]>
1 parent a870f35 commit efda1ce

File tree

1 file changed

+23
-2
lines changed

1 file changed

+23
-2
lines changed

http2/server.go

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,7 @@ type stream struct {
624624
wroteHeaders bool // whether we wrote headers (not status 100)
625625
readDeadline *time.Timer // nil if unused
626626
writeDeadline *time.Timer // nil if unused
627+
closeErr error // set before cw is closed
627628

628629
trailer http.Header // accumulated trailers
629630
reqTrailer http.Header // handler's Request.Trailer
@@ -1608,6 +1609,14 @@ func (sc *serverConn) closeStream(st *stream, err error) {
16081609

16091610
p.CloseWithError(err)
16101611
}
1612+
if e, ok := err.(StreamError); ok {
1613+
if e.Cause != nil {
1614+
err = e.Cause
1615+
} else {
1616+
err = errStreamClosed
1617+
}
1618+
}
1619+
st.closeErr = err
16111620
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
16121621
sc.writeSched.CloseStream(st.id)
16131622
}
@@ -1857,7 +1866,11 @@ func (st *stream) onReadTimeout() {
18571866
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
18581867
// when the stream's WriteTimeout has fired.
18591868
func (st *stream) onWriteTimeout() {
1860-
st.sc.writeFrameFromHandler(FrameWriteRequest{write: streamError(st.id, ErrCodeInternal)})
1869+
st.sc.writeFrameFromHandler(FrameWriteRequest{write: StreamError{
1870+
StreamID: st.id,
1871+
Code: ErrCodeInternal,
1872+
Cause: os.ErrDeadlineExceeded,
1873+
}})
18611874
}
18621875

18631876
func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
@@ -2471,7 +2484,15 @@ type responseWriterState struct {
24712484

24722485
type chunkWriter struct{ rws *responseWriterState }
24732486

2474-
func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
2487+
func (cw chunkWriter) Write(p []byte) (n int, err error) {
2488+
n, err = cw.rws.writeChunk(p)
2489+
if err == errStreamClosed {
2490+
// If writing failed because the stream has been closed,
2491+
// return the reason it was closed.
2492+
err = cw.rws.stream.closeErr
2493+
}
2494+
return n, err
2495+
}
24752496

24762497
func (rws *responseWriterState) hasTrailers() bool { return len(rws.trailers) > 0 }
24772498

0 commit comments

Comments
 (0)