From d0a07e555577dcd4a8f55f1b45d9e8e4e6366ab7 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Tue, 10 Mar 2026 17:27:26 +0100 Subject: HttpClient using libcurl, Unix Sockets for HTTP. HTTPS support (#770) The main goal of this change is to eliminate the cpr back-end altogether and replace it with the curl implementation. I would expect to drop cpr as soon as we feel happy with the libcurl back-end. That would leave us with a direct dependency on libcurl only, and cpr can be eliminated as a dependency. ### HttpClient Backend Overhaul - Implemented a new **libcurl-based HttpClient** backend (`httpclientcurl.cpp`, ~2000 lines) as an alternative to the cpr-based one - Made HttpClient backend **configurable at runtime** via constructor arguments and `-httpclient=...` CLI option (for zen, zenserver, and tests) - Extended HttpClient test suite to cover multipart/content-range scenarios ### Unix Domain Socket Support - Added Unix domain socket support to **httpasio** (server side) - Added Unix domain socket support to **HttpClient** - Added Unix domain socket support to **HttpWsClient** (WebSocket client) - Templatized `HttpServerConnectionT` and `WsAsioConnectionT` to handle TCP, Unix, and SSL sockets uniformly via `if constexpr` dispatch ### HTTPS Support - Added **preliminary HTTPS support to httpasio** (for Mac/Linux via OpenSSL) - Added **basic HTTPS support for http.sys** (Windows) - Implemented HTTPS test for httpasio - Split `InitializeServer` into smaller sub-functions for http.sys ### Other Notable Changes - Improved **zenhttp-test stability** with dynamic port allocation - Enhanced port retry logic in http.sys (handles ERROR_ACCESS_DENIED) - Fatal signal/exception handlers for backtrace generation in tests - Added `zen bench http` subcommand to exercise network + HTTP client/server communication stack --- src/zenhttp/clients/httpclientcommon.cpp | 57 ++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'src/zenhttp/clients/httpclientcommon.cpp') diff --git a/src/zenhttp/clients/httpclientcommon.cpp b/src/zenhttp/clients/httpclientcommon.cpp index 6f4c67dd0..e4d11547a 100644 --- a/src/zenhttp/clients/httpclientcommon.cpp +++ b/src/zenhttp/clients/httpclientcommon.cpp @@ -646,6 +646,63 @@ TEST_CASE("CompositeBufferReadStream") CHECK_EQ(IoHash::HashBuffer(Data), testutil::HashComposite(Data)); } +TEST_CASE("ParseContentRange") +{ + SUBCASE("normal range with total size") + { + auto [Offset, Length] = detail::ParseContentRange("bytes 0-99/500"); + CHECK_EQ(Offset, 0); + CHECK_EQ(Length, 100); + } + + SUBCASE("non-zero offset") + { + auto [Offset, Length] = detail::ParseContentRange("bytes 2638-5111437/44369878"); + CHECK_EQ(Offset, 2638); + CHECK_EQ(Length, 5111437 - 2638 + 1); + } + + SUBCASE("wildcard total size") + { + auto [Offset, Length] = detail::ParseContentRange("bytes 100-199/*"); + CHECK_EQ(Offset, 100); + CHECK_EQ(Length, 100); + } + + SUBCASE("no slash (total size omitted)") + { + auto [Offset, Length] = detail::ParseContentRange("bytes 50-149"); + CHECK_EQ(Offset, 50); + CHECK_EQ(Length, 100); + } + + SUBCASE("malformed input returns zeros") + { + auto [Offset1, Length1] = detail::ParseContentRange("not-bytes 0-99/500"); + CHECK_EQ(Offset1, 0); + CHECK_EQ(Length1, 0); + + auto [Offset2, Length2] = detail::ParseContentRange("bytes abc-def/500"); + CHECK_EQ(Offset2, 0); + CHECK_EQ(Length2, 0); + + auto [Offset3, Length3] = detail::ParseContentRange(""); + CHECK_EQ(Offset3, 0); + CHECK_EQ(Length3, 0); + + auto [Offset4, Length4] = detail::ParseContentRange("bytes 100/500"); + CHECK_EQ(Offset4, 0); + CHECK_EQ(Length4, 0); + } + + SUBCASE("single byte range") + { + auto [Offset, Length] = detail::ParseContentRange("bytes 42-42/1000"); + CHECK_EQ(Offset, 42); + CHECK_EQ(Length, 1); + } +} + TEST_CASE("MultipartBoundaryParser") { uint64_t Range1Offset = 2638; -- cgit v1.2.3