Did you know ... | Search Documentation: |
Serving plain files from the SWI-Prolog HTTPD |
Although the SWI-Prolog web-server is intended to serve documents that need to be computed dynamically, serving plain files is sometimes necessary. There are several options to serve files.
Before we can serve files, we first need to be able to find them on the file-system. This is a general topic, but we discuss it here because it is especially relevant to serving files. There are three options:
All code snippets below assume a running server and the library(http/http_dispatch) loaded. This means that running these examples require a file with this content to be loaded (8080 is the port; change as you please).
:- use_module(library(http/thread_httpd)). :- use_module(library(http/http_dispatch)). :- initialization http_server(http_dispatch, [port(8080)]).
All snippets are supposed to be loaded from a source-file, as opposed to be typed in the console.
Sometimes you have a fully dynamic server that needs to serve, for
example, a few images or CSS files. You can solve this directly using
http_reply_file/3. The example below serves /favicon.ico
from the
local file favicon.ico
.
:- http_handler('/favicon.ico', http_reply_file('favicon.ico', []), []).
The predicate http_reply_file/3 (by default) deals with caching
(If-modified-since
) and deals with different content-type
(mime-type) using the predicate file_mime_type/2.
Bigger servers often have lots of static files that contain images, CSS, JavaScript, etc. A good way to facilitate this is using serve_files_in_directory/2 from library(http/http_server_files). This predicate assumes aliases for searching files (see above) and for specifying HTTP locations as defined by library(http/http_path).
In the next example, we create a serve that serves images on
/images/...
from a directory /srv/htdocs/icons/...
. Note that
this server has no means for browsing by the user. It answers the file
or 404, which is typically precisely what we want for server resource
files.
First, we specify a path alias for the location handled by the server.
:- use_module(library(http/http_path)). http:location(images, root(images), []).
Next, we specify a file alias for the location on the file-system. We
do this in two steps: (1) we define an alias for our entire document-set
and (2) then we define the target icons
alias relative to this
central alias. This two-step approach allows for updating the server to
a modified environment easily. Note that the document_root
alias can
be in a different Prolog file (e.g., a global configuration file).
:- multifile user:file_search_path/2. user:file_search_path(document_root, '/srv/htdocs'). user:file_search_path(icons, document_root(icons)).
Finally, serve_files_in_directory combines the two aliases. It is common to use the same alias name for both the HTTP path and file. We used two different ones in this example to clarify their roles.
:- http_handler(images(.), serve_files_in_directory(icons), [prefix]).
If you want to give the user access to a set of files, the above is unsuitable because it does not support directory browsing. SWI-Prolog 5.11.29 and 5.10.6 provide library(http/http_files) to solve this problem. The predicate http_reply_from_files/3 combines http_reply_file/3 with http_reply_dirindex/3. Here is the complete code to serve files to a server running at port 8080 from the local directory. Note that the server disallows access to ../, etc., to protect sensitive files on the system.
:- use_module(library(http/thread_httpd)). :- use_module(library(http/http_dispatch)). :- use_module(library(http/http_files)). :- http_handler(root(.), http_reply_from_files('.', []), [prefix]). :- initialization http_server(http_dispatch, [port(8080)]).