| # `oghttp2`: a general purpose HTTP/2 library |
| |
| ## Overview |
| |
| The code in this directory implements the HTTP/2 internet protocol as specified |
| in [RFC 9113](https://www.rfc-editor.org/rfc/rfc9113.html). |
| |
| You will need the following additional pieces of code in order to build a |
| functioning client or server: |
| |
| * an event loop, like [`libevent`](https://libevent.org/) or |
| [`libuv`](https://libuv.org/); |
| * a TLS library, like [OpenSSL](https://www.openssl.org/); and |
| * application logic, to generate HTTP headers and bodies for the requests you |
| want to send, or the responses you want to serve. |
| |
| ### Motivation |
| |
| Back in 2018, the open source [Envoy proxy](https://github.com/envoyproxy/envoy) |
| community [discovered](https://github.com/envoyproxy/envoy/issues/5155) that the |
| [`http-parser`](https://github.com/nodejs/http-parser) HTTP/1.1 codec library in |
| use at the time was no longer actively maintained. While working to resolve this |
| issue, Google engineers evaluated several HTTP/1 codec libraries as potential |
| replacements. After much consideration, we decided to release the Google HTTP/1 |
| codec library (Balsa) as part of the [QUICHE](https://github.com/google/quiche) |
| open source project. |
| |
| At this point, the QUICHE project provided open source implementations of HTTP/1 |
| and HTTP/3, but not HTTP/2. We were motivated in part by this glaring omission, |
| but also by the desire to provide a modern, readable C++ implementation for use |
| by Envoy and other future projects. |
| |
| ### History |
| |
| We reused some existing open source code when building the `oghttp2` library. As |
| part of the [SPDY](https://www.chromium.org/spdy/spdy-whitepaper/) project, |
| developers on the Chromium project worked with other Google engineers to invent |
| a new multiplexed transport for HTTP. As the project evolved over time, those |
| engineers built several shared utilities, many of which survive to the present |
| day. |
| |
| These utilities are incorporated wholesale into `oghttp2`: |
| |
| * a wire format encoder, in `http2/core/spdy_framer.h`; |
| * a wire format decoder, in `http2/decoder/http2_frame_decoder.h`; |
| * a HPACK encoder, in `http2/hpack/hpack_encoder.h`; and |
| * a HPACK decoder, in `http2/hpack/hpack_decoder_adapter.h`. |
| |
| The name of the library is related to this history: it was built from the |
| "original generation" HTTP/2 implementation. |
| |
| Given that part of our motivation for the `oghttp2` project was the needs of the |
| Envoy open source project, the first piece that we built was a C++ API around |
| the existing HTTP/2 library that Envoy used at that time: |
| [`nghttp2`](https://nghttp2.org/). This API started as an "adapter" layer |
| between Envoy's notion of a codec and what the `nghttp2` library provided, which |
| is why `oghttp2` is located in `http2/adapter`. |
| |
| We would like to thank the `nghttp2` project for providing a straightforward C |
| API that we could build on. |
| |
| ## Code Overview |
| |
| The main structure of the library consists of two components: |
| |
| * a session object that represents a single multiplexed HTTP/2 connection |
| (called a `Http2Adapter` in the code), and |
| * a visitor interface (`Http2VisitorInterface`) that application code can |
| implement in order to receive HTTP/2 events. |
| |
| An application can take certain actions to update the state of the HTTP/2 |
| connection by invoking `Http2Adapter` methods. The application can observe the |
| effects of those actions and the behavior of the peer as `Http2VisitorInterface` |
| callbacks are invoked. |
| |
| Consider the following example: |
| |
| ``` |
| Http2Adapter* client_session = /* code to initialize the session */; |
| MyStreamStruct* stream_data = new MyStreamStruct; |
| const int32_t stream_id = |
| client_session->SubmitRequest({{":authority", "www.example.com"}, |
| {":scheme", "http"}, |
| {":method", "GET"}, |
| {":path", "/index.html"}}, |
| /*end_stream=*/true, |
| /*user_data=*/stream_data); |
| const int status = client_session->Send(); |
| // Handle error if status is nonzero. |
| ``` |
| |
| This is how a client would send a request on a new stream. When the request is |
| actually sent, the client application would receive an `OnFrameSent()` callback |
| with the `HEADERS` frame type, the stream ID on which the request was sent, the |
| payload size, and any flags set on the frame. |
| |
| ### Common Types |
| |
| Several protocol elements from the spec are defined as types in |
| `http2_protocol.h`: |
| |
| * `Http2StreamId`: the 31-bit stream ID |
| * `FrameType`: the 8-bit frame type value (e.g. `HEADERS`, `DATA`, etc.) |
| * `FrameFlags`: each of the frame flag values defined in the specification |
| * `Http2ErrorCode`: an enumeration of the error codes |
| * `Http2KnownSettingsId`: an enumeration of the `SETTINGS` identifiers |
| |
| This file also provides several useful constants related to limits or initial |
| values defined in the specification. |
| |
| ### Design |
| |
| ### Adapter Implementations |