Skip to content

Commit

Permalink
http2: return os.ErrDeadlineExceeded from timed-out response body writes
Browse files Browse the repository at this point in the history
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 <dneil@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Bryan Mills <bcmills@google.com>
  • Loading branch information
neild committed Nov 4, 2022
1 parent a870f35 commit efda1ce
Showing 1 changed file with 23 additions and 2 deletions.
25 changes: 23 additions & 2 deletions http2/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,7 @@ type stream struct {
wroteHeaders bool // whether we wrote headers (not status 100)
readDeadline *time.Timer // nil if unused
writeDeadline *time.Timer // nil if unused
closeErr error // set before cw is closed

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

p.CloseWithError(err)
}
if e, ok := err.(StreamError); ok {
if e.Cause != nil {
err = e.Cause
} else {
err = errStreamClosed
}
}
st.closeErr = err
st.cw.Close() // signals Handler's CloseNotifier, unblocks writes, etc
sc.writeSched.CloseStream(st.id)
}
Expand Down Expand Up @@ -1857,7 +1866,11 @@ func (st *stream) onReadTimeout() {
// onWriteTimeout is run on its own goroutine (from time.AfterFunc)
// when the stream's WriteTimeout has fired.
func (st *stream) onWriteTimeout() {
st.sc.writeFrameFromHandler(FrameWriteRequest{write: streamError(st.id, ErrCodeInternal)})
st.sc.writeFrameFromHandler(FrameWriteRequest{write: StreamError{
StreamID: st.id,
Code: ErrCodeInternal,
Cause: os.ErrDeadlineExceeded,
}})
}

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

type chunkWriter struct{ rws *responseWriterState }

func (cw chunkWriter) Write(p []byte) (n int, err error) { return cw.rws.writeChunk(p) }
func (cw chunkWriter) Write(p []byte) (n int, err error) {
n, err = cw.rws.writeChunk(p)
if err == errStreamClosed {
// If writing failed because the stream has been closed,
// return the reason it was closed.
err = cw.rws.stream.closeErr
}
return n, err
}

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

Expand Down

0 comments on commit efda1ce

Please sign in to comment.