Improve error reporting in WFE and WFE2 (#3452)
* Factor out sendError into web.SendError. * In web.SendError, ensure that ierr always gets added to the list of errors logged.
This commit is contained in:
parent
22bb47a275
commit
c628fc0119
|
|
@ -0,0 +1,56 @@
|
|||
package web
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
blog "github.com/letsencrypt/boulder/log"
|
||||
"github.com/letsencrypt/boulder/probs"
|
||||
)
|
||||
|
||||
// SendError does a few things that we want for each error response:
|
||||
// - Adds both the external and the internal error to a RequestEvent.
|
||||
// - If the ProblemDetails provided is a ServerInternalProblem, audit logs the
|
||||
// internal error.
|
||||
// - Prefixes the Type field of the ProblemDetails with a namespace.
|
||||
// - Sends an HTTP response containing the error and an error code to the user.
|
||||
func SendError(
|
||||
log blog.Logger,
|
||||
namespace string,
|
||||
response http.ResponseWriter,
|
||||
logEvent *RequestEvent,
|
||||
prob *probs.ProblemDetails,
|
||||
ierr error,
|
||||
) {
|
||||
// Determine the HTTP status code to use for this problem
|
||||
code := probs.ProblemDetailsToStatusCode(prob)
|
||||
|
||||
// Record details to the log event
|
||||
logEvent.AddError(fmt.Sprintf("%d :: %s :: %s", prob.HTTPStatus, prob.Type, prob.Detail))
|
||||
if ierr != nil {
|
||||
logEvent.AddError(fmt.Sprintf("%#v", ierr))
|
||||
}
|
||||
|
||||
// Only audit log internal errors so users cannot purposefully cause
|
||||
// auditable events.
|
||||
if prob.Type == probs.ServerInternalProblem {
|
||||
if ierr != nil {
|
||||
log.AuditErr(fmt.Sprintf("Internal error - %s - %s", prob.Detail, ierr))
|
||||
} else {
|
||||
log.AuditErr(fmt.Sprintf("Internal error - %s", prob.Detail))
|
||||
}
|
||||
}
|
||||
|
||||
prob.Type = probs.ProblemType(namespace) + prob.Type
|
||||
problemDoc, err := json.MarshalIndent(prob, "", " ")
|
||||
if err != nil {
|
||||
log.AuditErr(fmt.Sprintf("Could not marshal error message: %s - %+v", err, prob))
|
||||
problemDoc = []byte("{\"detail\": \"Problem marshalling error message.\"}")
|
||||
}
|
||||
|
||||
// Write the JSON problem response
|
||||
response.Header().Set("Content-Type", "application/problem+json")
|
||||
response.WriteHeader(code)
|
||||
response.Write(problemDoc)
|
||||
}
|
||||
36
wfe/wfe.go
36
wfe/wfe.go
|
|
@ -571,42 +571,10 @@ func (wfe *WebFrontEndImpl) verifyPOST(ctx context.Context, logEvent *web.Reques
|
|||
return []byte(payload), key, reg, nil
|
||||
}
|
||||
|
||||
// sendError sends an error response represented by the given ProblemDetails,
|
||||
// and, if the ProblemDetails.Type is ServerInternalProblem, audit logs the
|
||||
// internal ierr. The rendered Problem will have its Type prefixed with the ACME
|
||||
// v1 namespace.
|
||||
// sendError wraps web.SendError
|
||||
func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, logEvent *web.RequestEvent, prob *probs.ProblemDetails, ierr error) {
|
||||
// Determine the HTTP status code to use for this problem
|
||||
code := probs.ProblemDetailsToStatusCode(prob)
|
||||
|
||||
// Record details to the log event
|
||||
logEvent.AddError(fmt.Sprintf("%d :: %s :: %s", prob.HTTPStatus, prob.Type, prob.Detail))
|
||||
|
||||
// Only audit log internal errors so users cannot purposefully cause
|
||||
// auditable events.
|
||||
if prob.Type == probs.ServerInternalProblem {
|
||||
if ierr != nil {
|
||||
wfe.log.AuditErr(fmt.Sprintf("Internal error - %s - %s", prob.Detail, ierr))
|
||||
} else {
|
||||
wfe.log.AuditErr(fmt.Sprintf("Internal error - %s", prob.Detail))
|
||||
}
|
||||
}
|
||||
|
||||
// Increment a stat for this problem type
|
||||
wfe.stats.Inc(fmt.Sprintf("HTTP.ProblemTypes.%s", prob.Type), 1)
|
||||
|
||||
// Prefix the problem type with the ACME V1 error namespace and marshal to JSON
|
||||
prob.Type = probs.V1ErrorNS + prob.Type
|
||||
problemDoc, err := marshalIndent(prob)
|
||||
if err != nil {
|
||||
wfe.log.AuditErr(fmt.Sprintf("Could not marshal error message: %s - %+v", err, prob))
|
||||
problemDoc = []byte("{\"detail\": \"Problem marshalling error message.\"}")
|
||||
}
|
||||
|
||||
// Write the JSON problem response
|
||||
response.Header().Set("Content-Type", "application/problem+json")
|
||||
response.WriteHeader(code)
|
||||
response.Write(problemDoc)
|
||||
web.SendError(wfe.log, probs.V1ErrorNS, response, logEvent, prob, ierr)
|
||||
}
|
||||
|
||||
func link(url, relation string) string {
|
||||
|
|
|
|||
36
wfe2/wfe.go
36
wfe2/wfe.go
|
|
@ -423,42 +423,10 @@ func (wfe *WebFrontEndImpl) Nonce(
|
|||
response.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
|
||||
// sendError sends an error response represented by the given ProblemDetails,
|
||||
// and, if the ProblemDetails.Type is ServerInternalProblem, audit logs the
|
||||
// internal ierr. The rendered Problem will have its Type prefixed with the ACME
|
||||
// v2 error namespace.
|
||||
// sendError wraps web.SendError
|
||||
func (wfe *WebFrontEndImpl) sendError(response http.ResponseWriter, logEvent *web.RequestEvent, prob *probs.ProblemDetails, ierr error) {
|
||||
// Determine the HTTP status code to use for this problem
|
||||
code := probs.ProblemDetailsToStatusCode(prob)
|
||||
|
||||
// Record details to the log event
|
||||
logEvent.AddError(fmt.Sprintf("%d :: %s :: %s", prob.HTTPStatus, prob.Type, prob.Detail))
|
||||
|
||||
// Only audit log internal errors so users cannot purposefully cause
|
||||
// auditable events.
|
||||
if prob.Type == probs.ServerInternalProblem {
|
||||
if ierr != nil {
|
||||
wfe.log.AuditErr(fmt.Sprintf("Internal error - %s - %s", prob.Detail, ierr))
|
||||
} else {
|
||||
wfe.log.AuditErr(fmt.Sprintf("Internal error - %s", prob.Detail))
|
||||
}
|
||||
}
|
||||
|
||||
// Increment a stat for this problem type
|
||||
wfe.stats.httpErrorCount.With(prometheus.Labels{"type": string(prob.Type)}).Inc()
|
||||
|
||||
// Prefix the problem type with the ACME V2 error namespace and marshal to JSON
|
||||
prob.Type = probs.V2ErrorNS + prob.Type
|
||||
problemDoc, err := marshalIndent(prob)
|
||||
if err != nil {
|
||||
wfe.log.AuditErr(fmt.Sprintf("Could not marshal error message: %s - %+v", err, prob))
|
||||
problemDoc = []byte("{\"detail\": \"Problem marshalling error message.\"}")
|
||||
}
|
||||
|
||||
// Write the JSON problem response
|
||||
response.Header().Set("Content-Type", "application/problem+json")
|
||||
response.WriteHeader(code)
|
||||
response.Write(problemDoc)
|
||||
web.SendError(wfe.log, probs.V2ErrorNS, response, logEvent, prob, ierr)
|
||||
}
|
||||
|
||||
func link(url, relation string) string {
|
||||
|
|
|
|||
Loading…
Reference in New Issue