[ 
https://issues.apache.org/jira/browse/CAMEL-25033?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Claus Ibsen updated CAMEL-25033:
--------------------------------
    Fix Version/s: 4.23.0

> camel-bean: a parameter bound from ${body} or ${header.x} in the method name 
> loses its surrounding quotes, and the text "null" becomes a Java null
> --------------------------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: CAMEL-25033
>                 URL: https://issues.apache.org/jira/browse/CAMEL-25033
>             Project: Camel
>          Issue Type: Bug
>          Components: camel-core
>            Reporter: shashank
>            Priority: Minor
>             Fix For: 4.23.0
>
>
> The method option can bind parameters from Simple expressions, for example 
> {{bean(MyService.class, "process(${body})")}} or 
> {{to("bean:foo?method=check(${header.ETag})")}}. {{bean-binding.adoc}} 
> ("Parameter binding using method option") documents two different kinds of 
> value:
> * a String literal in quotes, such as {{'World'}}, is passed "without quotes";
> * a Simple token, such as {{${header.high}}}, is passed as the value of that 
> header.
> {{MethodInfo.ParameterExpression}} does not keep them apart. It evaluates 
> every parameter with the Simple language and then post-processes the *result*:
> {code:java}
> // MethodInfo.java:728
> if ("null".equals(parameterValue)) {
>     return Void.TYPE;                         // the parameter becomes null
> }
> ...
> // MethodInfo.java:789-793 convertParameterValue
> if (parameterValue instanceof String string) {
>     parameterValue = StringHelper.removeLeadingAndEndingQuotes(string);
> }
> {code}
> {{removeLeadingAndEndingQuotes}} ({{StringHelper.java:161-179}}) trims the 
> value and removes the first and last char when both are {{'}} or both are 
> {{"}}. So the quote handling that is meant for the literal text of the method 
> name is also applied to message data:
> * An HTTP {{ETag}} / {{If-None-Match}} value {{"33a64df5"}} reaches the 
> method as {{33a64df5}}.
> * A CSV line {{"ACME, Inc.","42"}} (for example after 
> {{split(body().tokenize("\n"))}}) reaches the method as {{ACME, Inc.","42}}.
> * A JSON string body {{"text"}} loses its quotes. A body {{'quoted'}} becomes 
> {{quoted}}, and {{  'x'  }} becomes {{x}}.
> * A header or body whose value is the four-letter text {{null}} is passed as 
> Java {{null}}.
> There is no error or log. The method gets different data than the message 
> holds.
> *Reproduction* (standalone program against main dbdd4b381, bean {{echo(String 
> s)}} returns {{[s]}}):
> {noformat}
> echo(${header.v})  header v = "33a64df551425fcc55e4d42a148795d9"   -> 
> [33a64df551425fcc55e4d42a148795d9]   expected 
> ["33a64df551425fcc55e4d42a148795d9"]
> to("bean:echo?method=echo(${header.v})")  same header                -> same 
> result
> echo(${body})      body "ACME, Inc.","42"                             -> 
> [ACME, Inc.","42]                    expected ["ACME, Inc.","42"]
> echo(${body})      body 'quoted'                                      -> 
> [quoted]
> echo(${body})      body "just a JSON string"                          -> 
> [just a JSON string]
> echo(${body})      body "  'x'  "                                     -> [x]
> echo(${body})      body ''                                            -> []
> two(${header.a}, ${header.b})  a='x' b="y"                            -> 
> [x|y]                                 expected ['x'|"y"]
> echo(${header.v})  header v = null (the text)                         -> 
> method receives null                  expected [null]
> controls: echo (no parameters in the method name) with the ETag body -> 
> ["33a…"]; echo('World') -> [World];
>           echo(${header.v}) with v = abc -> [abc]
> workaround: echo('${header.v}') with the ETag header -> ["33a…"], with v = 
> null (the text) -> [null]
> {noformat}
> A property-based test (jqwik) over random header values fails for every 
> quoted value (shrunk sample {{''}}) and, over an alphabet with quotes and the 
> letters of {{null}}, shrinks to {{'aaaa'}}. The control property (letters 
> only) passes 500 tries.
> A Lean model proves the following:
> * For every string {{w}}, a {{${...}}} value {{"w"}} or {{'w'}} is bound as 
> {{w}} ({{dquoted_value_corrupted}}, {{squoted_value_corrupted}}), so {{w}} 
> and {{'w'}} cannot be told apart ({{not_injective}}).
> * A value that {{removeLeadingAndEndingQuotes}} leaves unchanged and that is 
> not the text {{null}} is bound correctly today ({{unchanged_value_ok}}), and 
> literal parameters are already correct ({{literal_ok}}). The defect is 
> exactly: quoted data and the text {{null}}.
> * The fix below, which decides on the parameter text instead of the evaluated 
> value, meets the documented behaviour for every token ({{fix_meets_spec}}).
> The same {{removeLeadingAndEndingQuotes}} call after the Simple evaluation is 
> in camel-2.25.4 ({{MethodInfo.java:798}}), camel-3.0.0 ({{:719}}), 
> camel-4.0.0 ({{:713}}) and camel-4.14.0 ({{:762}}), so all maintained 
> versions are affected.
> *Proposed fix:* decide what to do from the parameter *text* of the method 
> name, before evaluating it:
> {code:java}
> String exp = ...;                                    // the parameter text, 
> e.g. 'World', ${header.x}, null, 5
> boolean nullKeyword = "null".equals(exp.trim());
> boolean quotedLiteral = StringHelper.isQuoted(exp.trim());
> if (nullKeyword) {
>     return Void.TYPE;
> }
> if (quotedLiteral) {
>     exp = StringHelper.removeLeadingAndEndingQuotes(exp);   // the quotes 
> belong to the method name syntax
> }
> Object parameterValue = evaluateSimpleExpression(exchange, index, exp);
> // no removeLeadingAndEndingQuotes and no "null" check on parameterValue
> {code}
> Then {{'World'}} gives {{World}}, {{'${body}'}} gives the body, {{${body}}} 
> gives the body unchanged, and {{null}} still passes {{null}}. A {{${...}}} 
> that evaluates to Java {{null}} keeps passing {{null}} (use a marker object 
> instead of the String {{"null"}} in {{evaluateSimpleExpression}}).
> Tests: {{BeanParameterValueTest}} with {{echo(${header.v})}} for the header 
> values {{"abc"}}, {{'abc'}} and {{null}} (the text); they must reach the 
> method unchanged. The existing literal tests ({{bar('Camel', true)}}, 
> {{doSomething('Hello World', 2)}}, {{put('isMaster','true')}}) must keep 
> passing.
> Related, lower severity (same parser, could be fixed in the same change): 
> {{StringQuoteHelper.splitSafeQuote}} ({{MethodInfo.java:612}}) splits at 
> every comma outside quotes, including commas inside {{${...}}}. 
> {{echo(${body.substring(0, 3)})}} and {{two(${body}, ${header.v.replace('a', 
> 'b')})}} fail with {{SimpleParserException: missing } to close the 
> function}}. CAMEL-24967 fixed the same problem for Simple function arguments 
> with a depth-aware splitter.
> _Filed with Claude Code on behalf of allthingssecurity._



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

Reply via email to