You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by lb...@apache.org on 2020/11/02 08:52:55 UTC

[camel-k-runtime] branch master updated: kamelet: ensure URL encoded values is properly handled

This is an automated email from the ASF dual-hosted git repository.

lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k-runtime.git


The following commit(s) were added to refs/heads/master by this push:
     new ee0e96e  kamelet: ensure URL encoded values is properly handled
ee0e96e is described below

commit ee0e96eb5184355344db623f20de2f172f43466b
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Fri Oct 30 18:08:45 2020 +0100

    kamelet: ensure URL encoded values is properly handled
---
 .../camel/component/kamelet/KameletComponent.java  | 115 ++++++++++++++++++---
 .../component/kamelet/KameletPropertiesTest.java   |  16 +++
 2 files changed, 116 insertions(+), 15 deletions(-)

diff --git a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java
index 6908f30..7f243af 100644
--- a/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java
+++ b/components/camel-kamelet/src/main/java/org/apache/camel/component/kamelet/KameletComponent.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.component.kamelet;
 
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -23,6 +24,7 @@ import java.util.Properties;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.atomic.AtomicBoolean;
 
+import org.apache.camel.AfterPropertiesConfigured;
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
 import org.apache.camel.RuntimeCamelException;
@@ -33,10 +35,11 @@ import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.PropertiesComponent;
 import org.apache.camel.spi.annotations.Component;
 import org.apache.camel.support.DefaultComponent;
+import org.apache.camel.support.DefaultEndpoint;
 import org.apache.camel.support.LifecycleStrategySupport;
 import org.apache.camel.support.service.ServiceHelper;
-import org.apache.camel.util.StringHelper;
 import org.apache.camel.util.URISupport;
+import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -65,6 +68,102 @@ public class KameletComponent extends DefaultComponent {
     }
 
     @Override
+    public Endpoint createEndpoint(String uri, Map<String, Object> properties) throws Exception {
+        // need to encode before its safe to parse with java.net.Uri
+        String encodedUri = UnsafeUriCharactersEncoder.encode(uri);
+        URI u = new URI(encodedUri);
+        String path;
+        if (u.getScheme() != null) {
+            // if there is a scheme then there is also a path
+            path = URISupport.extractRemainderPath(u, useRawUri());
+        } else {
+            // this uri has no context-path as the leading text is the component name (scheme)
+            path = null;
+        }
+
+        // use encoded or raw uri?
+        Map<String, Object> parameters;
+        if (useRawUri()) {
+            // when using raw uri then the query is taking from the uri as is
+            String query;
+            int idx = uri.indexOf('?');
+            if (idx > -1) {
+                query = uri.substring(idx + 1);
+            } else {
+                query = u.getRawQuery();
+            }
+            // and use method parseQuery
+            parameters = URISupport.parseQuery(query, true);
+        } else {
+            // however when using the encoded (default mode) uri then the query,
+            // is taken from the URI (ensures values is URI encoded)
+            // and use method parseParameters
+            parameters = URISupport.parseParameters(u);
+        }
+        if (properties != null) {
+            parameters.putAll(properties);
+        }
+        // This special property is only to identify endpoints in a unique manner
+        parameters.remove("hash");
+
+        // use encoded or raw uri?
+        uri = useRawUri() ? uri : encodedUri;
+
+        validateURI(uri, path, parameters);
+        if (LOGGER.isTraceEnabled()) {
+            // at trace level its okay to have parameters logged, that may contain passwords
+            LOGGER.trace("Creating endpoint uri=[{}], path=[{}], parameters=[{}]", URISupport.sanitizeUri(uri),
+                URISupport.sanitizePath(path), parameters);
+        } else if (LOGGER.isDebugEnabled()) {
+            // but at debug level only output sanitized uris
+            LOGGER.debug("Creating endpoint uri=[{}], path=[{}]", URISupport.sanitizeUri(uri), URISupport.sanitizePath(path));
+        }
+
+        // extract these global options and infer their value based on global/component level configuration
+        boolean basic = getAndRemoveParameter(parameters, "basicPropertyBinding", boolean.class, isBasicPropertyBinding()
+            ? isBasicPropertyBinding() : getCamelContext().getGlobalEndpointConfiguration().isBasicPropertyBinding());
+        boolean bridge = getAndRemoveParameter(parameters, "bridgeErrorHandler", boolean.class, isBridgeErrorHandler()
+            ? isBridgeErrorHandler() : getCamelContext().getGlobalEndpointConfiguration().isBridgeErrorHandler());
+        boolean lazy = getAndRemoveParameter(parameters, "lazyStartProducer", boolean.class, isLazyStartProducer()
+            ? isLazyStartProducer() : getCamelContext().getGlobalEndpointConfiguration().isLazyStartProducer());
+
+        // create endpoint
+        Endpoint endpoint = createEndpoint(uri, path, parameters);
+        if (endpoint == null) {
+            return null;
+        }
+        // inject camel context
+        endpoint.setCamelContext(getCamelContext());
+
+        // and setup those global options afterwards
+        if (endpoint instanceof DefaultEndpoint) {
+            DefaultEndpoint de = (DefaultEndpoint) endpoint;
+            de.setBasicPropertyBinding(basic);
+            de.setBridgeErrorHandler(bridge);
+            de.setLazyStartProducer(lazy);
+        }
+
+        URISupport.resolveRawParameterValues(parameters);
+
+        // configure remainder of the parameters
+        setProperties(endpoint, parameters);
+
+        // if endpoint is strict (not lenient) and we have unknown parameters configured then
+        // fail if there are parameters that could not be set, then they are probably misspell or not supported at all
+        if (!endpoint.isLenientProperties()) {
+            validateParameters(uri, parameters, null);
+        }
+
+        // allow custom configuration after properties has been configured
+        if (endpoint instanceof AfterPropertiesConfigured) {
+            ((AfterPropertiesConfigured) endpoint).afterPropertiesConfigured(getCamelContext());
+        }
+
+        afterConfiguration(uri, path, endpoint, parameters);
+        return endpoint;
+    }
+
+    @Override
     protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
         final String templateId = Kamelet.extractTemplateId(getCamelContext(), remaining, parameters);
         final String routeId = Kamelet.extractRouteId(getCamelContext(), remaining, parameters);
