Possible bug in http_reply_file: Permission denied on absolute paths

I’m using: SWI-Prolog version 8.1.24

I want the code to serve a HTML file with an absolute path. But every time it gives me a permission denied error. However, when I try relative paths, things work out fine.

To reproduce:

  1. https://github.com/rrooij/swi_prolog_http_file_bug clone this repo
  2. start swipl server.pl, note that the file blabla.html is loading fine
  3. Quit the server
  4. Change blabla.html in server.pl to /home/your_user/your_path/to/the/blabla.html
  5. Notice that you now get a permission denied error, whereas the relative path worked fine

This is by design. You can overrule this using the unsafe(true) option. Applications serving files from the applications typically use a file search path alias, e.g. web('page.html') or a relative path. The unsafe is mostly to avoid that servers will server e.g… /etc/passwd on a user request where the user specifies /etc/passwd or ../../../../../../../etc/passwd. I.e., a path is considered safe if it is not absolute and thus not contain ../, so it can only access files from a subtree that is setup by the server (its working directory or some file search path).

1 Like

I agree somewhat, but shouldn’t the server recognize that the absolute path in this case is from a directory that is allowed to be served?

That would be an alternative approach. As is, there is no notion of directories that are allowed. Implicitly that is the working directory if you pass paths to http_reply_file/3 without a search alias and any alias you use to wrap the file for http_reply_file/3. The latter option is by far the preferred way to deal with this.

If this doesn’t suit your needs, please describe these needs so we can seek a clean solution. The overall aim for deciding on the APIs is that anything a reasonable number of users need to do and that can be supported elegantly should be supported elegantly. Of course this isn’t set in stone and there are conflicts of interest, lack of resources, etc.

2 Likes

I can live with this! Now that I understand that it was a conscious decision.

The use case was that I have a server that I want to serve a specific file, but be able to run the server from different directories, for instance, the parent folder of the HTML. Using unsafe is probably fine for my use case as well, and I can always just cd in the right directory before starting the server.

1 Like

The typical solution is to define a path alias using file_search_path/2 for the root of the application and subsequently one based on that for e.g., the web related resources. E.g., in the main file you can do

xyz_version('1.0').

:- multifile user:file_search_path/2.

user:file_search_path(xyz, XYZDir) :-
   source_file(xyz_version(_), File),
   file_directory_name(File, XYZDir).
user:file_search_path(web, xyz(web)).
...

You can also (first) add a relative directory alias, so users can overrule the system files by installing the files locally. Having multiple directories using the same alias composes a new virtual directory as an overlay of multiple directories.