Skip to content
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

Add option to HTTP::StaticFileHandler initializer to disable directory listing #4403

Conversation

joaodiogocosta
Copy link
Contributor

@joaodiogocosta joaodiogocosta commented May 11, 2017

This PR follows the discussion on #4398.

Reason:

At this time, using HTTP::StaticFileHandler one can configure which directory to serve static files from by passing its path to the constructor:

HTTP::StaticFileHandler.new("public/")

This will serve files from public/ in the root path / and currently there is no way to change it. Additionally, it will display by default a directory list if a path to a directory is given.

In some cases, such as web frameworks, it's preferable not to let the user list files under a public directory for reasons like security.

In this sense, this PR adds an option to HTTP::StaticFileHandler that enables the user to turn off directory listing, preserving the default behaviour.

Code Changes:

  • Removed duplicate Dir.exists? call, resulting in one less system call.
  • Added an optional argument to HTTP::StaticFileHandler. The name of the argument is directory_listing and defaults to true, as it was before.
  • Added a test case to ensure this option prevents directory listing.

The default behaviour remains the same.

@joaodiogocosta joaodiogocosta force-pushed the static-file-handler-optional-directory-listing branch from 9c03dd7 to 70cdd3f Compare May 11, 2017 22:45
@@ -14,9 +14,10 @@ class HTTP::StaticFileHandler
# If *fallthrough* is `false`, this handler does not call next handler when
# request method is neither GET or HEAD, then serves `405 Method Not Allowed`.
# Otherwise, it calls next handler.
def initialize(public_dir : String, fallthrough = true)
def initialize(public_dir : String, fallthrough = true, list_dirs = true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A mention of list_dirs in the docs above would be necessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, forgot that. Done.

@joaodiogocosta joaodiogocosta force-pushed the static-file-handler-optional-directory-listing branch from 70cdd3f to ac3e536 Compare May 12, 2017 07:53
@straight-shoota
Copy link
Member

As this feature is commonly referred to as directory listing, I would suggest to name the flag argument directory_listing for convenience.

@ysbaddaden
Copy link
Contributor

I wonder if there shouldn't be two handlers: one for listing and navigating directory indexes, and another for serving static files.

@joaodiogocosta
Copy link
Contributor Author

@straight-shoota that was my first thought. I ended up renaming it to list_dirs because it implies an action, and it's shorter. directory_listing is more like disabling a feature, which does makes sense as well. I'm not keen on any of them and would happily change it, so perhaps we should wait for someone else to comment on this?

@joaodiogocosta
Copy link
Contributor Author

@ysbaddaden the first time I saw mentioned the static file handler, I imagined it just as it is, an handler that serves static files and directories. What I mean is that, for me, it's implicit that an handler that handles static files, also handles directories. This is good user experience.

If the handlers are to be split, I foresee a lot of the same logic in both places (knowing that one can extract the shared bit, of course). Another downside is perhaps the fact that it would be a breaking change of the current API.

@@ -49,16 +53,17 @@ class HTTP::StaticFileHandler

file_path = File.join(@public_dir, expanded_path)
is_dir = Dir.exists? file_path
is_file = File.exists?(file_path) && !is_dir
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor improvement: changing the order means one less system call for dirs: !is_dir && File.exists?(file_path)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@straight-shoota nice catch!

@straight-shoota
Copy link
Member

I don't think splitting this into two handlers would be a good idea. As @joaodiogocosta mentioned, most of the logic is the same. There are only a few specific parts for the directory listing apart from the ECR template.
If someone wants to implement their own listing class, they can just disable the directory listing and add their own handler.

@joaodiogocosta joaodiogocosta force-pushed the static-file-handler-optional-directory-listing branch from ac3e536 to 8c1dca7 Compare May 12, 2017 15:42
@ysbaddaden
Copy link
Contributor

Well, serving assets is checking whether the file exists and serve it. Indexing directories is checking whether a directory exists and list its contents. I don't see much overlap, except for expanding request.path from the public path.

@bcardiff
Copy link
Member

I thought of proposing to split them, but it's hard to imagine that someone will want directory listing without static file. Splitting them will mean to configure two handlers in the same way. Although currently is just the directory to serve, if we add in the future the path to where be mounted it will be more setting to duplicate if the handlers are split.

I like the directory_listing suggestion of @straight-shoota .

@joaodiogocosta joaodiogocosta force-pushed the static-file-handler-optional-directory-listing branch from 8c1dca7 to 5768fc6 Compare May 12, 2017 18:12
@joaodiogocosta
Copy link
Contributor Author

@bcardiff agree. As a user, like me, it just seems strange to have to set up separate handlers for this.

directory_listing it is!

@mverzilli
Copy link

LGTM too. @bcardiff, anything else left before merging?

@sdogruyol
Copy link
Member

Great 👍

@bcardiff bcardiff added this to the Next milestone May 15, 2017
@bcardiff bcardiff merged commit 6930423 into crystal-lang:master May 15, 2017
@bcardiff
Copy link
Member

Thanks @joaodiogocosta ! Happy first contribution :-)

@joaodiogocosta
Copy link
Contributor Author

joaodiogocosta commented May 15, 2017

Yey! Looking forward to use this in Soil 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants