HTTPS Client I/O v2
September 13, 2026 ยท View on GitHub
Status: bounded implementation for application outbound HTTP (#193); local focused evidence does not extend historical hosted or platform support claims. Audience: compiler contributors and host integrators implementing outbound HTTPS.
The additive compiler-owned operation is:
https_post(url: borrow Slice<u8>, body: borrow Slice<u8>, max: usize) -> own Bytes
Its persistent identity is core.host.https-post. It requires network.http
on the function and module. Arguments evaluate left to right and remain borrowed;
only a complete response becomes an owned result. Capacity and cleanup admission
use the same conservative 65,536-byte owned-result site as https_get.
The existing https-command-io.v1 profile admits the additive operation; its GET
behavior remains governed by v1.
URL input is nonempty UTF-8, at most 2048 bytes, with no NUL. POST accepts HTTPS
only and refuses userinfo and fragments. Request body is at most 65,536 bytes;
max is positive and at most 65,536, including the complete canonical response
headers and body. Empty bodies are valid. Concrete hosts send the fixed
Content-Type: application/octet-stream; source does not supply headers. Response projection reuses v1's
HTTP/1.1-shaped canonical bytes, independently of negotiated transport version.
Outbound request bytes count against the interpreter's cumulative network budget
before dispatch and are not refunded after failure.
Authority and failures
Declaring the effect alone does not authorize any POST destination. The provider must receive an explicit host-selected HTTPS origin policy (at most eight origins). No source-selected authentication header, source credential, ambient proxy, or environment-derived origin grants authority. The concrete Rust and native hosts do not follow redirects for POST and perform no automatic retries. The host retains TLS trust configuration. Origin authorization is not IP pinning or a guarantee about DNS rebinding; hosts requiring network-range restrictions must enforce them at their network boundary.
The existing semaprax.http.v1 status domain remains closed: 1 invalid URL,
2 insecure scheme, 3 transport failure, 4 capacity overflow, 5 unsupported HTTP
version, 6 authority denied. For POST, capacity includes request as well as
response bounds. A status after dispatch does not prove that an external effect
failed: even timeout, response overflow or response loss may follow successful
remote processing. Source failure aborts the invocation and publishes no partial
response; this operation does not return a checked delivery-outcome value.
Evidence and errors do not authorize a retry. Webhook delivery reconciliation,
checked uncertain-result APIs, signing and email remain separate work.
Explicit host configuration
Rust hosts use TcpNetworkProvider::with_https_post_origins or
set_https_post_origins with at most eight canonical HTTPS origins. TLS policy
remains injected through the existing provider constructors. An origin matches
scheme, host and effective port; there are no wildcard authorizations.
Generated native commands consume leading
--spx-https-post-origin=https://host[:port] host options before exposing the
remaining arguments to source. Embedders supply an explicit
spx_https_post_allowlist_v1 to
spx_https_command_run_with_post_allowlist_v1. The ordinary runner grants no
POST origin. Host option errors refuse before executing the source command.
Fixture v4 and Wasm
semaprax.network-fixture.v4 keeps v3's connections/listeners and HTTPS GET
fields and requires an additional ordered https_post array. Both https and
https_post are required arrays of at most eight entries each. A POST entry has
exactly url, body, and response, each a JSON string. Body and response use
UTF-8 bytes and are capped at 65,536 bytes; URL uses the source bound. This fixture
profile represents UTF-8 payloads, while the actual source operation accepts
arbitrary body bytes. The existing whole-document fixture limit still applies.
A replay requires exact URL and body bytes and sufficient response capacity. Mismatch or insufficient capacity preserves the entry. Earlier fixture versions remain accepted for their original operations and deny POST authority. Fixtures are replay data and never grant actual network authority.
Core Wasm adds spx_https_post_v1(url_root, url_len, body_root, body_len, max, out_owned) -> status, with six i32 parameters and the existing owned-result
validation/publication contract. The generated npm adapter executes this import
against the explicit fixture only, with no browser fetch or Node socket fallback.