Open-Source Wikis

/

Node.js

/

Systems

/

HTTP, HTTP/2, HTTP/3, and QUIC

nodejs/node

HTTP, HTTP/2, HTTP/3, and QUIC

Owners: @nodejs/http, @nodejs/http2, @nodejs/quic.

Purpose

Provide built-in HTTP servers and clients for HTTP/1.1 (http), HTTP/2 (http2), HTTP/3 (over QUIC, experimental), and the underlying QUIC transport (quic, experimental). The fetch API at globalThis.fetch ships through the vendored undici library.

Directory layout

lib/
  http.js                              // public HTTP/1.1 module
  https.js                             // HTTPS = HTTP/1.1 over TLS
  http2.js                             // public HTTP/2 module
  quic.js                              // public QUIC (experimental)
  _http_agent.js                       // ClientRequest / Agent connection pool
  _http_client.js                      // ClientRequest implementation
  _http_common.js                      // shared parser glue
  _http_incoming.js                    // IncomingMessage (Readable)
  _http_outgoing.js                    // OutgoingMessage (Writable)
  _http_server.js                      // Server, ServerResponse
  internal/http2/                      // http2 internals (compat, util, core)
  internal/quic/                       // QUIC JS shims (experimental)
src/
  node_http_parser.cc                  // llhttp wrapper
  node_http_common.{cc,h}              // shared HEADERS table for h1/h2/h3
  node_http2.{cc,h}                    // HTTP/2 binding (on nghttp2)
  node_http2_state.h                   // HTTP/2 session state
  quic/                                // QUIC implementation
    application.cc/.h                  // base ApplicationLayer
    http3.cc/.h                        // HTTP/3 ApplicationLayer
    session.{cc,h}                     // QuicSession
    endpoint.{cc,h}                    // QuicEndpoint (UDP socket binding)
    streams.{cc,h}                     // QuicStream (StreamBase)
    tlscontext.{cc,h}                  // QUIC TLS handshake glue
    bindingdata.{cc,h}                 // per-realm binding storage
    transportparams.{cc,h}             // RFC 9000 transport params
    tokens.{cc,h}                      // retry / new tokens
    cid.{cc,h}                         // connection IDs
    data.{cc,h}                        // packet/data primitives
    arena.h                            // pooled memory arena
deps/
  llhttp/                              // HTTP/1 parser
  nghttp2/                             // HTTP/2
  ngtcp2/                              // QUIC + nghttp3 for HTTP/3

HTTP/1.1

sequenceDiagram
    participant Client as http.ClientRequest
    participant Sock as net.Socket
    participant Parser as HTTPParser (llhttp)
    participant Server as http.Server
    participant Resp as ServerResponse / IncomingMessage

    Client->>Sock: write request bytes
    Sock->>Server: bytes via TCP
    Server->>Parser: feed onread bytes
    Parser-->>Server: onHeadersComplete -> emit 'request'
    Server->>Resp: build IncomingMessage + ServerResponse
    Resp-->>Sock: writeHead + body
    Sock-->>Client: response bytes
    Client->>Parser: response bytes -> emit 'response'
  • node_http_parser.cc wraps deps/llhttp/. Each Socket lazily attaches an HTTPParser instance that fires JS callbacks (onHeadersComplete, onBody, onMessageComplete).
  • Agent (_http_agent.js) maintains a per-host connection pool and keepalive policy. getAgent is overridable from user code; https swaps in a TLS-aware Agent.
  • IncomingMessage is a Readable; OutgoingMessage/ServerResponse/ClientRequest are Writable with chunked encoding logic baked in.
  • _http_server.js handles keepAlive, Expect: 100-continue, Upgrade, and Connection-header cleanup.

https.js is http.js with tls.connect/tls.createServer swapped for the underlying socket creation. The https.Agent reuses TLS sessions across keepalive connections.

HTTP/2

graph TD
    Sock[TLS or TCP socket] --> NHttp2[Http2Session : nghttp2]
    NHttp2 --> Streams[Http2Stream*]
    Streams --> Compat["Http2Stream → ServerHttp2Stream / Compat"]
    Compat --> ServerResp[Compat ServerResponse]
    Compat --> ClientReq[Compat ClientHttp2Stream]
  • src/node_http2.cc is one of the largest files in the tree (~131 K LOC).
  • Http2Session wraps an nghttp2_session. Frames in/out flow through callbacks OnFrameSend, OnDataChunkRecv, OnHeader, OnStreamClose.
  • Http2Stream is a StreamBase, so HTTP/2 server pushes get the same backpressure/pipe story as TCP.
  • The compat layer in lib/internal/http2/compat.js lets http2.createServer accept HTTP/1-style request handlers ((req, res) => …).
  • HPACK header tables are managed by nghttp2; Node imposes additional limits via --max-http-header-size and the security-conscious settings in lib/internal/http2/util.js.

QUIC and HTTP/3

src/quic/ is a from-scratch binding over deps/ngtcp2/ (QUIC) and deps/nghttp3/ (HTTP/3). It is gated by the build-time node_use_quic GYP variable and the --experimental-quic flag (see the features.quic getter in lib/internal/bootstrap/node.js).

  • QuicEndpoint (src/quic/endpoint.cc) binds a UDP socket via UDPWrap.
  • QuicSession (src/quic/session.cc, ~104K) drives the ngtcp2 conn, manages keys, paths, and streams.
  • QuicStream (src/quic/streams.cc) is a StreamBase wired into the session's outbound queues.
  • Http3Application (src/quic/http3.cc) plugs into nghttp3 for header compression and stream management.
  • TLS handshake state lives in tlscontext.cc; certificate validation reuses crypto_x509.

Fetch (globalThis.fetch)

globalThis.fetch, Request, Response, Headers, FormData, WebSocket, Blob, and the URL/URLPattern integration come from deps/undici/. The undici source is bundled by tools/js2c.cc along with Node's own lib/. The integration glue lives in lib/internal/bootstrap/web/ and adds a small set of Node-specific tweaks (proxy support via NODE_USE_ENV_PROXY, telemetry hooks via diagnostics_channel).

undici uses net/tls for transport so HTTP/2 fetch and HTTP/1 fetch share the same socket layer documented above.

Integration points

  • Streams: every body is a Readable/Writable (or a WHATWG ReadableStream for fetch).
  • TLS: https.Server and HTTP/2 reuse tls.Server; HTTP/3 reuses crypto/crypto_tls-style key extraction.
  • Permission model: net domain restrictions apply to all client connections and listeners.
  • Diagnostics channel: lib/_http_*.js and the node:http clients publish events to diagnostics_channel channels (http.client.request.start, http.server.request.start, etc.). undici similarly publishes to undici:request:create, undici:request:headers, …

Entry points for modification

  • HTTP/1 parser bug? Fixes go upstream at nodejs/llhttp; the Node side just regenerates deps/llhttp/.
  • HTTP/2 frame handling? Most logic is in src/node_http2.cc; small surface in lib/internal/http2/core.js.
  • QUIC: src/quic/session.cc (state machine), src/quic/streams.cc (data plane), src/quic/http3.cc (HTTP/3). New PRs should also touch doc/api/quic.md and the @nodejs/quic team.
  • Fetch behaviour: usually fixes go upstream to undici; sometimes lib/internal/bootstrap/web/ for environment plumbing.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

HTTP, HTTP/2, HTTP/3, and QUIC – Node.js wiki | Factory