gnodet-bot commented on code in PR #26758:
URL: https://github.com/apache/camel/pull/26758#discussion_r4079682637


##########
dsl/camel-yaml-dsl/camel-yaml-dsl-validator/src/main/java/org/apache/camel/dsl/yaml/validator/YamlValidator.java:
##########
@@ -668,6 +669,87 @@ void checkSimpleSyntaxInScripts(JsonNode node, NodePath 
path, List<Error> errors
         }
     }
 
+    /**
+     * to: http://host/stock/${header.sku}: the endpoint of a to: is resolved 
once when the route starts, so an
+     * expression in its path is never evaluated - it is sent as the text it 
is, url-encoded. That is what toD: is for
+     * (CAMEL-24917).
+     * <p/>
+     * Only the path is checked, never the options after the {@code ?}: an 
option such as the file component's
+     * {@code fileName=${date:now:yyyyMMdd}} is evaluated by the producer and 
is correct on a plain to:.
+     */
+    void checkDynamicUri(JsonNode node, NodePath path, List<Error> errors) {
+        if (node == null) {
+            return;
+        }
+        if (node.isArray()) {
+            for (int i = 0; i < node.size(); i++) {
+                checkDynamicUri(node.get(i), path.append(i), errors);
+            }
+            return;
+        }
+        if (!node.isObject()) {
+            return;
+        }
+        var fields = node.fieldNames();
+        while (fields.hasNext()) {
+            String name = fields.next();
+            JsonNode value = node.get(name);
+            if ("to".equals(name)) {
+                String uri = null;
+                NodePath at = path.append(name);
+                if (value.isTextual()) {
+                    uri = value.asText();
+                } else if (value.isObject() && value.has("uri") && 
value.get("uri").isTextual()) {
+                    uri = value.get("uri").asText();
+                    at = at.append("uri");
+                }
+                String expression = expressionInPath(uri);
+                if (expression != null) {
+                    errors.add(Error.builder()
+                            .keyword("type")
+                            .instanceLocation(at)
+                            .messageKey("type")
+                            .format(new MessageFormat("{0}"))
+                            .arguments("to: the uri holds an expression (" + 
expression + ") but the endpoint of a to:"
+                                       + " is fixed when the route starts, so 
it is sent as text: write toD: to build"
+                                       + " the uri for each message")
+                            .build());
+                }
+            }
+            checkDynamicUri(value, path.append(name), errors);
+        }
+    }
+
+    /**
+     * The first simple expression in the path of the uri (what comes before 
the options), or null when there is none.
+     */
+    private static String expressionInPath(String uri) {
+        if (uri == null) {
+            return null;
+        }
+        int scheme = uri.indexOf(':');
+        if (scheme > 0 && EVALUATED_PATH.contains(uri.substring(0, scheme))) {
+            return null;
+        }
+        String head = uri.indexOf('?') > 0 ? uri.substring(0, 
uri.indexOf('?')) : uri;
+        int start = head.indexOf("${");
+        if (start < 0) {
+            return null;
+        }
+        if (start >= 2 && head.startsWith(":#", start - 2)) {
+            return null; // :#${...} is a parameter the component binds per 
message, not part of the address
+        }
+        int end = head.indexOf('}', start);
+        return end > 0 ? head.substring(start, end + 1) : 
head.substring(start);
+    }
+
+    /**
+     * Components that read their path as a script, a statement or a template 
name and evaluate it for each message,
+     * where an expression in the path is what the component is for.
+     */
+    private static final Set<String> EVALUATED_PATH = Set.of("language", 
"sql", "sql-stored", "elsql", "jdbc",
+            "spring-jdbc", "mybatis", "xquery", "xslt");

Review Comment:
   ⚠️ **`xslt` and `xquery` do not belong in `EVALUATED_PATH`.**
   
   The Javadoc says these components "read their path as a script, a statement 
or a template name and evaluate it for each message" — but that is not what 
they do. Both `XsltEndpoint` and `XQueryEndpoint` resolve their `resourceUri` 
**once at startup** and load the stylesheet/query from that fixed path. They 
never evaluate a `${...}` in the URI path per-message; dynamic template 
selection in `xslt` is done via `allowTemplateFromHeader` (a message header, 
not a path expression).
   
   Consequence: a user who writes
   ```yaml
   - to:
       uri: "xslt:my-${header.type}.xsl"
   ```
   gets no warning. The expression is sent as literal text at startup — the 
exact runtime-silent bug this PR guards against — and the validator lets it 
pass.
   
   Remove both from the set. Add two test cases in 
`YamlValidatorDynamicUriTest` asserting that `xslt:my-${header.type}.xsl` and 
`xquery:my-${header.type}.xq` **are** flagged.
   
   ```suggestion
       private static final Set<String> EVALUATED_PATH = Set.of("language", 
"sql", "sql-stored", "elsql", "jdbc",
               "spring-jdbc", "mybatis");
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to