This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel.git
commit 6831f37c94e4906873a4836e8c1c2e34383951be Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Fri Dec 10 07:59:11 2021 +0100 CAMEL-17295: rest-dsl - Fix parse uri template for query parameters. --- .../servlet/rest/RestServletQueryParamTest.java | 20 ++- ...Test.java => RestServletQueryParamUriTest.java} | 28 ++-- .../apache/camel/model/rest/RestDefinition.java | 145 +++++++++++++-------- 3 files changed, 123 insertions(+), 70 deletions(-) diff --git a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamTest.java b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamTest.java index 68f7d29..4b49f8d 100644 --- a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamTest.java +++ b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamTest.java @@ -31,7 +31,7 @@ public class RestServletQueryParamTest extends ServletCamelRouterTestSupport { private ServletRestHttpBinding restHttpBinding = new ServletRestHttpBinding(); @Test - public void testServletProducerGet() throws Exception { + public void testQueryTrue() throws Exception { WebRequest req = new GetMethodWebRequest(contextUrl + "/services/users/"); req.setParameter("auth", "secret"); WebResponse response = query(req, false); @@ -41,25 +41,35 @@ public class RestServletQueryParamTest extends ServletCamelRouterTestSupport { assertEquals("secret;Donald Duck", response.getText()); } + @Test + public void testQueryFalse() throws Exception { + WebRequest req = new GetMethodWebRequest(contextUrl + "/services/users/"); + WebResponse response = query(req, false); + + assertEquals(400, response.getResponseCode()); + } + @Override protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { // configure to use servlet on localhost - restConfiguration().component("servlet").host("localhost").endpointProperty("httpBinding", "#myBinding"); + restConfiguration().component("servlet").host("localhost").endpointProperty("httpBinding", "#myBinding") + .clientRequestValidation(true); // use the rest DSL to define the rest services rest() - .get("/users/?auth={myToken}") + .get("/users/") .param() .name("auth") .type(RestParamType.query) + .required(true) .endParam() .route().to("mock:input").process(exchange -> { String auth = exchange.getIn().getHeader("auth", String.class); - exchange.getMessage().setBody(auth + ";Donald Duck"); - }); + exchange.getMessage().setBody(auth + ";Donald Duck"); + }); } }; } diff --git a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamTest.java b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamUriTest.java similarity index 73% copy from components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamTest.java copy to components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamUriTest.java index 68f7d29..4ed1b34 100644 --- a/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamTest.java +++ b/components/camel-servlet/src/test/java/org/apache/camel/component/servlet/rest/RestServletQueryParamUriTest.java @@ -20,18 +20,17 @@ import org.apache.camel.BindToRegistry; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.component.servlet.ServletCamelRouterTestSupport; import org.apache.camel.component.servlet.ServletRestHttpBinding; -import org.apache.camel.model.rest.RestParamType; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; -public class RestServletQueryParamTest extends ServletCamelRouterTestSupport { +public class RestServletQueryParamUriTest extends ServletCamelRouterTestSupport { @BindToRegistry("myBinding") private ServletRestHttpBinding restHttpBinding = new ServletRestHttpBinding(); @Test - public void testServletProducerGet() throws Exception { + public void testQueryTrue() throws Exception { WebRequest req = new GetMethodWebRequest(contextUrl + "/services/users/"); req.setParameter("auth", "secret"); WebResponse response = query(req, false); @@ -41,25 +40,32 @@ public class RestServletQueryParamTest extends ServletCamelRouterTestSupport { assertEquals("secret;Donald Duck", response.getText()); } + @Test + public void testQueryFalse() throws Exception { + WebRequest req = new GetMethodWebRequest(contextUrl + "/services/users/"); + WebResponse response = query(req, false); + + // we do not know if the query was required, so we cannot validate this + assertEquals(200, response.getResponseCode()); + assertEquals("null;Donald Duck", response.getText()); + } + @Override protected RouteBuilder createRouteBuilder() throws Exception { return new RouteBuilder() { @Override public void configure() throws Exception { // configure to use servlet on localhost - restConfiguration().component("servlet").host("localhost").endpointProperty("httpBinding", "#myBinding"); + restConfiguration().component("servlet").host("localhost").endpointProperty("httpBinding", "#myBinding") + .clientRequestValidation(true); // use the rest DSL to define the rest services rest() - .get("/users/?auth={myToken}") - .param() - .name("auth") - .type(RestParamType.query) - .endParam() + .get("/users/?auth={myAuth}") .route().to("mock:input").process(exchange -> { String auth = exchange.getIn().getHeader("auth", String.class); - exchange.getMessage().setBody(auth + ";Donald Duck"); - }); + exchange.getMessage().setBody(auth + ";Donald Duck"); + }); } }; } diff --git a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java index e56a633..df627cd 100644 --- a/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java +++ b/core/camel-core-model/src/main/java/org/apache/camel/model/rest/RestDefinition.java @@ -16,7 +16,6 @@ */ package org.apache.camel.model.rest; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -792,13 +791,11 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> } if (!options.isEmpty()) { - String query; try { - query = URISupport.createQueryString(options); - } catch (URISyntaxException e) { + from = URISupport.appendParametersToURI(from, options); + } catch (Exception e) { throw RuntimeCamelException.wrapRuntimeCamelException(e); } - from = from + "?" + query; } // we use the same uri as the producer (so we have a little route for @@ -885,9 +882,6 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> route.setRestBindingDefinition(binding); - // create the from endpoint uri which is using the rest component - String from = buildFromUri(verb); - // append options Map<String, Object> options = new HashMap<>(); // verb takes precedence over configuration on rest @@ -934,16 +928,6 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> options.put("description", description); } - if (!options.isEmpty()) { - String query; - try { - query = URISupport.createQueryString(options); - } catch (URISyntaxException e) { - throw RuntimeCamelException.wrapRuntimeCamelException(e); - } - from = from + "?" + query; - } - String path = getPath(); String s1 = FileUtil.stripTrailingSeparator(path); String s2 = FileUtil.stripLeadingSeparator(verb.getUri()); @@ -957,42 +941,17 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> } // each {} is a parameter (url templating) - if (allPath != null) { - String[] arr = allPath.split("\\/"); - for (String a : arr) { - // need to resolve property placeholders first - try { - a = camelContext.resolvePropertyPlaceholders(a); - } catch (Exception e) { - throw RuntimeCamelException.wrapRuntimeCamelException(e); - } - - Matcher m = Pattern.compile("\\{(.*?)\\}").matcher(a); - while (m.find()) { - String key = m.group(1); - // merge if exists - boolean found = false; - for (RestOperationParamDefinition param : verb.getParams()) { - // name is mandatory - String name = param.getName(); - StringHelper.notEmpty(name, "parameter name"); - // need to resolve property placeholders first - try { - name = camelContext.resolvePropertyPlaceholders(name); - } catch (Exception e) { - throw RuntimeCamelException.wrapRuntimeCamelException(e); - } - if (name.equalsIgnoreCase(key)) { - param.type(RestParamType.path); - found = true; - break; - } - } - if (!found) { - param(verb).name(key).type(RestParamType.path).endParam(); - } - } - } + Set<String> toRemove = null; + if (allPath != null && allPath.contains("?")) { + // special when having query parameters + String path1 = StringHelper.before(allPath, "?"); + uriTemplating(camelContext, verb, path1, false); + String path2 = StringHelper.after(allPath, "?"); + // there may be some query parameters that are templates which we then must remove + toRemove = uriTemplating(camelContext, verb, path2, true); + } else { + // no query parameters + uriTemplating(camelContext, verb, allPath, false); } if (verb.getType() != null) { @@ -1010,6 +969,36 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> } } + // create the from endpoint uri which is using the rest component + String from = buildFromUri(verb); + + // rebuild uri without these query parameters + if (toRemove != null && !toRemove.isEmpty()) { + try { + Map<String, Object> query = URISupport.parseQuery(URISupport.extractQuery(from)); + // remove if the value matches, eg: auth={myAuth} + toRemove.forEach(v -> { + query.values().removeIf(qv -> qv.toString().equals(v)); + }); + from = URISupport.stripQuery(from); + if (!query.isEmpty()) { + String q = URISupport.createQueryString(query); + from = URISupport.stripQuery(from) + "?" + q; + } + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeCamelException(e); + } + } + + // append additional options + if (!options.isEmpty()) { + try { + from = URISupport.appendParametersToURI(from, options); + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeCamelException(e); + } + } + // the route should be from this rest endpoint route.fromRest(from); route.setRestDefinition(this); @@ -1017,6 +1006,54 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> } } + private Set<String> uriTemplating( + CamelContext camelContext, VerbDefinition verb, + String path, boolean query) { + + if (path == null) { + return null; + } + + Set<String> params = new HashSet<>(); + String[] arr = path.split("\\/"); + for (String a : arr) { + // need to resolve property placeholders first + try { + a = camelContext.resolvePropertyPlaceholders(a); + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeCamelException(e); + } + + Matcher m = Pattern.compile("\\{(.*?)\\}").matcher(a); + while (m.find()) { + String key = m.group(1); + params.add("{" + key + "}"); + // merge if exists + boolean found = false; + for (RestOperationParamDefinition param : verb.getParams()) { + // name is mandatory + String name = param.getName(); + StringHelper.notEmpty(name, "parameter name"); + // need to resolve property placeholders first + try { + name = camelContext.resolvePropertyPlaceholders(name); + } catch (Exception e) { + throw RuntimeCamelException.wrapRuntimeCamelException(e); + } + if (name.equalsIgnoreCase(key)) { + param.type(query ? RestParamType.query : RestParamType.path); + found = true; + break; + } + } + if (!found) { + param(verb).name(key).type(query ? RestParamType.query : RestParamType.path).endParam(); + } + } + } + return params; + } + private String buildUri(VerbDefinition verb) { if (path != null && verb.getUri() != null) { return path + ":" + verb.getUri();