Factor out JSON writing in WFE (#2226)

This PR, removes some duplication in the WFE in regards to writing a JSON response. Fixes #2156
This commit is contained in:
Ben Irving 2016-10-11 11:29:57 -07:00 committed by Daniel McCarney
parent 5fabc90a16
commit 00708708e4
1 changed files with 53 additions and 65 deletions

View File

@ -193,6 +193,24 @@ func marshalIndent(v interface{}) ([]byte, error) {
return json.MarshalIndent(v, "", " ")
}
func (wfe *WebFrontEndImpl) writeJsonResponse(response http.ResponseWriter, logEvent *requestEvent, status int, v interface{}) error {
jsonReply, err := marshalIndent(v)
if err != nil {
return err // All callers are responsible for handling this error
}
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(status)
_, err = response.Write(jsonReply)
if err != nil {
// Don't worry about returning this error because the caller will
// never handle it.
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
logEvent.AddError(fmt.Sprintf("failed to write response: %s", err))
}
return nil
}
func (wfe *WebFrontEndImpl) relativeEndpoint(request *http.Request, endpoint string) string {
var result string
proto := "http"
@ -602,7 +620,14 @@ func (wfe *WebFrontEndImpl) NewRegistration(ctx context.Context, logEvent *reque
// Use an explicitly typed variable. Otherwise `go vet' incorrectly complains
// that reg.ID is a string being passed to %d.
regURL := wfe.relativeEndpoint(request, fmt.Sprintf("%s%d", regPath, reg.ID))
responseBody, err := marshalIndent(reg)
response.Header().Add("Location", regURL)
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newAuthzPath), "next"))
if len(wfe.SubscriberAgreementURL) > 0 {
response.Header().Add("Link", link(wfe.SubscriberAgreementURL, "terms-of-service"))
}
err = wfe.writeJsonResponse(response, logEvent, http.StatusCreated, reg)
if err != nil {
// ServerInternal because we just created this registration, and it
// should be OK.
@ -610,16 +635,6 @@ func (wfe *WebFrontEndImpl) NewRegistration(ctx context.Context, logEvent *reque
wfe.sendError(response, logEvent, probs.ServerInternal("Error marshaling registration"), err)
return
}
response.Header().Add("Location", regURL)
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newAuthzPath), "next"))
if len(wfe.SubscriberAgreementURL) > 0 {
response.Header().Add("Link", link(wfe.SubscriberAgreementURL, "terms-of-service"))
}
response.WriteHeader(http.StatusCreated)
response.Write(responseBody)
}
// NewAuthorization is used by clients to submit a new ID Authorization
@ -659,21 +674,16 @@ func (wfe *WebFrontEndImpl) NewAuthorization(ctx context.Context, logEvent *requ
// Make a URL for this authz, then blow away the ID and RegID before serializing
authzURL := wfe.relativeEndpoint(request, authzPath+string(authz.ID))
wfe.prepAuthorizationForDisplay(request, &authz)
responseBody, err := marshalIndent(authz)
response.Header().Add("Location", authzURL)
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newCertPath), "next"))
err = wfe.writeJsonResponse(response, logEvent, http.StatusCreated, authz)
if err != nil {
// ServerInternal because we generated the authz, it should be OK
wfe.sendError(response, logEvent, probs.ServerInternal("Error marshaling authz"), err)
return
}
response.Header().Add("Location", authzURL)
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newCertPath), "next"))
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(http.StatusCreated)
if _, err = response.Write(responseBody); err != nil {
logEvent.AddError(err.Error())
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
}
}
// RevokeCertificate is used by clients to request the revocation of a cert.
@ -986,7 +996,11 @@ func (wfe *WebFrontEndImpl) getChallenge(
wfe.prepChallengeForDisplay(request, authz, challenge)
jsonReply, err := marshalIndent(challenge)
authzURL := wfe.relativeEndpoint(request, authzPath+string(authz.ID))
response.Header().Add("Location", challenge.URI)
response.Header().Add("Link", link(authzURL, "up"))
err := wfe.writeJsonResponse(response, logEvent, http.StatusAccepted, challenge)
if err != nil {
// InternalServerError because this is a failure to decode data passed in
// by the caller, which got it from the DB.
@ -994,17 +1008,6 @@ func (wfe *WebFrontEndImpl) getChallenge(
wfe.sendError(response, logEvent, probs.ServerInternal("Failed to marshal challenge"), err)
return
}
authzURL := wfe.relativeEndpoint(request, authzPath+string(authz.ID))
response.Header().Add("Location", challenge.URI)
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(authzURL, "up"))
response.WriteHeader(http.StatusAccepted)
if _, err := response.Write(jsonReply); err != nil {
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
logEvent.AddError(err.Error())
return
}
}
func (wfe *WebFrontEndImpl) postChallenge(
@ -1059,24 +1062,18 @@ func (wfe *WebFrontEndImpl) postChallenge(
// assumption: UpdateAuthorization does not modify order of challenges
challenge := updatedAuthorization.Challenges[challengeIndex]
wfe.prepChallengeForDisplay(request, authz, &challenge)
jsonReply, err := marshalIndent(challenge)
authzURL := wfe.relativeEndpoint(request, authzPath+string(authz.ID))
response.Header().Add("Location", challenge.URI)
response.Header().Add("Link", link(authzURL, "up"))
err = wfe.writeJsonResponse(response, logEvent, http.StatusAccepted, challenge)
if err != nil {
// ServerInternal because we made the challenges, they should be OK
logEvent.AddError("failed to marshal challenge: %s", err)
wfe.sendError(response, logEvent, probs.ServerInternal("Failed to marshal challenge"), err)
return
}
authzURL := wfe.relativeEndpoint(request, authzPath+string(authz.ID))
response.Header().Add("Location", challenge.URI)
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(authzURL, "up"))
response.WriteHeader(http.StatusAccepted)
if _, err = response.Write(jsonReply); err != nil {
logEvent.AddError(err.Error())
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
return
}
}
// Registration is used by a client to submit an update to their registration.
@ -1163,20 +1160,18 @@ func (wfe *WebFrontEndImpl) Registration(ctx context.Context, logEvent *requestE
return
}
jsonReply, err := marshalIndent(updatedReg)
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newAuthzPath), "next"))
if len(wfe.SubscriberAgreementURL) > 0 {
response.Header().Add("Link", link(wfe.SubscriberAgreementURL, "terms-of-service"))
}
err = wfe.writeJsonResponse(response, logEvent, http.StatusAccepted, updatedReg)
if err != nil {
// ServerInternal because we just generated the reg, it should be OK
logEvent.AddError("unable to marshal updated registration: %s", err)
wfe.sendError(response, logEvent, probs.ServerInternal("Failed to marshal registration"), err)
return
}
response.Header().Set("Content-Type", "application/json")
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newAuthzPath), "next"))
if len(wfe.SubscriberAgreementURL) > 0 {
response.Header().Add("Link", link(wfe.SubscriberAgreementURL, "terms-of-service"))
}
response.WriteHeader(http.StatusAccepted)
response.Write(jsonReply)
}
func (wfe *WebFrontEndImpl) deactivateAuthorization(ctx context.Context, authz *core.Authorization, logEvent *requestEvent, response http.ResponseWriter, request *http.Request) bool {
@ -1254,20 +1249,15 @@ func (wfe *WebFrontEndImpl) Authorization(ctx context.Context, logEvent *request
wfe.prepAuthorizationForDisplay(request, &authz)
jsonReply, err := marshalIndent(authz)
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newCertPath), "next"))
err = wfe.writeJsonResponse(response, logEvent, http.StatusOK, authz)
if err != nil {
// InternalServerError because this is a failure to decode from our DB.
logEvent.AddError("Failed to JSON marshal authz: %s", err)
wfe.sendError(response, logEvent, probs.ServerInternal("Failed to JSON marshal authz"), err)
return
}
response.Header().Add("Link", link(wfe.relativeEndpoint(request, newCertPath), "next"))
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(http.StatusOK)
if _, err = response.Write(jsonReply); err != nil {
logEvent.AddError(err.Error())
wfe.log.Warning(fmt.Sprintf("Could not write response: %s", err))
}
}
var allHex = regexp.MustCompile("^[0-9a-f]+$")
@ -1400,14 +1390,12 @@ func (wfe *WebFrontEndImpl) deactivateRegistration(ctx context.Context, reg core
return
}
reg.Status = core.StatusDeactivated
jsonReply, err := marshalIndent(reg)
err = wfe.writeJsonResponse(response, logEvent, http.StatusOK, reg)
if err != nil {
// ServerInternal because registration is from DB and should be fine
logEvent.AddError("unable to marshal updated registration: %s", err)
wfe.sendError(response, logEvent, probs.ServerInternal("Failed to marshal registration"), err)
return
}
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(http.StatusOK)
response.Write(jsonReply)
}