Skip to content
pgitPublic

About

HTTP/1.1, H2 and H3 client/server library running on Asio or Capy/Corosio

Resources

Stars

0 stars

Watchers

2 watching

Forks

Repository files navigation

Overview

Build and run tests Documentation Coverage

Low-level C++23 HTTP client and server library, on one of two I/O runtimes, chosen at configure time:

  • ASIO, on Asio: every operation is an asynchronous operation of Asio and takes any completion token.
  • COROSIO, on Corosio: coroutines only.

Warning

This repository is purely experimental. It is not meant for production use, and anything in it can change or break at any time, without notice.

It supports HTTP/1.x, HTTP/2 and HTTP/3 behind a common, type-erasing interface, hence the any in the name -- and plain QUIC streams next to HTTP/3, for protocols of your own.

None of those protocols are implemented from scratch. Instead, it is a wrapper around the following well-established libraries:

This project started as a hand-written replacement for nghttp2-asio. Once the concept was working, HTTP/1.1 was added, and both protocols were hidden behind a type-erased interface. Finally, HTTP/3 was added with the help of agentic coding.

Documentation

https://pgit.github.io/anyhttp/ has the programmer's guide, which is the place to start, the API reference and how it all works: I/O runtimes, the end of a body, concurrent requests, moving to HTTP/3 and the HTTP/2 library. docs/README.md says how to make it.

Example

A server, which echoes every request, over HTTP/1.1, HTTP/2 and HTTP/3 on one port:

Task<void> echo(server::Request request, server::Response response)
{
   if (request.content_length())
      response.content_length(request.content_length().value());

   if (auto [ec] = co_await response.submit(200, {}); ec)
      co_return;

   std::array<uint8_t, 64 * 1024> buffer;
   for (;;)
   {
      auto [ec, n] = co_await request.read_some(boost::asio::buffer(buffer));
      if (ec == errors::eof)
         break;
      if (ec)
         co_return;

      if (auto [write_ec] = co_await response.write(boost::asio::buffer(buffer, n)); write_ec)
         co_return;
   }

   co_await response.write_eof();
}

A client, for which a plain GET is one operation, and anything else a few more:

Task<void> do_session(client::Client& client, boost::urls::url url)
{
   auto [ec1, session] = co_await client.connect();

   auto [ec2, message] = co_await session.get(url);
   std::println("{}: {} bytes", message.result_int(), message.body().size());

   auto [ec3, request] = co_await session.submit(url, {});
   auto [ec4] = co_await request.write_eof();
   auto [ec5, response] = co_await request.get_response();
}

Both I/O runtimes have every operation as such a coroutine, that yields a tuple and reports errors instead of throwing. On ASIO, each is also an asynchronous operation that takes any completion token. The whole programs are hello_server.cpp and hello_client.cpp.

Using it from a project

C++23, CMake 3.30 and Boost 1.88 or later, spdlog, nghttp2, ngtcp2 and nghttp3 -- the Dockerfiles in .devcontainer build all of them, and those are the versions that are tested.

include(FetchContent)
FetchContent_Declare(anyhttp
   GIT_REPOSITORY https://github.com/pgit/anyhttp.git
   GIT_TAG <commit>
   SYSTEM)
FetchContent_MakeAvailable(anyhttp)

target_link_libraries(my_program PRIVATE anyhttp::anyhttp)

An installed package works as well, on ASIO, see getting the library.

Links

For now, this section contains just a set of random links collected during development.

About

HTTP/1.1, H2 and H3 client/server library running on Asio or Capy/Corosio

Resources

Stars

0 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages