Skip to content

Conversation

@etr
Copy link
Owner

@etr etr commented Feb 10, 2026

Summary

  • Optimize per-request critical path with LRU route cache and reduced allocations
  • Fix use-after-free bug: copy cached data while holding lock
  • Fix race condition in unregister_resource cache invalidation
  • Apply validation fixes: bounds checks, DRY refactoring, const refs, empty guards

Test plan

  • make check passes all 14 tests
  • make valgrind-check shows no memory errors
  • Verify route caching works under concurrent requests
  • Verify unregister_resource properly invalidates cache entries

etr added 5 commits February 9, 2026 13:59
- Replace istringstream-based string_split with manual loop (string_utilities.cpp)
- Fix http_unescape: parse hex chars directly without substr allocations (http_utils.cpp)
- Flatten unique_ptr<string> members in modded_request to plain std::string,
  eliminating 2 heap allocations per request (modded_request.hpp, webserver.cpp)
- Fix strcmp/strcasecmp inconsistency: all HTTP method dispatch now uses
  case-sensitive strcmp per RFC 7230 (webserver.cpp)
- Optimize set_method: skip unnecessary copy+uppercase since MHD provides
  method strings in uppercase per spec (http_request.cpp)
- Cache get_path_pieces() result on first access to avoid re-tokenization
  on every call (http_request.hpp)
- Separate exact vs parameterized routes at registration time; only scan
  parameterized routes on regex fallback (webserver.hpp, webserver.cpp)
- Add shared LRU cache (256 entries) for URL-to-endpoint route matches
  to avoid repeated regex matching (webserver.hpp, webserver.cpp)
- Optimize standardize_url to modify in-place instead of creating extra
  copies (http_utils.cpp)
- Add bounds checking for url_pieces[chunks[i]] to prevent potential
  buffer overflow when cached endpoint chunks don't match request pieces
- Extract URL parameter extraction from cache hit/miss paths into single
  block after match resolution (DRY fix)
- Use const references for vectors instead of by-value copies to avoid
  heap allocations under cache lock
- Add empty-string guard to standardize_url before calling back()
- Extract ensure_path_pieces_cached() helper to deduplicate caching logic
  in get_path_pieces() and get_path_piece()
- Add RFC 7230 comment documenting case-sensitive strcmp intent
The matched_ep pointer referenced data inside route_cache_list that
could be invalidated by another thread (via invalidate_route_cache or
LRU eviction) after the cache mutex was released.

Fix by copying url_pars and chunk_positions vectors while holding the
cache lock, so parameter extraction afterwards uses owned data.
For cache miss path, the registered_resources_mutex shared lock is
still held so direct reference is safe, but copy for consistency.
Move route cache invalidation inside registered_resources_mutex lock
in unregister_resource() to prevent use-after-free when threads
retrieve cached resource pointers during unregistration.

Also invalidate route cache on register_resource() for correctness
when resources are dynamically registered at runtime.

Add threading model documentation to http_request lazy caching.
…l path

Performance optimizations for the HTTP request hot path:
- LRU route cache (256 entries) for regex endpoint matching
- Separate regex endpoint map to avoid scanning all endpoints
- Replace istringstream with manual find() loop in string_split
- Replace sscanf with direct hex arithmetic in http_unescape
- Cache path_pieces in http_request to avoid repeated tokenization
- Flatten unique_ptr<string> to plain string in modded_request
- Case-sensitive strcmp for HTTP methods per RFC 7230
- Standardize_url optimization with std::unique and pop_back
@codecov
Copy link

codecov bot commented Feb 10, 2026

Codecov Report

❌ Patch coverage is 56.36364% with 48 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.49%. Comparing base (42e769c) to head (03cf1e7).
⚠️ Report is 9 commits behind head on master.

Files with missing lines Patch % Lines
src/webserver.cpp 51.42% 8 Missing and 26 partials ⚠️
src/http_utils.cpp 57.89% 0 Missing and 8 partials ⚠️
src/string_utilities.cpp 54.54% 0 Missing and 5 partials ⚠️
src/httpserver/http_request.hpp 88.88% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #365      +/-   ##
==========================================
- Coverage   70.54%   70.49%   -0.05%     
==========================================
  Files          28       28              
  Lines        1436     1488      +52     
  Branches      570      593      +23     
==========================================
+ Hits         1013     1049      +36     
- Misses         35       43       +8     
- Partials      388      396       +8     
Files with missing lines Coverage Δ
src/http_request.cpp 70.94% <100.00%> (+0.55%) ⬆️
src/httpserver/details/modded_request.hpp 100.00% <ø> (ø)
src/httpserver/http_request.hpp 88.37% <88.88%> (+4.16%) ⬆️
src/string_utilities.cpp 72.72% <54.54%> (+3.49%) ⬆️
src/http_utils.cpp 66.82% <57.89%> (+3.51%) ⬆️
src/webserver.cpp 57.22% <51.42%> (-1.59%) ⬇️

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 42e769c...03cf1e7. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Fixes cpplint build/include_what_you_use warning.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant