Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Spec couche 2 — air-http (HTTP/1.1 + HTTP/2 + HTTP/3, patron sans-IO)

Spécification technique — Version 0.1 (proposition). Couche 2 « Frameworks système ».

Cadrage. air-http implémente HTTP/1.1 (RFC 9112), HTTP/2 (RFC 9113) et HTTP/3 (RFC 9114) — h1/h2/h3 en modules internes d’un crate unique (note réseau §4 : « air-http (h1/h2/h3 = modules internes) »), + WebSocket (RFC 6455/8441). Maison, pur Rust, zéro-C, zéro unsafe ; s’appuie sur air-tls (h1/h2), air-quic (h3), air-network (connexion). Suit le patron sans-IO 9-composants par version.

Position et méthode

HTTP est un protocole applicatif filaire (cœur sans-IO + pilote I/O mince). Chaque version a son cœur ; le crate expose une surface unifiée (Request/Response/ Body) au-dessus, la version étant négociée (ALPN via air-tls/air-quic).

Empilement (note §2.5) :

air-http (h3)  →  air-quic  →  air-socket (UDP)
air-http (h2)  →  air-tls 1.3 →  air-socket (TCP)
air-http (h1)  →  air-tls / air-socket (TCP)
       └── surface unifiée Request/Response/Body ; version choisie par ALPN

Décision — crate unique, versions internes. h1/h2/h3 partagent le modèle de message (Request/Response/HeaderMap/Body) ; les différences (framing, compression d’en-têtes, multiplexage) sont internes. Un consommateur écrit une requête une fois, la version est un détail négocié. (vs 3 crates séparés → API fragmentée.)

Périmètre de sécurité — moderne, borné

  • h1 : Content-Length/chunked stricts (anti request-smuggling : rejet des cadrages ambigus, une seule interprétation) ; pas de HTTP/0.9 ; en-têtes bornés.
  • h2/h3 : compression d’en-têtes HPACK (RFC 7541) / QPACK (RFC 9204) avec tables bornées (anti HPACK-bomb / CVE-2016-6581-class) ; limites de streams, de frames (anti Rapid-Reset CVE-2023-44487 : plafond de streams annulés/RTT).
  • TLS obligatoire pour h2/h3 (hérité air-tls/air-quic) ; h1 en clair explicite.
  • Bornes anti-abus : taille d’en-têtes, nombre de headers, profondeur, débit de frames de contrôle — tout borné (surface hostile distante).

Dépendances

  • Tierces externes : ZÉRO hors l’exception TLS déléguée (air-tls, ADR-042).
  • Crates Air : air-network (L2, connexion/ALPN), air-tls (L2, h1/h2), air-quic (L2, h3), air-runtime (L1, async), air-base-core (L1, erreurs/durées). (HTTP n’a pas de crypto propre.)
  • Zéro unsafe exposé ; parsing défensif (&[u8] vs &str, get(), longueurs bornées).

Anatomie : les 9 composants par version

#Composanth1h2h3
1FramerH1Framer (start-line + headers + body chunked/CL)H2FrameFramer (len/type/flags/streamid)sur streams QUIC (framing délégué à air-quic)
2CodecH1Codec (champs d’en-tête)H2FrameCodec + HpackH3FrameCodec + Qpack
3StateMachinerequête/réponse + keep-aliveconnexion + états de stream (RFC 9113 §5.1)idem sur streams QUIC
4Handshaker// délégué : TLS via air-tls, version via ALPNidem (+ SETTINGS échange)// délégué : QUIC/TLS via air-quic
5Flow Controller// NO : TCPH2FlowController (WINDOW_UPDATE, conn+stream)// délégué : flow control QUIC
6Multiplexer// NO : 1 requête/connexion (keep-alive séquentiel)H2StreamMux (streams sur 1 TCP)H3StreamMux (streams QUIC)
7Timer Managertimeouts requête/keep-alive+ PING/keepalive, rapid-reset guardidem
8Session Contextconnexion (keep-alive)SETTINGS + table dynamique HPACKSETTINGS + table dynamique QPACK
9Extension hooksUpgrade (WebSocket h1)extended CONNECT (WebSocket h2, RFC 8441)extended CONNECT (h3)

Inventaire des objets — ~33 objets

A. Surface unifiée publique — ~14

#ObjetRôle
1HttpClient (+ HttpClientConfig/Builder)client haut niveau (pool, ALPN, redirections)
2HttpServer (+ HttpServerConfig/Builder)serveur (handler par requête)
3Request (+ RequestBuilder)requête (méthode, URI, headers, body)
4Response (+ ResponseBuilder)réponse (statut, headers, body)
5HeaderMapmultimap d’en-têtes (ordre préservé, casse-insensible)
6HeaderName / HeaderValuenewtypes validés (HeaderValue = bytes, pas UTF-8 présumé)
7Methodenum (GET/POST/… + extension)
8StatusCodenewtype u16 validé (1xx–5xx)
9HttpVersionenum Http11/Http2/Http3
10UriURI parsé/validé (scheme/authority/path/query)
11Body / BodyStreamcorps en flux (back-pressure, ADR-028 buffers possédés)
12HttpConnectionconnexion négociée (sur air-network) — version transparente
13WebSocket (+ WebSocketMessage)RFC 6455/8441 (module, voir ci-dessous)
14HttpErrorenum (ADR-019) — protocole, transport, TLS

