Skip to content

Commit

Permalink
net/http: add context cancellation reason for server handlers
Browse files Browse the repository at this point in the history
When we cancel a HTTP server handler context, set an appropriate
cancel cause. This makes investigation of context cancellation
errors easier.

Fixes golang#64465
  • Loading branch information
sgielen committed Dec 15, 2024
1 parent e39e965 commit d23593e
Showing 1 changed file with 18 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/net/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ var (
// anything in the net/http package. Callers should not
// compare errors against this variable.
ErrWriteAfterFlush = errors.New("unused")

// ErrConnectionClosed is used as a context Cause for contexts
// cancelled because the client closed their connection while
// a request was being handled.
ErrConnectionClosed = errors.New("connection closed")

// ErrConnectionHandled is used as a context Cause for contexts
// cancelled because the request handler returned.
ErrConnectionHandled = errors.New("connection handled")
)

// A Handler responds to an HTTP request.
Expand Down Expand Up @@ -257,7 +266,7 @@ type conn struct {
server *Server

// cancelCtx cancels the connection-level context.
cancelCtx context.CancelFunc
cancelCtx context.CancelCauseFunc

// rwc is the underlying network connection.
// This is never wrapped by other types and is the value given out
Expand Down Expand Up @@ -754,8 +763,11 @@ func (cr *connReader) hitReadLimit() bool { return cr.remain <= 0 }
// down its context.
//
// It may be called from multiple goroutines.
func (cr *connReader) handleReadError(_ error) {
cr.conn.cancelCtx()
func (cr *connReader) handleReadError(err error) {
if errors.Is(err, io.EOF) {
err = ErrConnectionClosed
}
cr.conn.cancelCtx(err)
cr.closeNotify()
}

Expand Down Expand Up @@ -2005,9 +2017,9 @@ func (c *conn) serve(ctx context.Context) {

// HTTP/1.x from here on.

ctx, cancelCtx := context.WithCancel(ctx)
ctx, cancelCtx := context.WithCancelCause(ctx)
c.cancelCtx = cancelCtx
defer cancelCtx()
defer cancelCtx(ErrConnectionHandled)

c.r = &connReader{conn: c}
c.bufr = newBufioReader(c.r)
Expand Down Expand Up @@ -4021,7 +4033,7 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
n, err = w.c.rwc.Write(p)
if err != nil && w.c.werr == nil {
w.c.werr = err
w.c.cancelCtx()
w.c.cancelCtx(err)
}
return
}
Expand Down

0 comments on commit d23593e

Please sign in to comment.