statusError returns an error value that has a status code.
(err error)
| 1596 | |
| 1597 | // statusError returns an error value that has a status code. |
| 1598 | func statusError(err error) error { |
| 1599 | // if a response-based retry was exhausted, use the actual upstream |
| 1600 | // status code instead of a generic 502 |
| 1601 | if rre, ok := err.(retryableResponseError); ok { |
| 1602 | return caddyhttp.Error(rre.statusCode, err) |
| 1603 | } |
| 1604 | |
| 1605 | // errors proxying usually mean there is a problem with the upstream(s) |
| 1606 | statusCode := http.StatusBadGateway |
| 1607 | |
| 1608 | // timeout errors have a standard status code (see issue #4823) |
| 1609 | if err, ok := err.(net.Error); ok && err.Timeout() { |
| 1610 | statusCode = http.StatusGatewayTimeout |
| 1611 | } |
| 1612 | |
| 1613 | // if the client canceled the request (usually this means they closed |
| 1614 | // the connection, so they won't see any response), we can report it |
| 1615 | // as a client error (4xx) and not a server error (5xx); unfortunately |
| 1616 | // the Go standard library, at least at time of writing in late 2020, |
| 1617 | // obnoxiously wraps the exported, standard context.Canceled error with |
| 1618 | // an unexported garbage value that we have to do a substring check for: |
| 1619 | // https://github.com/golang/go/blob/6965b01ea248cabb70c3749fd218b36089a21efb/src/net/net.go#L416-L430 |
| 1620 | if errors.Is(err, context.Canceled) || strings.Contains(err.Error(), "operation was canceled") { |
| 1621 | // regrettably, there is no standard error code for "client closed connection", but |
| 1622 | // for historical reasons we can use a code that a lot of people are already using; |
| 1623 | // using 5xx is problematic for users; see #3748 |
| 1624 | statusCode = 499 |
| 1625 | } |
| 1626 | return caddyhttp.Error(statusCode, err) |
| 1627 | } |
| 1628 | |
| 1629 | // LoadBalancing has parameters related to load balancing. |
| 1630 | type LoadBalancing struct { |