pomerium/internal/httputil/errors.go
Bobby DeSimone bade9f50e6
internal/httputil: use error structs for http errors (#159)
The existing implementation used a ErrorResponse method to propogate
and create http error messages. Since we added functionality to
troubleshoot, signout, and do other tasks following an http error
it's useful to use Error struct in place of method arguments.

This fixes #157 where a troubleshooting links were appearing on pages
that it didn't make sense on (e.g. pages without valid sessions).
2019-06-03 20:00:37 -07:00

77 lines
2 KiB
Go

package httputil // import "github.com/pomerium/pomerium/internal/httputil"
import (
"encoding/json"
"fmt"
"io"
"net/http"
"github.com/pomerium/pomerium/internal/log"
"github.com/pomerium/pomerium/internal/templates"
)
// Error reports an http error, its http status code, a custom message, and
// whether it is CanDebug.
type Error struct {
Message string
Code int
CanDebug bool
}
// Error fulfills the error interface, returning a string representation of the error.
func (h Error) Error() string {
return fmt.Sprintf("%d %s: %s", h.Code, http.StatusText(h.Code), h.Message)
}
// CodeForError maps an error type and returns a corresponding http.Status
func CodeForError(err error) int {
switch err {
case ErrTokenRevoked:
return http.StatusUnauthorized
}
return http.StatusInternalServerError
}
// ErrorResponse renders an error page for errors given a message and a status code.
// If no message is passed, defaults to the text of the status code.
func ErrorResponse(rw http.ResponseWriter, r *http.Request, e *Error) {
requestID := ""
id, ok := log.IDFromRequest(r)
if ok {
requestID = id
}
if r.Header.Get("Accept") == "application/json" {
var response struct {
Error string `json:"error"`
}
response.Error = e.Message
writeJSONResponse(rw, e.Code, response)
} else {
rw.WriteHeader(e.Code)
t := struct {
Code int
Title string
Message string
RequestID string
CanDebug bool
}{
Code: e.Code,
Title: http.StatusText(e.Code),
Message: e.Message,
RequestID: requestID,
CanDebug: e.CanDebug,
}
templates.New().ExecuteTemplate(rw, "error.html", t)
}
}
// writeJSONResponse is a helper that sets the application/json header and writes a response.
func writeJSONResponse(rw http.ResponseWriter, code int, response interface{}) {
rw.Header().Set("Content-Type", "application/json")
rw.WriteHeader(code)
err := json.NewEncoder(rw).Encode(response)
if err != nil {
io.WriteString(rw, err.Error())
}
}