pomerium/internal/httputil/errors.go
bobby f837c92741
dev: update linter (#1728)
- gofumpt everything
- fix TLS MinVersion to be at least 1.2
- add octal syntax
- remove newlines
- fix potential decompression bomb in ecjson
- remove implicit memory aliasing in for loops.

Signed-off-by: Bobby DeSimone <bobbydesimone@gmail.com>
2020-12-30 09:02:57 -08:00

77 lines
2.2 KiB
Go

package httputil
import (
"html/template"
"net/http"
"github.com/pomerium/pomerium/internal/frontend"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/telemetry/requestid"
"github.com/pomerium/pomerium/internal/version"
)
var (
errorTemplate = template.Must(frontend.NewTemplates())
fullVersion = version.FullVersion()
)
// HTTPError contains an HTTP status code and wrapped error.
type HTTPError struct {
// HTTP status codes as registered with IANA.
Status int
// Err is the wrapped error
Err error
}
// NewError returns an error that contains a HTTP status and error.
func NewError(status int, err error) error {
return &HTTPError{Status: status, Err: err}
}
// Error implements the `error` interface.
func (e *HTTPError) Error() string {
return http.StatusText(e.Status) + ": " + e.Err.Error()
}
// Unwrap implements the `error` Unwrap interface.
func (e *HTTPError) Unwrap() error { return e.Err }
// Debugable reports whether this error represents a user debuggable error.
func (e *HTTPError) Debugable() bool {
return e.Status == http.StatusUnauthorized || e.Status == http.StatusForbidden
}
// ErrorResponse replies to the request with the specified error message and HTTP code.
// It does not otherwise end the request; the caller should ensure no further
// writes are done to w.
func (e *HTTPError) ErrorResponse(w http.ResponseWriter, r *http.Request) {
// indicate to clients that the error originates from Pomerium, not the app
w.Header().Set(HeaderPomeriumResponse, "true")
w.WriteHeader(e.Status)
log.FromRequest(r).Info().Err(e).Msg("httputil: ErrorResponse")
requestID := requestid.FromContext(r.Context())
response := struct {
Status int
Error string
StatusText string `json:"-"`
RequestID string `json:",omitempty"`
CanDebug bool `json:"-"`
Version string `json:"-"`
}{
Status: e.Status,
StatusText: http.StatusText(e.Status),
Error: e.Error(),
RequestID: requestID,
CanDebug: e.Debugable(),
Version: fullVersion,
}
if r.Header.Get("Accept") == "application/json" {
RenderJSON(w, e.Status, response)
return
}
w.Header().Set("Content-Type", "text/html; charset=UTF-8")
errorTemplate.ExecuteTemplate(w, "error.html", response)
}