The HTTP/2 library
HTTP/2, server and client both, runs on either nghttp2 or its ground-up rewrite, nghttp2 version 2, by the same author. The rewrite’s API is much closer to
nghttp3’s than to version 1’s: one nghttp2_conn instead of a session and an option object,
settings and callbacks as plain structs, callbacks for connection and HTTP events rather than for
frames, bodies taken by reference, and flow control credit extended by hand.
nghttp2 |
nghttp2 version 2 |
|
|---|---|---|
CMake |
|
|
Source |
|
|
This is a choice when a build is configured, not at runtime, because the two cannot share a process:
version 2 installs as its own package but still exports nine of version 1’s symbol names, among them
the four nghttp2_rcbuf_* whose structs differ. A build links one or the other, and compiles only
the backend directory that goes with it.
Nothing above the backend changes: the same Protocol::h2, the same API, and the same
behavior wherever the two libraries leave anyhttp the choice. Where they do not:
The
Connection: Upgradefrom HTTP/1.1 to h2c (RFC 7540, section 3.2) went with RFC 9113 and has no counterpart in version 2, so such a request is declined and served as HTTP/1.1 instead, which is always a valid answer to an upgrade.The
ALTSVCframe is gone. An alternative service still arrives as a response header field, which is how a server sends one anyway, see Moving to HTTP/3: Alt-Svc.
Version 2 has had no release yet, so a build pins a commit of it.
What h2v2/ has that h2/ has no counterpart for is its write mode, because version 2 takes an
outgoing body by reference where version 1 copied it. nghttp2 keeps reading from the vector it was
handed until it has framed all of it, which flow control can postpone indefinitely. So a response is
handed over straight out of the caller’s buffer, and a write cancelled with bytes still outstanding
resets the stream, there being no way to un-offer that memory. A request body is copied through a
bounded buffer of the stream’s, so that cancelling a write leaves the stream usable and the body can
still be ended afterwards. This is the same split, for the same reason, as HTTP/3 has.