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
 

Reply via email to