.. _library_http_process_transport:

``http_process_transport``
==========================

The ``http_process_transport`` library provides an alternative
implementation of the ``http_transport_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`` (version 3.0.0 or later), ``ncat`` (version 7.96 or
later), and ``socat`` (version 1.7.3.0 or later) commands must be
available on the system ``PATH``.

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

::

   $ brew install openssl nmap socat

Or using MacPorts:

::

   $ sudo port install openssl nmap socat

On Ubuntu, both commands can be installed using:

::

   $ sudo apt install openssl ncat socat

On RedHat distributions (8.x and later):

::

   $ sudo dnf install openssl nmap-ncat socat

For older RedHat distributions:

::

   $ sudo yum install openssl nmap-ncat socat

On Windows, ``openssl`` and ``ncat`` commands can be installed using
e.g. Chocolatey:

::

   > choco install openssl
   > choco install nmap

The ``socat`` command doesn't have an easy install solution on Windows;
use ``ncat`` instead.

API documentation
-----------------

Open the
`../../apis/library_index.html#http-process-transport <../../apis/library_index.html#http-process-transport>`__
link in a web browser.

Loading
-------

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

::

   | ?- logtalk_load(http_process_transport(loader)).

Testing
-------

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

::

   | ?- logtalk_load(http_process_transport(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_sequence/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_transport`` 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`` or ``socat`` on the ``PATH``
  (see the ``listener_helper_executable/1`` option; the default value
  depends on the operating-system)

- 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)`` (default)
- ``type(text)``
- ``connection_transport(tcp)`` (default)
- ``connection_transport(tls)``
- ``connection_helper_executable(ncat)`` (default on Windows)
- ``connection_helper_executable(socat)`` (default on POSIX systems)
- ``openssl_executable(Executable)`` (default ``openssl``)
- ``server_name(Name)`` (default ``default``)
- ``openssl_arguments(Arguments)`` (default ``[]``)

Notes on those options:

- ``type(binary)`` and ``type(text)`` match the shared
  ``http_socket_transport`` client-side option surface; the selected
  value is applied to the client connection streams after the helper
  process is started
- ``connection_transport(tcp)`` is the default and uses ``ncat`` as the
  helper process
- ``connection_transport(tls)`` uses ``openssl s_client`` for the client
  connection helper process
- the default ``server_name(default)`` value maps to the requested host
  except for colon-containing hosts, where the SNI option is omitted by
  default when ``connection_transport(tls)`` is selected
- ``openssl_arguments/1`` can be used to pass verification, CA, ALPN, or
  client certificate flags directly to ``openssl s_client`` when
  ``connection_transport(tls)`` is selected

Connection-pool options accepted by ``open_connection_pool/4``:

- ``min_size(N)`` (default ``0``)
- ``max_size(N)`` (default ``10``)
- ``connection_options(Options)`` (default ``[]``)

Listener options accepted by ``open_listener/4``:

- ``backlog(N)`` (default ``5``)
- ``type(binary)`` (default)
- ``type(text)``
- ``listener_transport(tcp)`` (default)
- ``listener_transport(tls)``
- ``listener_helper_executable(ncat)`` (default on Windows)
- ``listener_helper_executable(socat)`` (default on POSIX systems)
- ``temporary_tls_credentials(Prefix)``
- ``tls_certificate_file(File)``
- ``tls_key_file(File)``

Notes on those listener options:

- ``type/1`` is accepted for drop-in compatibility with
  ``http_socket_transport`` 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
- ``temporary_tls_credentials(Prefix)`` generates a temporary
  self-signed certificate and key owned by the listener when
  ``listener_transport(tls)`` is selected; both files are deleted by
  ``close_listener/1`` and by the ``serve_until_shutdown/4-5``
  finalization path
- ``tls_certificate_file/1`` and ``tls_key_file/1`` are required
  together when ``listener_transport(tls)`` is selected unless
  ``temporary_tls_credentials/1`` is used instead
- ``temporary_tls_credentials/1`` is mutually exclusive with
  ``tls_certificate_file/1`` and ``tls_key_file/1``

Helper predicate:

- ``temporary_tls_credentials_files(Prefix, CertificateFile, KeyFile)``
  computes the temporary certificate and key file paths for a given
  prefix without creating those files; this is useful for client-side
  trust configuration when the listener itself owns certificate creation
  via ``temporary_tls_credentials(Prefix)``

Serving options accepted by ``serve_listener/5``:

- ``shutdown(keep_open)`` (default)
- ``shutdown(close)``
- ``workers(serial)`` (default)
- ``workers(per_connection)``
- ``workers(pool(Size))``
- ``workers(pool(Size, rolling))``

Serving options accepted by ``serve_until_shutdown/4``:

- ``workers(serial)`` (default)
- ``workers(per_connection)``
- ``workers(pool(Size))``
- ``workers(pool(Size, rolling))``

Example:

::

   :- initialization((
       logtalk_load(http_process_transport(loader)),
       http_core::request(get, origin('/'), http(1,1), [host-host('example.com')], empty, [], Request),
       http_process_transport::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_transport`` 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_core`` 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.

Peer close and end-of-file
--------------------------

The process-backed transport exposes streams owned by external helper
processes. A peer close is therefore observed by Logtalk through the
helper process and its pipes, and applications should not assume that it
is reported as an immediate ``end_of_file`` on every backend Prolog
compiler and operating system combination.

This is not required for normal HTTP request-response exchanges, nor for
normal WebSocket sessions, which end through WebSocket close frames. The
SSE library can also exchange complete events and close handles
explicitly without depending on raw peer-close detection. Code that
deliberately uses peer close itself as a control signal, however,
depends on the selected backend and helper process reporting stream
exhaustion promptly; that behavior should be tested on the target
deployment platform.

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_process_transport(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_process_transport`` 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

Known issues
------------

The ``ncat`` version provided by ``nmap`` 7.991 causes the HTTP
libraries tests to crash on exit (usually printing a "Terminated: 15"
message). Either use the previous version (7.99) or ``socat``.
