Update util dep
parent
51f9741b34
commit
9e6127d12a
|
@ -92,7 +92,7 @@
|
||||||
{
|
{
|
||||||
"importpath": "github.com/matrix-org/util",
|
"importpath": "github.com/matrix-org/util",
|
||||||
"repository": "https://github.com/matrix-org/util",
|
"repository": "https://github.com/matrix-org/util",
|
||||||
"revision": "0bbc3896e02031e7e7338948b73ce891aa73ab2b",
|
"revision": "4de125c773716ad380f2f80cc6c04789ef4c906a",
|
||||||
"branch": "master"
|
"branch": "master"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,8 +5,14 @@ import "fmt"
|
||||||
// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
|
// HTTPError An HTTP Error response, which may wrap an underlying native Go Error.
|
||||||
type HTTPError struct {
|
type HTTPError struct {
|
||||||
WrappedError error
|
WrappedError error
|
||||||
|
// A human-readable message to return to the client in a JSON response. This
|
||||||
|
// is ignored if JSON is supplied.
|
||||||
Message string
|
Message string
|
||||||
|
// HTTP status code.
|
||||||
Code int
|
Code int
|
||||||
|
// JSON represents the JSON that should be serialized and sent to the client
|
||||||
|
// instead of the given Message.
|
||||||
|
JSON interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e HTTPError) Error() string {
|
func (e HTTPError) Error() string {
|
||||||
|
|
|
@ -68,7 +68,10 @@ func Protect(handler http.HandlerFunc) http.HandlerFunc {
|
||||||
"Request panicked!\n%s", debug.Stack(),
|
"Request panicked!\n%s", debug.Stack(),
|
||||||
)
|
)
|
||||||
jsonErrorResponse(
|
jsonErrorResponse(
|
||||||
w, req, &HTTPError{nil, "Internal Server Error", 500},
|
w, req, &HTTPError{
|
||||||
|
Message: "Internal Server Error",
|
||||||
|
Code: 500,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -112,7 +115,10 @@ func MakeJSONAPI(handler JSONRequestHandler) http.HandlerFunc {
|
||||||
if !ok {
|
if !ok {
|
||||||
r, err := json.Marshal(res)
|
r, err := json.Marshal(res)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
jsonErrorResponse(w, req, &HTTPError{nil, "Failed to serialise response as JSON", 500})
|
jsonErrorResponse(w, req, &HTTPError{
|
||||||
|
Message: "Failed to serialise response as JSON",
|
||||||
|
Code: 500,
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
resBytes = r
|
resBytes = r
|
||||||
|
@ -135,9 +141,23 @@ func jsonErrorResponse(w http.ResponseWriter, req *http.Request, httpErr *HTTPEr
|
||||||
|
|
||||||
w.WriteHeader(httpErr.Code) // Set response code
|
w.WriteHeader(httpErr.Code) // Set response code
|
||||||
|
|
||||||
r, err := json.Marshal(&JSONError{
|
var err error
|
||||||
|
var r []byte
|
||||||
|
if httpErr.JSON != nil {
|
||||||
|
r, err = json.Marshal(httpErr.JSON)
|
||||||
|
if err != nil {
|
||||||
|
// failed to marshal the supplied interface. Whine and fallback to the HTTP message.
|
||||||
|
logger.WithError(err).Error("Failed to marshal HTTPError.JSON")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// failed to marshal or no custom JSON was supplied, send message JSON.
|
||||||
|
if err != nil || httpErr.JSON == nil {
|
||||||
|
r, err = json.Marshal(&JSONError{
|
||||||
Message: httpErr.Message,
|
Message: httpErr.Message,
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// We should never fail to marshal the JSON error response, but in this event just skip
|
// We should never fail to marshal the JSON error response, but in this event just skip
|
||||||
// marshalling altogether
|
// marshalling altogether
|
||||||
|
|
|
@ -29,12 +29,26 @@ func TestMakeJSONAPI(t *testing.T) {
|
||||||
ExpectCode int
|
ExpectCode int
|
||||||
ExpectJSON string
|
ExpectJSON string
|
||||||
}{
|
}{
|
||||||
{nil, &HTTPError{nil, "Everything is broken", 500}, 500, `{"message":"Everything is broken"}`}, // Error return values
|
// Error message return values
|
||||||
{nil, &HTTPError{nil, "Not here", 404}, 404, `{"message":"Not here"}`}, // With different status codes
|
{nil, &HTTPError{nil, "Everything is broken", 500, nil}, 500, `{"message":"Everything is broken"}`},
|
||||||
{&MockResponse{"yep"}, nil, 200, `{"foo":"yep"}`}, // Success return values
|
// Error JSON return values
|
||||||
{[]MockResponse{{"yep"}, {"narp"}}, nil, 200, `[{"foo":"yep"},{"foo":"narp"}]`}, // Top-level array success values
|
{nil, &HTTPError{nil, "Everything is broken", 500, struct {
|
||||||
{[]byte(`actually bytes`), nil, 200, `actually bytes`}, // raw []byte escape hatch
|
Foo string `json:"foo"`
|
||||||
{func(cannotBe, marshalled string) {}, nil, 500, `{"message":"Failed to serialise response as JSON"}`}, // impossible marshal
|
}{"yep"}}, 500, `{"foo":"yep"}`},
|
||||||
|
// Error JSON return values which fail to be marshalled should fallback to text
|
||||||
|
{nil, &HTTPError{nil, "Everything is broken", 500, struct {
|
||||||
|
Foo interface{} `json:"foo"`
|
||||||
|
}{func(cannotBe, marshalled string) {}}}, 500, `{"message":"Everything is broken"}`},
|
||||||
|
// With different status codes
|
||||||
|
{nil, &HTTPError{nil, "Not here", 404, nil}, 404, `{"message":"Not here"}`},
|
||||||
|
// Success return values
|
||||||
|
{&MockResponse{"yep"}, nil, 200, `{"foo":"yep"}`},
|
||||||
|
// Top-level array success values
|
||||||
|
{[]MockResponse{{"yep"}, {"narp"}}, nil, 200, `[{"foo":"yep"},{"foo":"narp"}]`},
|
||||||
|
// raw []byte escape hatch
|
||||||
|
{[]byte(`actually bytes`), nil, 200, `actually bytes`},
|
||||||
|
// impossible marshal
|
||||||
|
{func(cannotBe, marshalled string) {}, nil, 500, `{"message":"Failed to serialise response as JSON"}`},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tst := range tests {
|
for _, tst := range tests {
|
||||||
|
@ -58,7 +72,7 @@ func TestMakeJSONAPI(t *testing.T) {
|
||||||
func TestMakeJSONAPIRedirect(t *testing.T) {
|
func TestMakeJSONAPIRedirect(t *testing.T) {
|
||||||
log.SetLevel(log.PanicLevel) // suppress logs in test output
|
log.SetLevel(log.PanicLevel) // suppress logs in test output
|
||||||
mock := MockJSONRequestHandler{func(req *http.Request) (interface{}, *HTTPError) {
|
mock := MockJSONRequestHandler{func(req *http.Request) (interface{}, *HTTPError) {
|
||||||
return nil, &HTTPError{nil, "https://matrix.org", 302}
|
return nil, &HTTPError{nil, "https://matrix.org", 302, nil}
|
||||||
}}
|
}}
|
||||||
mockReq, _ := http.NewRequest("GET", "http://example.com/foo", nil)
|
mockReq, _ := http.NewRequest("GET", "http://example.com/foo", nil)
|
||||||
mockWriter := httptest.NewRecorder()
|
mockWriter := httptest.NewRecorder()
|
||||||
|
|
Loading…
Reference in New Issue