aboutsummaryrefslogtreecommitdiff
path: root/src/zen/zen.cpp
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2026-03-10 17:27:26 +0100
committerGitHub Enterprise <[email protected]>2026-03-10 17:27:26 +0100
commitd0a07e555577dcd4a8f55f1b45d9e8e4e6366ab7 (patch)
tree2dfe1e3e0b620043d358e0b7f8bdf8320d985491 /src/zen/zen.cpp
parentchangelog entry which was inadvertently omitted from PR merge (diff)
downloadarchived-zen-d0a07e555577dcd4a8f55f1b45d9e8e4e6366ab7.tar.xz
archived-zen-d0a07e555577dcd4a8f55f1b45d9e8e4e6366ab7.zip
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<SocketType>` and `WsAsioConnectionT<SocketType>` 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
Diffstat (limited to 'src/zen/zen.cpp')
-rw-r--r--src/zen/zen.cpp75
1 files changed, 71 insertions, 4 deletions
diff --git a/src/zen/zen.cpp b/src/zen/zen.cpp
index 9a466da2e..86c29344e 100644
--- a/src/zen/zen.cpp
+++ b/src/zen/zen.cpp
@@ -196,6 +196,7 @@ ZenCmdBase::GetSubCommand(cxxopts::Options&,
ZenSubCmdBase::ZenSubCmdBase(std::string_view Name, std::string_view Description)
: m_SubOptions(std::string(Name), std::string(Description))
+, m_Description(Description)
{
m_SubOptions.add_options()("h,help", "Print help");
}
@@ -213,6 +214,35 @@ ZenCmdWithSubCommands::OnParentOptionsParsed(const ZenCliOptions& /*GlobalOption
}
void
+ZenCmdWithSubCommands::PrintHelp()
+{
+ // Show all option groups except the internal "__hidden__" group used to
+ // silently capture positional arguments.
+ std::vector<std::string> Groups = Options().groups();
+ Groups.erase(std::remove(Groups.begin(), Groups.end(), std::string("__hidden__")), Groups.end());
+
+ Options().set_width(TuiConsoleColumns(80));
+ printf("%s\n", Options().help(Groups).c_str());
+
+ // Append subcommand listing.
+ size_t MaxNameLen = 0;
+ for (ZenSubCmdBase* SubCmd : m_SubCommands)
+ {
+ MaxNameLen = std::max(MaxNameLen, SubCmd->SubOptions().program().size());
+ }
+
+ printf("subcommands:\n");
+ for (ZenSubCmdBase* SubCmd : m_SubCommands)
+ {
+ printf(" %-*s %s\n",
+ static_cast<int>(MaxNameLen),
+ SubCmd->SubOptions().program().c_str(),
+ std::string(SubCmd->Description()).c_str());
+ }
+ printf("\nFor global options run: zen --help\n");
+}
+
+void
ZenCmdWithSubCommands::Run(const ZenCliOptions& GlobalOptions, int argc, char** argv)
{
std::vector<cxxopts::Options*> SubOptionPtrs;
@@ -226,15 +256,47 @@ ZenCmdWithSubCommands::Run(const ZenCliOptions& GlobalOptions, int argc, char**
std::vector<char*> SubCommandArguments;
int ParentArgc = GetSubCommand(Options(), argc, argv, SubOptionPtrs, MatchedSubOption, SubCommandArguments);
- if (!ParseOptions(Options(), ParentArgc, argv))
+ // Intercept --help/-h in the parent arg range before calling ParseOptions so
+ // we can append subcommand information to the output. When a subcommand was
+ // found argv[ParentArgc-1] is the subcommand name itself, which we exclude.
+ int ParentArgEnd = (MatchedSubOption != nullptr) ? ParentArgc - 1 : ParentArgc;
+ for (int i = 1; i < ParentArgEnd; ++i)
{
- return;
+ std::string_view Arg(argv[i]);
+ if (Arg == "--help" || Arg == "-h")
+ {
+ PrintHelp();
+ return;
+ }
+ }
+
+ // Parse parent options. When a subcommand was matched we strip its name from
+ // the arg list so the parent parser does not see it as an unmatched positional.
+ if (MatchedSubOption != nullptr)
+ {
+ std::vector<char*> ParentArgs;
+ ParentArgs.reserve(static_cast<size_t>(ParentArgc - 1));
+ ParentArgs.push_back(argv[0]);
+ std::copy(argv + 1, argv + ParentArgc - 1, std::back_inserter(ParentArgs));
+ if (!ParseOptions(Options(), static_cast<int>(ParentArgs.size()), ParentArgs.data()))
+ {
+ return;
+ }
+ }
+ else
+ {
+ if (!ParseOptions(Options(), ParentArgc, argv))
+ {
+ return;
+ }
}
if (MatchedSubOption == nullptr)
{
+ PrintHelp();
+
ExtendableStringBuilder<128> VerbList;
- for (bool First = true; ZenSubCmdBase * SubCmd : m_SubCommands)
+ for (bool First = true; ZenSubCmdBase* SubCmd : m_SubCommands)
{
if (!First)
{
@@ -243,7 +305,7 @@ ZenCmdWithSubCommands::Run(const ZenCliOptions& GlobalOptions, int argc, char**
VerbList.Append(SubCmd->SubOptions().program());
First = false;
}
- throw OptionParseException(fmt::format("No subcommand specified. Available subcommands: {}", VerbList.ToView()), Options().help());
+ throw OptionParseException(fmt::format("No subcommand specified. Available subcommands: {}", VerbList.ToView()), {});
}
ZenSubCmdBase* MatchedSubCmd = nullptr;
@@ -621,6 +683,9 @@ main(int argc, char** argv)
Options.add_options()("malloc", "Configure memory allocator subsystem", cxxopts::value(MemoryOptions)->default_value("mimalloc"));
Options.add_options()("help", "Show command line help");
Options.add_options()("c, command", "Sub command", cxxopts::value<std::string>(SubCommand));
+ Options.add_options()("httpclient",
+ "Select HTTP client implementation (e.g. 'curl', 'cpr')",
+ cxxopts::value<std::string>(GlobalOptions.HttpClientBackend)->default_value("cpr"));
int CoreLimit = 0;
@@ -783,6 +848,8 @@ main(int argc, char** argv)
FreeCallstack(Callstack);
});
+ zen::SetDefaultHttpClientBackend(GlobalOptions.HttpClientBackend);
+
zen::MaximizeOpenFileCount();
//////////////////////////////////////////////////////////////////////////