From 0b667ac94e2c3f224c50330e3b22a5436cb8cb9b Mon Sep 17 00:00:00 2001 From: Charlie Getzen Date: Thu, 14 Oct 2021 15:09:05 -0500 Subject: [PATCH] TimeoutHandler: distinguish between timeouts and client hangups --- src/net/http/server.go | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/net/http/server.go b/src/net/http/server.go index 55fd4ae22f..6d325fdbc5 100644 --- a/src/net/http/server.go +++ b/src/net/http/server.go @@ -3304,6 +3304,7 @@ func TimeoutHandler(h Handler, dt time.Duration, msg string) Handler { // ErrHandlerTimeout is returned on ResponseWriter Write calls // in handlers which have timed out. var ErrHandlerTimeout = errors.New("http: Handler timeout") +var ErrClientHangup = errors.New("http: Client hung up") type timeoutHandler struct { handler Handler @@ -3364,9 +3365,14 @@ func (h *timeoutHandler) ServeHTTP(w ResponseWriter, r *Request) { case <-ctx.Done(): tw.mu.Lock() defer tw.mu.Unlock() - w.WriteHeader(StatusServiceUnavailable) - io.WriteString(w, h.errorBody()) - tw.timedOut = true + switch err := ctx.Err(); err { + case context.DeadlineExceeded: + w.WriteHeader(StatusServiceUnavailable) + io.WriteString(w, h.errorBody()) + tw.timedOut = true + case context.Canceled: + tw.clientHangup = true + } } } @@ -3376,10 +3382,11 @@ type timeoutWriter struct { wbuf bytes.Buffer req *Request - mu sync.Mutex - timedOut bool - wroteHeader bool - code int + mu sync.Mutex + timedOut bool + clientHangup bool + wroteHeader bool + code int } var _ Pusher = (*timeoutWriter)(nil) @@ -3400,6 +3407,9 @@ func (tw *timeoutWriter) Write(p []byte) (int, error) { if tw.timedOut { return 0, ErrHandlerTimeout } + if tw.clientHangup { + return 0, ErrClientHangup + } if !tw.wroteHeader { tw.writeHeaderLocked(StatusOK) }