This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 32ec5a5c91ea CAMEL-25345: camel-util - URISupport.normalizeUri gives
the same uri for a normalized uri with # or two @ in the path (#27468)
32ec5a5c91ea is described below
commit 32ec5a5c91ea5e972319150d09666d581512c884
Author: allthingssecurity <[email protected]>
AuthorDate: Wed Oct 7 15:56:38 2026 +0530
CAMEL-25345: camel-util - URISupport.normalizeUri gives the same uri for a
normalized uri with # or two @ in the path (#27468)
URISupport.normalizeUri was not idempotent for a path with # or a user info
with two @ combined with a query value needing a percent escape: the second
pass encoded the path, creating a duplicate endpoint. The fast normalizer path
now produces the same result as the complex one so normalizing an already
normalized uri is stable.
Closes #27468
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../camel/impl/engine/DefaultCamelContextTest.java | 15 ++++++++++
.../java/org/apache/camel/util/URISupport.java | 17 ++++++++----
.../java/org/apache/camel/util/URISupportTest.java | 32 +++++++++++++++++++++-
.../ROOT/pages/camel-4x-upgrade-guide-4_23.adoc | 6 ++--
4 files changed, 61 insertions(+), 9 deletions(-)
diff --git
a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java
b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java
index c61cd2859be3..be8c7c1c9ec3 100644
---
a/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java
+++
b/core/camel-core/src/test/java/org/apache/camel/impl/engine/DefaultCamelContextTest.java
@@ -304,6 +304,21 @@ public class DefaultCamelContextTest extends TestSupport {
"Should have thrown exception");
}
+ @Test
+ public void testGetEndpointByItsUriWithHashOrTwoAtInPath() {
+ // CAMEL-25345: the uri of an endpoint finds the same endpoint
(normalizing a normalized uri gives the same uri)
+ DefaultCamelContext ctx = new DefaultCamelContext(false);
+ ctx.disableJMX();
+ Endpoint endpoint =
ctx.getEndpoint("log:[email protected]@host?marker=a=b");
+ Endpoint other = ctx.getEndpoint("log:a#b?marker=#c");
+
+ assertSame(endpoint, ctx.getEndpoint(endpoint.getEndpointUri()));
+ assertSame(endpoint, ctx.hasEndpoint(endpoint.getEndpointUri()));
+ assertSame(other, ctx.getEndpoint(other.getEndpointUri()));
+ assertSame(other, ctx.hasEndpoint(other.getEndpointUri()));
+ assertEquals(2, ctx.getEndpointRegistry().size());
+ }
+
@Test
public void testGetRouteById() throws Exception {
DefaultCamelContext ctx = new DefaultCamelContext(false);
diff --git
a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
index 004425829f16..21e86cb35ddb 100644
--- a/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
+++ b/core/camel-util/src/main/java/org/apache/camel/util/URISupport.java
@@ -770,11 +770,13 @@ public final class URISupport {
return uri;
}
// use the faster and more simple normalizer
- return doFastNormalizeUri(parts);
- } else {
- // use the legacy normalizer as the uri is complex and may have
unsafe URL characters
- return doComplexNormalizeUri(uri);
+ String answer = doFastNormalizeUri(parts);
+ if (answer != null) {
+ return answer;
+ }
}
+ // use the legacy normalizer as the uri is complex and may have unsafe
URL characters
+ return doComplexNormalizeUri(uri);
}
/**
@@ -870,6 +872,8 @@ public final class URISupport {
/**
* The fast parser for normalizing Camel endpoint URIs when the URI is not
complex and can be parsed in a much more
* efficient way.
+ *
+ * @return the normalized uri, or <tt>null</tt> if the uri must be
normalized by the complex normalizer
*/
private static String doFastNormalizeUri(String[] parts) throws
URISyntaxException {
String scheme = parts[0];
@@ -902,9 +906,10 @@ public final class URISupport {
query = buildSafeQueryString(keys, parameters);
if (query.indexOf('%') != -1) {
// a key or value needed a percent escape (such as = or # in a
value), and a uri with % is normalized by
- // the complex normalizer, which form-encodes the whole query;
encode the same way here so normalizing a
+ // the complex normalizer, which form-encodes the whole query and
also encodes the path (such as # and all
+ // but the last @ of the user info); let the complex normalizer
normalize this uri as well, so normalizing a
// normalized uri gives the same uri (the fast parser only takes
uris without %, so all % come from here)
- query = createQueryString(keys, parameters, true);
+ return null;
}
return buildUri(scheme, path, query);
}
diff --git
a/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
b/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
index a8b6f46ff24a..44a0b98b27ef 100644
--- a/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
+++ b/core/camel-util/src/test/java/org/apache/camel/util/URISupportTest.java
@@ -162,7 +162,8 @@ public class URISupportTest {
@Test
public void testNormalizeValueWithPercentEscapeFormEncodesTheQuery()
throws Exception {
// CAMEL-25188: a value with = or # needs a percent escape, and a uri
with % is normalized by the complex
- // normalizer, so the fast normalizer form-encodes the whole query the
same way, whatever the key order
+ // normalizer, so the fast normalizer hands such a uri to the complex
normalizer (CAMEL-25345), which
+ // form-encodes the whole query, whatever the key order
assertThat(URISupport.normalizeUri("log:foo?secretKey=abc/def=="))
.isEqualTo("log://foo?secretKey=abc%2Fdef%3D%3D");
assertThat(URISupport.normalizeUri("log:foo?marker=a#b/c")).isEqualTo("log://foo?marker=a%23b%2Fc");
@@ -209,6 +210,35 @@ public class URISupportTest {
}
}
+ @Test
+ public void testNormalizeTwiceGivesTheSameUriWithHashOrTwoAtInPath()
throws Exception {
+ // CAMEL-25345: a value that needs a percent escape, and a path with #
or with more than one @ (an email address
+ // as user), are normalized by the complex normalizer, which encodes
the path
+
assertThat(URISupport.normalizeUri("sftp://[email protected]@host/in?password=pa=ss"))
+ .isEqualTo("sftp://me%40example.com@host/in?password=pa%3Dss");
+
assertThat(URISupport.normalizeUri("sql:select+*+from+t+where+id=:#id?dataSource=#ds"))
+
.isEqualTo("sql://select+*+from+t+where+id=:%23id?dataSource=%23ds");
+
assertThat(URISupport.normalizeUri("imaps://[email protected]@imap.example.com?password=x&sslContextParameters=#ssl"))
+
.isEqualTo("imaps://me%[email protected]?password=x&sslContextParameters=%23ssl");
+ // without a percent escape in the query the path is kept as is
+
assertThat(URISupport.normalizeUri("sftp://[email protected]@host/in?binary=true"))
+ .isEqualTo("sftp://[email protected]@host/in?binary=true");
+
assertThat(URISupport.normalizeUri("sql:select+*+from+t+where+id=:#id?dataSource=ds"))
+
.isEqualTo("sql://select+*+from+t+where+id=:#id?dataSource=ds");
+
+ String[] uris = {
+ "sftp://[email protected]@host/in?password=pa=ss",
+ "sql:select+*+from+t+where+id=:#id?dataSource=#ds",
+
"imaps://[email protected]@imap.example.com?password=x&sslContextParameters=#ssl",
+
"ftp://[email protected]@host/in/a@b?password=se=cret&binary=true",
+ "http://host/a#b?q=#x",
+ "log:a#b?marker=x=y&showAll=true" };
+ for (String uri : uris) {
+ String once = URISupport.normalizeUri(uri);
+ assertThat(URISupport.normalizeUri(once)).as("normalizing %s
twice", uri).isEqualTo(once);
+ }
+ }
+
@Test
public void testParseParametersURLEncodedValue() throws Exception {
String out =
URISupport.normalizeUri("http://www.google.com?q=S%C3%B8ren%20Hansen");
diff --git
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
index 1d7e57b09a62..44bcffc25a7a 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
@@ -1259,10 +1259,12 @@ query string is also less aggressive: characters that
are legal unescaped in a U
value) are no longer percent-encoded, as long as no key or value in the query
needs a percent escape.
A value with `=` or `#` (for example `secretKey=abc/def==`) needs one, and
then the whole query is
form-encoded as in earlier releases, the same way as an endpoint URI that is
already percent-encoded, so
-normalizing a normalized URI gives the same URI.
+normalizing a normalized URI gives the same URI. Such a URI is then normalized
as a whole like a percent-encoded
+URI, so a `#` in the path becomes `%23`, and in a user info with more than one
`@` (an email address as the user)
+every `@` but the last becomes `%40`, for example
`sftp://me%40example.com@host/in?password=pa%3Dss`.
Code that asserts a literal, fully-normalized endpoint URI string containing
one of those characters in a
-query value may need to update the expected string to the (now consistently)
unencoded form.
+query value may need to update the expected string to the form described above.
=== camel-core - double && in endpoint URIs