Build native HTTP clients and servers
ASPL 0.7.0 · Current release
Run paired text, JSON, byte and TLS clients/services, publish state and shut down with ASPL 0.7.0.
On this page
Prepare native HTTP
Native only, published ASPL 0.7.0. Install the native toolchain on x86-64 Linux with glibc 2.34 or later. aspl --version must print aspl 0.7.0. The browser playground and private embedding profile reject HTTP before execution. Downloads on this page preserve supplied source; they do not open a browser draft or run a program.
Use the HTTP collection to download a root and its required modules. Keep Arabic and English variants in separate directories with their original filenames. Arabic sources use Arabic filenames, user identifiers and escapes; English sources use English names and escapes. Each file imports what it uses: import core::http; activates http, and استورد أساسي::ويب. activates ويب. Only the written prefix is available; supplied members have exact aliases. Both .aspl and .لبات work for roots and imported modules.
The API reference lists the public types, signatures, defaults, limits and error codes. Follow the deployment guide for certificate preparation, system trust and deployment. The earlier raw guide (opens in a new tab) and raw deployment source (opens in a new tab) retain their earlier release scope.
Serve text, JSON and bytes
Download the service family with settings.aspl and handlers.aspl of the selected variant. Save them together. From that source directory, run:
aspl check service.aspl
aspl run service.asplFor Arabic source use خدمة.لبات, إعدادات.لبات and معالجات.لبات. The service stays in the foreground on 127.0.0.1:8080. Reserve that port first. It needs no input lines or data assets for the plain client exercise. Its /upstream route additionally needs a trusted server.pem in the process working directory and a verified peer at https://localhost:9443/hello.
Execution: Native only · ASPL 0.7.0
- Native only. Published ASPL 0.7.0 on x86-64 Linux with glibc 2.34 or later. No input lines. Listen on 127.0.0.1:8080; run the client in another terminal. /count reads then increments state. POST /stop drains the service. /upstream additionally needs server.pem and a verified HTTPS peer at localhost:9443/hello.
Input: No input lines are required.
Arabic source · Required source modules, keep each variant in a separate directory:
English source · Required source modules, keep each variant in a separate directory:
import core::http;
import settings.aspl as app;
import handlers.aspl as handlers;
fn start_main() -> i64 {
let result = http::serve(app::server(false), handlers::routes(),
app::Config { upstream: "https://localhost:9443/hello", ca: "server.pem" },
app::State { count: 0 });
if not result::ok { print(result::error::code); return 1; }
return 0;
}
Follow the Linux instructions to run this example. Download the source to keep a copy.
Download service.asplExpected outcomes
{
"native": {
"check": 0,
"status": 0,
"output": ""
}
}handlers::handle is a named top-level function with no captured locals. Its request and Context<app::Config,app::State> match the router's nominal types. The checker rejects unsafe and blocking handler paths, including ordinary foreign calls and line/file input hidden behind helpers. Other admitted handlers can progress while one waits for an HTTP child call; ASPL execution stays serialized.
GET /hello returns مرحبا من ASPL. POST /submit checks UTF-8 and echoes explicit JSON text with application/json; charset=utf-8; it does not parse or validate JSON structure. POST /bytes echoes arbitrary bytes, and GET /download returns exactly 00 FF 41. /count reports the state before incrementing it. read_state returns a value copy, and replace_state publishes a whole replacement. Reading, waiting and replacing are not atomic. Reread after a wait or use versioned snapshots.
GET /upstream makes a verified child request using app::Config. A child failure becomes a 502 containing its stable code while the parent is live. Parent cancellation revokes child work and discards late output and publication; it does not resume the cancelled handler with a failed result. Forward body bytes deliberately, since peer compressed length/encoding metadata may be stale.
Check client outcomes
Keep the client root beside its matching requests.aspl. With the service running, use another terminal in that source directory:
aspl check client.aspl
aspl run client.asplExecution: Native only · ASPL 0.7.0
- Native only. Published ASPL 0.7.0 on x86-64 Linux with glibc 2.34 or later. No input lines. Start the matching plain service on 127.0.0.1:8080 first. Keep requests.لبات from the same source variant beside the root.
Input: No input lines are required.
Arabic source · Required source modules, keep each variant in a separate directory:
English source · Required source modules, keep each variant in a separate directory:
import requests.aspl as requests;
fn start_main() -> i64 { return requests::exercise("http://127.0.0.1:8080", false); }
Follow the Linux instructions to run this example. Download the source to keep a copy.
Download client.asplExpected outcomes
{
"native": {
"check": 0,
"status": 0,
"output": "checked text, JSON, 00 FF 41, and 404"
}
}The client verifies text, JSON echo, exact binary bytes and a complete 404 response. It prints checked text, JSON, 00 FF 41, and 404 without a trailing newline and returns 0. http.request returns a successful result for complete 404/500 messages. Inspect status separately. Invalid UTF-8 decoding gives http.invalid_utf8; the original body stays available. JSON has no implicit parser or serializer.
The refusal example assumes no listener at 127.0.0.1:9, prints http.connect_failed and returns 0 after checking that failure. A live peer changes the assumption. Branch on error::code, not human diagnostic text. Recoverable results differ from source errors, terminal traps and execution cancellation.
Verify HTTPS and respect limits
The direct-TLS service uses the same helper modules on 127.0.0.1:8443. Supply server.pem and its matching unencrypted server.key in the working directory. The HTTPS client uses https://localhost:8443 and explicitly trusts server.pem, with localhost in the certificate's DNS SAN. Private CA replaces system trust and keeps chain, date and identity verification mandatory. Missing or invalid server material gives http.tls_config_failed before listening.
aspl check direct-tls.aspl
aspl run direct-tls.asplIn the separate client terminal:
aspl check client-tls.aspl
aspl run client-tls.asplThe system-trust client instead calls https://localhost:9443/hello. Success requires a peer trusted by the host. An untrusted local certificate produces http.tls_verify_failed, output containing that code and status 1. Missing or malformed trust gives http.ca_load_failed. See certificate preparation and trust selection.
Follow the complete upstream deployment exercise for the matching peer, working directory, verified requests and failure outcomes.
Redirect following and gzip decoding default to false. Enabled redirects stay within one origin and share the original total deadline. Gzip checks both encoded and decoded limits. There is no automatic transport retry. The limits example demonstrates that lowering outbound capacity below the default 16 idle connections also requires lowering idle capacity. Numeric settings reserve no resources. See message and runtime limits and deadlines.
Progress a session and publish copied state
Use blocking serve when serving owns the application's control flow. Use start to obtain Session<C,S> and call progress explicitly from application code. A successful start has ready listeners; normal handlers run only through progress. Application-only session helpers cannot run inside handlers. Handler Context authority expires with that invocation.
The session family needs free port 127.0.0.1:8081 and no peer or TLS files. It copies state without publishing the local mutation, publishes 11 against a current snapshot, and checks successful false for stale publication. It then requests drain, progresses until SESSION_CLOSED, closes aliases repeatedly and checks http.closed_session. The saved snapshot still contains 10. Success has no output and status 0.
Execution: Native only · ASPL 0.7.0
- Native only. Published ASPL 0.7.0 on x86-64 Linux with glibc 2.34 or later. No input lines. Reserve 127.0.0.1:8081. No external requests, source modules or TLS assets are needed. The program copies state, publishes 11 conditionally, refuses stale publication with successful false, drains and closes shared aliases.
Input: No input lines are required.
import core::http;
record State { count: i64 }
fn handle(req: http::IncomingRequest, ctx: http::Context<bool,State>) -> http::ServerResponse {
let saved = http::snapshot_state(ctx);
let published = http::replace_state_if_current(ctx, saved, State { count: saved::value::count + 1 });
if not published::ok or not published::value { return http::response(409, [])::value; }
return http::response(200, [])::value;
}
fn start_main() -> i64 {
let routes = http::router([http::route("GET", "/", handle)::value])::value;
var server = http::server_config();
server::listeners = [http::listener("127.0.0.1", 8081)::value];
let started = http::start(server, routes, false, State { count: 10 });
if not started::ok { print(started::error::code); return 1; }
let owner = started::value;
let alias = owner;
let saved = http::snapshot_session_state(owner)::value;
var copied = http::session_state(owner)::value;
copied::count = 99;
if http::session_state(owner)::value::count not matches 10 { return 2; }
let published = http::replace_session_state_if_current(owner, saved, State { count: 11 });
if not published::ok or not published::value { return 3; }
let stale = http::replace_session_state_if_current(alias, saved, State { count: 12 });
if not stale::ok or stale::value { return 4; }
if http::session_state(owner)::value::count not matches 11 { return 5; }
if not http::stop_session(owner)::ok { return 6; }
var budget = http::progress_budget();
budget::wait_ms = 1;
var closed = false;
while not closed {
let advanced = http::progress(owner, budget);
if not advanced::ok { print(advanced::error::code); return 7; }
closed = advanced::value matches http::SESSION_CLOSED;
}
if not http::close_session(alias)::ok or not http::close_session(owner)::ok { return 8; }
if http::session_state(alias)::error::code not matches "http.closed_session" { return 9; }
if saved::value::count not matches 10 { return 10; }
return 0;
}
Follow the Linux instructions to run this example. Download the source to keep a copy.
Download session.asplExpected outcomes
{
"native": {
"check": 0,
"status": 0,
"output": ""
}
}aspl check session.aspl
aspl run session.asplSession copies share one managed owner. Closing one invalidates every alias; losing the last reachable alias releases the resource. StateSnapshot<S> contains a copied, read-only value and hidden session/version identity. Foreign-session publication fails with http.invalid_argument. Managed handles inside snapshots retain the same native owner, not a clone of its mutable state. See serving lifetimes and publication.
Shut down and build an ELF
For the plain service, POST /stop from another terminal:
curl --http1.1 --request POST http://127.0.0.1:8080/stopFor the TLS service, use the trusted CA and its port:
curl --http1.1 --cacert server.pem --request POST https://localhost:8443/stopHandler stop(ctx) requests drain and is idempotent. The current response can finish. serve returns normally only after releasing its owned work. Explicit stop_session likewise needs subsequent progress until closed. close_session revokes work and releases the owner. First Ctrl+C or SIGTERM drains then ends execution with status 7; a second signal skips the rest of drain. A trap stays terminal with status 5 and never becomes an automatic 500. Parent expiry, disconnect or drain expiry can discard handler completion and state publication.
aspl build -o service-program service.aspl
aspl build -o client-program client.aspl
./service-program --aspl-diagnostic-language=en --aspl-color=neverRun ./client-program in another terminal, then POST /stop. Use the Arabic root filename when building that variant. The ELF includes the checked module graph and VM and runs without ASPL, source files or a C compiler. TLS files and any ordinary declared C shared libraries remain external inputs. Generated programs accept the reserved diagnostic/color options; ASPL CLI commands and arbitrary application arguments are not supported. See build and process status.