Andrea Cosentino created CAMEL-25345:
----------------------------------------

             Summary: camel-util - URISupport.normalizeUri is not idempotent 
when the path has # or two @ and a query value has = or #
                 Key: CAMEL-25345
                 URL: https://issues.apache.org/jira/browse/CAMEL-25345
             Project: Camel
          Issue Type: Bug
          Components: camel-core
            Reporter: Andrea Cosentino


CAMEL-25188 made the *query* side of {{URISupport.normalizeUri}} idempotent. 
The *path* side still changes on a second pass, for two triggers only.

h2. Reproduction

Against {{camel-util}} built from current main:

{noformat}
[NOT IDEMPOTENT] sftp://[email protected]@host/in?password=pa=ss
      pass1: sftp://[email protected]@host/in?password=pa%3Dss
      pass2: sftp://me%40example.com@host/in?password=pa%3Dss

[NOT IDEMPOTENT] sql:select+*+from+t+where+id=:#id?dataSource=#ds
      pass1: sql://select+*+from+t+where+id=:#id?dataSource=%23ds
      pass2: sql://select+*+from+t+where+id=:%23id?dataSource=%23ds

[NOT IDEMPOTENT] 
imaps://[email protected]@imap.example.com?password=x&sslContextParameters=#ssl
      pass1: 
imaps://[email protected]@imap.example.com?password=x&sslContextParameters=%23ssl
      pass2: 
imaps://me%[email protected]?password=x&sslContextParameters=%23ssl

[idempotent]   direct:start?foo=bar
{noformat}

h2. Why

{{normalizeUri}} dispatches on {{CamelURIParser.fastParseUri}}:

{code:java}
String[] parts = CamelURIParser.fastParseUri(uri);
if (parts != null) {
    ...
    return doFastNormalizeUri(parts);
} else {
    return doComplexNormalizeUri(uri);
}
{code}

The fast path copies the path through verbatim. The first pass encodes the 
*query* ({{=}} to {{%3D}}, {{#}} to {{%23}}), and that introduced {{%}} is what 
makes the second pass take the complex branch - which then also encodes the 
path, turning {{#}} into {{%23}} and the second {{@}} into {{%40}}.

So both triggers need a query value containing {{=}} or {{#}} (a {{#bean}} 
reference is enough) *and* a path containing {{#}} or a second {{@}} (an email 
address as the user, which is ordinary for sftp/imaps).

h2. End to end impact

Smaller than the normalization difference suggests, and only one case is a 
regression:

* The *two-{{@}}* case is a regression against 4.22.1: 
{{getEndpoint(endpoint.getEndpointUri())}} normalizes a second time, does not 
match the cached key, and creates a **duplicate endpoint**; {{hasEndpoint}} 
returns null for it.
* The *{{#}}-in-path* case was already missed on 4.22.1, because 
{{getEndpointUri()}} returns the {{UnsafeUriCharactersEncoder}} form.
* {{interceptSendToEndpoint}} with the exact URI matches on both.

h2. Fix direction (validated, not yet implemented)

In {{normalizeUri}}, when {{doFastNormalizeUri(parts)}} produced a {{%}}, 
return {{doComplexNormalizeUri(uri)}} instead, so one URI never gets normalized 
by two different normalizers.

A 600k-URI fuzz over three seeds, comparing against 4.22.1, reported 0 
non-idempotent results and no change to the values a default component 
receives, with all 76 {{URISupportTest}} cases passing.

**That evidence comes from an earlier run and has not been reproduced since**, 
and this is a central code path, so it is worth re-running before the change 
lands. Note also the precedent in CAMEL-25190, where a related normalization 
defect was deliberately deferred to Camel 5 because fixing it would change the 
values endpoints receive. The difference here is that this fix is intended to 
be value-preserving and to affect only second-pass stability - which is exactly 
the claim the fuzz needs to confirm.

Filed unassigned.

h2. Doc nit

The CAMEL-24524 section of {{camel-4x-upgrade-guide-4_23.adoc}} still ends by 
describing the "(now consistently) unencoded form", which no longer matches the 
behaviour after CAMEL-25188.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to