Cette page décrit ce que Chappe fait quand une requête arrive : comment la connexion est acceptée, comment le préambule TCP/TLS est inspecté, comment HTTP/1.1 et HTTP/2 sont parsés, comment le Router est invoqué, comment la réponse est écrite. Aucun chiffre de performance ici — voir lien:https://codeberg.org/Vidocq/chappe/blob/main/BENCH.md[BENCH.md].
Architecture en couches
-
chappe-apin’a aucune dépendance interne — elle expose les interfaces. -
chappe-httpne dépend que dechappe-api. -
chappe-coreorchestre et fournit l’implémentationServerProviderviaServiceLoader.
Boucle d’acceptation
-
ChappeServer#start()ouvre unServerSocketChannel(mode bloquant). -
Un virtual thread (« acceptor ») boucle sur
accept(). -
Pour chaque socket, un nouveau virtual thread est lancé via
Executors.newVirtualThreadPerTaskExecutor(). -
Le thread inspecte le préambule (
TLS ClientHelloou requête HTTP/1.1 cleartext) puis dispatch versHttpConnectionouHttp2Connection.
Pas de Selector applicatif. La VM gère le multiplexage des virtual threads sur les carrier threads plateforme.
Pipeline HTTP/1.1 — séquence requête
Composants impliqués (io.vidocq.chappe.http) :
-
HttpRequestParser— parse request line + headers en zero-allocation sur le hot path (réutilise les buffers duByteBufferPool). -
ChunkedInputStream/FixedLengthInputStream— lecture body lazy. -
HttpResponseWriter— écriture coalescée (status line + headers + premier chunk en un seulwrite). -
ArrayHeaders— stockage compact, lookup case-insensitive sans allocation.
Pipeline HTTP/2 — séquence requête
Implémentation (io.vidocq.chappe.http.h2) :
-
Http2FrameReader/Http2FrameWriter— framing RFC 9113. -
HpackEncoder/HpackDecoder— RFC 7541 (table statique 61 entrées, table dynamique paramétrée parSETTINGS, Huffman pour les valeurs courtes). -
HpackHuffman— tables d’encodage/décodage générées statiquement. -
Http2Settings—HEADER_TABLE_SIZE,MAX_CONCURRENT_STREAMS,INITIAL_WINDOW_SIZE,MAX_FRAME_SIZE,MAX_HEADER_LIST_SIZE. -
Http2Stream— état FSM (idle → open → half-closed local/remote → closed). -
Http2ConnectionException/Http2ErrorCode— gestionGOAWAY/RST_STREAM.
Modèle threading
Points de design :
-
Aucun thread plateforme dédié à Chappe — uniquement des virtual threads.
-
Pas de pinning — pas de
synchronizedsur le hot path, pas de JNI bloquant.RequestContextutiliseScopedValue, pasThreadLocal. -
Body lazy — la lecture du body n’est faite qu’à l’appel de
req.body().asInputStream(). Si le handler retourne sans consommer, le body est drainé proprement avant la requête suivante (keep-alive HTTP/1.1) ou le reset du stream (HTTP/2).
Optimisations zéro-allocation sur le hot path
Documentées dans chappe/OPTIMS.md :
-
Write coalescing — status line + headers + premier chunk émis dans un seul
write(). -
Zero-alloc headers —
ArrayHeadersréutilise un buffer scratch, pas deHashMapsur le hot path. -
Thread-local buffer pool —
ByteBufferPoolpartage desByteBufferdirect entre virtual threads via les carriers. -
Fast path 200 OK — status line
HTTP/1.1 200 OKpré-encodé, copie directe. -
StatusCodeCache—StatusCodeenum cachée enString[]indexé.
Pour les chiffres mesurés, voir lien:https://codeberg.org/Vidocq/chappe/blob/main/BENCH.md[BENCH.md] et chappe/BENCHMARKS.md.
Static index O(1)
StaticFileHandler charge un index META-INF/chappe-static-index.properties (généré par chappe-static-index-maven-plugin au build). Lookup O(1) par chemin, pas de scan filesystem au runtime. Les sidecars .gz (et .br si fournis) sont signalés dans l’index — preferPrecompressed(true) les sert zero-copy quand Accept-Encoding les inclut.