shashank created CAMEL-26083:
--------------------------------
Summary: camel-support - RestConsumerContextPathMatcher: stopping
one consumer of a wildcard path stops the wildcard matching of every other
consumer with the same path
Key: CAMEL-26083
URL: https://issues.apache.org/jira/browse/CAMEL-26083
Project: Camel
Issue Type: Bug
Components: camel-netty-http, camel-servlet, camel-support,
camel-undertow
Reporter: shashank
Assignee: shashank
{{RestConsumerContextPathMatcher}} keeps the compiled regex of each wildcard
consumer path in a static map keyed only by the path string ({{PATH_PATTERN}},
main 6a2f66ddec3e line 43). {{register(path)}} puts it, {{unRegister(path)}}
removes it (lines 245-272), and {{matchWildCard}} returns false for a path
without a pattern (line 388), the last step of {{matchBestPath}}. The map is
one per JVM, so all consumers with the same path share one entry: the same
wildcard path for two HTTP methods ({{GET /files/*}} and {{POST /files/*}}), on
two ports, in two CamelContexts or two components. Stopping, suspending
(netty-http with {{send503whenSuspended=false}}), removing or reloading one of
them removes the pattern for all: every other consumer of that path, still
started, no longer matches. Its requests get 404, or are routed to a broader
wildcard consumer of the same server ({{/*}}). Callers: netty-http
{{HttpServerMultiplexChannelHandler}}, servlet/jetty
{{CamelServlet.connect/disconnect}} (camel-http-common), undertow
{{RestRootHandler}}.
*Fix*: each entry counts the consumers that registered the path; {{unRegister}}
removes the pattern only when no consumer is left
({{ConcurrentHashMap.compute}}/{{computeIfPresent}}). Compiling on demand was
not chosen, as it would change matching for camel-rest-openapi and
camel-rest-postman, which call {{matchBestPath}} without registering.
{{CamelServlet.disconnect}} (servlet, jetty) now unregisters only when
{{consumers.remove(endpointUri, consumer)}} removed this consumer: with an
{{httpRegistry}} shared by servlets of different names,
{{CamelHttpTransportServlet.connect}} registers a consumer only in the servlet
of its name while {{disconnect}} ran for every servlet, and a connect refused
as "Duplicate request path" was followed by a {{disconnect}} that unregistered
a path it never registered (and removed the other consumer's map entry).
*Tests*: new {{NettyHttpTwoRoutesSameWildcardPathStopOneRouteTest}}, 2 tests,
both fail on main ({{expected: <post> but was: <>}} after stopping the GET
route of the same path; {{expected: <other-port> but was: <catch-all>}} after
stopping the same path on another port); new
{{ServletSharedHttpRegistryWildcardPathTest}} (shared {{httpRegistry}} with
servlets {{a}} and {{b}}; stop one of two consumers of a path; a duplicate
consumer), 2 tests, fail on main and with only the matcher change; new
{{RestConsumerContextPathMatcherTest#wildcardPathStaysRegisteredWhileAnotherConsumerUsesIt}}
fails on main ({{expected: not <null>}}). Unit tests with the fix:
camel-netty-http 316 run, 0 failures, 8 skipped; camel-servlet 112 run, 0
failures, 2 skipped; camel-http-common 48 run, 0 failures.
*How it was found*: spec mining of {{RestConsumerContextPathMatcherTest}} and a
stateful lifecycle-sequence harness over HTTP consumers sharing a server.
*Affected*: main, camel-4.22.x, camel-4.18.x and camel-4.14.x (same code).
Read, not run.
_Filed with Claude Code on behalf of allthingssecurity._
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)