diff --git a/tsweb/log.go b/tsweb/log.go index 619537118..788e46720 100644 --- a/tsweb/log.go +++ b/tsweb/log.go @@ -6,7 +6,6 @@ package tsweb import ( "encoding/json" - "fmt" "strings" "time" ) @@ -42,20 +41,3 @@ func (m Msg) String() string { json.NewEncoder(&buf).Encode(m) return strings.TrimRight(buf.String(), "\n") } - -// HTTPError is an error with embedded HTTP response information. When -// received by an ErrHandler, the Code and Msg are sent to the client, -// while Err is logged on the server. -type HTTPError struct { - Code int - Msg string // sent to the end-user - Err error -} - -// Error implements the error interface. -func (e HTTPError) Error() string { return fmt.Sprintf("httperror{%d, %q, %v}", e.Code, e.Msg, e.Err) } - -// Error returns an HTTPError containing the given information. -func Error(code int, msg string, err error) HTTPError { - return HTTPError{Code: code, Msg: msg, Err: err} -} diff --git a/tsweb/tsweb.go b/tsweb/tsweb.go index e7409f34f..2f8bb3a5d 100644 --- a/tsweb/tsweb.go +++ b/tsweb/tsweb.go @@ -140,9 +140,21 @@ func stripPort(hostport string) string { } // Handler is like net/http.Handler, but the handler can return an -// error. +// error instead of writing to its ResponseWriter. +// +// ServeHTTPErr should behave like http.Handler.ServeHTTP, except that +// it can choose to return an error instead of writing to its +// http.ResponseWriter. +// +// Callers of Handler should handle an error by serving a 500 error to +// the user. The error details should not be sent to the client, as +// they may contain sensitive information. +// +// In addition, if the returned error is an HTTPError, callers should +// use the HTTP response code and message as the response to the +// client. type Handler interface { - ServeHTTP(http.ResponseWriter, *http.Request) error + ServeHTTPErr(http.ResponseWriter, *http.Request) error } // handler is an http.Handler that wraps a Handler and handles errors. @@ -151,6 +163,7 @@ type handler struct { logf logger.Logf } +// ServeHTTP implements the http.Handler interface. func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { msg := Msg{ Where: "http", @@ -162,7 +175,7 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { Referer: r.Referer(), }, } - err := h.h.ServeHTTP(w, r) + err := h.h.ServeHTTPErr(w, r) if err == context.Canceled { // No need to inform client, but still log the // cancellation. @@ -188,12 +201,28 @@ func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { h.logf("%s", msg) } -// ErrHandler returns an http.Handler that logs requests and handles -// errors from the inner Handler. -func ErrHandler(h Handler, logf logger.Logf) http.Handler { +// StdHandler converts a Handler into a standard http.Handler. +// Handled requests and any errors returned by h are logged using +// logf. Errors are handled as specified by the Handler interface. +func StdHandler(h Handler, logf logger.Logf) http.Handler { return handler{h, logf} } +// HTTPError is an error with embedded HTTP response information. +type HTTPError struct { + Code int // HTTP response code to send to client + Msg string // Response body to send to client + Err error // Detailed error to log on the server +} + +// Error implements the error interface. +func (e HTTPError) Error() string { return fmt.Sprintf("httperror{%d, %q, %v}", e.Code, e.Msg, e.Err) } + +// Error returns an HTTPError containing the given information. +func Error(code int, msg string, err error) HTTPError { + return HTTPError{Code: code, Msg: msg, Err: err} +} + // varzHandler is an HTTP handler to write expvar values into the // prometheus export format: //