mirror of
https://github.com/caddyserver/caddy.git
synced 2024-12-16 21:56:40 -05:00
reverseproxy: Handle "operation was canceled" errors (#3816)
* fix(caddy): Avoid "operation was canceled" errors - Also add error handling for StatusGatewayTimeout * revert(caddy): Revert 504 handling - This will potentially break load balancing and health checks * Handle client cancellation as different error Co-authored-by: Matthew Holt <mholt@users.noreply.github.com>
This commit is contained in:
parent
b0f8fc7aae
commit
53aa60afff
1 changed files with 24 additions and 3 deletions
|
@ -18,6 +18,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -384,8 +385,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
|
||||||
// DialInfo struct should have valid network address syntax
|
// DialInfo struct should have valid network address syntax
|
||||||
dialInfo, err := upstream.fillDialInfo(r)
|
dialInfo, err := upstream.fillDialInfo(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("making dial info: %v", err)
|
return statusError(fmt.Errorf("making dial info: %v", err))
|
||||||
return caddyhttp.Error(http.StatusBadGateway, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach to the request information about how to dial the upstream;
|
// attach to the request information about how to dial the upstream;
|
||||||
|
@ -438,7 +438,7 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyht
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return caddyhttp.Error(http.StatusBadGateway, proxyErr)
|
return statusError(proxyErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareRequest modifies req so that it is ready to be proxied,
|
// prepareRequest modifies req so that it is ready to be proxied,
|
||||||
|
@ -762,6 +762,27 @@ func removeConnectionHeaders(h http.Header) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// statusError returns an error value that has a status code.
|
||||||
|
func statusError(err error) error {
|
||||||
|
// errors proxying usually mean there is a problem with the upstream(s)
|
||||||
|
statusCode := http.StatusBadGateway
|
||||||
|
|
||||||
|
// if the client canceled the request (usually this means they closed
|
||||||
|
// the connection, so they won't see any response), we can report it
|
||||||
|
// as a client error (4xx) and not a server error (5xx); unfortunately
|
||||||
|
// the Go standard library, at least at time of writing in late 2020,
|
||||||
|
// obnoxiously wraps the exported, standard context.Canceled error with
|
||||||
|
// an unexported garbage value that we have to do a substring check for:
|
||||||
|
// https://github.com/golang/go/blob/6965b01ea248cabb70c3749fd218b36089a21efb/src/net/net.go#L416-L430
|
||||||
|
if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "operation was canceled") {
|
||||||
|
// regrettably, there is no standard error code for "client closed connection", but
|
||||||
|
// for historical reasons we can use a code that a lot of people are already using;
|
||||||
|
// using 5xx is problematic for users; see #3748
|
||||||
|
statusCode = 499
|
||||||
|
}
|
||||||
|
return caddyhttp.Error(statusCode, err)
|
||||||
|
}
|
||||||
|
|
||||||
// LoadBalancing has parameters related to load balancing.
|
// LoadBalancing has parameters related to load balancing.
|
||||||
type LoadBalancing struct {
|
type LoadBalancing struct {
|
||||||
// A selection policy is how to choose an available backend.
|
// A selection policy is how to choose an available backend.
|
||||||
|
|
Loading…
Reference in a new issue