
thread_httpd.pl -- Threaded HTTP serverMost 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 library defines the HTTP server frontend of choice for SWI-Prolog. It is based on the multi-threading capabilities of SWI-Prolog and thus exploits multiple cores to serve requests concurrently. The server scales well and can cooperate with library(thread_pool) to control the number of concurrent requests of a given type. For example, it can be configured to handle 200 file download requests concurrently, 2 requests that potentially uses a lot of memory and 8 requests that use a lot of CPU resources.
On Unix systems, this library can be combined with library(http/http_unix_daemon) to realise a proper Unix service process that creates a web server at port 80, runs under a specific account, optionally detaches from the controlling terminal, etc.
Combined with library(http/http_ssl_plugin) from the SSL package, this library can be used to create an HTTPS server. See <plbase>/doc/packages/examples/ssl/https for an example server using a self-signed SSL certificate.
http_server(:Goal, :Options) is detAF_UNIX). See socket_create/2.main thread.
If you need to control resource usage you may consider the
spawn option of http_handler/3 and library(thread_pool).true (default false), do not print an informational
message that the server was started.A typical initialization for an HTTP server that uses http_dispatch/1 to relay requests to predicates is:
:- use_module(library(http/thread_httpd)).
:- use_module(library(http/http_dispatch)).
start_server(Port) :-
http_server(http_dispatch, [port(Port)]).
Note that multiple servers can coexist in the same Prolog process. A notable application of this is to have both an HTTP and HTTPS server, where the HTTP server redirects to the HTTPS server for handling sensitive requests.
make_socket(+Address, :OptionsIn, -OptionsOut) is det[private]queue(QueueId).
make_addr_atom(+Scheme, +Address, -Atom) is det[private]
create_server(:Goal, +Address, +Options) is det[private]
http_current_server(:Goal, ?Port) is nondet
http_server_property(?Port, ?Property) is nondethttp or https.
http_workers(?Port, -Workers) is nondet
http_add_worker(+Port, +Options) is det
http_current_worker(?Port, ?ThreadID) is nondet
accept_server(:Goal, +Initiator, +Options)[private]
close_server_socket(+Options)[private]
close_pending_accepts(+Queue)[private]
http_stop_server(+Port, +Options)
http_enough_workers(+Queue, +Why, +Peer) is det
http:schedule_workers(+Data:dict) is semidet[multifile]accept for a new connection or keep_alive if a
worker tries to reschedule itself.
Note that, when called with reason:accept, we are called in
the time critical main accept loop. An implementation of this
hook shall typically send the event to thread dedicated to
dynamic worker-pool management.
create_workers(+Options)[private]
resize_pool(+Queue, +Workers) is det[private]
http_worker(+Options)[private]
If the message quit(Sender) is read from the queue, the worker
stops.
open_client(+Message, +Queue, -Goal, -In, -Out, +Options, -ClientOptions) is semidet[private]
open_client(+Message, +Goal, -In, -Out, -ClientOptions, +Options) is det[private]
check_keep_alive_connection(+In, +TimeOut, +Peer, +In, +Out) is semidet[private]
done_worker[private]
recreate_worker(+Status, +Queue) is semidet[private]
The first clause deals with the possibility that we cannot write to
user_error. This is possible when Prolog is started as a service
using some service managers. Would be nice if we could write an
error, but where?
thread_httpd:message_level(+Exception, -Level)[multifile]
read_remaining_request(+StartBody, +Request) is semidet[private]
http_requeue(+Header)
http_close_connection(+Request)
close_connection(+Peer, +In, +Out)[private]
http_spawn(:Goal, +Options) is detIf a pool does not exist, this predicate calls the multifile hook create_pool/1 to create it. If this predicate succeeds the operation is retried.
create_pool(+Pool)[private]
thread_repeat_wait(:Goal) is multi[private]repeat, thread_idle(Goal), choosing whether to use a
long or short idle time based on the average firing rate.
new_rate_mma(+N, +Resolution, -State) is det[private]
update_rate_mma(!State, -MMA) is det[private]