tsujigiri/axiom

No way to expose static resources directly under ./public

piotr-sobczyk opened this issue · 15 comments

Both documentation and code prove that only files in subdirectories of ./public directory can be accessed as a static resources. I really need to be able to expose files directly under ./public directory (or at least access file in subdirectory of public but using url like host:port/static_filename).

Is it on purpose/by design that files under ./public cannot be accessed or is it a bug?

This is bothering me as well. This is a limitation that comes/came from Cowboy. I will investigate if this is still the case with Cowboy 0.8.0.

So, it is possible to route the contents of a directory to be accessible directly under / by the client. The problem is, that this is handled by cowboy_static, which can't be told to upgrade to another handler, when no file is found. If I am not mistaken, it is also not possible to directly put the actual file in the router's match specification. This was the problem in the first place, which lead to the current implementation. This leaves us with the following options:

  • Leave it as is
  • Remove it completely and let a real web server deliver the static content, which should be done in production use anyway, but is inconvenient in development
  • Implement the static file handling ourselves or somehow find a way to trick cowboy_static into doing it anyway
  • Patch the cowboy_router to make it match files

At the moment the last option seems to be the least hacky.

Yeah, I was investigating this too and I see the problem.

  • I don't really like option 2 - why to resign from a feature that is already there in cowboy and we have it for free? And as you mentioned it is very convenient for development of for making demo aplications (as in my case) that aren't intended to run on production.
  • I was thinking about something similar to your point 3. Couldn't we in handle(Req, State) detect if file has extension (like index.html) and if no, we do the normal stuff, if yes, we somehow delegate the job to cowboy_static by invoking it manually? I didn't have enough time to examine in more detail how cowboy code works so it may be not possible.

There is actually one more solution that actually works (and I tested it). If you would take a look at "File configuration" in documentation of cowboy_static you can see that there is additional file configuration option (like {file, <<"page.html">>}). What I managed to do is to add mapping from route "page.html" to actual html file passed in file option. Then if I typed in url bar http://localhost:8080/page.html, the static page was displayed and if I put there anything else than "file.html", the normal dynamic handling was used.

The problem with this approach is that we would need to know all static files under /public when start(Handler, Options) is invoked to map them to correct routes. We could scan /public directory to know these files and automatically register them. But users will expect that they will be able to drop static files anytime they want to /public dir and refresh page in browser to see them. And that is not correct, because those files would be added only once (during start). So maybe additional configuration setting like staticfiles would be better with the list of all static files directly under /public that are to be served?

I probably didn't put it clearly enough, so may I provide a small patch to demonstrate you what I mean?

I think I understand perfectly. I've seen the file option, but I was under the impression, that it still wasn't possible to directly map to the files. It appears that you proved me wrong. :) This is similar to what we do currently, just that we only take the directories into account. Having to restart the server once files are being changed might be the least inconvenient way. It should even be possible to write a start script, that monitors the static files and restarts the server automatically. What do you think?

Yeah, you're right, we do it very similarly with directories (we scan all directories in public folder) so scanning files wouldn't be any worse that scanning directories currently is (there is currently a need to restart server when new directory is dropped).

Given that we don't currently don't support dropping-in directories we don't necessarily need to support dropping-in files. I just didn't wanted files to behave in different way than directories. And now I see they won't :).

Wow, I didn't even proposed monitoring static files because I thought it would be very hard to implement if not impossible. And now you suggest it :). Do you have an idea how this could be done?

I thought of something like a script that uses inotify and in some way triggers the restart. But let's think about that later and in a separate ticket. :)

Exactly. As long as there is no inconsistency between how directory mapping and file mapping works (both don't support dropping in), we don't need to care about this issue right now.

So the idea is basicaly to leave old directory mapping code as it is and add code that scans all the files directly under /public directory and add corresponding matching rules for them to Cowboy configuration, right?

That's correct.

Uploaded pull request. Sorry, wanted to join it to this thread instead of creating new issue but didn't know how to do it :(.

I don't know if it is possible to directly associate a pull request with an existing issue. Would be neat. You can still link it like this: #13

I thought that it would be be nice (although it would be definitely a new ticket) to allow any level of nesting of directories in ./public. Currently we only map directories directly under ./public to the request path, but why not map them recursive (at least to some reasonable maximal level)? What do you think about it?

Allow all the levels! :) See my comment at #13. filelib:fold_files/5 can be given a flag to list files recursively.

Ok, so you suggest to no longer do directory mapping at all and instead map all files in all subdirectories recursively with cowboy file option using fold_files/5?

Yes.

Solved in #13.