@@ -123,14 +222,6 @@ public class KameletComponent extends DefaultComponent {
             // set endpoint specific properties
             setProperties(endpoint, parameters);
 
-            // determine the parameters that the kamelet should take by using the original
-            // uri as we need to preserve the original format.
-            final String query = StringHelper.after(uri, "?");
-            final Map<String, Object> queryParams = URISupport.parseQuery(query, true, true);
-
-            // replace resolved params with the original ones
-            parameters.replaceAll(queryParams::getOrDefault);
-
             //
             // The properties for the kamelets are determined by global properties
             // and local endpoint parameters,
@@ -176,12 +267,6 @@ public class KameletComponent extends DefaultComponent {
     }
 
     @Override
-    public boolean useRawUri() {
-        // should use encoded uri by default
-        return true;
-    }
-
-    @Override
     protected void doInit() throws Exception {
         getCamelContext().addLifecycleStrategy(lifecycleHandler);
 
diff --git a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java
index fa6891e..91302e0 100644
--- a/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java
+++ b/components/camel-kamelet/src/test/java/org/apache/camel/component/kamelet/KameletPropertiesTest.java
@@ -108,6 +108,14 @@ public class KameletPropertiesTest extends CamelTestSupport {
             .hasFieldOrPropertyWithValue("proxyAuthPassword", "p+wd");
     }
 
+    @Test
+    public void urlEncodingIsRespected() {
+        assertThat(context.getEndpoint("kamelet:timer-source?message=Hello+Kamelets&period=1000", KameletEndpoint.class).getKameletProperties())
+            .containsEntry("message", "Hello Kamelets");
+        assertThat(context.getEndpoint("kamelet:timer-source?message=messaging.knative.dev%2Fv1beta1&period=1000", KameletEndpoint.class).getKameletProperties())
+            .containsEntry("message", "messaging.knative.dev/v1beta1");
+    }
+
     // **********************************************
     //
     // test set-up
@@ -145,6 +153,14 @@ public class KameletPropertiesTest extends CamelTestSupport {
                     .from("kamelet:source")
                         .log("info")
                         .to("http://localhost:8080?proxyAuthUsername={{proxyUsr}}&proxyAuthPassword={{proxyPwd}}");
+
+                // template
+                routeTemplate("timer-source")
+                    .templateParameter("period")
+                    .templateParameter("message")
+                    .from("timer:tick")
+                        .setBody().constant("{{message}}")
+                        .to("kamelet:sink");
             }
         };
     }