diff --git a/.changelog/849.bugfix.md b/.changelog/849.bugfix.md new file mode 100644 index 000000000..df81f2485 --- /dev/null +++ b/.changelog/849.bugfix.md @@ -0,0 +1,4 @@ +API: Return CORS headers on request timeouts + +Moved `CorsMiddleware` outside of `TimeoutHandler` to ensure CORS headers are +included in responses even when requests time out. diff --git a/cmd/api/api.go b/cmd/api/api.go index 6f2fc0eae..4b1fea770 100644 --- a/cmd/api/api.go +++ b/cmd/api/api.go @@ -199,14 +199,14 @@ func (s *Service) Start() { BaseRouter: baseRouter, ErrorHandlerFunc: api.HumanReadableJsonErrorHandler(*s.logger), }) - // Manually apply the CORS middleware; we want it to run always. - // HandlerWithOptions() above does not apply it to some requests (404 URLs, requests with bad params, etc.). - handler = api.CorsMiddleware(handler) // By default, request context is not cancelled when write timeout is reached. The connection // is closed, but the handler continues to run. Ref: https://github.com/golang/go/issues/59602 // We use `http.TimeoutHandler`, to cancel requests and return a 503 to the client when timeout is reached. // The handler also cancels the downstream request context on timeout. handler = http.TimeoutHandler(handler, s.requestTimeout, "request timed out") + // Manually apply the CORS middleware; we want it to run always. + // HandlerWithOptions() above does not apply it to some requests (404 URLs, requests with bad params, etc.). + handler = api.CorsMiddleware(handler) // Manually apply the metrics middleware; we want it to run always, and at the outermost layer. // HandlerWithOptions() above does not apply it to some requests (404 URLs, requests with bad params, etc.). handler = api.MetricsMiddleware(metrics.NewDefaultRequestMetrics(moduleName), *s.logger)(handler)