{"id":28557686,"url":"https://github.com/fantasy-peak/simple_http","last_synced_at":"2026-04-10T03:16:01.760Z","repository":{"id":293664991,"uuid":"984734051","full_name":"fantasy-peak/simple_http","owner":"fantasy-peak","description":"A C++20 header-only HTTP library that supports both HTTP/2 and HTTP/1, based on Beast, nghttp2, Asio.","archived":false,"fork":false,"pushed_at":"2026-03-27T08:51:20.000Z","size":166,"stargazers_count":25,"open_issues_count":0,"forks_count":5,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-27T14:56:48.781Z","etag":null,"topics":["asio","beast","cpp20-coroutine","http-client","http-server","http1-1","http2","nghttp2"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fantasy-peak.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-16T12:21:06.000Z","updated_at":"2026-03-27T08:48:01.000Z","dependencies_parsed_at":"2025-06-10T07:20:08.655Z","dependency_job_id":null,"html_url":"https://github.com/fantasy-peak/simple_http","commit_stats":null,"previous_names":["fantasy-peak/simple_http"],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/fantasy-peak/simple_http","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fantasy-peak%2Fsimple_http","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fantasy-peak%2Fsimple_http/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fantasy-peak%2Fsimple_http/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fantasy-peak%2Fsimple_http/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fantasy-peak","download_url":"https://codeload.github.com/fantasy-peak/simple_http/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fantasy-peak%2Fsimple_http/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31292217,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T21:15:39.731Z","status":"ssl_error","status_checked_at":"2026-04-01T21:15:34.046Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["asio","beast","cpp20-coroutine","http-client","http-server","http1-1","http2","nghttp2"],"created_at":"2025-06-10T07:38:52.330Z","updated_at":"2026-04-01T21:24:48.026Z","avatar_url":"https://github.com/fantasy-peak.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# simple_http\n\n[![gcc](https://github.com/fantasy-peak/simple_http/actions/workflows/gcc.yaml/badge.svg)](https://github.com/fantasy-peak/simple_http/actions/workflows/gcc.yaml)\n[![clang](https://github.com/fantasy-peak/simple_http/actions/workflows/clang.yaml/badge.svg)](https://github.com/fantasy-peak/simple_http/actions/workflows/clang.yaml)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n`simple_http` is a lightweight, high-performance, asynchronous HTTP/1.1 \u0026 HTTP/2 server and client library for C++20, built upon Boost.Asio and nghttp2. It is designed as header-only for easy integration and use.\n\n## ✨ Features\n\n- **Header-only**: Easy to integrate into any project by just including headers.\n- **Modern C++**: Leverages C++20/23/26 and coroutines for clean, asynchronous logic.\n- **Dual Protocol Support**: Supports both HTTP/1.1 and HTTP/2 with automatic negotiation.\n- **Server \u0026 Client**: Provides a consistent API for both server and client functionalities.\n- **Secure Communication**: Supports HTTPS and TLS mutual authentication (mTLS).\n- **Highly Configurable**: Easily configure server worker threads, concurrent stream limits, window sizes, and more.\n- **Middleware Support**: Offers a `setBefore` interface for middleware-style request pre-processing.\n- **IPv4 \u0026 IPv6**: Full dual-stack support.\n- **UNIX Domain Sockets**: High-performance local IPC with zero network overhead.\n\n## 🚀 Requirements\n\n- **C++20/23/26** compatible compiler (e.g., GCC 13+, Clang 20+).\n- **xmake**: Used for building examples and dependency management.\n- **Boost** (`beast`)\n- **nghttp2**\n- **OpenSSL**\n\n\u003e **Note**: When building with `xmake`, it automatically downloads and links all necessary dependencies, so you don't need to install them manually.\n\n## 📦 C++20 Modules Support (Experimental)\n\n`simple_http` provides experimental support for C++20 Modules via `include/simple_http.cppm`. This allows for faster compilation and better code isolation compared to traditional header inclusions.\n\n\u003e **Note**: Currently, C++20 Modules support is verified on **Clang 20+**. Support for GCC and MSVC is planned.\n\n### Usage in C++\nTo use the module, simply replace your `#include` with an `import` statement:\n\n```cpp\nimport simple_http;\n\nsimple_http::HttpServer hs(cfg);\n```\n\n### Integration with xmake\nThe following example shows how to integrate `simple_http` as a C++20 module in your `xmake.lua` project:\n\n```lua\nadd_requires(\"simple_http\")\n\nset_policy(\"build.c++.modules\", true)\nset_policy(\"build.c++.modules.std\", true)\n\ntarget(\"server\")\n    set_kind(\"binary\")\n\n    add_cxflags(\"-fuse-ld=mold\")\n    add_cxxflags(\"-stdlib=libc++\")\n\n    on_load(function (target)\n        local pkg = target:pkg(\"simple_http\")\n        if pkg then\n            local installdir = pkg:installdir()\n            local module_file = path.join(installdir, \"include\", \"simple_http.cppm\")\n            target:add(\"files\", module_file)\n            print(\"Successfully linked C++20 module from: \" .. module_file)\n        end\n    end)\n\n    add_files(\"src/main.cpp\")\n    add_packages(\"simple_http\")\n```\n\n\n## 🛠 Configuration Macros\n\nThe following macros can be defined to enable or customize specific features:\n\n- `SIMPLE_HTTP_EXPERIMENT_WEBSOCKET`: Enables experimental WebSocket support.\n- `SIMPLE_HTTP_EXPERIMENT_HTTP2CLIENT`: Enables experimental HTTP/2 client support.\n- `SIMPLE_HTTP_USE_BOOST_REGEX`: Uses `boost::regex` instead of `std::regex` for header parsing and routing. This can provide better performance and compatibility in certain environments.\n- `SIMPLE_HTTP_BIND_UNIX_SOCKET`: Enables support for binding the server to UNIX Domain Sockets (UDS) for high-performance local IPC.\n\n## Server Example\n```\nimport std;\nimport simple_http;\n\nasio::awaitable\u003cvoid\u003e start() {\n    simple_http::Config cfg{\n        .ip = \"0.0.0.0\",\n        .port = 7788,\n        .worker_num = 8,\n        .concurrent_streams = 200,\n        .window_size = std::nullopt,\n        .max_frame_size = std::nullopt,\n        .ssl_crt = \"./test/tls_certificates/server_cert.pem\",\n        .ssl_key = \"./test/tls_certificates/server_key.pem\",\n        .ssl_mutual = true,\n        .ssl_ca = \"./test/tls_certificates/ca_cert.pem\",\n        .socket_setup_cb =\n            [](asio::ip::tcp::socket\u0026 socket) {\n                // Set socket properties\n                socket.set_option(asio::socket_base::keep_alive(true));\n            },\n        .enable_ipv6 = true,\n        .ipv6_addr = \"::1\",\n        .ipv6_port = 7788,\n        .unix_socket = std::nullopt,\n        .websocket_setup_cb = [](auto socket) { std::visit([](auto\u0026\u0026 arg) { arg-\u003ecompress(false); }, socket); },\n    };\n    simple_http::HttpServer hs(cfg);\n    simple_http::LOG_CB = [](simple_http::LogLevel level, auto file, auto line, std::string msg) {\n        std::println(\"{} {} {} {}\", to_string(level), file, line, msg);\n    };\n    hs.setBefore([](const auto\u0026 reader, const auto\u0026 writer) -\u003e asio::awaitable\u003cbool\u003e {\n        if (reader-\u003etarget() != \"/hello\") {\n            auto res = simple_http::makeHttpResponse(http::status::bad_request);\n            writer-\u003ewriteHttpResponse(res);\n            co_return false;\n        }\n        co_return true;\n    });\n    hs.setHttpHandler(\"/hello\",\n        [](auto req, auto writer) -\u003e asio::awaitable\u003cvoid\u003e {\n            writer-\u003ewriteStatus(200);\n            writer-\u003ewriteHeader(http::field::content_type, simple_http::mime::text_plain);\n            writer-\u003ewriteStreamHeaderEnd();\n            writer-\u003ewriteStreamBody(\"hello world\");\n            writer-\u003ewriteStreamEnd();\n            co_return;\n        });\n    co_await hs.start();\n}\n\nint main() {\n    simple_http::IoCtxPool pool{1};\n    pool.start();\n    asio::co_spawn(pool.getIoContext(), start(), asio::detached);\n    while (true)\n        sleep(1000);\n    return 0;\n}\n```\n## Client Example\n```\nimport std;\nimport simple_http;\n\nasio::awaitable\u003cvoid\u003e client(simple_http::IoCtxPool\u0026 pool) {\n    simple_http::HttpClientConfig cfg{\n        .host = \"127.0.0.1\",\n        .port = 7788,\n        .concurrent_streams = 200,\n        .use_tls = true,\n        .verify_peer = true,\n        .ssl_ca = \"./test/tls_certificates/ca_cert.pem\",\n        .ssl_crt = \"./test/tls_certificates/client_cert.pem\",\n        .ssl_key = \"./test/tls_certificates/client_key.pem\",\n        .ssl_context = nullptr,\n        .tlsext_host_name = \"SimpleHttpServer\",\n    };\n    // only support h2 and h2c not support http1.1\n    auto client = std::make_shared\u003csimple_http::Http2Client\u003e(cfg, pool.getIoContextPtr());\n    auto [ret, err] = co_await client-\u003easyncStart(std::chrono::seconds(5), asio::use_awaitable);\n    if (!ret) {\n        std::println(\"{}\", err);\n        co_return;\n    }\n    std::vector\u003cstd::pair\u003cstd::string, std::string\u003e\u003e headers{{\"test\", \"hello\"}};\n    auto stream_spec = std::make_shared\u003csimple_http::StreamSpec\u003e(simple_http::http::verb::post, \"/hello\", headers);\n    auto opt = co_await client-\u003eopenStream(stream_spec, asio::use_awaitable);\n    if (!opt) {\n        co_return;\n    }\n    auto\u0026 [w, r] = opt.value();\n    w-\u003ewriterBody(\"hello\", simple_http::WriteMode::More);\n    w-\u003ewriterBody(\"client\", simple_http::WriteMode::Last);\n    auto [ec, d] = co_await r-\u003easyncReadDataFrame();\n    if (std::holds_alternative\u003csimple_http::ParseHeaderDone\u003e(d)) {\n        std::println(\"recv ParseHeaderDone\");\n    }\n    for (;;) {\n        auto [ec, d] = co_await r-\u003easyncReadDataFrame();\n        if (ec) {\n            std::println(\"read error: {}\", ec.message());\n            break;\n        }\n        bool should_continue = std::visit(simple_http::overloaded{\n            [](std::string str) {\n                std::println(\"recv data: {}\", str);\n                return true;\n            },\n            [](simple_http::Eof) { return false; },\n            [](simple_http::Disconnect) { return false; },\n            [](simple_http::ParseHeaderDone) { return false; }}\n        , std::move(d));\n        if (!should_continue) {\n            break;\n        }\n    }\n    co_return;\n}\n\nint main() {\n    simple_http::LOG_CB = [](simple_http::LogLevel level, auto file, auto line, std::string msg) {\n        std::println(\"{} {} {} {}\", to_string(level), file, line, msg);\n    };\n    simple_http::IoCtxPool pool{1};\n    pool.start();\n    asio::co_spawn(pool.getIoContext(), client(pool), [](const std::exception_ptr\u0026 ep) {\n        try {\n            if (ep)\n                std::rethrow_exception(ep);\n        } catch (const std::exception\u0026 e) {\n            SIMPLE_HTTP_ERROR_LOG(\"{}\", e.what());\n        } catch (...) {\n            SIMPLE_HTTP_ERROR_LOG(\"unknown exception\");\n        }\n    });\n    while (true)\n        sleep(1000);\n    return 0;\n}\n```\n\n## 📊 Performance\n\nThe following benchmark was performed using `h2load`.\n\n**Machine Configuration:**\n- **OS**: Ubuntu 25.10\n- **CPU**: 13th Gen Intel(R) Core(TM) i7-13620H (16 vCPUs)\n- **Memory**: 41Gi RAM\n\n**Test Configuration:**\n- **Request Size**: 1KB (via `b.txt`)\n- **Response Size**: 10KB\n- **Command**: `h2load -t 4 -n 1000000 -c 1000 -m 40 -H 'Content-Type: application/json' --data=b.txt http://localhost:7788/hello`\n\n**Results:**\n\n```text\nfinished in 10.04s, 99558.82 req/s, 976.28MB/s\nrequests: 1000000 total, 1000000 started, 1000000 done, 1000000 succeeded, 0 failed, 0 errored, 0 timeout\nstatus codes: 1000000 2xx, 0 3xx, 0 4xx, 0 5xx\ntraffic: 9.58GB (10282450426) total, 2.89MB (3026000) headers (space savings 95.12%), 9.54GB (10243000000) data\n                     min         max         mean         sd        +/- sd\ntime for request:     5.99ms       1.43s    342.76ms    137.20ms    77.08%\ntime for connect:     5.65ms    151.01ms     62.93ms     37.19ms    67.60%\ntime to 1st byte:    79.20ms       1.02s    537.90ms    308.48ms    51.80%\nreq/s           :     100.72      124.03      105.92        4.56    71.10%\n```\n\n## Test Cmd\n```\ncurl -N -v --http2-prior-knowledge http://localhost:7788/hello\\?key1\\=value1\\\u0026key2\\=value2\ncurl -N -v --http2-prior-knowledge http://localhost:7788/hello -d \"abcd\"\ncurl -N -v --http2 http://localhost:7788/hello -d \"abcd\"\n\nnghttp --upgrade -v http://127.0.0.1:7788/hello\nnghttp --upgrade -v http://nghttp2.org\nh2load -n 60000 -c 1000 -m 200 -H 'Content-Type: application/json' --data=b.txt http://localhost:7788/hello\n\nneed define SIMPLE_HTTP_BIND_UNIX_SOCKET macro\ncurl --unix-socket /tmp/simple_http.sock https://SimpleHttpServer:7788/hello?123456 --cacert ca_cert.pem --cert client_cert.pem --key client_key.pem -X POST -d \"123\"\n```\n\n## 🤝 Contributing\n\nContributions of any kind are welcome! Please read [CONTRIBUTING.md](CONTRIBUTING.md) to learn how to contribute to the project.\n\n## 📄 License\n\n`simple_http` is licensed under the [MIT License](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffantasy-peak%2Fsimple_http","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffantasy-peak%2Fsimple_http","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffantasy-peak%2Fsimple_http/lists"}