-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Split StaticFileHandler#call into structured components
#15678
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
Merged
straight-shoota
merged 15 commits into
crystal-lang:master
from
straight-shoota:refactor/static_file_handler
May 10, 2025
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
d57486d
`check_request_method!`
straight-shoota 6e48c44
`check_request_path!`
straight-shoota d01074f
`check_redirect_to_expanded_path!`
straight-shoota 8a53129
simplify `call` logic
straight-shoota 08744b3
`directory_index`
straight-shoota f829ae3
`serve_file_with_cache`
straight-shoota d7d6fc9
`file_info`
straight-shoota 4ad1332
Add type restrictions
straight-shoota 974c7c6
`request_path`
straight-shoota afe80ec
Refactor `check_redirect_to_expanded_path!` into `#normalize_request_…
straight-shoota ffafbcc
Move `Accept-Ranges` header to `serve_file`
straight-shoota c26e758
Extract `serve_file_compressed`
straight-shoota 3bb6b58
Move `Content-Type` header to `serve_file`
straight-shoota 1726987
fixup! Move `Content-Type` header to `serve_file`
straight-shoota ae5ce88
fixup
straight-shoota File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
suggestion: I'd expect a bang method to raise an exception, not return a boolean. Maybe a name such as
#allowed_request_path?would be more explicit to the intent? Then we'd have nice guards: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 don't like that because these methods are not just predicates. They directly affect the behaviour (e.g. the HTTP response) in case of an error.
The purpose of the exclamation mark is to indicate that the method handles errors itself and just returns a boolean that indicates whether the caller should continue or stop execution.
Uh oh!
There was an error while loading. Please reload this page.
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'm not fond of the extracted methods still having some implicit expectations and intermixed behavior: validation + action + implicit out-of-scope control-flow. Maybe split again? Granted, it would be much more verbose but the helpers would do one thing.
Note: it could be interesting to wrap it the context + methods into amaybe not, a struct would mean it's hard to customize, and a class would mean an allocation (but maybe not a bad idea).struct, and then we could have a nice public API!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.
The combination of validation + action forms a self-contained component. The only tricky thing about it is handling control flow in the caller scope.
If we want more granular components, we can split the bodies of the
check_methods into separate helpers, of course. But I don't see much benefit from that.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.
Would it be better if we pronounce the action more in the method name?
check_request_method! || return->respond_on_invalid_request_method && returncheck_request_path! || return->respond_on_invalid_request_path && returncheck_redirect_to_expanded_path! || return->redirect_to_expanded_path && returnUh oh!
There was an error while loading. Please reload this page.
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.
Maybe? I still prefer braindead flow-control, and do one thing helpers, but it's prolly just my taste.
Uh oh!
There was an error while loading. Please reload this page.
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.
Just to be clear, you mean something like this:
Especially the latter one would be a bit unfortunate because the redirect needs to check the same conditions again as the validation.
But that's similar for the other as well. The action and condition are strongly connected together. For example, both must consider the same request methods as allowed. If separate methods can be overridden individually, they can get out of sync.
Uh oh!
There was an error while loading. Please reload this page.
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 suppose the path redirect could easily be refactored to this:
EDIT: Amended in afe80ec
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.
You may just want to configure the accepted HTTP methods or paths, or overload the checks and call
previous_def, but you may also just want to render a custom response, independently from the checks.