http_socket_process

The http_socket_process library provides an alternative implementation of the http_socket_protocol protocol. Based on the process library and external commands, it provides TLS support for HTTPS and WSS connections. The current implementation uses openssl s_client to expose a reusable client-side byte stream suitable for the existing http_client_core predicates. The current server-side implementation defaults to ncat to own the public listener socket and expose accepted connections to the parent object using a loopback relay listener plus peer metadata parsed from helper diagnostics.

This library requires backend support for the process and socket libraries. Sequential client-side transport, including reusable connections, one-shot client exchanges, and connection pools, depends on binary process pipes.

When using a backend that doesn’t support threads, this library still supports client-side reusable connections, sequential client pooling, one-shot and reusable client exchanges, and serial single-connection HTTPS and WSS serving. Worker-based serving modes and shutdown control still require backend thread support.

Requirements

The openssl and ncat commands must be available on the current PATH.

On macOS, both commands can be installed using e.g. Homebrew:

$ brew install openssl nmap

Or using MacPorts:

$ sudo port install openssl nmap

On Ubuntu, both commands can be installed using:

$ sudo apt install openssl ncat

On RedHat distributions (8.x and later):

$ sudo dnf install openssl nmap-ncat

For older RedHat distributions:

$ sudo yum install openssl nmap-ncat

On Windows, both commands can be installed using e.g. Chocolatey:

> choco install openssl
> choco install nmap

API documentation

Open the ../../apis/library_index.html#http_socket_process link in a web browser.

Loading

To load the library, load the loader.lgt file:

| ?- logtalk_load(http_socket_process(loader)).

Testing

To test this library, load the tester.lgt file:

| ?- logtalk_load(http_socket_process(tester)).

Current scope

  • reusable client connections (open_connection/4, close_connection/1)

  • reusable client connection pools (open_connection_pool/4, close_connection_pool/1)

  • reusable-connection and one-shot exchanges (exchange/3-4, exchange_connection/3-4)

  • helper-backed plain TCP listeners (open_listener/4, close_listener/1)

  • helper-backed TLS listeners (open_listener/4 with listener_transport(tls))

  • server-side serving (serve_once/3, serve_websocket_once/5, serve_listener/4-5, serve_until_shutdown/4, request_shutdown/1)

  • the same public connection and pool handle shapes used by http_socket to keep downstream endpoint validation compatible

Current limitations

  • worker-based serving modes and shutdown control require backend thread support

  • the openssl executable must be available on the PATH unless overridden with the openssl_executable/1 option

  • server-side listeners require ncat on the PATH unless overridden with the listener_helper_executable/1 option to use socat instead

  • the TLS listener implementation is limited to server-side stream exposure and handshake handling; advanced TLS options such as ALPN, client certificate verification, and protocol version tuning are not provided

Connection options accepted by open_connection/4:

  • type(binary)

  • type(text)

  • openssl_executable(Executable)

  • server_name(Name)

  • openssl_arguments(Arguments)

Notes on those options:

  • type(binary) and type(text) match the shared http_socket client-side option surface; the selected value is applied to the client connection streams after the openssl s_client process is started

  • the default server_name(default) value maps to the requested host except for colon-containing hosts, where the SNI option is omitted by default

  • openssl_arguments/1 can be used to pass verification, CA, ALPN, or client certificate flags directly to openssl s_client

Connection-pool options accepted by open_connection_pool/4:

  • min_size(N)

  • max_size(N)

  • connection_options(Options)

Listener options accepted by open_listener/4:

  • backlog(N)

  • type(binary)

  • type(text)

  • listener_transport(tcp)

  • listener_transport(tls)

  • listener_helper_executable(Executable)

  • tls_certificate_file(File)

  • tls_key_file(File)

Notes on those listener options:

  • type/1 is accepted for drop-in compatibility with http_socket but does not change the internal relay socket type used by the listener implementation

  • listener_helper_executable/1 is a compatibility option name for selecting the helper executable used for the public listener and loopback relay

  • tls_certificate_file/1 and tls_key_file/1 are required together when listener_transport(tls) is selected

Serving options accepted by serve_listener/5:

  • shutdown(keep_open)

  • shutdown(close)

  • workers(serial)

  • workers(per_connection)

  • workers(pool(Size))

  • workers(pool(Size, rolling))

Serving options accepted by serve_until_shutdown/4:

  • workers(serial)

  • workers(per_connection)

  • workers(pool(Size))

  • workers(pool(Size, rolling))

Example:

:- initialization((
    logtalk_load(http_socket_process(loader)),
    http_core::request(get, origin('/'), http(1,1), [host-host('example.com')], empty, [], Request),
    http_socket_process::exchange(
        'example.com',
        443,
        Request,
        Response
    ),
    writeq(Response), nl,
    halt
)).

The one-shot exchange predicates add Connection: close automatically when the request does not already specify connection handling, mirroring the existing http_socket behavior.

On the server side, a long-lived helper listener keeps ownership of the public listener socket and relays each accepted connection into a local loopback listener. Peer addresses are recovered from helper diagnostics, allowing the parent object to keep returning ClientInfo terms while still exposing real binary streams to http_server and the existing WebSocket layers. The same listener shape is used for both plain TCP and TLS listeners, which allows the higher-level HTTP and WebSocket layers to serve HTTPS and WSS requests without depending on backend-specific SSL predicates.

Live smoke tests

The normal tester.lgt driver only runs non-network tests. Opt-in live smoke tests are provided in tests_live.lgt and can be run using tester_live.lgt:

| ?- logtalk_load(http_socket_process(tester_live)).

The live smoke tests cover two parts:

  • external HTTPS client-side smoke tests against a configurable public endpoint

  • local loopback server-side smoke tests for plain HTTP, HTTPS, and WSS using the http_socket_process listener path

The client-side live smoke tests default to the proven endpoint:

  • host: httpbin.org

  • port: 443

  • path: /

The endpoint can be overridden using environment variables before running the driver:

  • LOGTALK_HTTP_SOCKET_PROCESS_LIVE_HOST

  • LOGTALK_HTTP_SOCKET_PROCESS_LIVE_PORT

  • LOGTALK_HTTP_SOCKET_PROCESS_LIVE_PATH

These live tests exercise the one-shot exchange path, reusable connections, sequential reuse on the same connection, and pooled reuse while keeping the normal automated test suite free of external network dependencies.

The server-side live smoke tests generate a temporary self-signed certificate, open local loopback listeners, and then verify:

  • plain serve_once/3

  • TLS serve_once/3

  • WSS serve_websocket_once/5 plus a small frame round-trip on the upgraded streams