deno
a2eb5ba6 - feat(ext/node): rewrite node:http with llhttp and native TCPWrap (#33208)

Commit
94 days ago
feat(ext/node): rewrite node:http with llhttp and native TCPWrap (#33208) ## Summary Rewrite the entire `node:http` stack to use llhttp (Node.js's HTTP parser) with native TCP socket I/O via a new Rust `TCPWrap`, replacing the hyper-based implementation. The code now closely mirrors Node.js's file structure and behavior. ### Architecture **Native TCP layer**: New Rust `TCPWrap` (692 lines) provides libuv-compatible TCP handles with connect, listen, accept, read, and write operations. `LibUvStreamWrap` is stripped to a thin JS interface delegating to native handles. TLS wraps the native TCP handle directly. **HTTP layer**: Four new JS files ported from Node.js (`_http_client.js`, `_http_server.js`, `_http_incoming.js`, `_http_common.js`) implement the full HTTP/1.1 protocol over these native sockets, using the llhttp parser for response/request parsing. **HTTP/2**: Sessions use a JS socket data-pump path (`socket.on("data")` + `handle.getOutgoingData()`) since `consume_stream` is not used. GOAWAY frames are now properly flushed to TCP, and graceful close notifications fire correctly after the JS path drains nghttp2 output. ### Key changes - **`_http_outgoing.ts`**: `_send()`, `_writeRaw()`, `end()` match Node.js (direct socket writes, JS-side chunked encoding, header string building) - **`_http_agent.js`**: Aligned with Node.js; rejects non-writable sockets from keepalive pool - **`_http_client.js`**: Transparent retry on stale keepalive sockets (saves outputData pre-flush, re-queues through agent) - **`http.ts`**: 2,621 -> 122 lines. Thin facade re-exporting from the above modules. - **`https.ts`**: Rewritten `https.request()`/`Agent` to match Node.js, fixes critical agent options mutation bug - **`http2.ts`**: GOAWAY frames flushed via `scheduleSendPending` after `submitGoaway`; `get_outgoing_data` calls `maybe_notify_graceful_close_complete` - **`tcp_wrap.ts`**: Stripped from 611 to ~80 lines, delegates to native Rust `TCPWrap` ### Removed - **5 Rust HTTP ops** (822 lines): `op_node_http_request_with_conn`, `op_node_http_await_response`, `op_node_http_await_information`, `op_node_http_response_reclaim_conn`, `op_node_http_fetch_response_upgrade` - **Old HTTP classes**: `IncomingMessageForClient`, `IncomingMessageForServer`, `FakeSocket`, old `ServerResponse`/`Server` (used `Deno.serve()` / `TransformStream`) - **`kStreamBaseField` proxy** and legacy async I/O code from `LibuvStreamWrap` --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: Nathan Whitaker <nathan@deno.com>
Author
Parents
Loading