Project 16: C++20 Coroutine HTTP Server

An HTTP server using C++20 coroutines where handlers are written with co_await—looking like synchronous code but running asynchronously. Build on top of your epoll/io_uring code.

Quick Reference

Attribute Value
Primary Language C++20
Alternative Languages Rust (async/await), Go (goroutines)
Difficulty Level 4: Expert
Time Estimate 3 weeks
Knowledge Area C++20 Coroutines, Executors, Async Patterns
Tooling Modern async server framework
Prerequisites Projects 9 or 15, solid C++17 knowledge

What You Will Build

An HTTP server using C++20 coroutines where handlers are written with co_await—looking like synchronous code but running asynchronously. Build on top of your epoll/io_uring code.

Why It Matters

This project builds core skills that appear repeatedly in real-world systems and tooling.

Core Challenges

  • Understanding coroutine mechanics → maps to promise_type, coroutine_handle
  • Building awaitable types → maps to await_ready, await_suspend, await_resume
  • Integrating with event loop → maps to resuming coroutines on I/O completion
  • Error propagation → maps to exceptions in coroutines

Key Concepts

  • C++20 Coroutines: “C++20 - The Complete Guide” Chapters 14-16 - Josuttis
  • Awaitable Types: “C++ Concurrency in Action, 2nd Ed” Chapter 13 - Williams
  • Coroutine Theory: Lewis Baker’s blog posts (essential reading)
  • Integration Patterns: Asio with coroutines

Real-World Outcome

// Handler code looks synchronous but runs async!
Task<HttpResponse> handle_request(HttpRequest req) {
    std::string body = co_await read_file_async(req.path);
    co_return HttpResponse{200, "OK", body};
}

Task<void> handle_connection(TcpStream stream) {
    while (true) {
        HttpRequest req = co_await stream.read_request();
        HttpResponse resp = co_await handle_request(req);
        co_await stream.write_response(resp);
    }
}

Implementation Guide

  1. Reproduce the simplest happy-path scenario.
  2. Build the smallest working version of the core feature.
  3. Add input validation and error handling.
  4. Add instrumentation/logging to confirm behavior.
  5. Refactor into clean modules with tests.

Milestones

  • Milestone 1: Minimal working program that runs end-to-end.
  • Milestone 2: Correct outputs for typical inputs.
  • Milestone 3: Robust handling of edge cases.
  • Milestone 4: Clean structure and documented usage.

Validation Checklist

  • Output matches the real-world outcome example
  • Handles invalid inputs safely
  • Provides clear errors and exit codes
  • Repeatable results across runs

References

  • Main guide: LEARN_CPP_NETWORK_PROGRAMMING.md
  • “C++20 - The Complete Guide” by Nicolai Josuttis