Radix Router Engine
Relevant source files
The following files were used as context for generating this wiki page:
The Radix Router Engine manages HTTP request routing by mapping URL paths to specific executable endpoints. It uses a specialized tree structure to perform high-performance path matching, supporting static routes, path parameters, and universal wildcards.
The engine integrates with the HXLibs coroutine system, allowing asynchronous execution of endpoint handlers and interceptors. It serves as the primary dispatching mechanism for the HttpServer, ensuring that incoming HttpRequest objects are routed to the correct logic based on the HTTP method and URI.
Sources: include/HXLibs/net/router/Router.hpp, include/HXLibs/net/router/RouterTree.hpp
Core Architecture
The routing system consists of three main layers: the Router frontend, the RouterTree management layer, and the underlying RadixTreeNode data structure.
Router Components
| Component | Description |
|---|---|
Router | The primary interface for adding endpoints and retrieving handlers based on method and path. |
RouterTree | Manages the hierarchical structure of path segments and handles the recursive lookup logic. |
RadixTreeNode | A node in the tree containing an optional endpoint and a map of child nodes indexed by path segments. |
EndpointFunc | A std::function wrapper for coroutine tasks that process HTTP requests and responses. |
Sources: include/HXLibs/net/router/Router.hpp:38-40, include/HXLibs/net/router/RouterTree.hpp:60-63, include/HXLibs/container/RadixTree.hpp:31-48
Relationship Diagram
This diagram shows the relationship between the high-level Router and the underlying Radix Tree nodes.
Path Matching Logic
The engine matches paths by splitting the URL into segments using the / delimiter. The first segment used in the internal lookup is always the HTTP Method (e.g., "GET", "POST").
Lookup Priority
When the RouterTree searches for a matching node, it follows a specific order of precedence:
- Static Match: Matches the exact string segment (e.g.,
home). - Path Parameter: Matches the segment against a
*wildcard if a parameter like{id}was registered. - Universal Wildcard: Matches the remainder of the path if a
**wildcard is present.
Sources: include/HXLibs/net/router/Router.hpp:51-55, include/HXLibs/net/router/RouterTree.hpp:117-130
Routing Flowchart
The following flowchart describes how an incoming request path is resolved to an endpoint.
Request Parsing and Wildcards
The engine supports dynamic path segments that extract data from the URL during routing. This is handled by the RequestTemplateParsing utility and internal logic within Router.
Parameter Types
| Wildcard Syntax | Internal Mapping | Description |
|---|---|---|
{variable} | * | Matches exactly one path segment and stores it in HttpRequest::_wildcarDataArr. |
/** | ** | Matches all remaining path segments and stores them in HttpRequest::_urlWildcardData. |
Sources: include/HXLibs/net/router/RouterTree.hpp:95-97, include/HXLibs/net/router/RequestParsing.hpp:40-58, include/HXLibs/net/router/Router.hpp:150-160
Parameter Extraction
When a route contains {} parameters, the Router pre-calculates the indices of these parameters during registration. When a request arrives, the engine extracts the values at these indices from the split path and populates the HttpRequest object.
// Example of path parameter extraction logic
auto pureRequesPath = req.getPureReqPath();
auto pathSplitArr = utils::StringUtil::split<std::string_view>(pureRequesPath, "/");
std::vector<std::string_view> wildcarArr;
for (auto idx : indexArr) {
wildcarArr.emplace_back(pathSplitArr[idx]);
}
req._wildcarDataArr = wildcarArr;
Sources: include/HXLibs/net/router/Router.hpp:172-179, include/HXLibs/net/protocol/http/Request.hpp:558-570
Interceptor Execution
The Router supports middleware-like interceptors that execute before and after the main endpoint handler. Interceptors must implement before and after methods.
Execution Sequence
- Before Interceptors: Executed in the order they were registered. If any
beforecall returnsfalse, the chain breaks, and the main endpoint is skipped. - Endpoint Handler: The core logic registered for the route.
- After Interceptors: Executed after the endpoint finishes.
Sources: include/HXLibs/net/router/Router.hpp:163-189, 219-244
Sequence Diagram: Request Handling
Error Handling
If the RouterTree fails to find a matching node, it returns a _notFoundHandler. By default, this handler returns an HTTP 404 response with a standard HTML body. Developers can customize this behavior using setErrorEndpointFunc.
Sources: include/HXLibs/net/router/RouterTree.hpp:64-85, include/HXLibs/net/router/Router.hpp:67-87
Technical Implementation Details
- RadixTree Specialization: The implementation is a string-based version of a trie, optimized for URL segments divided by
/. Sources: include/HXLibs/container/RadixTree.hpp:50-55 - Transparent Hashing: Uses
internal::StrHashandinternal::StrEqto allowstd::unordered_maplookups usingstd::string_viewwithout creating temporarystd::stringobjects. Sources: include/HXLibs/net/router/RouterTree.hpp:36-57 - Method-Based Rooting: The tree effectively creates a separate namespace for every HTTP method by making the method string the first key in every
buildLink. Sources: include/HXLibs/net/router/Router.hpp:212-216
The Radix Router Engine provides a structured and efficient way to handle complex URL patterns while maintaining low latency through prefix-based matching and coroutine-safe execution.
Sources: include/HXLibs/net/router/Router.hpp, tests/net/router/router.cpp