From 3cf080c7bd6a92d3e2a622406153b1dea1cb40e4 Mon Sep 17 00:00:00 2001 From: Juan Cruz Viotti Date: Tue, 24 Feb 2026 15:42:59 -0400 Subject: [PATCH] Upgrade Core to `5d5098cc7c7537f4ff3da9848233ea314faffb2f` Signed-off-by: Juan Cruz Viotti --- DEPENDENCIES | 2 +- .../core/src/core/uritemplate/CMakeLists.txt | 2 - .../sourcemeta/core/uritemplate_error.h | 20 ++++ .../sourcemeta/core/uritemplate_router.h | 6 +- .../uritemplate/uritemplate_router_view.cc | 101 +++++++++++++++--- 5 files changed, 108 insertions(+), 23 deletions(-) diff --git a/DEPENDENCIES b/DEPENDENCIES index 85bebd7d..4f3f73af 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -1,6 +1,6 @@ vendorpull https://github.com/sourcemeta/vendorpull 1dcbac42809cf87cb5b045106b863e17ad84ba02 uwebsockets https://github.com/uNetworking/uWebSockets v20.75.0 -core https://github.com/sourcemeta/core bfe15320e844eb6b2a93e9f6cb5601f0b4726d9a +core https://github.com/sourcemeta/core 5d5098cc7c7537f4ff3da9848233ea314faffb2f blaze https://github.com/sourcemeta/blaze e4d790d56981aa746702a4041a205cc3afdfcfb1 jsonbinpack https://github.com/sourcemeta/jsonbinpack c9038f1ca016890cf0dc6929e668b77784f91332 hydra https://github.com/sourcemeta/hydra 2f46a5e2d1b24fd1bdd2d4b98e71646403a6bdce diff --git a/vendor/core/src/core/uritemplate/CMakeLists.txt b/vendor/core/src/core/uritemplate/CMakeLists.txt index 427d7955..cf03111b 100644 --- a/vendor/core/src/core/uritemplate/CMakeLists.txt +++ b/vendor/core/src/core/uritemplate/CMakeLists.txt @@ -5,5 +5,3 @@ sourcemeta_library(NAMESPACE sourcemeta PROJECT core NAME uritemplate if(SOURCEMETA_CORE_INSTALL) sourcemeta_library_install(NAMESPACE sourcemeta PROJECT core NAME uritemplate) endif() - -target_link_libraries(sourcemeta_core_uritemplate PUBLIC sourcemeta::core::io) diff --git a/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_error.h b/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_error.h index 0898a39c..9a7b42d0 100644 --- a/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_error.h +++ b/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_error.h @@ -123,6 +123,26 @@ class SOURCEMETA_CORE_URITEMPLATE_EXPORT URITemplateRouterSaveError const char *message_; }; +/// @ingroup uritemplate +/// An error that represents a failure to read the router from disk +class SOURCEMETA_CORE_URITEMPLATE_EXPORT URITemplateRouterReadError + : public std::exception { +public: + URITemplateRouterReadError(std::filesystem::path path) + : path_{std::move(path)} {} + + [[nodiscard]] auto what() const noexcept -> const char * override { + return "Failed to open router file for reading"; + } + + [[nodiscard]] auto path() const noexcept -> const std::filesystem::path & { + return this->path_; + } + +private: + std::filesystem::path path_; +}; + #if defined(_MSC_VER) #pragma warning(default : 4251 4275) #endif diff --git a/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_router.h b/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_router.h index 81d80103..702b7aa4 100644 --- a/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_router.h +++ b/vendor/core/src/core/uritemplate/include/sourcemeta/core/uritemplate_router.h @@ -5,8 +5,6 @@ #include #endif -#include - #include // std::uint16_t, std::uint32_t, std::uint8_t #include // std::filesystem::path #include // std::function @@ -85,7 +83,7 @@ class SOURCEMETA_CORE_URITEMPLATE_EXPORT URITemplateRouter { }; /// @ingroup uritemplate -/// A read-only memory-mapped view of a serialized URI Template router +/// A read-only view of a serialized URI Template router class SOURCEMETA_CORE_URITEMPLATE_EXPORT URITemplateRouterView { public: /// A serialized node in the binary format @@ -127,7 +125,7 @@ class SOURCEMETA_CORE_URITEMPLATE_EXPORT URITemplateRouterView { -> URITemplateRouter::Identifier; private: - FileView file_view_; + std::vector data_; }; #if defined(_MSC_VER) diff --git a/vendor/core/src/core/uritemplate/uritemplate_router_view.cc b/vendor/core/src/core/uritemplate/uritemplate_router_view.cc index 425e0f34..882137a2 100644 --- a/vendor/core/src/core/uritemplate/uritemplate_router_view.cc +++ b/vendor/core/src/core/uritemplate/uritemplate_router_view.cc @@ -2,7 +2,7 @@ #include // assert #include // std::memcmp -#include // std::ofstream +#include // std::ofstream, std::ifstream #include // std::numeric_limits #include // std::queue #include // std::string @@ -28,8 +28,14 @@ struct RouterHeader { inline auto binary_search_literal_children( const URITemplateRouterView::Node *nodes, const char *string_table, const std::uint32_t first_child, const std::uint32_t child_count, - const char *segment, const std::uint32_t segment_length) noexcept - -> std::uint32_t { + const char *segment, const std::uint32_t segment_length, + const std::uint32_t node_count, const std::size_t string_table_size) + noexcept -> std::uint32_t { + if (first_child >= node_count || + first_child + child_count > node_count) { + return NO_CHILD; + } + std::uint32_t low = 0; std::uint32_t high = child_count; @@ -37,6 +43,9 @@ inline auto binary_search_literal_children( const auto middle = low + (high - low) / 2; const auto child_index = first_child + middle; const auto &child = nodes[child_index]; + if (child.string_offset + child.string_length > string_table_size) { + return NO_CHILD; + } // Compare segments lexicographically (content first, then length) const auto min_length = segment_length < child.string_length @@ -170,21 +179,65 @@ auto URITemplateRouterView::save(const URITemplateRouter &router, } } -URITemplateRouterView::URITemplateRouterView(const std::filesystem::path &path) - : file_view_{path} {} +URITemplateRouterView::URITemplateRouterView( + const std::filesystem::path &path) { + std::ifstream file(path, std::ios::binary | std::ios::ate); + if (!file) { + throw URITemplateRouterReadError{path}; + } + + const auto position = file.tellg(); + if (position < 0) { + throw URITemplateRouterReadError{path}; + } + + const auto size = static_cast(position); + file.seekg(0, std::ios::beg); + this->data_.resize(size); + file.read(reinterpret_cast(this->data_.data()), + static_cast(size)); + if (!file) { + throw URITemplateRouterReadError{path}; + } + + if (size < sizeof(RouterHeader)) { + throw URITemplateRouterReadError{path}; + } + + const auto *header = + reinterpret_cast(this->data_.data()); + if (header->magic != ROUTER_MAGIC || header->version != ROUTER_VERSION) { + throw URITemplateRouterReadError{path}; + } + + const auto minimum_size = + sizeof(RouterHeader) + header->node_count * sizeof(Node); + if (minimum_size > size) { + throw URITemplateRouterReadError{path}; + } +} auto URITemplateRouterView::match(const std::string_view path, const URITemplateRouter::Callback &callback) const -> URITemplateRouter::Identifier { - const auto *header = this->file_view_.as(); - assert(header->magic == ROUTER_MAGIC); - assert(header->version == ROUTER_VERSION); + const auto *header = + reinterpret_cast(this->data_.data()); + const auto node_count = header->node_count; + if (node_count == 0) { + return 0; + } - const auto *nodes = this->file_view_.as(sizeof(RouterHeader)); + const auto *nodes = + reinterpret_cast(this->data_.data() + sizeof(RouterHeader)); const auto *string_table = - header->string_table_offset < this->file_view_.size() - ? this->file_view_.as(header->string_table_offset) + header->string_table_offset <= this->data_.size() + ? reinterpret_cast(this->data_.data() + + header->string_table_offset) : nullptr; + const auto string_table_size = + string_table != nullptr + ? this->data_.size() - header->string_table_offset + : 0; // Empty path matches empty template if (path.empty()) { @@ -200,7 +253,7 @@ auto URITemplateRouterView::match(const std::string_view path, const auto match = binary_search_literal_children( nodes, string_table, root.first_literal_child, root.literal_child_count, - "", 0); + "", 0, node_count, string_table_size); return match != NO_CHILD ? nodes[match].identifier : 0; } @@ -231,13 +284,18 @@ auto URITemplateRouterView::match(const std::string_view path, return 0; } + if (current_node >= node_count) { + return 0; + } + const auto &node = nodes[current_node]; // Try literal children first if (node.first_literal_child != NO_CHILD) { const auto literal_match = binary_search_literal_children( nodes, string_table, node.first_literal_child, - node.literal_child_count, segment_start, segment_length); + node.literal_child_count, segment_start, segment_length, + node_count, string_table_size); if (literal_match != NO_CHILD) { current_node = literal_match; if (position >= path_end) { @@ -249,10 +307,17 @@ auto URITemplateRouterView::match(const std::string_view path, } // Fall back to variable child - if (node.variable_child != NO_CHILD) { - assert(variable_index <= - std::numeric_limits::max()); + if (node.variable_child != NO_CHILD && node.variable_child < node_count) { + if (variable_index > + std::numeric_limits::max()) { + return 0; + } + const auto &variable_node = nodes[node.variable_child]; + if (variable_node.string_offset + variable_node.string_length > + string_table_size) { + return 0; + } // Check if this is an expansion (catch-all) if (variable_node.type == URITemplateRouter::NodeType::Expansion) { @@ -283,6 +348,10 @@ auto URITemplateRouterView::match(const std::string_view path, return 0; } + if (current_node >= node_count) { + return 0; + } + return nodes[current_node].identifier; }