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


##########
components/camel-kamelet/src/main/docs/kamelet-component.adoc:
##########
@@ -163,6 +163,52 @@ The usage of this Kamelet into a Camel route is going to 
be the same as any othe
 
 WARNING: beware of any potential circular reference you may introduce when 
using chain of Kamelets, in which case, the runtime will likely be idle 
consuming a high amount of resources.
 
+=== Advanced component endpoint options
+
+Kamelets expose a defined set of parameters, but the underlying Camel 
component may support additional endpoint options. You can pass these options 
when using a Kamelet by prefixing them with `source.` or `sink.`, depending on 
the type of Kamelet.
+
+The prefix is removed when the options are applied to the underlying endpoint 
URI. The options must be supported by the component used by that endpoint.
+
+==== Source Kamelets
+
+For source Kamelets, use the `source.` prefix to pass additional options to 
the underlying source component endpoint.
+
+For example:
+
+[source,java]
+----
+from("kamelet:my-source?source.block=true")

Review Comment:
   💡 **Low: `block` is a producer-only option — misleading as a source example**
   
   `block` is annotated `@UriParam(label = "producer")` on `DirectEndpoint` — 
it controls producer-side blocking when no consumer is active. Using it as the 
primary `source.*` example (applied to a `from()` consumer) is technically 
valid but semantically misleading. Consider a more representative consumer 
option like `bridgeErrorHandler`, or a component-neutral property that actually 
affects consumption behaviour.



##########
components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/Kamelet.java:
##########
@@ -184,6 +205,164 @@ public static void 
extractKameletEnvironmentVariables(Map<String, Object> proper
         }
     }
 
+    /**
+     * Extracts advanced options without discarding camelCase and kebab-case 
aliases before normalization.
+     */
+    private static Map<String, Object> extractAdvancedOptions(Map<String, 
Object> parameters, String prefix) {
+        Map<String, Object> options = new LinkedHashMap<>();
+        if (parameters == null) {
+            return options;
+        }
+
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            String key = entry.getKey();
+            if (key != null && key.startsWith(prefix)) {
+                options.put(key.substring(prefix.length()), entry.getValue());
+            }
+        }
+
+        return options;
+    }
+
+    /**
+     * Normalizes option names so that camelCase and kebab-case aliases do not 
cause the same option to be appended more
+     * than once. When both forms are present, the kebab-case form takes 
precedence.
+     */
+    private static Map<String, Object> normalizeParameterNames(Map<String, 
Object> parameters) {
+        Map<String, Object> normalized = new LinkedHashMap<>();
+        Map<String, Boolean> canonicalKeys = new HashMap<>();
+
+        if (parameters == null) {
+            return normalized;
+        }
+
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            String originalName = entry.getKey();
+            String name = StringHelper.camelCaseToDash(originalName);
+            boolean isCanonical = originalName.equals(name);
+
+            if (!normalized.containsKey(name) || (isCanonical && 
!canonicalKeys.getOrDefault(name, false))) {
+                normalized.put(name, entry.getValue());
+                canonicalKeys.put(name, isCanonical);
+            }
+        }
+
+        return normalized;
+    }
+
+    /**
+     * Appends query parameters without parsing or re-encoding the endpoint 
URI. This preserves property placeholders
+     * and RAW expressions that may appear in the URI.
+     */
+    private static String appendParametersToURI(String uri, Map<String, 
Object> parameters) {
+        if (parameters == null || parameters.isEmpty()) {
+            return uri;
+        }
+
+        String result = uri;
+        for (Map.Entry<String, Object> entry : parameters.entrySet()) {
+            String name = entry.getKey();
+            String value = String.valueOf(entry.getValue());
+
+            result = removeQueryParameter(result, name);
+            result += result.contains("?") ? "&" : "?";
+            result += name + "=" + value;

Review Comment:
   ⚠️ **Medium: URI corruption for values containing `&` or `=`**
   
   Values appended here have already been through 
`URISupport.resolveRawParameterValues()` in 
`KameletComponent.createEndpoint()`, which strips `RAW()` wrappers. If a user 
passes `sink.password=RAW(p@ss&word)`, the value arriving here is `p@ss&word`, 
and naive concatenation produces `&password=p@ss&word` — the `word` part 
becomes a spurious parameter.
   
   Consider wrapping URI-sensitive values in `RAW()` before appending:
   
   ```suggestion
               result = removeQueryParameter(result, name);
               result += result.contains("?") ? "&" : "?";
               // Re-wrap values that contain URI-sensitive characters in RAW() 
to prevent
               // corruption when the value contains '&', '=', or '?' (e.g., 
passwords)
               if (value.contains("&") || value.contains("=") || 
value.contains("?")) {
                   result += name + "=RAW(" + value + ")";
               } else {
                   result += name + "=" + value;
               }
   ```



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