-
-
Notifications
You must be signed in to change notification settings - Fork 132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: middleware to warn if response headers are invalid #262
Conversation
Thanks!
Not yet a full review, but AFAIK built-in middleware runs both before and after the user's middleware: let my_middleware user's_middleware = fun request ->
do_stuff_before;
let%lwt response = user's_middleware request in
do_stuff_after;
response |
Ah thanks for clarifying. I'll re-implement this as a built-in middleware then to log a warning if there are empty header keys. |
😆
This cracks me up because I'm assuming you've written the middleware logic yourself. |
Need to be careful in case I forgot or something has been broken since :) |
7620ac7
to
a7303fe
Compare
unfortunately can't use expect-test against log outputs because we can't control the time when the logger executes. not that i can see any option. since i'm not performing any mutations anyways, think we're safe to not have a test. done! |
|
||
|
||
let%expect_test _ = | ||
let%expect_test "middleware runs sequentially onion-style" = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
autoformatter kicked in for the file too.
I can merge this now to avoid extending this PR unnecessarily. However, as I recall, I wanted to move Dream away from the built-in middleware model. That's why there was only one left, and the plan was to find a way to get rid of it as a built-in middleware as well. I think this warning can go unconditionally into the HTTP adapters -- hopefully in a place where it will be triggered for both HTTP1 and HTTP2. This area: Lines 407 to 448 in a2961cd
already has several wrappers around the user's handler, so we just need to add the middleware here unconditionally. It should run outside of the |
I'd prefer do this as a follow-up too - re: move the header check to h1/h2 paths. I thought it was a little strange to have important checks be opt-in, so I'm glad to see this direction change. The gold standard imo is asp.net & phoenix. Baking in security and best-practices seems best. |
test/expect/http/dune
Outdated
(library | ||
(name test_expect_http) | ||
(libraries | ||
base | ||
dream | ||
dream.http | ||
lwt | ||
lwt.unix | ||
ppx_expect.common | ||
ppx_inline_test.config | ||
ppx_expect.config_types)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
leaving these dune files here for the future instead of having to set them up again.
|
||
let built_in_middleware error_handler = | ||
Message.pipeline [ | ||
Catch.catch (Error_handler.app error_handler); | ||
check_headers_middleware; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be the outer middleware, as the error handler can also be a source of empty headers, while, conversely, check_headers_middleware
cannot raise any exceptions.
Not sure what you mean here -- built-in middlewares are/were opt-out, they are included in the middleware stack by default. |
Oops! Yes you're right. It's already defaulted to true. I forgot to check the actual default value 😅 . I only ever read the lines below, and not specifically the args set on
|
I've made a few edits. Notably: diff --git a/src/http/http.ml b/src/http/http.ml
index 11943be..d1b7614 100644
--- a/src/http/http.ml
+++ b/src/http/http.ml
@@ -390,7 +390,7 @@ let check_headers_middleware next_handler request =
in
if invalid_headers_exist then
log.warning (fun log ->
- log "A response header is empty or contains only whitespace");
+ log ~request "A response header is empty or contains only whitespace");
Lwt.return response
let built_in_middleware error_handler = changes the log output from
to
I then tested example diff --git a/example/9-error/error.eml.ml b/example/9-error/error.eml.ml
index 515091c..8a995d7 100644
--- a/example/9-error/error.eml.ml
+++ b/example/9-error/error.eml.ml
@@ -12,6 +12,7 @@ let my_error_template _error debug_info suggested_response =
</body>
</html>
end;
+ Dream.set_header suggested_response "" "abc";
Lwt.return suggested_response
let () = The PR didn't warn about this header, as expected, so I added diff --git a/src/http/http.ml b/src/http/http.ml
index d1b7614..2deb1db 100644
--- a/src/http/http.ml
+++ b/src/http/http.ml
@@ -395,8 +395,8 @@ let check_headers_middleware next_handler request =
let built_in_middleware error_handler =
Message.pipeline [
- Catch.catch (Error_handler.app error_handler);
check_headers_middleware;
+ Catch.catch (Error_handler.app error_handler);
]
It now warns about empty headers set in error handlers:
|
Thank you! As for built-in middleware, it's probably fine to leave the implementation in |
Resolves #233. I was unable to replicate the socket hanging issue on alpine because I couldn't build it due to ssl dep issues. However, I ran the debian build on fly.io, and fly rejects http messages with invalid headers. So we should fix this regardless of linux distro. We can fix the alpine ssl issue separately.