This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/master by this push: new 056c97d CAMEL-16220: camel-http - optimize producer when sending to uri without any change 056c97d is described below commit 056c97dc21f9dbbae55356a344b6d4857521d4d3 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Tue Feb 16 17:21:03 2021 +0100 CAMEL-16220: camel-http - optimize producer when sending to uri without any change --- .../org/apache/camel/http/base/HttpHelper.java | 10 ++-- .../apache/camel/component/http/HttpProducer.java | 54 +++++++++++++++++--- .../camel/component/http/HeaderFilteringTest.java | 9 +++- .../camel/component/http/HttpProducerLoadTest.java | 6 +-- ...erLoadTest.java => HttpQueryParameterTest.java} | 57 ++++++---------------- .../http/handler/DrinkQueryValidationHandler.java | 34 +++++++++++++ 6 files changed, 113 insertions(+), 57 deletions(-) diff --git a/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpHelper.java b/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpHelper.java index 9469a02..db64572 100644 --- a/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpHelper.java +++ b/components/camel-http-base/src/main/java/org/apache/camel/http/base/HttpHelper.java @@ -67,13 +67,17 @@ public final class HttpHelper { public static void setCharsetFromContentType(String contentType, Exchange exchange) { if (contentType != null) { - String charset = getCharsetFromContentType(contentType); + String charset = IOHelper.getCharsetNameFromContentType(contentType); if (charset != null) { - exchange.setProperty(Exchange.CHARSET_NAME, IOHelper.normalizeCharset(charset)); + exchange.setProperty(Exchange.CHARSET_NAME, charset); } } } + /** + * @deprecated use {@link IOHelper#getCharsetNameFromContentType(String)} + */ + @Deprecated public static String getCharsetFromContentType(String contentType) { if (contentType != null) { // find the charset and set it to the Exchange @@ -124,7 +128,7 @@ public final class HttpHelper { * This implementation supports HTTP multi value parameters which is based on the syntax of * <tt>[value1, value2, value3]</tt> by returning a {@link List} containing the values. * <p/> - * If the value is not a HTTP mulit value the value is returned as is. + * If the value is not a HTTP multi value the value is returned as is. * * @param value the parameter value * @return the extracted parameter value, see more details in javadoc. diff --git a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java index 4278b87..154debb 100644 --- a/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java +++ b/components/camel-http/src/main/java/org/apache/camel/component/http/HttpProducer.java @@ -55,6 +55,7 @@ import org.apache.camel.support.SynchronizationAdapter; import org.apache.camel.util.IOHelper; import org.apache.camel.util.StringHelper; import org.apache.camel.util.URISupport; +import org.apache.camel.util.UnsafeUriCharactersEncoder; import org.apache.http.Header; import org.apache.http.HeaderIterator; import org.apache.http.HttpEntity; @@ -90,6 +91,7 @@ public class HttpProducer extends DefaultProducer { private HeaderFilterStrategy httpProtocolHeaderFilterStrategy = new HttpProtocolHeaderFilterStrategy(); private int minOkRange; private int maxOkRange; + private String defaultUrl; public HttpProducer(HttpEndpoint endpoint) { super(endpoint); @@ -109,11 +111,24 @@ public class HttpProducer extends DefaultProducer { minOkRange = Integer.parseInt(StringHelper.before(range, "-")); maxOkRange = Integer.parseInt(StringHelper.after(range, "-")); } + + // optimize and build default url when there are no override headers + String url = getEndpoint().getHttpUri().toASCIIString(); + url = UnsafeUriCharactersEncoder.encodeHttpURI(url); + URI uri = new URI(url); + String queryString = getEndpoint().getHttpUri().getRawQuery(); + if (queryString == null) { + queryString = uri.getRawQuery(); + } + if (queryString != null) { + queryString = UnsafeUriCharactersEncoder.encodeHttpURI(queryString); + uri = URISupport.createURIWithQuery(uri, queryString); + } + defaultUrl = uri.toASCIIString(); } @Override public void process(Exchange exchange) throws Exception { - if (getEndpoint().isClearExpiredCookies() && !getEndpoint().isBridgeEndpoint()) { // create the cookies before the invocation getEndpoint().getCookieStore().clearExpired(new Date()); @@ -527,11 +542,36 @@ public class HttpProducer extends DefaultProducer { * @throws Exception is thrown if error creating RequestEntity */ protected HttpRequestBase createMethod(Exchange exchange) throws Exception { - // creating the url to use takes 2-steps - String url = HttpHelper.createURL(exchange, getEndpoint()); - URI uri = HttpHelper.createURI(exchange, url, getEndpoint()); - // get the url from the uri - url = uri.toASCIIString(); + if (defaultUrl == null) { + throw new IllegalArgumentException("Producer must be started"); + } + String url = defaultUrl; + + // the exchange can have some headers that override the default url and forces to create + // a new url that is dynamic based on header values + // these checks are checks that is done in HttpHelper.createURL and HttpHelper.createURI methods + boolean create = false; + if (exchange.getIn().getHeader("CamelRestHttpUri") != null) { + create = true; + } else if (exchange.getIn().getHeader("CamelHttpUri") != null && !getEndpoint().isBridgeEndpoint()) { + create = true; + } else if (exchange.getIn().getHeader("CamelHttpPath") != null) { + create = true; + } else if (exchange.getIn().getHeader("CamelRestHttpQuery") != null) { + create = true; + } else if (exchange.getIn().getHeader("CamelHttpRawQuery") != null) { + create = true; + } else if (exchange.getIn().getHeader("CamelHttpQuery") != null) { + create = true; + } + + if (create) { + // creating the url to use takes 2-steps + url = HttpHelper.createURL(exchange, getEndpoint()); + URI uri = HttpHelper.createURI(exchange, url, getEndpoint()); + // get the url from the uri + url = uri.toASCIIString(); + } // create http holder objects for the request HttpMethods methodToUse = HttpMethodHelper.createMethod(exchange, getEndpoint()); @@ -560,7 +600,7 @@ public class HttpProducer extends DefaultProducer { // there must be a host on the method if (method.getURI().getScheme() == null || method.getURI().getHost() == null) { throw new IllegalArgumentException( - "Invalid uri: " + uri + "Invalid url: " + url + ". If you are forwarding/bridging http endpoints, then enable the bridgeEndpoint option on the endpoint: " + getEndpoint()); } diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/HeaderFilteringTest.java b/components/camel-http/src/test/java/org/apache/camel/component/http/HeaderFilteringTest.java index 69e75f4..faed11f 100644 --- a/components/camel-http/src/test/java/org/apache/camel/component/http/HeaderFilteringTest.java +++ b/components/camel-http/src/test/java/org/apache/camel/component/http/HeaderFilteringTest.java @@ -54,9 +54,11 @@ public class HeaderFilteringTest { @Test public void shouldFilterIncomingHttpHeadersInProducer() throws Exception { - final HttpComponent http = new HttpComponent(); - final DefaultCamelContext context = new DefaultCamelContext(); + context.start(); + + final HttpComponent http = context.getComponent("http", HttpComponent.class); + final Producer producer = http.createProducer(context, "http://localhost:" + port, GET.name(), "/test", null, null, APPLICATION_JSON.getMimeType(), APPLICATION_JSON.getMimeType(), new RestConfiguration(), Collections.emptyMap()); @@ -67,11 +69,14 @@ public class HeaderFilteringTest { in.setBody(BODY); exchange.setIn(in); + producer.start(); try { producer.process(exchange); } catch (final HttpOperationFailedException e) { fail(e.getMessage() + "\n%s", e.getResponseBody()); } + producer.stop(); + context.stop(); } @BeforeEach diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerLoadTest.java b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerLoadTest.java index e9fc12b..006a072 100644 --- a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerLoadTest.java +++ b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerLoadTest.java @@ -30,14 +30,13 @@ import org.apache.http.impl.bootstrap.HttpServer; import org.apache.http.impl.bootstrap.ServerBootstrap; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.apache.camel.component.http.HttpMethods.GET; -@Disabled("Manual test") +//@Disabled("Manual test") public class HttpProducerLoadTest extends BaseHttpTest { private static final Logger LOG = LoggerFactory.getLogger(HttpProducerLoadTest.class); @@ -72,8 +71,7 @@ public class HttpProducerLoadTest extends BaseHttpTest { @Override public void configure() throws Exception { from("direct:echo") - .to("http://localhost:" + localServer.getLocalPort() - + "/echo?throwExceptionOnFailure=false"); + .to("http://localhost:5678?copyHeaders=false"); } }; } diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerLoadTest.java b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpQueryParameterTest.java similarity index 57% copy from components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerLoadTest.java copy to components/camel-http/src/test/java/org/apache/camel/component/http/HttpQueryParameterTest.java index e9fc12b..0559939 100644 --- a/components/camel-http/src/test/java/org/apache/camel/component/http/HttpProducerLoadTest.java +++ b/components/camel-http/src/test/java/org/apache/camel/component/http/HttpQueryParameterTest.java @@ -16,31 +16,19 @@ */ package org.apache.camel.component.http; -import java.util.HashMap; -import java.util.Map; - -import org.apache.camel.Endpoint; -import org.apache.camel.Exchange; -import org.apache.camel.Producer; import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; -import org.apache.camel.component.http.handler.DrinkValidationHandler; -import org.apache.camel.util.StopWatch; +import org.apache.camel.component.http.handler.DrinkQueryValidationHandler; import org.apache.http.impl.bootstrap.HttpServer; import org.apache.http.impl.bootstrap.ServerBootstrap; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import static org.apache.camel.component.http.HttpMethods.GET; +import static org.junit.jupiter.api.Assertions.assertEquals; -@Disabled("Manual test") -public class HttpProducerLoadTest extends BaseHttpTest { - - private static final Logger LOG = LoggerFactory.getLogger(HttpProducerLoadTest.class); +public class HttpQueryParameterTest extends BaseHttpTest { private HttpServer localServer; @@ -50,7 +38,8 @@ public class HttpProducerLoadTest extends BaseHttpTest { localServer = ServerBootstrap.bootstrap().setHttpProcessor(getBasicHttpProcessor()) .setConnectionReuseStrategy(getConnectionReuseStrategy()).setResponseFactory(getHttpResponseFactory()) .setExpectationVerifier(getHttpExpectationVerifier()).setSslContext(getSSLContext()) - .registerHandler("/echo", new DrinkValidationHandler(GET.name(), null, null, "myHeader")).create(); + .registerHandler("/moes", new DrinkQueryValidationHandler(GET.name(), null, null, "drink")) + .registerHandler("/joes", new DrinkQueryValidationHandler(GET.name(), null, null, "drink")).create(); localServer.start(); super.setUp(); @@ -71,38 +60,24 @@ public class HttpProducerLoadTest extends BaseHttpTest { return new RouteBuilder() { @Override public void configure() throws Exception { - from("direct:echo") + from("direct:moes") .to("http://localhost:" + localServer.getLocalPort() - + "/echo?throwExceptionOnFailure=false"); + + "/moes?drink=beer"); + + from("direct:joes") + .to("http://localhost:" + localServer.getLocalPort() + + "/joes?drink=wine"); } }; } @Test - public void testProducerLoad() throws Exception { - Map<String, Object> map = new HashMap<>(); - for (int i = 0; i < 40; i++) { - map.put("mykey" + i, "myvalue" + i); - } - - StopWatch watch = new StopWatch(); - - // do not use template but reuse exchange/producer to be light-weight - // and not create additional objects in the JVM as we want to analyze - // the "raw" http producer - Endpoint to = getMandatoryEndpoint("direct:echo"); - Producer producer = to.createProducer(); - producer.start(); - - Exchange exchange = to.createExchange(); - exchange.getMessage().setHeaders(map); - for (int i = 0; i < 10000000; i++) { - exchange.getMessage().setBody("Message " + i); - producer.process(exchange); - } - producer.stop(); + public void testQueryParameter() throws Exception { + String out = fluentTemplate.to("direct:moes").request(String.class); + assertEquals("Drinking /moes?drink=beer", out); - LOG.info("Took {} ms", watch.taken()); + out = fluentTemplate.to("direct:joes").request(String.class); + assertEquals("Drinking /joes?drink=wine", out); } } diff --git a/components/camel-http/src/test/java/org/apache/camel/component/http/handler/DrinkQueryValidationHandler.java b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/DrinkQueryValidationHandler.java new file mode 100644 index 0000000..0af1303 --- /dev/null +++ b/components/camel-http/src/test/java/org/apache/camel/component/http/handler/DrinkQueryValidationHandler.java @@ -0,0 +1,34 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.http.handler; + +import org.apache.http.HttpRequest; + +public class DrinkQueryValidationHandler extends BasicValidationHandler { + + private final String name; + + public DrinkQueryValidationHandler(String expectedMethod, String expectedQuery, Object expectedContent, String name) { + super(expectedMethod, expectedQuery, expectedContent, null); + this.name = name; + } + + @Override + protected String buildResponse(HttpRequest request) { + return "Drinking " + request.getRequestLine().getUri(); + } +}