From 7723e3b48a112d107bb0f6f3c0569b565e937e7d Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 13 Mar 2026 09:02:52 +0100 Subject: Switch httpclient default back-end over to libcurl (#832) Switches the default HTTP client to the libcurl-based backend and follows up with a series of correctness fixes and code quality improvements to `CurlHttpClient`. **Backend switch & build fixes:** - Switch default HTTP client to libcurl-based backend - Suppress `[[nodiscard]]` warning when building fmt - Miscellaneous bugfixes in HttpClient/libcurl - Pass `-y` to `xmake config` in `xmake test` task **Boilerplate reduction:** - Add `Session::SetHeaders()` for RAII ownership of `curl_slist`, eliminating manual `curl_slist_free_all` calls from every verb method - Add `Session::PerformWithResponseCallbacks()` to absorb the repeated 12-line write+header callback setup block - Extract `ParseHeaderLine()` shared helper, replacing 4 duplicate header-parsing implementations - Extract `BuildHeaderMap()` and `ApplyContentTypeFromHeaders()` helpers to deduplicate header-to-map conversion and Content-Type scanning - Unify the two `DoWithRetry` overloads (PayloadFile variant now delegates to the Validate variant) **Correctness fixes:** - `TransactPackage`: both phases now use `PerformWithResponseCallbacks()`, fixing missing abort support and a dead header collection loop - `TransactPackage`: error path now routes through `CommonResponse`, preserving curl error codes and messages for the caller - `ValidatePayload`: merged 3 separate header-scan loops into a single pass **Performance improvements:** - Replace `fmt::format` with `ExtendableStringBuilder` in `BuildHeaderList` and `BuildUrlWithParameters`, eliminating heap allocations in the common case - Replace `curl_easy_escape`/`curl_free` with inline URL percent-encoding using `AsciiSet` - Remove wasteful `CommonResponse(...)` construction in retry logging, formatting directly from `CurlResult` fields --- src/zencore/include/zencore/string.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'src/zencore/include') diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h index 4deca63ed..5a8a66fae 100644 --- a/src/zencore/include/zencore/string.h +++ b/src/zencore/include/zencore/string.h @@ -953,6 +953,24 @@ StrCaseCompare(const char* Lhs, const char* Rhs, int64_t Length = -1) #endif } +inline int32_t +StrCaseCompare(std::string_view Lhs, std::string_view Rhs) +{ + int32_t Result = StrCaseCompare(Lhs.data(), Rhs.data(), std::min(Lhs.size(), Rhs.size())); + if (Result == 0) + { + if (Lhs.size() < Rhs.size()) + { + return -1; + } + else if (Lhs.size() > Rhs.size()) + { + return 1; + } + } + return Result; +} + /** * @brief * Helper function to implement case sensitive spaceship operator for strings. -- cgit v1.2.3 From 3abde8d88bde436dce423eae9edee0f4e8af915a Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 13 Mar 2026 17:06:39 +0100 Subject: Add clang-cl build support - Add clang-cl warning suppressions in xmake.lua matching Linux/macOS set - Guard /experimental:c11atomics with {tools="cl"} for MSVC-only - Fix long long / int64_t redefinition in string.h for clang-cl - Fix unclosed namespace in callstacktrace.cpp #else branch - Fix missing override in httpplugin.cpp - Reorder WorkerPool fields to match designated initializer order - Use INVALID_SOCKET instead of SOCKET_ERROR for SOCKET comparisons --- src/zencore/include/zencore/string.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/zencore/include') diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h index 5a8a66fae..7b46f0e38 100644 --- a/src/zencore/include/zencore/string.h +++ b/src/zencore/include/zencore/string.h @@ -331,7 +331,7 @@ public: return AppendAscii(Str); } -#if defined(__clang__) && !defined(__APPLE__) +#if defined(__clang__) && !defined(__APPLE__) && !defined(_MSC_VER) /* UE Toolchain Clang has different types for int64_t and long long so an override is needed here. Without it, Clang can't disambiguate integer overloads */ inline StringBuilderImpl& operator<<(long long n) -- cgit v1.2.3 From 162d7412405e78198ede361a8fbae8dc8b82278a Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Fri, 13 Mar 2026 22:30:32 +0100 Subject: Made CPR optional, html generated at build time (#840) - Fix potential crash on startup caused by logging macros being invoked before the logging system is initialized (null logger dereference in `ZenServerState::Sweep()`). `LoggerRef::ShouldLog` now guards against a null logger pointer. - Make CPR an optional dependency (`--zencpr` build option, enabled by default) so builds can proceed without it - Make zenvfs Windows-only (platform-specific target) - Generate the frontend zip at build time from source HTML files instead of checking in a binary blob which would accumulate with every single update --- src/zencore/include/zencore/logbase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/zencore/include') diff --git a/src/zencore/include/zencore/logbase.h b/src/zencore/include/zencore/logbase.h index ad2ab218d..046e96db3 100644 --- a/src/zencore/include/zencore/logbase.h +++ b/src/zencore/include/zencore/logbase.h @@ -101,7 +101,7 @@ struct LoggerRef inline logging::Logger* operator->() const; inline logging::Logger& operator*() const; - bool ShouldLog(logging::LogLevel Level) const { return m_Logger->ShouldLog(Level); } + bool ShouldLog(logging::LogLevel Level) const { return m_Logger && m_Logger->ShouldLog(Level); } void SetLogLevel(logging::LogLevel NewLogLevel) { m_Logger->SetLevel(NewLogLevel); } logging::LogLevel GetLogLevel() { return m_Logger->GetLevel(); } -- cgit v1.2.3 From e5b97e8e769108ba45d6a064a46f892b68f1e950 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Mon, 16 Mar 2026 10:16:46 +0100 Subject: block/file cloning support for macOS / Linux (#786) - Add block cloning (copy-on-write) support for Linux and macOS to complement the existing Windows (ReFS) implementation - **Linux**: `TryCloneFile` via `FICLONE` ioctl, `CloneQueryInterface` with range cloning via `FICLONERANGE` (Btrfs/XFS) - **macOS**: `TryCloneFile` via `clonefile()` syscall (APFS), `SupportsBlockRefCounting` via `VOL_CAP_INT_CLONE`. `CloneQueryInterface` is not implemented as macOS lacks a sub-file range clone API - Promote `ScopedFd` to file scope for broader use in filesystem code - Add test scripts for block cloning validation on Linux (Btrfs via loopback) and macOS (APFS) - Also added test script for testing on Windows (ReFS) --- src/zencore/include/zencore/filesystem.h | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/zencore/include') diff --git a/src/zencore/include/zencore/filesystem.h b/src/zencore/include/zencore/filesystem.h index 16e2b59f8..6dc159a83 100644 --- a/src/zencore/include/zencore/filesystem.h +++ b/src/zencore/include/zencore/filesystem.h @@ -187,6 +187,14 @@ void ScanFile(void* NativeHandle, void WriteFile(void* NativeHandle, const void* Data, uint64_t Size, uint64_t FileOffset, uint64_t ChunkSize, std::error_code& Ec); void ReadFile(void* NativeHandle, void* Data, uint64_t Size, uint64_t FileOffset, uint64_t ChunkSize, std::error_code& Ec); +// Interface for sub-file range cloning on filesystems that support copy-on-write. +// GetCloneQueryInterface() returns nullptr on platforms without range clone support. +// +// Platform capabilities: +// Windows (ReFS) - True CoW range cloning via FSCTL_DUPLICATE_EXTENTS_TO_FILE. +// Linux (Btrfs/XFS) - True CoW range cloning via FICLONERANGE ioctl. +// macOS (APFS) - Not implemented. No sub-file range clone API exists. +// Whole-file CoW cloning is available via TryCloneFile (clonefile syscall). class CloneQueryInterface { public: -- cgit v1.2.3 From 6df7bce35e84f91c868face688587c26a3765c7e Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Mon, 16 Mar 2026 10:27:24 +0100 Subject: URI decoding, process env, compiler info, httpasio strands, regex route removal (#841) - Percent-decode URIs in ASIO HTTP server to match http.sys CookedUrl behavior, ensuring consistent decoded paths across backends - Add Environment field to CreateProcOptions for passing extra env vars to child processes (Windows: merged into Unicode environment block; Unix: setenv in fork) - Add GetCompilerName() and include it in build options startup logging - Suppress Windows CRT error dialogs in test harness for headless/CI runs - Fix mimalloc package: pass CMAKE_BUILD_TYPE, skip cfuncs test for cross-compile - Add virtual destructor to SentryAssertImpl to fix debug-mode warning - Simplify object store path handling now that URIs arrive pre-decoded - Add URI decoding test coverage for percent-encoded paths and query params - Simplify httpasio request handling by using strands (guarantees no parallel handlers per connection) - Removed deprecated regex-based route matching support - Fix full GC never triggering after cross-toolchain builds: The `gc_state` file stores `system_clock` ticks, but the tick resolution differs between toolchains (nanoseconds on GCC/standard clang, microseconds on UE clang). A nanosecond timestamp misinterpreted as microseconds appears far in the future (~year 58,000), bypassing the staleness check and preventing time-based full GC from ever running. Fixed by also resetting when the stored timestamp is in the future. - Clamp GC countdown display to configured interval: Prevents nonsensical log output (e.g. "Full GC in 492128002h") caused by the above or any other clock anomaly. The clamp applies to both the scheduler log and the status API. --- src/zencore/include/zencore/process.h | 9 +++++++++ src/zencore/include/zencore/system.h | 1 + 2 files changed, 10 insertions(+) (limited to 'src/zencore/include') diff --git a/src/zencore/include/zencore/process.h b/src/zencore/include/zencore/process.h index 809312c7b..3177f64c1 100644 --- a/src/zencore/include/zencore/process.h +++ b/src/zencore/include/zencore/process.h @@ -6,6 +6,9 @@ #include #include +#include +#include +#include namespace zen { @@ -68,6 +71,12 @@ struct CreateProcOptions const std::filesystem::path* WorkingDirectory = nullptr; uint32_t Flags = 0; std::filesystem::path StdoutFile; + + /// Additional environment variables for the child process. These are merged + /// with the parent's environment — existing variables are inherited, and + /// entries here override or add to them. + std::vector> Environment; + #if ZEN_PLATFORM_WINDOWS JobObject* AssignToJob = nullptr; // When set, the process is created suspended, assigned to the job, then resumed #endif diff --git a/src/zencore/include/zencore/system.h b/src/zencore/include/zencore/system.h index a67999e52..2e39cc660 100644 --- a/src/zencore/include/zencore/system.h +++ b/src/zencore/include/zencore/system.h @@ -17,6 +17,7 @@ std::string_view GetOperatingSystemName(); std::string GetOperatingSystemVersion(); std::string_view GetRuntimePlatformName(); // "windows", "wine", "linux", or "macos" std::string_view GetCpuName(); +std::string_view GetCompilerName(); struct SystemMetrics { -- cgit v1.2.3 From 79e10a165cf09dc2cc120b3a226c51f87c235f20 Mon Sep 17 00:00:00 2001 From: Stefan Boberg Date: Mon, 16 Mar 2026 10:52:45 +0100 Subject: Enable cross compilation of Windows targets on Linux (#839) This PR makes it *possible* to do a Windows build on Linux via `clang-cl`. It doesn't actually change any build process. No policy change, just mechanics and some code fixes to clear clang compilation. The code fixes are mainly related to #include file name casing, to match the on-disk casing of the SDK files (via xwin). --- src/zencore/include/zencore/string.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/zencore/include') diff --git a/src/zencore/include/zencore/string.h b/src/zencore/include/zencore/string.h index 7b46f0e38..60293a313 100644 --- a/src/zencore/include/zencore/string.h +++ b/src/zencore/include/zencore/string.h @@ -333,7 +333,8 @@ public: #if defined(__clang__) && !defined(__APPLE__) && !defined(_MSC_VER) /* UE Toolchain Clang has different types for int64_t and long long so an override is - needed here. Without it, Clang can't disambiguate integer overloads */ + needed here. Without it, Clang can't disambiguate integer overloads. + On MSVC ABI (including clang-cl), int64_t is long long so no separate overload is needed. */ inline StringBuilderImpl& operator<<(long long n) { IntNum Str(n); -- cgit v1.2.3