Most code doesn't need to use this directly; instead use
library(http/http_server)
, which combines this library with
the typical HTTP libraries that most servers need.
This module can be placed between http_wrapper.pl
and
the application code to associate HTTP locations to predicates
that serve the pages. In addition, it associates parameters with
locations that deal with timeout handling and user authentication. The
typical setup is:
server(Port, Options) :- http_server(http_dispatch, [ port(Port) | Options ]). :- http_handler('/index.html', write_index, []). write_index(Request) :- ...
'/home.html'
or a term
Alias(Relative). Where Alias is associated with a concrete path using http:location/3
and resolved using http_absolute_location/3. Relative
can be a single atom or a term‘Segment1/Segment2/...`, where each
element is either an atom or a variable. If a segment is a variable it
matches any segment and the binding may be passed to the closure. If the
last segment is a variable it may match multiple segments. This allows
registering REST paths, for example:
:- http_handler(root(user/User), user(Method, User), [ method(Method), methods([get,post,put]) ]). user(get, User, Request) :- ... user(post, User, Request) :- ...
If an HTTP request arrives at the server that matches Path, Closure is called as below, where Request is the parsed HTTP request.
call(Closure, Request)
Options is a list containing the following options:
http_authenticate.pl
provides a plugin for user/password based Basic
HTTP
authentication.Transfer-encoding: chunked
if the client allows for it.true
on a prefix-handler (see prefix), possible children
are masked. This can be used to (temporary) overrule part of the tree.methods([Method])
. Using method(*)
allows for
all methods.:- http_handler(/, http_404([index('index.html')]), [spawn(my_pool),prefix]).
infinite
, default
or a positive number
(seconds). If
default
, the value from the setting http:time_limit
is taken. The default of this setting is 300 (5 minutes). See
setting/2.Note that http_handler/3 is normally invoked as a directive and processed using term-expansion. Using term-expansion ensures proper update through make/0 when the specification is modified.
existence_error(http_location, Location)
permission_error(http_method, Method, Location)
path
member of Request.
If multiple handlers match due to the prefix
option or
variables in path segments (see http_handler/3),
the longest specification is used. If multiple specifications of equal
length match the one with the highest priority is used.method
member of the
Request or throw permission_error(http_method, Method, Location)
http_reply(Term, ExtraHeader, Context)
exceptions.method(Method)
as one of the options.call(Goal, Request0, Request, Options)
If multiple goals are registered they expand the request in a pipeline starting with the expansion hook with the lowest rank.
Besides rewriting the request, for example by validating the user identity based on HTTP authentication or cookies and adding this to the request, the hook may raise HTTP exceptions to indicate a bad request, permission error, etc. See http_status_reply/4.
Initially, auth_expansion/3 is
registered with rank 100
to deal with the older http:authenticate/3
hook.
id(ID)
appears in the option list of the handler, ID
it is used and takes preference over using the predicate.Module:Pred
If the handler is declared with a pattern, e.g., root(user/User)
,
the location to access a particular user may be accessed using
e.g., user('Bob')
. The number of arguments to the compound
term must match the number of variables in the path pattern.
A plain atom ID can be used to find a handler with a
pattern. The returned location is the path up to the first variable,
e.g.,
/user/
in the example above.
User code is adviced to use http_link_to_id/3 which can also add query parameters to the URL. This predicate is a helper for http_link_to_id/3.
existence_error(http_handler_id, Id)
.library(http/html_write)
construct
location_by_id(ID)
or its abbreviation #(ID)
root(user_details)
)
is irrelevant in this equation and HTTP locations can thus be moved
freely without breaking this code fragment.
:- http_handler(root(user_details), user_details, []). user_details(Request) :- http_parameters(Request, [ user_id(ID) ]), ... user_link(ID) --> { user_name(ID, Name), http_link_to_id(user_details, [id(ID)], HREF) }, html(a([class(user), href(HREF)], Name)).
HandleID | is either an atom, possibly module qualified predicate or a compound term if the hander is defined using a pattern. See http_handler/3 and http_location_by_id/2. |
Parameters | is one of
|
true
(default), handle If-modified-since and send
modification time.true
(default false
) and, in addition to
the plain file, there is a .gz
file that is not older than
the plain file and the client acceps gzip
encoding, send
the compressed file with Transfer-encoding: gzip
.true
(default false
) the system maintains
cached gzipped files in a directory accessible using the file search
path http_gzip_cache
and serves these similar to the static_gzip(true)
option. If the gzip file does not exist or is older than the input the
file is recreated.false
(default), validate that FileSpec does
not contain references to parent directories. E.g., specifications such
as www('../../etc/passwd')
are not allowed.
If caching is not disabled, it processes the request headers
If-modified-since
and Range
.
http_reply(not_modified)
http_reply(file(MimeType, Path))
alias(Sub)
, than Sub cannot have
references to parent directories.
permission_error(read, file, FileSpec)
:- http_handler(root(.), http_redirect(moved, myapp('index.html')), []).
How | is one of moved , moved_temporary
or see_other |
To | is an atom, a aliased path as defined by
http_absolute_location/3.
or a term location_by_id(Id) or its abbreviations #(Id)
or #(Id)+Parameters . If To is not absolute, it
is resolved relative to the current location. |
http_reply(not_found(Path))
"HTTP 101 Switching Protocols"
reply. After sending
the reply, the HTTP library calls call(Goal, InStream, OutStream)
,
where InStream and OutStream are the raw streams to the HTTP client.
This allows the communication to continue using an an alternative
protocol.
If Goal fails or throws an exception, the streams are
closed by the server. Otherwise Goal is responsible for
closing the streams. Note that Goal runs in the HTTP handler
thread. Typically, the handler should be registered using the spawn
option if http_handler/3 or Goal
must call thread_create/3 to allow the
HTTP worker to return to the worker pool.
The streams use binary (octet) encoding and have their I/O timeout set to the server timeout (default 60 seconds). The predicate set_stream/2 can be used to change the encoding, change or cancel the timeout.
This predicate interacts with the server library by throwing an exception.
The following options are supported:
headers(+Headers)
.