55 "errors"
66 "net/http"
77 "net/http/httptest"
8+
9+ "github.com/studiolambda/cosmos/framework/hook"
10+ "github.com/studiolambda/cosmos/problem"
811)
912
1013// Handler defines the function signature for HTTP request handlers in Cosmos.
@@ -50,6 +53,28 @@ type HTTPStatus interface {
5053 HTTPStatus () int
5154}
5255
56+ func handleError (w http.ResponseWriter , r * http.Request , err error ) {
57+ status := http .StatusInternalServerError
58+
59+ if errors .Is (err , context .Canceled ) || errors .Is (err , context .DeadlineExceeded ) {
60+ status = 499 // A non-standard status code: 499 Client Closed Request
61+ }
62+
63+ if s , ok := err .(HTTPStatus ); ok {
64+ status = s .HTTPStatus ()
65+ }
66+
67+ // We can check if the error can be directly
68+ // handled by using a [http.Handler], in the case
69+ // we'll simply handle it using ServeHTTP.
70+ if h , ok := err .(http.Handler ); ok {
71+ h .ServeHTTP (w , r )
72+ return
73+ }
74+
75+ problem .NewProblem (err , status ).ServeHTTP (w , r )
76+ }
77+
5378// ServeHTTP implements the http.Handler interface, allowing Cosmos handlers
5479// to be used with the standard HTTP server. It bridges the gap between
5580// Cosmos's error-returning handlers and Go's standard http.Handler interface.
@@ -59,18 +84,21 @@ type HTTPStatus interface {
5984// response to the client. However, if the response has already been partially
6085// written (e.g., during streaming), the error response may not be deliverable.
6186func (handler Handler ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
62- if err := handler (w , r ); err != nil {
63- status := http .StatusInternalServerError
87+ hooks := hook .NewManager ()
88+ wrapped := hook .NewResponseWriter (w , hooks )
89+ ctx := context .WithValue (r .Context (), hook .Key , hooks )
90+ err := handler (wrapped , r .WithContext (ctx ))
6491
65- if errors . Is ( err , context . Canceled ) || errors . Is ( err , context . DeadlineExceeded ) {
66- status = 499 // A non-standard status code: 499 Client Closed Request
67- }
92+ if err != nil {
93+ handleError ( w , r , err )
94+ }
6895
69- if s , ok := err .( HTTPStatus ); ok {
70- status = s . HTTPStatus ( )
71- }
96+ if ! wrapped . WriteHeaderCalled () {
97+ wrapped . WriteHeader ( http . StatusNoContent )
98+ }
7299
73- http .Error (w , err .Error (), status )
100+ for _ , callback := range hooks .AfterResponseFuncs () {
101+ callback (err )
74102 }
75103}
76104
0 commit comments