---
tags: http
---
*[GCoS]: Google Summer of Code
# A C++ HTTP/2 Library based on Seastar
> Students work with an open source organization on a **10 week** programming project during their break from school.
> -- [GCoS](https://summerofcode.withgoogle.com/)
We mimick a Google summer of code (GCoS) project from 2021.07.01 to 2021.09.09 (a total of 10 weeks) with the aim of supporting seastar with an HTTP/2 library ([issue 734](https://github.com/scylladb/seastar/issues/734)).
### References
- rfc7540 {
[html](https://datatracker.ietf.org/doc/html/rfc7540),
[txt](https://www.rfc-editor.org/rfc/rfc7540.txt)
}: Hypertext Transfer Protocol Version 2 (HTTP/2)
- rfc7541 {
[html](https://datatracker.ietf.org/doc/html/rfc7541),
[txt](https://www.rfc-editor.org/rfc/rfc7541.txt)
}: HPACK: Header Compression for HTTP/2
- [Seastar documentation](http://docs.seastar.io/master/index.html)
- [tutorial](https://github.com/scylladb/seastar/blob/master/doc/tutorial.md)
- [TLS](https://l.messenger.com/l.php?u=http%3A%2F%2Fdocs.seastar.io%2Fmaster%2Fnamespaceseastar_1_1tls.html&h=AT1MvbfgAz41LwSEmRQV8uRTGpvi5OEUiw-CrRbj29TjJKevU3FcEY3rhygsCcIKd7gBjaoS5XS-Vm5OqWpnbGyWK86vO2bzo-F9Ggxt5YC7lQq02lUEjLPvSsC-6g)
- [httpd](http://docs.seastar.io/master/httpd_8hh_source.html)
- [Seastar: A C++ Asynchronous Programming Framework](https://www.scylladb.com/wp-content/uploads/Avi_Building_efficient_IO_intensive_applications_with_Seastar.pdf)
- [OpenSSL 1.1.1](https://www.openssl.org/docs/man1.1.1/man3/)
- [A Universal Async Abstraction for C++](https://cor3ntin.github.io/posts/executors/), cor3ntin
- [Kernel HTTPS/TCP/IP stack for HTTP DDoS mitigation](https://ostconf.com/system/attachments/files/000/001/338/original/Alexander_Krizhanovsky.pdf), Tempesta Technologies
- [Asymmetric Transfer](https://lewissbaker.github.io/), Lewiss Baker
- [My tutorial and take on C++20 coroutines](https://www.scs.stanford.edu/~dm/blog/c++-coroutines.html), David Mazières
## Rationale
We were assigned to craft a HTTP server with unix socket in C/C++ as the final project of an introductory course on computer networking.
Initially, we were ambitious to implement HTTP/2 with modern C++.
We successfully implemented HPACK; in fact, our implementation was slightly better than that of nghttp2.
However, the rest was tragic.
In the end, we had to revert to HTTP/1.1 over TLS (OpenSSL) in C.
Upon reflection, we identified the causes to our failure:
1. Insufficient knowledge of design principles regarding async, future, coroutine, and executor.
2. Insufficeint knowledge of modern C++ as a whole.
3. Poor development strategies.
We should adopt version control, CI/CD, and agile.
4. Poor documentation.
Even with a codebase of just 2000 lines of code, documentation of our architecture and APIs is still necessary.
After a few months, we decided to revisit the failed project of crafting a HTTP/2 server with modern C++.
After lengthy reviews, we settled on *seastar*, as seastar supports TCP/IP (native and DPDK), TLS (gnutls),threads, fibers, futures, coroutines, and executors.
Better yet, seastar has a working [demo](https://github.com/scylladb/seastar/blob/master/src/http/httpd.cc) of an HTTP/1.1 server.
Furthermore, seastar raised the project idea, "[Add support to HTTP/2 protocol](https://github.com/scylladb/seastar/wiki/Google-Summer-of-Code-2018#add-support-to-http2-protocol)", for GCoS 2018.
However, there is still no progress on HTTP/2 support as indicated by [issue 734](https://github.com/scylladb/seastar/issues/734).
We intend to work toward solving issue 734.
## Plan
{%youtube eozFlgu6ByY%}
:::warning
Before anything, set up a git workflow with CI/CD, and understand agile.
:::
:::danger
Check out the software license.
:::
### First 4 weeks
A simple HTTP/1.1 server over GnuTLS that serves static files and a server side action (tentatively, a simple calculator or an HPACK inspector).
1. Install the seastar library and build seastar-httpd.
Unfortunately, the current (2021.06.19) vcpkg doesn't package seastar.
2. Revise the original C implementation of HTTP/1.1 over OpenSSL in C\++20 with seastar.
3. Consult the [seastar httpd source](https://github.com/scylladb/seastar/blob/master/src/http/httpd.cc), [cpv-framework](https://github.com/cpv-project/cpv-framework), and *envoy* at the same time.
4. Familiarize ourselves with seastar and C\++20.
Study and take notes of C++20 and asynchronous design.
5. Extend [seastar-tls](https://github.com/scylladb/seastar/blob/master/src/net/tls.cc) with [ALPN](https://www.gnutls.org/manual/html_node/Application-Layer-Protocol-Negotiation-_0028ALPN_0029.html).
#### seastar-tls ALPN
[Curl's example](https://github.com/curl/curl/blob/bfa03091752408c6b2db6657587aba04ff9b2874/lib/vtls/gtls.c#L639) on the usage of [*gnutls_alpn_set_protocols*](https://www.gnutls.org/manual/html_node/Core-TLS-API.html#gnutls_005falpn_005fset_005fprotocols):
```cpp
int cur = 0;
gnutls_datum_t protocols[2];
if (data->state.httpwant >= CURL_HTTP_VERSION_2
&& (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
) {
protocols[cur].data = (unsigned char *)ALPN_H2;
protocols[cur].size = ALPN_H2_LENGTH;
cur++;
}
protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
cur++;
gnutls_alpn_set_protocols(session, protocols, cur, 0);
```
The constants `ALPN_H2`, `ALPN_H2_LENGTH`, `ALPN_HTTP_1_1`, `ALPN_HTTP_1_1_LENGTH` are defined in [*curl/lib/vtls/vtls.h*](https://github.com/curl/curl/blob/b31d9ccfc2da288900e6857ad8d048c612328cac/lib/vtls/vtls.h#L136)
Referring to the [*gnutls.org/manual*](https://gnutls.org/manual/html_node/Common-types.html), [*seastar/include/seastar/net/tls.hh*](https://github.com/scylladb/seastar/blob/fb183d2c661d8fb988d9cd46809be7214d06488f/include/seastar/net/tls.hh#L60), and [*seastar/src/net/tls.cc*](https://github.com/scylladb/seastar/blob/fb183d2c661d8fb988d9cd46809be7214d06488f/src/net/tls.cc#L55):
```cpp
// gnutls.org/manual
typedef struct {
unsigned char *data;
unsigned int size;
} gnutls_datum_t;
// seastar/include/seastar/net/tls.hh
typedef std::basic_string_view<char> blob;
// seastar/src/net/tls.cc
class blob_wrapper : public gnutls_datum_t {
public:
blob_wrapper(const tls::blob& in) : gnutls_datum_t {
reinterpret_cast<uint8_t *>(const_cast<char *>(in.data())),
unsigned(in.size())
} {}
};
```
the following lines should be added to [*do_handshake*](https://github.com/scylladb/seastar/blob/fb183d2c661d8fb988d9cd46809be7214d06488f/src/net/tls.cc#L1063).
```cpp
seastar::blob_wrapper protocols[] = {"h2", "http/1.1"};
::gnutls_alpn_set_protocols(session, protocols, std::size(protocols), 0);
```
The corresponding failure handler must also be registered.
Note that initializing `std::string_view` with a `const char *` drops the terminating null-charater; see [this](https://en.cppreference.com/w/cpp/string/basic_string_view/basic_string_view#:~:text=constructs%20a%20view%20of%20the%20null-terminated%20character%20string%20pointed%20to%20by%20s%2C%20not%20including%20the%20terminating%20null%20character.).
### Next 4 weeks
A simple HTTP/1.1 server over GnuTLS that serves static files and a server side action (tentatively, a simple calculator or an HPACK inspector)
1. Test [rfc7541](https://datatracker.ietf.org/doc/html/rfc7541) which is already implemented.
2. Implement [rfc7540](https://datatracker.ietf.org/doc/html/rfc7540) disregarding proxies.
3. Optimize.
4. Consult nghttp2, nginx, envoy, and cpv-framework.

#### HTTP/2
- [x] Starting HTTP/2
- This is solved by extending ALPN to seastar-tls.
- [ ] HTTP Frames
- [ ] Frame Format
- [x] HPACK
- [ ] Streams and Multiplexing
- [ ] Stream States
- [ ] Flow Control
- [Flow control cannot be disabled.](https://datatracker.ietf.org/doc/html/rfc7540#:~:text=flow%20control%20cannot%20be%20disabled.)
- [ ] ~~Stream Priority~~ (optional)
- [to allow an endpoint to express how
it would **prefer** its peer to allocate resources when managing
concurrent streams](https://datatracker.ietf.org/doc/html/rfc7540#:~:text=to%20allow%20an%20endpoint%20to%20express%20how%20it%20would%20prefer%20its%20peer%20to%20allocate%20resources%20when%20managing%20concurrent%20streams)
- [HTTP/2: Race between PUSH_PROMISE and exclusive PRIORITY](https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0597.html)
- [cloudflare](https://blog.cloudflare.com/better-http-2-prioritization-for-a-faster-web/)
- [akamai](https://developer.akamai.com/blog/2019/01/31/http2-discover-performance-impacts-effective-prioritization)
- [ ] Error Handling
- [ ] [Frame Definitions](https://datatracker.ietf.org/doc/html/rfc7540#section-11.2)
- [ ] [Error Codes](https://datatracker.ietf.org/doc/html/rfc7540#section-11.4)
- [ ] HTTP Message Exchanges
- [ ] HTTP Request/Response Exchange
- [ ] ~~Server Push~~ (optional)
- [Intent to Remove: HTTP/2 and gQUIC server push](https://groups.google.com/a/chromium.org/g/blink-dev/c/K3rYLvmQUBY/m/vOWBKZGoAQAJ), Chrome
- [ ] ~~The CONNECT Method~~ (optional)
- We can sidestep this by signaling [connection error](https://datatracker.ietf.org/doc/html/rfc7540#:~:text=a%20tcp%20connection%20error%20is%20signaled%20with%20rst_stream) each time.
- [ ] Additional HTTP Requirements/Considerations
- [ ] Connection Management
- [ ] Use of TLS Features
- Might require extending seastar-tls even further
### Last 2 weeks
1. Further testing and optimization.
2. Observe with [prometheus](https://github.com/scylladb/seastar/blob/master/doc/prometheus.md).
3. Clean up the documentation.
4. Finalize a server.
#### Final server
- [ ] command line flags
- [ ] action routing
- [ ] simple file caching
### Future
- File cache
- SQL: [MariaDB connector](https://mariadb.com/docs/clients/connector-cpp/)
- CQL: [ScyllaDB C++ driver](https://github.com/scylladb/cpp-driver)
- [BBR for TCP congestion control](https://github.com/scylladb/seastar/wiki/Google-Summer-of-Code-2018#improve-native-tcpip-stacks-congestion-control)
- Now that we have QUIC (
[rfc9000](https://datatracker.ietf.org/doc/html/rfc9000),
[rfc9001](https://datatracker.ietf.org/doc/html/rfc9001),
[rfc9002](https://datatracker.ietf.org/doc/html/rfc9002)
), we prefer to prioritize UDP-QUIC-HTTP/3 over TCP-BBR.
## Caveats
- [issue 906](https://github.com/scylladb/seastar/issues/906):
Closing a TLS socket's input stream unexpectedly breaks its output stream as well
## Python CGI
Explain these:
- wsgi, asgi, fastapi, uwsgi
- uwsgi, gunicorn, uvicorn, nginx mod_, apache mod_, bjoern, cherokee, caddy, daphne
- flask, django, tornado