B. Cœurs sans-IO internes — ~15

  • Partagé : HeaderCodec, BodyReader/ChunkedCodec, UriCodec.
  • h1 : H1Framer, H1Codec, H1StateMachine.
  • h2 : H2FrameCodec, Hpack (encoder+decoder, table dynamique bornée), H2StreamMux, H2FlowController, H2StateMachine.
  • h3 : H3FrameCodec, Qpack (encoder+decoder), H3StateMachine.

C. Enums/valeurs wire — ~4

H2FrameType, H3FrameType, SettingId, WebSocketOpcode.

Codecs (bytes ↔ messages)

#![allow(unused)]
fn main() {
/// Trait de codec commun (borné, anti-panic) — décliné h1/h2/h3.
pub trait HttpCodec { /* encode(&self, &mut Vec<u8>) ; decode(&mut Reader) -> Result<…> */ }

// h1 : start-line + en-têtes CRLF + corps (chunked | content-length).
//   REJET des cadrages ambigus (CL + TE, doubles CL) → HttpError (anti-smuggling).
// h2 : HPACK (RFC 7541) — table dynamique BORNÉE (SETTINGS_HEADER_TABLE_SIZE),
//   décodage d'entiers/chaînes Huffman borné (anti-bomb).
// h3 : QPACK (RFC 9204) — table dynamique + flux d'encodeur/décodeur, bornés.
}

HPACK/QPACK = la surface hostile n°1 (compression d’en-têtes venant du pair) → fuzz obligatoire, tables bornées, décompression jamais non bornée.

Machine à états — multi-thread (mono-propriétaire, sans-IO)

#![allow(unused)]
fn main() {
impl HttpClient {
    pub async fn send(&self, request: Request) -> Result<Response, HttpError>;   // version transparente
    pub async fn connect(&self, uri: &Uri) -> Result<HttpConnection, HttpError>; // ALPN choisit h1/h2/h3
}
// Cœur sans-IO par version : feed(&[u8]) -> events ; poll_transmit() -> &[u8] ;
//   handle_timeout(now). Pilote I/O = air-network (connexion) + air-runtime (async).
}

Thread model : HttpConnection Send/!Sync (une connexion, une tâche ; le multiplexage h2/h3 se fait dans la connexion, pas entre threads) ; HttpClient partageable (Arc, pool de connexions) ; configs Arc Send/Sync. Thread-per-core (ADR-038/039).

WebSocket (module, RFC 6455 + 8441)

#![allow(unused)]
fn main() {
impl WebSocket {
    /// Sur h1 : Upgrade (RFC 6455). Sur h2/h3 : extended CONNECT (RFC 8441).
    pub async fn connect(uri: &Uri, params: &HttpClientConfig) -> Result<Self, HttpError>;
    pub async fn send(&mut self, msg: WebSocketMessage) -> Result<(), HttpError>;   // Text/Binary/Ping/Close
    pub async fn receive(&mut self) -> Result<WebSocketMessage, HttpError>;
}
// Framing WS : masquage client obligatoire, bornes de frame, close handshake propre.
}

Stratégie de tests

  • Couverture couche 2 > 90 % (viser 100 % sur les codecs sans-IO).
  • Par composant : Framer/Codec fuzzés (h1 smuggling, HPACK/QPACK bombs, frames h2 malformées) ; StateMachine property/model-based (états de stream) ; FlowController property (fenêtre h2) ; rapid-reset guard (plafond streams annulés/RTT).
  • Conformité : suite h2spec/h3spec, vecteurs HPACK (RFC 7541 annexe) / QPACK ; interop vs curl/nginx/quiche.
  • Pilote I/O : loopback réel via air-network (h1/h2 sur TLS, h3 sur QUIC).

Récapitulatif & décisions

FamilleObjets
A. Surface unifiée~14
B. Cœurs sans-IO (h1/h2/h3 + partagé)~15
C. Enums wire~4
Total~33
  1. Crate unique, h1/h2/h3 modules internes ; surface unifiée Request/Response/ Body ; version par ALPN.
  2. Moderne, borné : anti-smuggling (h1), HPACK/QPACK bornés, anti rapid-reset ; TLS obligatoire h2/h3.
  3. Zéro-C, zéro unsafe ; compose air-tls/air-quic/air-network.
  4. WebSocket intégré (RFC 6455 h1 + 8441 h2/h3).
  5. Async 1ʳᵉ classe (ADR-038), connexion Send/!Sync, pool Arc.

Travail à reprendre

  • Priorité d’implémentation : h1 d’abord (sur air-tls/air-socket), puis h2, puis h3 (attend air-quic).
  • Consommateur : l’équivalent URLSession (client URL-loading haut niveau) — couche à confirmer (couche 4 élargie ?), cf. note api-reseau-strategie.
  • Cookies, cache, redirections, auth (couche cliente haut niveau) ; h2 Server Push (déprécié → omis) ; ABI C différée.

Licence du document : MPL 2.0 Statut : Spécification air-http (couche 2) v0.1 — HTTP/1.1+2+3 pur Rust, crate unique, patron sans-IO ; compose air-tls/air-quic/air-network. Implémentation à suivre (h1 d’abord).