{"id":51620665,"url":"https://github.com/SSARCandy/cofetch","last_synced_at":"2026-07-28T01:00:42.434Z","repository":{"id":370670674,"uuid":"612883365","full_name":"SSARCandy/cofetch","owner":"SSARCandy","description":"Chainable, high-performance async HTTP client for modern C++ event loops.","archived":false,"fork":false,"pushed_at":"2026-07-10T07:19:40.000Z","size":276,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-07-10T07:19:45.272Z","etag":null,"topics":["asio","async","coroutines","cpp17","cpp20","curl","http-client","libcurl"],"latest_commit_sha":null,"homepage":"http://ssarcandy.tw/cofetch/","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/SSARCandy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":"2023-03-12T09:12:42.000Z","updated_at":"2026-07-10T07:10:32.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SSARCandy/cofetch","commit_stats":null,"previous_names":["ssarcandy/cofetch"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/SSARCandy/cofetch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SSARCandy%2Fcofetch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SSARCandy%2Fcofetch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SSARCandy%2Fcofetch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SSARCandy%2Fcofetch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SSARCandy","download_url":"https://codeload.github.com/SSARCandy/cofetch/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SSARCandy%2Fcofetch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35970843,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-27T02:00:06.776Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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","async","coroutines","cpp17","cpp20","curl","http-client","libcurl"],"created_at":"2026-07-12T19:00:23.761Z","updated_at":"2026-07-28T01:00:42.424Z","avatar_url":"https://github.com/SSARCandy.png","language":"C++","funding_links":[],"categories":["Networking"],"sub_categories":[],"readme":"# cofetch: async HTTP client for C++.\n\n[![CI](https://github.com/SSARCandy/cofetch/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/SSARCandy/cofetch/actions/workflows/ci.yml)\n[![codecov](https://codecov.io/gh/SSARCandy/cofetch/graph/badge.svg)](https://codecov.io/gh/SSARCandy/cofetch)\n[![Documentation](https://img.shields.io/badge/docs-online-informational?style=flat\u0026link=https://ssarcandy.tw/cofetch)](https://ssarcandy.tw/cofetch)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n\nRequests **build as a chain**, setters flow off `request()` and the HTTP verb fires the transfer, without blocking the thread:\n\n```cpp\nhttp\n  .request(\"https://api.example.com/orders\")\n  .headers({\"content-type: application/json\"})\n  .body(R\"({\"qty\": 1})\")\n  .timeout(std::chrono::seconds(2))\n  .post([](std::error_code ec, cofetch::Response res) {\n    // transport errors in ec; HTTP status in res.http_code_\n  });\n```\n\nOn C++20 that includes coroutines: dependent requests in linear code, no nesting:\n\n```cpp\nconst auto user  = co_await http.async_get(api + \"/user\", asio::use_awaitable);\nconst auto posts = co_await http.async_post(api + \"/posts\", user.data_, asio::use_awaitable);\n```\n\n## Why cofetch\n\n- **Header-only.** One file, bring libcurl (linked) and ASIO (include path), then `#include \u003ccofetch.h\u003e`.\n- **Chainable syntax.** Build a request with setters, fire it with the HTTP verb. The same chain works with callbacks, futures, or coroutines.\n- **ASIO-native.** Requests run on the `asio::io_context`. Drive it with `run()`, or `poll()` it from a busy loop that must never block.\n- **C++17-friendly.** Works on C++17; C++20 adds the `co_await` interface.\n- **libcurl underneath.** HTTP/1.1 and HTTP/2 multiplexing, TLS, compression, connection pooling, redirects. For anything cofetch does not wrap, `.curl([](CURL* h) { ... })` exposes the raw handle per request.\n\n## Benchmarks\n\nSame workload for every client: 20,000 GETs against a local nginx. [cpr](https://github.com/libcpr/cpr) and [cpp-httplib](https://github.com/yhirose/cpp-httplib) are synchronous (one request per thread); cofetch keeps 100 in flight requests on a single thread, and wins every scenario: **+35%** single-thread throughput over the fastest sync client, **+31%** with one event loop per core against equal-sized thread pools, **+16%** on sequential chains driven from a busy-poll loop.\n\n\u003cpicture\u003e\n  \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"docs/benchmark-dark.svg\"\u003e\n  \u003cimg alt=\"cofetch benchmark results\" src=\"docs/benchmark-light.svg\"\u003e\n\u003c/picture\u003e\n\nExact numbers, environment, and how to reproduce:\n[bench/README.md](bench/README.md).\n\n## Quick start\n\n```cpp\n#include \u003casio.hpp\u003e\n#include \u003ciostream\u003e\n#include \u003ccofetch.h\u003e\n\nint main() {\n  asio::io_context io;\n  cofetch::Client http(io);\n\n  http\n    .request(\"https://postman-echo.com/post\")\n    .body(\"hello=cofetch\")\n    .post([](std::error_code ec, cofetch::Response res) {\n      if (ec) {\n        std::cerr \u003c\u003c ec.message() \u003c\u003c \"\\n\";  // DNS, TLS, timeout...\n        return;\n      }\n      std::cout \u003c\u003c res.http_code_ \u003c\u003c \" \" \u003c\u003c res.data_ \u003c\u003c \"\\n\";\n    });\n\n  io.run();  // or io.poll() from your own loop — examples/example_reactors.cpp\n}\n```\n\nOn C++20 the same flow reads linearly with `co_await` (`examples/example_coroutine.cpp`); the full set lives in [examples/](examples/README.md). Every public symbol at a glance: the [API reference](docs/api-reference.md) cheatsheet.\n\nPrefer a plain value? `cofetch::Request` holds the same fields and fires later via `http.async_perform(std::move(req), token)`.\n\n## Installation\n\nRequirements:\n- libcurl ≥ 7.55 (dev headers)\n- C++17 compiler (the `co_await` interface needs C++20)\n- [ASIO](https://github.com/chriskohlhoff/asio) or Boost.Asio, via `-DCOFETCH_USE_BOOST_ASIO=ON`\n\n### vcpkg\n\ncofetch is in the [vcpkg registry](https://github.com/microsoft/vcpkg/tree/master/ports/cofetch); `asio` and `curl` come along as dependencies, so this is the turnkey path:\n\n```bash\nvcpkg install cofetch\n```\n\n```cmake\nfind_package(cofetch CONFIG REQUIRED)\ntarget_link_libraries(your_app PRIVATE cofetch::cofetch)\n```\n\n### CMake (FetchContent)\n\n```cmake\ninclude(FetchContent)\nFetchContent_Declare(cofetch\n    GIT_REPOSITORY https://github.com/SSARCandy/cofetch.git\n    GIT_TAG v0.1.2\n)\nFetchContent_MakeAvailable(cofetch)\ntarget_link_libraries(your_app PRIVATE cofetch::cofetch)\n```\n\ncofetch does not impose an ASIO on consumers: point it at yours (any include path providing `\u003casio.hpp\u003e`), or enable the vendored submodule with `-DCOFETCH_USE_VENDORED_ASIO=ON`.\n\n### Manual\n\nCopy `include/cofetch.h`, add asio to your include path, link `libcurl`.\n\n## What cofetch is not\n\n- **Not a server.** Client only. For a server (or a tiny zero-dependency client), use [cpp-httplib](https://github.com/yhirose/cpp-httplib).\n- **Not thread-safe.** One `Client` per `io_context` thread by design, no locks on the hot path. The client must outlive its in-flight requests.\n\n## Development\n\n```bash\ngit submodule update --init          # asio + googletest (dev only)\n./build.sh -t                        # Debug build + tests + coverage\n./linter.sh                          # clang-format check (v19 pinned in CI)\ndoxygen Doxyfile                     # API reference -\u003e docs/api/html/\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSSARCandy%2Fcofetch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSSARCandy%2Fcofetch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSSARCandy%2Fcofetch/lists"}