Skip to content

Commit d23593e

Browse files
committed
net/http: add context cancellation reason for server handlers
When we cancel a HTTP server handler context, set an appropriate cancel cause. This makes investigation of context cancellation errors easier. Fixes golang#64465
1 parent e39e965 commit d23593e

File tree

1 file changed

+18
-6
lines changed

1 file changed

+18
-6
lines changed

src/net/http/server.go

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ var (
5959
// anything in the net/http package. Callers should not
6060
// compare errors against this variable.
6161
ErrWriteAfterFlush = errors.New("unused")
62+
63+
// ErrConnectionClosed is used as a context Cause for contexts
64+
// cancelled because the client closed their connection while
65+
// a request was being handled.
66+
ErrConnectionClosed = errors.New("connection closed")
67+
68+
// ErrConnectionHandled is used as a context Cause for contexts
69+
// cancelled because the request handler returned.
70+
ErrConnectionHandled = errors.New("connection handled")
6271
)
6372

6473
// A Handler responds to an HTTP request.
@@ -257,7 +266,7 @@ type conn struct {
257266
server *Server
258267

259268
// cancelCtx cancels the connection-level context.
260-
cancelCtx context.CancelFunc
269+
cancelCtx context.CancelCauseFunc
261270

262271
// rwc is the underlying network connection.
263272
// This is never wrapped by other types and is the value given out
@@ -754,8 +763,11 @@ func (cr *connReader) hitReadLimit() bool { return cr.remain <= 0 }
754763
// down its context.
755764
//
756765
// It may be called from multiple goroutines.
757-
func (cr *connReader) handleReadError(_ error) {
758-
cr.conn.cancelCtx()
766+
func (cr *connReader) handleReadError(err error) {
767+
if errors.Is(err, io.EOF) {
768+
err = ErrConnectionClosed
769+
}
770+
cr.conn.cancelCtx(err)
759771
cr.closeNotify()
760772
}
761773

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

20062018
// HTTP/1.x from here on.
20072019

2008-
ctx, cancelCtx := context.WithCancel(ctx)
2020+
ctx, cancelCtx := context.WithCancelCause(ctx)
20092021
c.cancelCtx = cancelCtx
2010-
defer cancelCtx()
2022+
defer cancelCtx(ErrConnectionHandled)
20112023

20122024
c.r = &connReader{conn: c}
20132025
c.bufr = newBufioReader(c.r)
@@ -4021,7 +4033,7 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
40214033
n, err = w.c.rwc.Write(p)
40224034
if err != nil && w.c.werr == nil {
40234035
w.c.werr = err
4024-
w.c.cancelCtx()
4036+
w.c.cancelCtx(err)
40254037
}
40264038
return
40274039
}

0 commit comments

Comments
 (0)