Skip to content

Commit

Permalink
feat(errors): Also handle errors as RFC 7807 problems in reverse proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
rkettelerij committed Apr 3, 2024
1 parent cb66a23 commit d59348b
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 12 deletions.
13 changes: 10 additions & 3 deletions engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@ func (e *Engine) ReverseProxyAndValidate(w http.ResponseWriter, r *http.Request,
r.Out.Header.Set(HeaderBaseURL, e.Config.BaseURL.String())
}

errorHandler := func(w http.ResponseWriter, _ *http.Request, err error) {
log.Printf("failed to proxy request: %v", err)
RenderProblem(ProblemBadGateway, w)
}

modifyResponse := func(proxyRes *http.Response) error {
if prefer204 {
// OGC spec: If the tile has no content due to lack of data in the area, but is within the data
Expand All @@ -334,7 +339,6 @@ func (e *Engine) ReverseProxyAndValidate(w http.ResponseWriter, r *http.Request,
if proxyRes.Header.Get(HeaderContentEncoding) == FormatGzip {
reader, err = gzip.NewReader(proxyRes.Body)
if err != nil {
log.Printf("%v", err.Error())
return err
}
} else {
Expand All @@ -343,15 +347,18 @@ func (e *Engine) ReverseProxyAndValidate(w http.ResponseWriter, r *http.Request,
defer reader.Close()
res, err := io.ReadAll(reader)
if err != nil {
log.Printf("%v", err.Error())
return err
}
e.ServeResponse(w, r, false, true, contentType, res)
}
return nil
}

reverseProxy := &httputil.ReverseProxy{Rewrite: rewrite, ModifyResponse: modifyResponse}
reverseProxy := &httputil.ReverseProxy{
Rewrite: rewrite,
ModifyResponse: modifyResponse,
ErrorHandler: errorHandler,
}
reverseProxy.ServeHTTP(w, r)
}

Expand Down
10 changes: 5 additions & 5 deletions engine/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestEngine_ReverseProxy(t *testing.T) {
defer mockTargetServer.Close()

engine, targetURL := makeEngine(mockTargetServer)
rec, req := makeAPICall(t, mockTargetServer)
rec, req := makeAPICall(t, mockTargetServer.URL)

// when
engine.ReverseProxy(rec, req, targetURL, false, "")
Expand All @@ -85,7 +85,7 @@ func TestEngine_ReverseProxyAndValidate(t *testing.T) {
defer mockTargetServer.Close()

engine, targetURL := makeEngine(mockTargetServer)
rec, req := makeAPICall(t, mockTargetServer)
rec, req := makeAPICall(t, mockTargetServer.URL)

// when
engine.ReverseProxyAndValidate(rec, req, targetURL, false, MediaTypeJSON, true)
Expand All @@ -103,7 +103,7 @@ func TestEngine_ReverseProxy_Status204(t *testing.T) {
defer mockTargetServer.Close()

engine, targetURL := makeEngine(mockTargetServer)
rec, req := makeAPICall(t, mockTargetServer)
rec, req := makeAPICall(t, mockTargetServer.URL)

// when
engine.ReverseProxy(rec, req, targetURL, true, "audio/wav")
Expand All @@ -126,9 +126,9 @@ func makeEngine(mockTargetServer *httptest.Server) (*Engine, *url.URL) {
return engine, targetURL
}

func makeAPICall(t *testing.T, mockTargetServer *httptest.Server) (*httptest.ResponseRecorder, *http.Request) {
func makeAPICall(t *testing.T, mockTargetServer string) (*httptest.ResponseRecorder, *http.Request) {
rec := httptest.NewRecorder()
req, err := http.NewRequest(http.MethodGet, mockTargetServer.URL+"/some/path", nil)
req, err := http.NewRequest(http.MethodGet, mockTargetServer+"/some/path", nil)
if err != nil {
t.Fatal(err)
}
Expand Down
12 changes: 8 additions & 4 deletions engine/problems.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,20 @@ import (
)

const (
timestampKey = "timestamp"
messageInternalServer = "An unexpected error has occurred, try again or contact support if the problem persists"
timestampKey = "timestamp"
defaultMessageServerErr = "An unexpected error has occurred, try again or contact support if the problem persists"
defaultMessageBadGateway = "Failed to proxy request, try again or contact support if the problem persists"
)

var Now = time.Now // allow mocking

// The following problems should be added to openapi/problems.go.json
var (
Now = time.Now // allow mocking
ProblemServerError = problem.Of(http.StatusInternalServerError).Append(problem.Detail(messageInternalServer))
ProblemBadRequest = problem.Of(http.StatusBadRequest)
ProblemNotFound = problem.Of(http.StatusNotFound)
ProblemNotAcceptable = problem.Of(http.StatusNotAcceptable)
ProblemServerError = problem.Of(http.StatusInternalServerError).Append(problem.Detail(defaultMessageServerErr))
ProblemBadGateway = problem.Of(http.StatusBadGateway).Append(problem.Detail(defaultMessageBadGateway))
)

func RenderProblem(p *problem.Problem, w http.ResponseWriter, details ...string) {
Expand Down
10 changes: 10 additions & 0 deletions engine/templates/openapi/problems.go.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,14 @@
}
}
}
"502": {
"description": "Bad Gateway: An unexpected error occurred while forwarding/proxying the request to another server.",
"content": {
"application/problem+json": {
"schema": {
"$ref": "#/components/schemas/exception"
}
}
}
}
{{ end }}

0 comments on commit d59348b

Please sign in to comment.