[
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)