Skip to content

Commit dcee7a2

Browse files
etrclaude
andcommitted
refactor: rename radix_tree->segment_trie and modded_request::dhr->request
Two mechanical renames (bundled -- they overlap in webserver_request.cpp and webserver_dispatch.cpp, so they cannot be split cleanly at file granularity). Both are pure renames; no behavior change. Build green, full suite 109/109. 1. radix_tree data structure -> segment_trie The structure is an uncompressed per-segment trie (one node per '/'- delimited path segment, no edge compression), not a radix tree: radix_tree -> segment_trie radix_node -> segment_trie_node radix_match -> segment_trie_match radix_tree.hpp -> segment_trie.hpp (+ include guard) plus "radix tree"/"radix-tree" prose -> "segment trie". The route *tier* keeps its historical name (route_tier_kind::radix, "radix tier", upsert_v2_radix_route) -- a separate concept (the parameterized-path tier), out of scope here. 2. modded_request::dhr member -> request `dhr` was inherited v1 shorthand carried through ~50 dispatch call sites as mr->dhr; now mr->request. Unrelated local `dhr` header-map variables in http_request_impl.cpp and the v1 baseline benchmark are left untouched. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 0136578 commit dcee7a2

23 files changed

Lines changed: 171 additions & 169 deletions

src/Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ libhttpserver_la_SOURCES = string_utilities.cpp webserver.cpp webserver_add_hook
2929
# noinst_HEADERS: shipped in the tarball but NEVER installed under $prefix/include.
3030
# Detail headers (httpserver/detail/*.hpp) live here so they cannot leak to
3131
# downstream consumers — the public surface comes in through <httpserver.hpp>.
32-
noinst_HEADERS = httpserver/string_utilities.hpp httpserver/detail/modded_request.hpp httpserver/detail/http_endpoint.hpp httpserver/detail/body.hpp httpserver/detail/webserver_impl.hpp httpserver/detail/webserver_impl_dispatch.hpp httpserver/detail/connection_state.hpp httpserver/detail/secure_zero.hpp httpserver/detail/http_request_impl.hpp httpserver/detail/resource_hook_table.hpp httpserver/detail/route_entry.hpp httpserver/detail/lambda_resource.hpp httpserver/detail/radix_tree.hpp httpserver/detail/route_cache.hpp httpserver/detail/route_tier.hpp httpserver/detail/unescape_helpers.hpp gettext.h
32+
noinst_HEADERS = httpserver/string_utilities.hpp httpserver/detail/modded_request.hpp httpserver/detail/http_endpoint.hpp httpserver/detail/body.hpp httpserver/detail/webserver_impl.hpp httpserver/detail/webserver_impl_dispatch.hpp httpserver/detail/connection_state.hpp httpserver/detail/secure_zero.hpp httpserver/detail/http_request_impl.hpp httpserver/detail/resource_hook_table.hpp httpserver/detail/route_entry.hpp httpserver/detail/lambda_resource.hpp httpserver/detail/segment_trie.hpp httpserver/detail/route_cache.hpp httpserver/detail/route_tier.hpp httpserver/detail/unescape_helpers.hpp gettext.h
3333
nobase_include_HEADERS = httpserver.hpp httpserver/body_kind.hpp httpserver/cookie.hpp httpserver/constants.hpp httpserver/create_webserver.hpp httpserver/create_webserver_setters.hpp httpserver/create_test_request.hpp httpserver/webserver.hpp httpserver/webserver_routes.hpp httpserver/webserver_runtime.hpp httpserver/webserver_websocket.hpp httpserver/webserver_hooks.hpp httpserver/websocket_handler.hpp httpserver/http_utils.hpp httpserver/http_utils_inet.hpp httpserver/ip_representation.hpp httpserver/file_info.hpp httpserver/http_request.hpp httpserver/http_request_auth.hpp httpserver/http_request_getters.hpp httpserver/http_response.hpp httpserver/http_response_factories.hpp httpserver/http_resource.hpp httpserver/feature_unavailable.hpp httpserver/iovec_entry.hpp httpserver/http_arg_value.hpp httpserver/http_method.hpp httpserver/hook_phase.hpp httpserver/hook_action.hpp httpserver/hook_handle.hpp httpserver/hook_context.hpp
3434

3535
AM_CXXFLAGS += -fPIC -Wall

