Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle context canceled errors + better http proxy error handling #644

Merged
merged 2 commits into from
Dec 5, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions proxy/http_handler.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package proxy

import (
"context"
"io"
"log"
"net"
"net/http"
"net/http/httputil"
"net/url"
"time"
)

// StatusClientClosedRequest non-standard HTTP status code for client disconnection
const StatusClientClosedRequest = 499

func newHTTPProxy(target *url.URL, tr http.RoundTripper, flush time.Duration) http.Handler {
return &httputil.ReverseProxy{
// this is a simplified director function based on the
Expand All @@ -25,5 +32,35 @@ func newHTTPProxy(target *url.URL, tr http.RoundTripper, flush time.Duration) ht
},
FlushInterval: flush,
Transport: tr,
ErrorHandler: httpProxyErrorHandler,
}
}

func httpProxyErrorHandler(w http.ResponseWriter, r *http.Request, err error) {
// According to https://golang.org/src/net/http/httputil/reverseproxy.go#L74, Go will return a 502 (Bad Gateway) StatusCode by default if no ErroHandler is provided
// If a "context canceled" error is returned by the http.Request handler this means the client closed the connection before getting a response
// So we are changing the StatusCode on these situations to the non-standard 499 (Client Closed Request)

statusCode := http.StatusInternalServerError

if e, ok := err.(net.Error); ok {
if e.Timeout() {
statusCode = http.StatusGatewayTimeout
} else {
statusCode = http.StatusBadGateway
}
} else if err == io.EOF {
statusCode = http.StatusBadGateway
} else if err == context.Canceled {
statusCode = StatusClientClosedRequest
}

w.WriteHeader(statusCode)
// Theres nothing we can do if the client closes the connection and logging the "context canceled" errors will just add noise to the error log
// Note: The access_log will still log the 499 response status codes
if statusCode != StatusClientClosedRequest {
log.Print("[ERROR] ", err)
}

return
}