From 6532c933030e33e46c28ddc5018d17f3d3926720 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Tue, 19 Apr 2022 12:07:57 +0200 Subject: [PATCH] Improve read.ProtoJSON bad protobuf body error handling --- api/read/read.go | 61 +++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/api/read/read.go b/api/read/read.go index 7482c272..6cfc90ee 100644 --- a/api/read/read.go +++ b/api/read/read.go @@ -10,6 +10,7 @@ import ( "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/proto" + "github.com/smallstep/certificates/api/render" "github.com/smallstep/certificates/errs" ) @@ -29,49 +30,35 @@ func ProtoJSON(r io.Reader, m proto.Message) error { if err != nil { return errs.BadRequestErr(err, "error reading request body") } - if err := protojson.Unmarshal(data, m); err != nil { - if errors.Is(err, proto.Error) { - return newBadProtoJSONError(err) - } + + switch err := protojson.Unmarshal(data, m); { + case errors.Is(err, proto.Error): + return badProtoJSONError(err.Error()) + default: + return err } - return err } -// BadProtoJSONError is an error type that is used when a proto -// message cannot be unmarshaled. Usually this is caused by an error -// in the request body. -type BadProtoJSONError struct { - err error - Type string `json:"type"` - Detail string `json:"detail"` - Message string `json:"message"` +// badProtoJSONError is an error type that is returned by ProtoJSON +// when a proto message cannot be unmarshaled. Usually this is caused +// by an error in the request body. +type badProtoJSONError string + +// Error implements error for badProtoJSONError +func (e badProtoJSONError) Error() string { + return string(e) } -// newBadProtoJSONError returns a new instance of BadProtoJSONError -// This error type is always caused by an error in the request body. -func newBadProtoJSONError(err error) *BadProtoJSONError { - return &BadProtoJSONError{ - err: err, +// Render implements render.RenderableError for badProtoJSONError +func (e badProtoJSONError) Render(w http.ResponseWriter) { + v := struct { + Type string `json:"type"` + Detail string `json:"detail"` + Message string `json:"message"` + }{ Type: "badRequest", Detail: "bad request", - Message: err.Error(), + Message: e.Error(), } -} - -// Error implements the error interface -func (e *BadProtoJSONError) Error() string { - return e.err.Error() -} - -// Render implements render.RenderableError for BadProtoError -func (e *BadProtoJSONError) Render(w http.ResponseWriter) { - - errData, err := json.Marshal(e) - if err != nil { - panic(err) - } - - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - w.Write(errData) + render.JSONStatus(w, v, http.StatusBadRequest) }