src/detail/webserver_aliases.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ void install_internal_error_alias(
101101
impl->handler_exception_alias_ =
102102
[user_handler = std::move(user_handler)](
103103
const handler_exception_ctx& ctx) -> hook_action {
104-
// mr->dhr is always non-null at the call site in
104+
// mr->request is always non-null at the call site in
105105
// handle_dispatch_exception; this guard is purely defensive for
106106
// any future call site that relaxes that invariant. If that
107107
// invariant is violated in debug builds, assert fires first.

src/detail/webserver_body_pipeline.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ bool fire_and_maybe_short_circuit_body_chunk(webserver_impl* impl,
9999
// upload callback (the *upload_data_size == 0 call that routes to
100100
// complete_request), which never reaches this fire site.
101101
::httpserver::body_chunk_ctx ctx{
102-
mr->dhr.get(),
102+
mr->request.get(),
103103
std::as_bytes(std::span<const char>(upload_data, upload_data_size)),
104104
mr->body_bytes_seen,
105105
/*is_final=*/false};
@@ -199,11 +199,11 @@ MHD_Result webserver_impl::requests_answer_first_step(MHD_Connection* connection
199199
// MHD_CONNECTION_INFO_SOCKET_CONTEXT, then allocates the http_request_impl
200200
// from that arena. The arena plumbing is therefore implicit at this call
201201
// site but explicit within the constructor.
202-
mr->dhr.reset(new http_request(connection, parent->unescaper));
203-
mr->dhr->set_file_cleanup_callback(parent->file_cleanup_callback);
202+
mr->request.reset(new http_request(connection, parent->unescaper));
203+
mr->request->set_file_cleanup_callback(parent->file_cleanup_callback);
204204
// Propagate the redaction-bypass bit so operator<< honours
205205
// the builder opt-in for every request the webserver dispatches.
206-
mr->dhr->set_expose_credentials_in_logs(parent->expose_credentials_in_logs);
206+
mr->request->set_expose_credentials_in_logs(parent->expose_credentials_in_logs);
207207

208208
// request_received hook. Fires after the http_request is
209209
// populated but before any body bytes are read (and before any
@@ -216,7 +216,7 @@ MHD_Result webserver_impl::requests_answer_first_step(MHD_Connection* connection
216216
// No post-processor exists at this point, so no teardown is needed.
217217
if (has_hooks_for(::httpserver::hook_phase::request_received)) {
218218
::httpserver::request_received_ctx ctx{
219-
mr->dhr.get(),
219+
mr->request.get(),
220220
std::chrono::steady_clock::now()};
221221
if (auto sc = fire_request_received(ctx)) {
222222
mr->response.emplace(std::move(*sc));
@@ -229,7 +229,7 @@ MHD_Result webserver_impl::requests_answer_first_step(MHD_Connection* connection
229229
return MHD_YES;
230230
}
231231

232-
mr->dhr->set_content_size_limit(parent->content_size_limit);
232+
mr->request->set_content_size_limit(parent->content_size_limit);
233233
const char *encoding = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, http_utils::http_header_content_type);
234234

235235
if (parent->post_process_enabled &&
@@ -265,7 +265,7 @@ MHD_Result webserver_impl::requests_answer_second_step(MHD_Connection* connectio
265265
}
266266

267267
// body_chunk hook fires per chunk BEFORE the bytes are
268-
// appended to mr->dhr / fed to MHD_post_process.
268+
// appended to mr->request / fed to MHD_post_process.
269269
if (has_hooks_for(::httpserver::hook_phase::body_chunk)) {
270270
if (fire_and_maybe_short_circuit_body_chunk(
271271
this, mr, upload_data, *upload_data_size)) {
@@ -294,7 +294,7 @@ MHD_Result webserver_impl::requests_answer_second_step(MHD_Connection* connectio
294294
// all other content (which is indicated by mr-pp == nullptr)
295295
// has to be put to the content even if put_processed_data_to_content is set to false
296296
if (mr->pp == nullptr || parent->put_processed_data_to_content) {
297-
mr->dhr->grow_content(upload_data, *upload_data_size);
297+
mr->request->grow_content(upload_data, *upload_data_size);
298298
}
299299
run_post_processor_if_attached(mr, parent, upload_data, *upload_data_size);
300300

src/detail/webserver_callbacks.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void webserver_impl::request_completed(void *cls, struct MHD_Connection *connect
9999
// Fire request_completed BEFORE the modded_request is
100100
// destroyed so the ctx pointers remain backed by live storage. The
101101
// gate-and-fire helper reads any_hooks_[request_completed] and
102-
// builds the ctx from mr->dhr, mr->response, and the MHD
102+
// builds the ctx from mr->request, mr->response, and the MHD
103103
// termination code. The fire site is the very first thing this
104104
// callback does, while mr is still untouched.
105105
auto* mr = static_cast<detail::modded_request*>(*con_cls);
@@ -380,9 +380,9 @@ MHD_Result webserver_impl::handle_post_form_arg(detail::modded_request* mr,
380380
// means MHD is feeding us a continuation chunk of a previously-
381381
// started value, so append rather than replace.
382382
if (off > 0) {
383-
mr->dhr->grow_last_arg(key, std::string(data, size));
383+
mr->request->grow_last_arg(key, std::string(data, size));
384384
} else {
385-
mr->dhr->set_arg(key, std::string(data, size));
385+
mr->request->set_arg(key, std::string(data, size));
386386
}
387387
return MHD_YES;
388388
}
@@ -435,7 +435,7 @@ void webserver_impl::manage_upload_stream(detail::modded_request* mr,
435435
MHD_Result webserver_impl::process_file_upload(detail::modded_request* mr,
436436
const char* key, const char* filename, const char* content_type,
437437
const char* transfer_encoding, const char* data, size_t size) const {
438-
http::file_info& file = mr->dhr->get_or_create_file_info(key, filename);
438+
http::file_info& file = mr->request->get_or_create_file_info(key, filename);
439439
if (file.get_file_system_file_name().empty()) {
440440
if (!setup_new_upload_file_info(file, filename, content_type, transfer_encoding)) {
441441
return MHD_NO;
@@ -463,8 +463,8 @@ MHD_Result webserver_impl::post_iterator(void *cls, enum MHD_ValueKind kind,
463463

464464
try {
465465
if (mr->ws->file_upload_target != FILE_UPLOAD_DISK_ONLY) {
466-
mr->dhr->set_arg_flat(key,
467-
std::string(mr->dhr->get_arg(key)) + std::string(data, size));
466+
mr->request->set_arg_flat(key,
467+
std::string(mr->request->get_arg(key)) + std::string(data, size));
468468
}
469469
if (*filename != '\0' && mr->ws->file_upload_target != FILE_UPLOAD_MEMORY_ONLY) {
470470
MHD_Result r = mr->ws->impl_->process_file_upload(

src/detail/webserver_dispatch.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ webserver_impl::lookup_v2(http_method method, const std::string& path) {
226226
std::shared_lock table_lock(route_table_mutex_);
227227

228228
// Radix tier — segment-trie walk.
229-
radix_match<route_entry> rm;
229+
segment_trie_match<route_entry> rm;
230230
if (param_and_prefix_routes_.find(key.path, rm) && rm.entry) {
231231
result.found = true;
232232
result.tier = tier_hit::radix;
@@ -314,9 +314,9 @@ bool webserver_impl::resolve_resource_for_request(detail::modded_request* mr,
314314
// Replay captured URL parameters into the request. Per-name
315315
// set_arg matches v1 behaviour exactly — duplicates with later
316316
// wins, etc.
317-
if (mr->dhr != nullptr) {
317+
if (mr->request != nullptr) {
318318
for (const auto& [name, value] : result.captured_params) {
319-
mr->dhr->set_arg(name, value);
319+
mr->request->set_arg(name, value);
320320
}
321321
}
322322

@@ -369,7 +369,7 @@ void handle_dispatch_exception(
369369
// (Naming the capture makes clear we are taking a reference to
370370
// the in-flight exception object.)
371371
auto current_exc = std::current_exception();
372-
handler_exception_ctx ctx{mr->dhr.get(), current_exc, message};
372+
handler_exception_ctx ctx{mr->request.get(), current_exc, message};
373373
if (server_chain) {
374374
if (auto sc = impl->fire_handler_exception(ctx)) {
375375
mr->response.emplace(std::move(*sc));
@@ -427,7 +427,7 @@ void webserver_impl::dispatch_resource_handler(detail::modded_request* mr,
427427
// by value; the prvalue is moved into the
428428
// per-connection optional anchor. shared_ptr has no
429429
// operator->*, so call as ((*ptr).*pmf)(...).
430-
mr->response.emplace(((*hrm).*(mr->callback))(*mr->dhr));
430+
mr->response.emplace(((*hrm).*(mr->callback))(*mr->request));
431431
if (mr->response->get_status() == -1) {
432432
// No exception was thrown, but the handler
433433
// returned the default-sentinel response. Route through

src/detail/webserver_error_pages.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
// double-fault-safe wrapper around the user internal_error_handler
2929
// (run_internal_error_handler_safely). They are pure const helpers off
3030
// webserver_impl and share no state with the rest of the dispatch TU
31-
// beyond `parent->*` user handlers and `mr->dhr`.
31+
// beyond `parent->*` user handlers and `mr->request`.
3232

3333
#include "httpserver/webserver.hpp"
3434
#include "httpserver/detail/webserver_impl.hpp"
@@ -51,15 +51,15 @@ namespace detail {
5151

5252
http_response webserver_impl::not_found_page(detail::modded_request* mr) const {
5353
if (parent->not_found_handler != nullptr) {
54-
return parent->not_found_handler(*mr->dhr);
54+
return parent->not_found_handler(*mr->request);
5555
}
5656
return http_response::string(std::string{constants::NOT_FOUND_ERROR})
5757
.with_status(http_utils::http_not_found);
5858
}
5959

6060
http_response webserver_impl::method_not_allowed_page(detail::modded_request* mr) const {
6161
if (parent->method_not_allowed_handler != nullptr) {
62-
return parent->method_not_allowed_handler(*mr->dhr);
62+
return parent->method_not_allowed_handler(*mr->request);
6363
}
6464
return http_response::string(std::string{constants::METHOD_ERROR})
6565
.with_status(http_utils::http_method_not_allowed);
@@ -80,7 +80,7 @@ http_response webserver_impl::internal_error_page(
8080
}
8181
// Invoke the user handler with the originating message.
8282
if (parent->internal_error_handler != nullptr) {
83-
return parent->internal_error_handler(*mr->dhr, msg);
83+
return parent->internal_error_handler(*mr->request, msg);
8484
}
8585
// The default body is the fixed string
8686
// "Internal Server Error" to avoid CWE-209 information disclosure of

src/detail/webserver_finalize.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ bool webserver_impl::fire_before_handler_gated(
102102
/*is_prefix=*/mr->matched_is_prefix};
103103
}
104104
before_handler_ctx ctx{
105-
/*request=*/mr->dhr.get(),
105+
/*request=*/mr->request.get(),
106106
/*matched=*/std::move(desc),
107107
/*method=*/mr->method_enum,
108108
/*resource=*/hrm.get()};
@@ -148,7 +148,7 @@ void webserver_impl::fire_after_handler_gated(detail::modded_request* mr,
148148
if (!server_gate && !route_gate) return;
149149
if (!mr->response) return; // defensive: never fire without a response
150150

151-
after_handler_ctx ctx{mr->dhr.get(), &*mr->response};
151+
after_handler_ctx ctx{mr->request.get(), &*mr->response};
152152
if (server_gate) {
153153
if (auto sc = fire_after_handler(ctx)) {
154154
// Short-circuit: REPLACE mr->response (emplace
@@ -207,7 +207,7 @@ void webserver_impl::fire_response_sent_gated(detail::modded_request* mr,
207207
? std::chrono::duration_cast<std::chrono::nanoseconds>(
208208
std::chrono::steady_clock::now() - mr->start_time)
209209
: std::chrono::nanoseconds::zero();
210-
response_sent_ctx ctx{mr->dhr.get(), &*mr->response,
210+
response_sent_ctx ctx{mr->request.get(), &*mr->response,
211211
mr->response->get_status(), bytes_queued, elapsed};
212212
fire_response_sent(ctx);
213213
// Per-route chain AFTER server-wide + its alias slot.
@@ -273,7 +273,7 @@ void webserver_impl::fire_request_completed_gated(
273273
: std::chrono::duration_cast<std::chrono::nanoseconds>(
274274
raw_duration);
275275
request_completed_ctx ctx{
276-
/*request=*/mr->dhr.get(),
276+
/*request=*/mr->request.get(),
277277
/*resp=*/resp_ptr,
278278
/*succeeded=*/(toe == MHD_REQUEST_TERMINATED_COMPLETED_OK),
279279
/*duration=*/duration,

src/detail/webserver_register.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,8 @@ void webserver_impl::register_v2_route(const detail::http_endpoint& idx,
199199
// Place a register_path / register_prefix registration into the
200200
// v2 3-tier route table. Tier placement via classify_route_tier()
201201
// (single source-of-truth):
202-
// - family=true -> radix tree (prefix terminus).
203-
// - radix tier -> radix tree (exact terminus, wildcard nodes).
202+
// - family=true -> segment trie (prefix terminus).
203+
// - radix tier -> segment trie (exact terminus, wildcard nodes).
204204
// - regex tier -> regex_routes_ (pre-compiled at registration time).
205205
// - exact tier -> exact_routes_ hash map.
206206
std::unique_lock table_lock(route_table_mutex_);

src/detail/webserver_request.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ static void fire_route_resolved_gated(webserver_impl* impl,
275275
/*is_prefix=*/mr->matched_is_prefix};
276276
}
277277
route_resolved_ctx ctx{
278-
/*request=*/mr->dhr.get(),
278+
/*request=*/mr->request.get(),
279279
/*matched=*/std::move(desc),
280280
/*resource=*/hrm ? hrm.get() : nullptr};
281281
impl->fire_route_resolved(ctx);
@@ -381,9 +381,9 @@ MHD_Result webserver_impl::finalize_answer(MHD_Connection* connection,
381381
MHD_Result webserver_impl::complete_request(MHD_Connection* connection, struct detail::modded_request* mr, const char* version, const char* method) {
382382
// mr->ws is pre-populated in answer_to_connection (hoisted there for
383383
// early-path request_completed coverage); no need to set it again here.
384-
mr->dhr->set_path(mr->standardized_url);
385-
mr->dhr->set_method(method);
386-
mr->dhr->set_version(version);
384+
mr->request->set_path(mr->standardized_url);
385+
mr->request->set_method(method);
386+
mr->request->set_version(version);
387387

388388
return finalize_answer(connection, mr);
389389
}
@@ -438,7 +438,7 @@ MHD_Result webserver_impl::answer_to_connection(void* cls, MHD_Connection* conne
438438
auto* mr = static_cast<detail::modded_request*>(*con_cls);
439439
auto* impl = static_cast<webserver_impl*>(cls);
440440

441-
if (mr->dhr) {
441+
if (mr->request) {
442442
return impl->requests_answer_second_step(connection, method, version,
443443
upload_data, upload_data_size, mr);
444444
}
@@ -468,7 +468,7 @@ MHD_Result webserver_impl::answer_to_connection(void* cls, MHD_Connection* conne
468468
base_unescaper(&t_url, impl->parent->unescaper);
469469
// SECURITY: collapse dot-segments ("." / "..") into the canonical
470470
// path here, at the single point where the routing/auth path is
471-
// derived. Both the route matcher (radix_tree::find via
471+
// derived. Both the route matcher (segment_trie::find via
472472
// mr->standardized_url) and should_skip_auth() must interpret the
473473
// path identically; should_skip_auth() runs the path through
474474
// normalize_path() (which pops ".."), but standardize_url() only

src/detail/webserver_routes_upsert.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,9 @@ const detail::route_entry* webserver_impl::find_v2_entry_by_path_(
128128
// it as the wildcard child) and descends that unconstrained
129129
// wildcard child. A constrained "{id|[0-9]+}" segment, however,
130130
// fails the constraint regex_match in step_to_child_
131-
// (radix_tree.hpp) and is NOT found -- the literal pattern text
131+
// (segment_trie.hpp) and is NOT found -- the literal pattern text
132132
// does not satisfy its own constraint.
133-
detail::radix_match<detail::route_entry> rm;
133+
detail::segment_trie_match<detail::route_entry> rm;
134134
if (param_and_prefix_routes_.find(key, rm)
135135
&& rm.entry != nullptr && !rm.is_prefix_match) {
136136
return rm.entry;
@@ -265,9 +265,9 @@ void webserver_impl::upsert_v2_radix_route(const std::string& key,
265265
// symmetric guard in register_v2_route). Must run BEFORE the
266266
// read-merge below so a thrown exception leaves the table intact.
267267
reject_terminus_collision(key, /*want_is_prefix=*/false);
268-
// Read-merge-reinsert: radix_tree::insert always overwrites the
268+
// Read-merge-reinsert: segment_trie::insert always overwrites the
269269
// terminus, so we must fold any existing entry's methods in first.
270-
detail::radix_match<detail::route_entry> existing;
270+
detail::segment_trie_match<detail::route_entry> existing;
271271
detail::route_entry merged;
272272
if (param_and_prefix_routes_.find(key, existing)
273273
&& existing.entry && !existing.is_prefix_match) {

0 commit comments

Comments
 (0)