Unify streaming/WebSocket routes into http_router with path params#2559
Merged
Conversation
Move streaming and WebSocket route storage from flat path -> handler maps on http_server into basic_http_router, sharing the radix-tree matcher with normal routes. Streaming and WebSocket routes now support :param and *wildcard segments, and routers carrying any mix of route kinds can be passed to server.mount(). - Extract route_table<H> from basic_http_router; the router holds three (normal/streaming/websocket) sharing the radix tree. - Add stream/stream_get/stream_post/websocket on the router, plus match_streaming/match_websocket lookup methods. - http_server::stream*/websocket delegate to root_router; the flat streaming_handlers_/websocket_handlers_ maps are removed. - mount() propagates all three kinds. - Fast-path: skip streaming match in process_full_request_with_conn when no streaming routes are registered, avoiding per-request allocations for the common case. - Fix wildcard params leak: match_node now erases the wildcard capture on every failure path (parity with the :param branch). - Fix half-register on throw: route_table::add now installs in the radix tree first, then populates the routes map. - Migration: router.routes (field) is now router.normal_routes.routes; routes() accessor method provided for source compatibility. Behavior change: streaming routes are now matched before normal routes, so a streaming /items/:id will intercept what a normal /items/42 would have handled. Previously streaming was an exact-path map and :param streaming routes were effectively dead.
… redundant tree header Address PR review nits: - route_table::split_path is documented as the canonical implementation; basic_http_router::split_path delegates to it. - route_table::print_tree no longer prints "Radix Tree Structure:" since basic_http_router::print_tree already groups three sub-trees under labelled [normal routes]/[streaming routes]/[websocket routes] sections.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses the design feedback in #2550 (from @JnCrMx). Moves streaming and WebSocket route storage off
http_server's flat path → handler maps and intobasic_http_router, where they share the radix-tree matcher with normal routes. As a result, streaming and WebSocket routes now support:paramand*wildcardpath segments, and routers carrying any mix of route kinds can be passed toserver.mount().The requested API now works:
What changed
route_table<H>frombasic_http_router; the router now holds three of them (normal_routes,streaming_routes,websocket_routes) sharing one radix-tree implementation.stream,stream_get,stream_post,websocket,match_streaming,match_websocket.http_server::stream*/http_server::websocketdelegate toroot_router. The flatstreaming_handlers_andwebsocket_handlers_maps are removed.mount()propagates all three route kinds; each is rewritten with the mount prefix and added to the server's root router.process_full_request_with_connskips the streaming match when no streaming routes are registered, restoring per-request cost for the common case.route_table::match_nodenow erases the wildcard capture on every failure path (was leaking onis_endpoint=false, wrong method, or constraint failure — parity with the existing:parambranch).route_table::addinstalls in the radix tree first, then populates the routes map, so a route conflict thrown fromadd_routeno longer leaves a half-registered entry that iteration sees butmatch()never reaches.Behavior change
Previously
streaming_handlers_was an exact-path map, sostream_get(\"/items/:id\", ...)was effectively dead and a request to/items/42fell through to the normal router. After the unification, streaming routes are matched before normal routes, so a streaming/items/:idwill intercept requests that a normal/items/42would otherwise handle. Documented indocs/networking/http-router.md(Streaming Routes section + Route Priority section).Migration
router.routes(public field) is nowrouter.normal_routes.routes. Aroutes()accessor method is provided for source compatibility (a reference data member would dangle through the implicit move constructor). Updated callers:http_server::mount,http_server::enable_openapi_spec,tests/networking_tests/openapi_test, anddocs/networking/rest-registry.md.Test plan
tests/networking_tests/http_chunked_test/http_chunked_test.cpp::paramdirect on server,:paramviahttp_router+mount(), mixing normal + streaming on one router, wildcard segment,:param+ query string combo, URL-decoded:param,route_spec::constraintsrejection (200 vs 404).tests/networking_tests/websocket_test/websocket_client_test.cpp::paramdirect on server,:paramvia router + mount, wildcard segment, all-three-kinds (normal + streaming + WebSocket) coexisting on one mounted router.sleep_for(200ms)server-readiness waits in the new streaming tests with a TCP-connect-probe helper for robustness on busy CI.http_chunked_test: 57/57 tests, 230 asserts.websocket_client_test: 34/34 tests, 146 asserts.http_router_test: 21/21 tests, 81 asserts.http_server_api_tests: 49/49 tests, 152 asserts.openapi_test: 1/1 tests, 5 asserts.Docs updated
docs/networking/http-router.md— new "Streaming Routes" and "WebSocket Routes" sections; "Route Priority" extended to cover cross-kind dispatch order.docs/networking/http-server.md—mount()propagation note in "Mounting Sub-routers".docs/networking/advanced-networking.md—router.websocket(...)+ path-param note in the WebSocket section.docs/networking/rest-registry.md— field rename in the endpoint-discovery example.