Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 00D8F200BDA for ; Tue, 13 Dec 2016 09:21:55 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id F38F6160B15; Tue, 13 Dec 2016 08:21:54 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 443D6160B31 for ; Tue, 13 Dec 2016 09:21:53 +0100 (CET) Received: (qmail 72259 invoked by uid 500); 13 Dec 2016 08:21:52 -0000 Mailing-List: contact commits-help@camel.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@camel.apache.org Delivered-To: mailing list commits@camel.apache.org Received: (qmail 72233 invoked by uid 99); 13 Dec 2016 08:21:52 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 13 Dec 2016 08:21:52 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 014A4F175D; Tue, 13 Dec 2016 08:21:52 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: nferraro@apache.org To: commits@camel.apache.org Date: Tue, 13 Dec 2016 08:21:53 -0000 Message-Id: <2a896696db0c43d39a15a4985b3ea185@git.apache.org> In-Reply-To: <639037b706eb43f8b58e3fc302e7f160@git.apache.org> References: <639037b706eb43f8b58e3fc302e7f160@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [3/3] camel git commit: CAMEL-10564: fixing netty-http nested configuration archived-at: Tue, 13 Dec 2016 08:21:55 -0000 CAMEL-10564: fixing netty-http nested configuration Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/b971204a Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/b971204a Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/b971204a Branch: refs/heads/master Commit: b971204a5c6d288696c5abfe76ccebbe7a3abeba Parents: d034c4d Author: Nicola Ferraro Authored: Mon Dec 12 18:05:07 2016 +0100 Committer: Nicola Ferraro Committed: Tue Dec 13 09:20:58 2016 +0100 ---------------------------------------------------------------------- .../camel-netty-http-starter/pom.xml | 8 + .../NettyHttpComponentConfiguration.java | 299 +++++++++++++++++- .../NettyHttpAutoConfigurationTest.java | 74 +++++ .../http/springboot/NettyStarterTestHelper.java | 43 +++ .../camel-netty4-http-starter/pom.xml | 8 + .../NettyHttpComponentConfiguration.java | 300 ++++++++++++++++++- .../Netty4HttpAutoConfigurationTest.java | 74 +++++ .../springboot/Netty4StarterTestHelper.java | 43 +++ .../src/main/docs/netty-http-component.adoc | 2 +- .../netty/http/NettyHttpComponent.java | 9 + .../src/main/docs/netty4-http-component.adoc | 2 +- .../netty4/http/NettyHttpComponent.java | 9 + 12 files changed, 841 insertions(+), 30 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty-http-starter/pom.xml ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty-http-starter/pom.xml b/components-starter/camel-netty-http-starter/pom.xml index 3bf5ce1..b77fb98 100644 --- a/components-starter/camel-netty-http-starter/pom.xml +++ b/components-starter/camel-netty-http-starter/pom.xml @@ -37,6 +37,14 @@ camel-netty-http ${project.version} + + + org.apache.camel + camel-http-starter + ${project.version} + test + + org.apache.camel http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty-http-starter/src/main/java/org/apache/camel/component/netty/http/springboot/NettyHttpComponentConfiguration.java ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty-http-starter/src/main/java/org/apache/camel/component/netty/http/springboot/NettyHttpComponentConfiguration.java b/components-starter/camel-netty-http-starter/src/main/java/org/apache/camel/component/netty/http/springboot/NettyHttpComponentConfiguration.java index 13f4166..68348c6 100644 --- a/components-starter/camel-netty-http-starter/src/main/java/org/apache/camel/component/netty/http/springboot/NettyHttpComponentConfiguration.java +++ b/components-starter/camel-netty-http-starter/src/main/java/org/apache/camel/component/netty/http/springboot/NettyHttpComponentConfiguration.java @@ -17,7 +17,6 @@ package org.apache.camel.component.netty.http.springboot; import org.apache.camel.LoggingLevel; -import org.apache.camel.component.netty.NettyConfiguration; import org.apache.camel.component.netty.http.NettyHttpBinding; import org.apache.camel.component.netty.http.SecurityAuthenticator; import org.apache.camel.component.netty.http.SecurityConstraint; @@ -40,6 +39,10 @@ public class NettyHttpComponentConfiguration { @NestedConfigurationProperty private NettyHttpBinding nettyHttpBinding; /** + * To use the NettyConfiguration as configuration when creating endpoints. + */ + private NettyHttpConfigurationNestedConfiguration configuration; + /** * To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter * headers. */ @@ -52,11 +55,6 @@ public class NettyHttpComponentConfiguration { */ private NettyHttpSecurityConfigurationNestedConfiguration securityConfiguration; /** - * To use the NettyConfiguration as configuration when creating endpoints. - */ - @NestedConfigurationProperty - private NettyConfiguration configuration; - /** * The core pool size for the ordered thread pool if its in use. The default * value is 16. */ @@ -70,6 +68,15 @@ public class NettyHttpComponentConfiguration { this.nettyHttpBinding = nettyHttpBinding; } + public NettyHttpConfigurationNestedConfiguration getConfiguration() { + return configuration; + } + + public void setConfiguration( + NettyHttpConfigurationNestedConfiguration configuration) { + this.configuration = configuration; + } + public HeaderFilterStrategy getHeaderFilterStrategy() { return headerFilterStrategy; } @@ -88,14 +95,6 @@ public class NettyHttpComponentConfiguration { this.securityConfiguration = securityConfiguration; } - public NettyConfiguration getConfiguration() { - return configuration; - } - - public void setConfiguration(NettyConfiguration configuration) { - this.configuration = configuration; - } - public Integer getMaximumPoolSize() { return maximumPoolSize; } @@ -104,6 +103,278 @@ public class NettyHttpComponentConfiguration { this.maximumPoolSize = maximumPoolSize; } + public static class NettyHttpConfigurationNestedConfiguration { + public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.netty.http.NettyHttpConfiguration.class; + /** + * The protocol to use which is either http or https + */ + private String protocol; + /** + * The local hostname such as localhost, or 0.0.0.0 when being a + * consumer. The remote HTTP server hostname when using producer. + */ + private String host; + /** + * The port number. Is default 80 for http and 443 for https. + */ + private Integer port; + /** + * Allow using gzip/deflate for compression on the Netty HTTP server if + * the client supports it from the HTTP headers. + */ + private Boolean compression; + /** + * Option to disable throwing the HttpOperationFailedException in case + * of failed responses from the remote server. This allows you to get + * all responses regardless of the HTTP status code. + */ + private Boolean throwExceptionOnFailure; + /** + * If enabled and an Exchange failed processing on the consumer side, + * and if the caused Exception was send back serialized in the response + * as a application/x-java-serialized-object content type. On the + * producer side the exception will be deserialized and thrown as is, + * instead of the HttpOperationFailedException. The caused exception is + * required to be serialized. + *

+ * This is by default turned off. If you enable this then be aware that + * Java will deserialize the incoming data from the request to Java and + * that can be a potential security risk. + */ + private Boolean transferException; + /** + * If this option is enabled, then during binding from Netty to Camel + * Message then the header values will be URL decoded (eg %20 will be a + * space character. Notice this option is used by the default + * org.apache.camel.component.netty.http.NettyHttpBinding and therefore + * if you implement a custom + * org.apache.camel.component.netty.http.NettyHttpBinding then you would + * need to decode the headers accordingly to this option. + */ + private Boolean urlDecodeHeaders; + /** + * If this option is enabled, then during binding from Netty to Camel + * Message then the headers will be mapped as well (eg added as header + * to the Camel Message as well). You can turn off this option to + * disable this. The headers can still be accessed from the + * org.apache.camel.component.netty.http.NettyHttpMessage message with + * the method getHttpRequest() that returns the Netty HTTP request + * org.jboss.netty.handler.codec.http.HttpRequest instance. + */ + private Boolean mapHeaders; + /** + * Whether or not Camel should try to find a target consumer by matching + * the URI prefix if no exact match is found. + */ + private Boolean matchOnUriPrefix; + /** + * If the option is true, the producer will ignore the Exchange.HTTP_URI + * header, and use the endpoint's URI for request. You may also set the + * throwExceptionOnFailure to be false to let the producer send all the + * fault response back. The consumer working in the bridge mode will + * skip the gzip compression and WWW URL form encoding (by adding the + * Exchange.SKIP_GZIP_ENCODING and Exchange.SKIP_WWW_FORM_URLENCODED + * headers to the consumed exchange). + */ + private Boolean bridgeEndpoint; + /** + * Resource path + */ + private String path; + /** + * Determines whether or not the raw input stream from Netty + * HttpRequest#getContent() is cached or not (Camel will read the stream + * into a in light-weight memory based Stream caching) cache. By default + * Camel will cache the Netty input stream to support reading it + * multiple times to ensure it Camel can retrieve all data from the + * stream. However you can set this option to true when you for example + * need to access the raw stream, such as streaming it directly to a + * file or other persistent store. Mind that if you enable this option, + * then you cannot read the Netty stream multiple times out of the box, + * and you would need manually to reset the reader index on the Netty + * raw stream. + */ + private Boolean disableStreamCache; + /** + * Whether to send back HTTP status code 503 when the consumer has been + * suspended. If the option is false then the Netty Acceptor is unbound + * when the consumer is suspended, so clients cannot connect anymore. + */ + private Boolean send503whenSuspended; + /** + * Value in bytes the max content length per chunked frame received on + * the Netty HTTP server. + */ + private Integer chunkedMaxContentLength; + /** + * The maximum length of all headers. If the sum of the length of each + * header exceeds this value, a {@link TooLongFrameException} will be + * raised. + */ + private Integer maxHeaderSize; + private Boolean allowDefaultCodec; + /** + * The status codes which is considered a success response. The values + * are inclusive. The range must be defined as from-to with the dash + * included. + *

+ * The default range is 200-299 + */ + private String okStatusCodeRange = "200-299"; + /** + * Sets whether to use a relative path in HTTP requests. + *

+ * Some third party backend systems such as IBM Datapower do not support + * absolute URIs in HTTP POSTs, and setting this option to true + * can work around this problem. + */ + private Boolean useRelativePath; + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Boolean getCompression() { + return compression; + } + + public void setCompression(Boolean compression) { + this.compression = compression; + } + + public Boolean getThrowExceptionOnFailure() { + return throwExceptionOnFailure; + } + + public void setThrowExceptionOnFailure(Boolean throwExceptionOnFailure) { + this.throwExceptionOnFailure = throwExceptionOnFailure; + } + + public Boolean getTransferException() { + return transferException; + } + + public void setTransferException(Boolean transferException) { + this.transferException = transferException; + } + + public Boolean getUrlDecodeHeaders() { + return urlDecodeHeaders; + } + + public void setUrlDecodeHeaders(Boolean urlDecodeHeaders) { + this.urlDecodeHeaders = urlDecodeHeaders; + } + + public Boolean getMapHeaders() { + return mapHeaders; + } + + public void setMapHeaders(Boolean mapHeaders) { + this.mapHeaders = mapHeaders; + } + + public Boolean getMatchOnUriPrefix() { + return matchOnUriPrefix; + } + + public void setMatchOnUriPrefix(Boolean matchOnUriPrefix) { + this.matchOnUriPrefix = matchOnUriPrefix; + } + + public Boolean getBridgeEndpoint() { + return bridgeEndpoint; + } + + public void setBridgeEndpoint(Boolean bridgeEndpoint) { + this.bridgeEndpoint = bridgeEndpoint; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Boolean getDisableStreamCache() { + return disableStreamCache; + } + + public void setDisableStreamCache(Boolean disableStreamCache) { + this.disableStreamCache = disableStreamCache; + } + + public Boolean getSend503whenSuspended() { + return send503whenSuspended; + } + + public void setSend503whenSuspended(Boolean send503whenSuspended) { + this.send503whenSuspended = send503whenSuspended; + } + + public Integer getChunkedMaxContentLength() { + return chunkedMaxContentLength; + } + + public void setChunkedMaxContentLength(Integer chunkedMaxContentLength) { + this.chunkedMaxContentLength = chunkedMaxContentLength; + } + + public Integer getMaxHeaderSize() { + return maxHeaderSize; + } + + public void setMaxHeaderSize(Integer maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; + } + + public Boolean getAllowDefaultCodec() { + return allowDefaultCodec; + } + + public void setAllowDefaultCodec(Boolean allowDefaultCodec) { + this.allowDefaultCodec = allowDefaultCodec; + } + + public String getOkStatusCodeRange() { + return okStatusCodeRange; + } + + public void setOkStatusCodeRange(String okStatusCodeRange) { + this.okStatusCodeRange = okStatusCodeRange; + } + + public Boolean getUseRelativePath() { + return useRelativePath; + } + + public void setUseRelativePath(Boolean useRelativePath) { + this.useRelativePath = useRelativePath; + } + } + public static class NettyHttpSecurityConfigurationNestedConfiguration { public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.netty.http.NettyHttpSecurityConfiguration.class; /** http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyHttpAutoConfigurationTest.java ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyHttpAutoConfigurationTest.java b/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyHttpAutoConfigurationTest.java new file mode 100644 index 0000000..0dde926 --- /dev/null +++ b/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyHttpAutoConfigurationTest.java @@ -0,0 +1,74 @@ +/** + * 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.netty.http.springboot; + +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.stereotype.Component; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.apache.camel.component.netty.http.springboot.NettyStarterTestHelper.getPort; +import static org.junit.Assert.assertEquals; + +/** + * Testing the servlet mapping + */ +@RunWith(SpringRunner.class) +@SpringBootApplication +@DirtiesContext +@ContextConfiguration(classes = {NettyHttpComponentAutoConfiguration.class, CamelAutoConfiguration.class}) +@SpringBootTest(properties = { + "camel.component.netty-http.configuration.compression=true" +}) +public class NettyHttpAutoConfigurationTest { + + @Autowired + private ProducerTemplate producerTemplate; + + @Test + public void testEndpoint() throws Exception { + String result = producerTemplate.requestBody("http://localhost:" + getPort(), null, String.class); + assertEquals("Hello", result); + } + + @Test + public void testConfigOverride() throws Exception { + Exchange exchange = producerTemplate.request("http://localhost:" + getPort(), x -> x.getIn().setHeader("Accept-Encoding", "gzip")); + Assert.assertEquals("gzip", exchange.getOut().getHeader("Content-Encoding")); + } + + @Component + public static class TestRoutes extends RouteBuilder { + @Override + public void configure() throws Exception { + from("netty-http:http://localhost:" + getPort()) + .transform().constant("Hello"); + } + } + +} + http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyStarterTestHelper.java ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyStarterTestHelper.java b/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyStarterTestHelper.java new file mode 100644 index 0000000..6ec4163 --- /dev/null +++ b/components-starter/camel-netty-http-starter/src/test/java/org/apache/camel/component/netty/http/springboot/NettyStarterTestHelper.java @@ -0,0 +1,43 @@ +package org.apache.camel.component.netty.http.springboot; + +import java.io.File; +import java.io.FileOutputStream; + +import org.apache.camel.converter.IOConverter; +import org.apache.camel.test.AvailablePortFinder; + +public final class NettyStarterTestHelper { + + private static volatile int port = -1; + + private static void initPort() throws Exception { + if (port <= 0) { + File file = new File("target/nettyport.txt"); + + if (!file.exists()) { + // start from somewhere in the 26xxx range + port = AvailablePortFinder.getNextAvailable(26000); + } else { + // read port number from file + String s = IOConverter.toString(file, null); + port = Integer.parseInt(s); + // use next free port + port = AvailablePortFinder.getNextAvailable(port + 1); + } + + // save to file, do not append + try (FileOutputStream fos = new FileOutputStream(file, false)) { + fos.write(String.valueOf(port).getBytes()); + } + } + } + + public static int getPort() { + try { + initPort(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return port; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty4-http-starter/pom.xml ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty4-http-starter/pom.xml b/components-starter/camel-netty4-http-starter/pom.xml index 9ce69bf..c87bdf1 100644 --- a/components-starter/camel-netty4-http-starter/pom.xml +++ b/components-starter/camel-netty4-http-starter/pom.xml @@ -37,6 +37,14 @@ camel-netty4-http ${project.version} + + + org.apache.camel + camel-http-starter + ${project.version} + test + + org.apache.camel http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty4-http-starter/src/main/java/org/apache/camel/component/netty4/http/springboot/NettyHttpComponentConfiguration.java ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty4-http-starter/src/main/java/org/apache/camel/component/netty4/http/springboot/NettyHttpComponentConfiguration.java b/components-starter/camel-netty4-http-starter/src/main/java/org/apache/camel/component/netty4/http/springboot/NettyHttpComponentConfiguration.java index 407722a..4746c1d 100644 --- a/components-starter/camel-netty4-http-starter/src/main/java/org/apache/camel/component/netty4/http/springboot/NettyHttpComponentConfiguration.java +++ b/components-starter/camel-netty4-http-starter/src/main/java/org/apache/camel/component/netty4/http/springboot/NettyHttpComponentConfiguration.java @@ -18,7 +18,6 @@ package org.apache.camel.component.netty4.http.springboot; import io.netty.util.concurrent.EventExecutorGroup; import org.apache.camel.LoggingLevel; -import org.apache.camel.component.netty4.NettyConfiguration; import org.apache.camel.component.netty4.http.NettyHttpBinding; import org.apache.camel.component.netty4.http.SecurityAuthenticator; import org.apache.camel.component.netty4.http.SecurityConstraint; @@ -41,6 +40,10 @@ public class NettyHttpComponentConfiguration { @NestedConfigurationProperty private NettyHttpBinding nettyHttpBinding; /** + * To use the NettyConfiguration as configuration when creating endpoints. + */ + private NettyHttpConfigurationNestedConfiguration configuration; + /** * To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter * headers. */ @@ -58,11 +61,6 @@ public class NettyHttpComponentConfiguration { */ private Integer maximumPoolSize; /** - * To use the NettyConfiguration as configuration when creating endpoints. - */ - @NestedConfigurationProperty - private NettyConfiguration configuration; - /** * To use the given EventExecutorGroup */ @NestedConfigurationProperty @@ -76,6 +74,15 @@ public class NettyHttpComponentConfiguration { this.nettyHttpBinding = nettyHttpBinding; } + public NettyHttpConfigurationNestedConfiguration getConfiguration() { + return configuration; + } + + public void setConfiguration( + NettyHttpConfigurationNestedConfiguration configuration) { + this.configuration = configuration; + } + public HeaderFilterStrategy getHeaderFilterStrategy() { return headerFilterStrategy; } @@ -102,14 +109,6 @@ public class NettyHttpComponentConfiguration { this.maximumPoolSize = maximumPoolSize; } - public NettyConfiguration getConfiguration() { - return configuration; - } - - public void setConfiguration(NettyConfiguration configuration) { - this.configuration = configuration; - } - public EventExecutorGroup getExecutorService() { return executorService; } @@ -118,6 +117,279 @@ public class NettyHttpComponentConfiguration { this.executorService = executorService; } + public static class NettyHttpConfigurationNestedConfiguration { + public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.netty4.http.NettyHttpConfiguration.class; + /** + * The protocol to use which is either http or https + */ + private String protocol; + /** + * The local hostname such as localhost, or 0.0.0.0 when being a + * consumer. The remote HTTP server hostname when using producer. + */ + private String host; + /** + * The port number. Is default 80 for http and 443 for https. + */ + private Integer port; + /** + * Allow using gzip/deflate for compression on the Netty HTTP server if + * the client supports it from the HTTP headers. + */ + private Boolean compression; + /** + * Option to disable throwing the HttpOperationFailedException in case + * of failed responses from the remote server. This allows you to get + * all responses regardless of the HTTP status code. + */ + private Boolean throwExceptionOnFailure; + /** + * If enabled and an Exchange failed processing on the consumer side, + * and if the caused Exception was send back serialized in the response + * as a application/x-java-serialized-object content type. On the + * producer side the exception will be deserialized and thrown as is, + * instead of the HttpOperationFailedException. The caused exception is + * required to be serialized. + *

+ * This is by default turned off. If you enable this then be aware that + * Java will deserialize the incoming data from the request to Java and + * that can be a potential security risk. + */ + private Boolean transferException; + /** + * If this option is enabled, then during binding from Netty to Camel + * Message then the header values will be URL decoded (eg %20 will be a + * space character. Notice this option is used by the default + * org.apache.camel.component.netty.http.NettyHttpBinding and therefore + * if you implement a custom + * org.apache.camel.component.netty4.http.NettyHttpBinding then you + * would need to decode the headers accordingly to this option. + */ + private Boolean urlDecodeHeaders; + /** + * If this option is enabled, then during binding from Netty to Camel + * Message then the headers will be mapped as well (eg added as header + * to the Camel Message as well). You can turn off this option to + * disable this. The headers can still be accessed from the + * org.apache.camel.component.netty.http.NettyHttpMessage message with + * the method getHttpRequest() that returns the Netty HTTP request + * io.netty.handler.codec.http.HttpRequest instance. + */ + private Boolean mapHeaders; + /** + * Whether or not Camel should try to find a target consumer by matching + * the URI prefix if no exact match is found. + */ + private Boolean matchOnUriPrefix; + /** + * If the option is true, the producer will ignore the Exchange.HTTP_URI + * header, and use the endpoint's URI for request. You may also set the + * throwExceptionOnFailure to be false to let the producer send all the + * fault response back. The consumer working in the bridge mode will + * skip the gzip compression and WWW URL form encoding (by adding the + * Exchange.SKIP_GZIP_ENCODING and Exchange.SKIP_WWW_FORM_URLENCODED + * headers to the consumed exchange). + */ + private Boolean bridgeEndpoint; + /** + * Resource path + */ + private String path; + /** + * Determines whether or not the raw input stream from Netty + * HttpRequest#getContent() or HttpResponset#getContent() is cached or + * not (Camel will read the stream into a in light-weight memory based + * Stream caching) cache. By default Camel will cache the Netty input + * stream to support reading it multiple times to ensure it Camel can + * retrieve all data from the stream. However you can set this option to + * true when you for example need to access the raw stream, such as + * streaming it directly to a file or other persistent store. Mind that + * if you enable this option, then you cannot read the Netty stream + * multiple times out of the box, and you would need manually to reset + * the reader index on the Netty raw stream. Also Netty will auto-close + * the Netty stream when the Netty HTTP server/HTTP client is done + * processing, which means that if the asynchronous routing engine is in + * use then any asynchronous thread that may continue routing the + * {@link org.apache.camel.Exchange} may not be able to read the Netty + * stream, because Netty has closed it. + */ + private Boolean disableStreamCache; + /** + * Whether to send back HTTP status code 503 when the consumer has been + * suspended. If the option is false then the Netty Acceptor is unbound + * when the consumer is suspended, so clients cannot connect anymore. + */ + private Boolean send503whenSuspended; + /** + * Value in bytes the max content length per chunked frame received on + * the Netty HTTP server. + */ + private Integer chunkedMaxContentLength; + /** + * The maximum length of all headers. If the sum of the length of each + * header exceeds this value, a + * {@link io.netty.handler.codec.TooLongFrameException} will be raised. + */ + private Integer maxHeaderSize; + private Boolean allowDefaultCodec; + /** + * The status codes which is considered a success response. The values + * are inclusive. The range must be defined as from-to with the dash + * included. + *

+ * The default range is 200-299 + */ + private String okStatusCodeRange = "200-299"; + /** + * Sets whether to use a relative path in HTTP requests. + */ + private Boolean useRelativePath; + + public String getProtocol() { + return protocol; + } + + public void setProtocol(String protocol) { + this.protocol = protocol; + } + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public Integer getPort() { + return port; + } + + public void setPort(Integer port) { + this.port = port; + } + + public Boolean getCompression() { + return compression; + } + + public void setCompression(Boolean compression) { + this.compression = compression; + } + + public Boolean getThrowExceptionOnFailure() { + return throwExceptionOnFailure; + } + + public void setThrowExceptionOnFailure(Boolean throwExceptionOnFailure) { + this.throwExceptionOnFailure = throwExceptionOnFailure; + } + + public Boolean getTransferException() { + return transferException; + } + + public void setTransferException(Boolean transferException) { + this.transferException = transferException; + } + + public Boolean getUrlDecodeHeaders() { + return urlDecodeHeaders; + } + + public void setUrlDecodeHeaders(Boolean urlDecodeHeaders) { + this.urlDecodeHeaders = urlDecodeHeaders; + } + + public Boolean getMapHeaders() { + return mapHeaders; + } + + public void setMapHeaders(Boolean mapHeaders) { + this.mapHeaders = mapHeaders; + } + + public Boolean getMatchOnUriPrefix() { + return matchOnUriPrefix; + } + + public void setMatchOnUriPrefix(Boolean matchOnUriPrefix) { + this.matchOnUriPrefix = matchOnUriPrefix; + } + + public Boolean getBridgeEndpoint() { + return bridgeEndpoint; + } + + public void setBridgeEndpoint(Boolean bridgeEndpoint) { + this.bridgeEndpoint = bridgeEndpoint; + } + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public Boolean getDisableStreamCache() { + return disableStreamCache; + } + + public void setDisableStreamCache(Boolean disableStreamCache) { + this.disableStreamCache = disableStreamCache; + } + + public Boolean getSend503whenSuspended() { + return send503whenSuspended; + } + + public void setSend503whenSuspended(Boolean send503whenSuspended) { + this.send503whenSuspended = send503whenSuspended; + } + + public Integer getChunkedMaxContentLength() { + return chunkedMaxContentLength; + } + + public void setChunkedMaxContentLength(Integer chunkedMaxContentLength) { + this.chunkedMaxContentLength = chunkedMaxContentLength; + } + + public Integer getMaxHeaderSize() { + return maxHeaderSize; + } + + public void setMaxHeaderSize(Integer maxHeaderSize) { + this.maxHeaderSize = maxHeaderSize; + } + + public Boolean getAllowDefaultCodec() { + return allowDefaultCodec; + } + + public void setAllowDefaultCodec(Boolean allowDefaultCodec) { + this.allowDefaultCodec = allowDefaultCodec; + } + + public String getOkStatusCodeRange() { + return okStatusCodeRange; + } + + public void setOkStatusCodeRange(String okStatusCodeRange) { + this.okStatusCodeRange = okStatusCodeRange; + } + + public Boolean getUseRelativePath() { + return useRelativePath; + } + + public void setUseRelativePath(Boolean useRelativePath) { + this.useRelativePath = useRelativePath; + } + } + public static class NettyHttpSecurityConfigurationNestedConfiguration { public static final Class CAMEL_NESTED_CLASS = org.apache.camel.component.netty4.http.NettyHttpSecurityConfiguration.class; /** http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4HttpAutoConfigurationTest.java ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4HttpAutoConfigurationTest.java b/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4HttpAutoConfigurationTest.java new file mode 100644 index 0000000..883c6b4 --- /dev/null +++ b/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4HttpAutoConfigurationTest.java @@ -0,0 +1,74 @@ +/** + * 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.netty4.http.springboot; + +import org.apache.camel.Exchange; +import org.apache.camel.ProducerTemplate; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.stereotype.Component; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import static org.apache.camel.component.netty4.http.springboot.Netty4StarterTestHelper.getPort; +import static org.junit.Assert.assertEquals; + +/** + * Testing the servlet mapping + */ +@RunWith(SpringRunner.class) +@SpringBootApplication +@DirtiesContext +@ContextConfiguration(classes = {NettyHttpComponentAutoConfiguration.class, CamelAutoConfiguration.class}) +@SpringBootTest(properties = { + "camel.component.netty4-http.configuration.compression=true" +}) +public class Netty4HttpAutoConfigurationTest { + + @Autowired + private ProducerTemplate producerTemplate; + + @Test + public void testEndpoint() throws Exception { + String result = producerTemplate.requestBody("http://localhost:" + getPort(), null, String.class); + assertEquals("Hello", result); + } + + @Test + public void testConfigOverride() throws Exception { + Exchange exchange = producerTemplate.request("http://localhost:" + getPort(), x -> x.getIn().setHeader("Accept-Encoding", "gzip")); + Assert.assertEquals("gzip", exchange.getOut().getHeader("Content-Encoding")); + } + + @Component + public static class TestRoutes extends RouteBuilder { + @Override + public void configure() throws Exception { + from("netty4-http:http://localhost:" + getPort()) + .transform().constant("Hello"); + } + } + +} + http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4StarterTestHelper.java ---------------------------------------------------------------------- diff --git a/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4StarterTestHelper.java b/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4StarterTestHelper.java new file mode 100644 index 0000000..f46b85d --- /dev/null +++ b/components-starter/camel-netty4-http-starter/src/test/java/org/apache/camel/component/netty4/http/springboot/Netty4StarterTestHelper.java @@ -0,0 +1,43 @@ +package org.apache.camel.component.netty4.http.springboot; + +import java.io.File; +import java.io.FileOutputStream; + +import org.apache.camel.converter.IOConverter; +import org.apache.camel.test.AvailablePortFinder; + +public final class Netty4StarterTestHelper { + + private static volatile int port = -1; + + private static void initPort() throws Exception { + if (port <= 0) { + File file = new File("target/nettyport.txt"); + + if (!file.exists()) { + // start from somewhere in the 26xxx range + port = AvailablePortFinder.getNextAvailable(26000); + } else { + // read port number from file + String s = IOConverter.toString(file, null); + port = Integer.parseInt(s); + // use next free port + port = AvailablePortFinder.getNextAvailable(port + 1); + } + + // save to file, do not append + try (FileOutputStream fos = new FileOutputStream(file, false)) { + fos.write(String.valueOf(port).getBytes()); + } + } + } + + public static int getPort() { + try { + initPort(); + } catch (Exception e) { + throw new IllegalStateException(e); + } + return port; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components/camel-netty-http/src/main/docs/netty-http-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/docs/netty-http-component.adoc b/components/camel-netty-http/src/main/docs/netty-http-component.adoc index ee90c80..9726a1e 100644 --- a/components/camel-netty-http/src/main/docs/netty-http-component.adoc +++ b/components/camel-netty-http/src/main/docs/netty-http-component.adoc @@ -91,9 +91,9 @@ The Netty HTTP component supports 5 options which are listed below. |======================================================================= | Name | Java Type | Description | nettyHttpBinding | NettyHttpBinding | To use a custom org.apache.camel.component.netty.http.NettyHttpBinding for binding to/from Netty and Camel Message API. +| configuration | NettyHttpConfiguration | To use the NettyConfiguration as configuration when creating endpoints. | headerFilterStrategy | HeaderFilterStrategy | To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter headers. | securityConfiguration | NettyHttpSecurityConfiguration | Refers to a org.apache.camel.component.netty.http.NettyHttpSecurityConfiguration for configuring secure web resources. -| configuration | NettyConfiguration | To use the NettyConfiguration as configuration when creating endpoints. | maximumPoolSize | int | The core pool size for the ordered thread pool if its in use. The default value is 16. |======================================================================= {% endraw %} http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java index 87b2e54..2fccfcd 100644 --- a/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java +++ b/components/camel-netty-http/src/main/java/org/apache/camel/component/netty/http/NettyHttpComponent.java @@ -214,6 +214,15 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt this.nettyHttpBinding = nettyHttpBinding; } + @Override + public NettyHttpConfiguration getConfiguration() { + return (NettyHttpConfiguration) super.getConfiguration(); + } + + public void setConfiguration(NettyHttpConfiguration configuration) { + super.setConfiguration(configuration); + } + public HeaderFilterStrategy getHeaderFilterStrategy() { return headerFilterStrategy; } http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc ---------------------------------------------------------------------- diff --git a/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc b/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc index 382e090..bb7d1ca 100644 --- a/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc +++ b/components/camel-netty4-http/src/main/docs/netty4-http-component.adoc @@ -90,10 +90,10 @@ The Netty4 HTTP component supports 6 options which are listed below. |======================================================================= | Name | Java Type | Description | nettyHttpBinding | NettyHttpBinding | To use a custom org.apache.camel.component.netty4.http.NettyHttpBinding for binding to/from Netty and Camel Message API. +| configuration | NettyHttpConfiguration | To use the NettyConfiguration as configuration when creating endpoints. | headerFilterStrategy | HeaderFilterStrategy | To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter headers. | securityConfiguration | NettyHttpSecurityConfiguration | Refers to a org.apache.camel.component.netty4.http.NettyHttpSecurityConfiguration for configuring secure web resources. | maximumPoolSize | int | The thread pool size for the EventExecutorGroup if its in use. The default value is 16. -| configuration | NettyConfiguration | To use the NettyConfiguration as configuration when creating endpoints. | executorService | EventExecutorGroup | To use the given EventExecutorGroup |======================================================================= {% endraw %} http://git-wip-us.apache.org/repos/asf/camel/blob/b971204a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java ---------------------------------------------------------------------- diff --git a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java index 5cbea53..48c6686 100644 --- a/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java +++ b/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpComponent.java @@ -223,6 +223,15 @@ public class NettyHttpComponent extends NettyComponent implements HeaderFilterSt this.nettyHttpBinding = nettyHttpBinding; } + @Override + public NettyHttpConfiguration getConfiguration() { + return (NettyHttpConfiguration) super.getConfiguration(); + } + + public void setConfiguration(NettyHttpConfiguration configuration) { + super.setConfiguration(configuration); + } + public HeaderFilterStrategy getHeaderFilterStrategy() { return headerFilterStrategy; }