Crafter.Network/interfaces/Crafter.Network.cppm

32 lines
1.3 KiB
Text
Raw Normal View History

2026-07-22 17:55:45 +02:00
//SPDX-License-Identifier: LGPL-3.0-only
//SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
2025-11-02 15:00:53 +01:00
export module Crafter.Network;
export import :ClientTCP;
export import :ListenerTCP;
export import :ClientHTTP;
export import :ListenerHTTP;
2026-05-06 04:06:17 +02:00
export import :HTTP;
export import :ClientQUIC;
2026-05-19 02:53:50 +02:00
export import :ListenerQUIC;
export import :WebTransport;
#ifndef CRAFTER_NETWORK_BROWSER
// Exposed so user code can build WebTransport clients by hand against a
// ClientQUIC until we ship a ClientWebTransport wrapper. Most callers do
// not need the HTTP/3 frame helpers directly. Excluded from the browser
// build — HTTP3 uses throw and the wasm target runs with -fno-exceptions.
export import :HTTP3;
feat(http1): add an HTTP/1.1 client and listener HTTP/3-only is not a deployable position yet: plenty of clients, proxies and CI tooling still speak nothing but HTTP/1.1. This adds that path using the request/response types the HTTP/3 stack already uses, so a route handler or call site moves between the two protocols by changing the class name. - :HTTP1 — transport-free wire format. Serialisation with the framing headers owned by the serialiser, and an incremental parser that takes arbitrary socket chunks and yields one message at a time: keep-alive, pipelining, content-length and chunked bodies (with trailers), read-to-EOF responses, interim 1xx skipping, HEAD/204/304 framing and Expect: 100-continue. Ambiguous framing is rejected rather than guessed at (content-length with transfer-encoding, disagreeing content-lengths, whitespace before a colon), and CR/LF in a value we are asked to serialise is refused. - ClientHTTP1 — persistent connection, redialling once when a pooled connection turns out to have been closed by the peer, which is the race HTTP/1.1 keep-alive cannot avoid. Nothing is replayed after a response byte has arrived. - ListenerHTTP1 — one thread per connection (keep-alive connections are idle most of their life and would pin every ThreadPool thread), automatic Date, HEAD, 100-continue, handler-requested close, idle and request timeouts, and 400/404/500 responses. Routes fall back to the query-stripped path so `/thing?x=1` reaches the handler for `/thing`. No TLS: this is `http://` only. Encrypted traffic still goes over HTTP/3, or through a TLS-terminating proxy. Tests: codec unit tests including the malformed inputs above, a client/server round-trip, keep-alive and stale-connection recovery, a 10 MiB body both ways, and interop both directions against curl and python3's http.server (skipped when those are not installed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 00:45:09 +00:00
// HTTP/1.1 over TCP, for peers that are not ready for HTTP/3. Native only:
// in the browser this job is already done by fetch() behind :ClientHTTP,
// and these partitions use exceptions and POSIX sockets.
export import :HTTP1;
feat(tls): add a libssl TLS transport and an https:// HTTP/1.1 stack HTTP/1.1 was plaintext-only, which left `https://` to either an HTTP/3 listener or a terminating proxy in front. Neither helps the callers this stack exists for — curl scripts, CI tooling, old proxies — so wrap the transport in libssl instead. Two new partitions: :Stream a ByteStream with per-call deadlines on both directions, plus the plaintext socket implementation. The HTTP/1.1 client and listener now hold a ByteStream& and never learn which transport they have, which is what lets one code path serve both schemes. :TLS TLSContext/TLSStream over OpenSSL 3, with credentials for both roles: chain and hostname verification on by default, private trust anchors, client certificates, mutual TLS, ALPN, and an in-process self-signed certificate for development. Both descriptors go non-blocking and every read and write is driven by poll() against a deadline. That is required for TLS — a blocking descriptor cannot express a handshake timeout — and it means a plaintext write can now time out too, instead of parking forever against a peer that stopped reading. ClientHTTP1 and ListenerHTTP1 gain credential-taking constructors; the existing ones still speak http://. The listener handshakes on the connection's own thread, so a peer that stalls mid-handshake costs one thread rather than the accept loop, and a failed handshake is counted rather than logged — on a public port it is ordinary traffic. MessageParser gains SetDefaultScheme so origin-form targets report the scheme the transport actually used; handlers shared with ListenerHTTP now see the same "https" they would over HTTP/3. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-28 20:13:30 +00:00
// The byte-stream abstraction the HTTP/1.1 endpoints run over, and the libssl
// TLS transport that turns them into https://. Exported so callers can build
// credentials, and so anything else holding a connected socket can wrap it the
// same way.
export import :Stream;
export import :TLS;
feat(http1): add an HTTP/1.1 client and listener HTTP/3-only is not a deployable position yet: plenty of clients, proxies and CI tooling still speak nothing but HTTP/1.1. This adds that path using the request/response types the HTTP/3 stack already uses, so a route handler or call site moves between the two protocols by changing the class name. - :HTTP1 — transport-free wire format. Serialisation with the framing headers owned by the serialiser, and an incremental parser that takes arbitrary socket chunks and yields one message at a time: keep-alive, pipelining, content-length and chunked bodies (with trailers), read-to-EOF responses, interim 1xx skipping, HEAD/204/304 framing and Expect: 100-continue. Ambiguous framing is rejected rather than guessed at (content-length with transfer-encoding, disagreeing content-lengths, whitespace before a colon), and CR/LF in a value we are asked to serialise is refused. - ClientHTTP1 — persistent connection, redialling once when a pooled connection turns out to have been closed by the peer, which is the race HTTP/1.1 keep-alive cannot avoid. Nothing is replayed after a response byte has arrived. - ListenerHTTP1 — one thread per connection (keep-alive connections are idle most of their life and would pin every ThreadPool thread), automatic Date, HEAD, 100-continue, handler-requested close, idle and request timeouts, and 400/404/500 responses. Routes fall back to the query-stripped path so `/thing?x=1` reaches the handler for `/thing`. No TLS: this is `http://` only. Encrypted traffic still goes over HTTP/3, or through a TLS-terminating proxy. Tests: codec unit tests including the malformed inputs above, a client/server round-trip, keep-alive and stale-connection recovery, a 10 MiB body both ways, and interop both directions against curl and python3's http.server (skipped when those are not installed). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-27 00:45:09 +00:00
export import :ClientHTTP1;
export import :ListenerHTTP1;
2026-05-19 02:53:50 +02:00
#endif