Proloxy uses an extensible Prolog predicate to relay
requests to different web services: For each arriving
HTTP request, Proloxy calls the predicate
request_prefix_target(+Request, -Prefix, -Target). Its
Prefix is prepended to relative paths in
HTTP redirects that the target service emits, so
that the next client request is again relayed to the intended
Target is the URI of the target service.
You configure Proloxy by providing a Prolog file that
contains the definition of request_prefix_target/3 and
any additional predicates and directives you need. For each web
service you want to make available, add a clause of
request_prefix_target/3 to relate an instantiated
HTTP request to a prefix and the desired target.
Each clause may use arbitrary Prolog code to analyse the request
and form the target.
When dispatching an HTTP request, Proloxy considers the clauses of
request_prefix_target/3 in the order they appear in your
configuration file and commits to the first clause that
succeeds. It relays the request to the computed target, and
then sends the target's response to the client.
For example, the following clause relays all requests to a
local web server on port 3031, passing along the original request
path. The target server can for example host the site's main page,
to be used if no other rules apply:
config.pl shows a sample
configuration file that uses Prolog rules to dispatch requests
to two different web services.
The rule language is general enough to
express virtual hosts. In the case
of name-based virtual hosts, this means that you dispatch
requests to different web services based on
the domain name that is used to access your site.
For example, to dispatch all requests of users who access your
server via your-domain.com to a web server running on
port 4040 (while leaving the path unchanged), use:
In some cases, it is convenient to respond directly with plain
text or HTML content instead of relaying the request
to a different web service. If a clause of
request_prefix_target/3 emits any text on standout output,
then this output is sent to the client as the
HTTP response. Such responses typically start with
Content-type: text/plain (or text/html),
followed by two newlines and the body of the reply. In
rules that emit output, Target must be the
atom - to avoid relaying the request to a
Proloxy provides the predicate output_from_process(+Program,
+Args) to emit process output (from stdout
and stderr) on standard output. For example, we
can configure Proloxy to show the system's uptime when the
URL /uptime is accessed:
Auxiliary programs and scripts can be conveniently invoked with
Relaying header fields
The extensible predicate transmit_header_field/1 allows you to
relay header fields that the target service emits to the client.
The argument is the name of the header field you want to
transmit if it exists in the target's response. For example, you
can put the following in config.pl:
The name of the header field is matched case-insensitively and
underscore (_) matches hyphen (-).
By default, Proloxy does not relay any response
This enables HTTP Strict Transport Security (HSTS), which is useful
when running HTTPS servers.
Testing the configuration
Since each configuration file is also a valid Prolog program, you can
easily test your configuration. Consulting the Prolog program in
SWI-Prolog lets you detect syntax errors and singleton variables in
your configuration file. To test whether HTTP requests are dispatched
as you intend, query request_prefix_target/3. For example:
$ swipl config.pl
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.14)
?- once(request_prefix_target([request_uri(/)], P, T)).
P = '',
T = 'http://localhost:3031/'.
?- once(request_prefix_target([request_uri('/rits/demo.html')], P, T)).
P = '/rits',
T = 'http://localhost:4040/demo.html'.
we are using once/1 to commit to the first clause that succeeds.
we are simulating an actual HTTP request, using a list of header fields.
the answers tell us how the given HTTP requests are dispatched.
The ability to conveniently test your configuration is a nice
property, and a natural consequence of using Prolog as the
configuration language. You can also write unit tests for your
configuration and therefore easily detect regressions.
You can run Proloxy as an HTTPS server and thus encrypt
traffic for all hosted services at once.
See LetSWICrypt for more
A common use case when using HTTPS is to run a second Proloxy
instance as a regular HTTP server on port 80 to
redirect each request for http://*X*
to https://*X*. You can do this with the following
configuration file for the HTTP server:
WebSocket connections are automatically detected via the
Upgrade: websocket and other header fields.
Serving very large files
In typical use cases, Proloxy relays requests to other
web servers, and sends their answers to the client. The overhead
is typically negligible, since the other web services usually reside
on the same machine.
However, if a web server sends very large files in response to some
requests, Proloxy may not have enough global stack space to
collect the response.
In such cases, one solution is to configure Proloxy so that such
large files are sent directly by Proloxy, without involving a
different web service. For example, the following snippet
configures Proloxy to directly send any files (such as
ISO images) that are located in /home/web/iso, and
are accessed via /iso/.