You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/10/19 12:46:46 UTC
[camel] branch main updated: CAMEL-18593: Platform-http : add reverse proxy feature (#8574)
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
The following commit(s) were added to refs/heads/main by this push:
new c34a9b6be2d CAMEL-18593: Platform-http : add reverse proxy feature (#8574)
c34a9b6be2d is described below
commit c34a9b6be2d38c6307b6a878c7bc8e38597c4b04
Author: Zineb BENDHIBA <be...@gmail.com>
AuthorDate: Wed Oct 19 14:46:40 2022 +0200
CAMEL-18593: Platform-http : add reverse proxy feature (#8574)
---
.../camel/catalog/components/platform-http.json | 2 +-
components/camel-platform-http-vertx/pom.xml | 6 +
.../src/main/docs/platform-http-vertx.adoc | 14 +++
.../http/vertx/VertxPlatformHttpConsumer.java | 8 ++
.../http/vertx/VertxPlatformHttpProxyTest.java | 91 ++++++++++++++
.../http/vertx/VertxPlatformHttpsProxyTest.java | 135 +++++++++++++++++++++
.../src/test/resources/proxy/keystore.p12 | Bin 0 -> 2716 bytes
components/camel-platform-http/pom.xml | 6 +-
.../component/platform/http/platform-http.json | 2 +-
.../src/main/docs/platform-http-component.adoc | 6 +
.../platform/http/PlatformHttpEndpoint.java | 10 +-
.../http/JettyCustomPlatformHttpConsumer.java | 37 +++++-
.../platform/http/PlatformHttpProxyTest.java | 54 +++++++++
.../builder/endpoint/StaticEndpointBuilders.java | 6 +-
.../dsl/PlatformHttpEndpointBuilderFactory.java | 6 +-
15 files changed, 372 insertions(+), 11 deletions(-)
diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/platform-http.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/platform-http.json
index 805e0c10109..b48a5f2fa93 100644
--- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/platform-http.json
+++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/platform-http.json
@@ -27,7 +27,7 @@
"engine": { "kind": "property", "displayName": "Engine", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.platform.http.spi.PlatformHttpEngine", "deprecated": false, "autowired": false, "secret": false, "description": "An HTTP Server engine implementation to serve the requests" }
},
"properties": {
- "path": { "kind": "path", "displayName": "Path", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The path under which this endpoint serves the HTTP requests" },
+ "path": { "kind": "path", "displayName": "Path", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The path under which this endpoint serves the HTTP requests, for proxy use 'proxy'" },
"consumes": { "kind": "parameter", "displayName": "Consumes", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The content type this endpoint accepts as an input, such as application\/xml or application\/json. null or *\/* mean no restriction." },
"httpMethodRestrict": { "kind": "parameter", "displayName": "Http Method Restrict", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "A comma separated list of HTTP methods to serve, e.g. GET,POST . If no methods are specified, all methods will be served." },
"matchOnUriPrefix": { "kind": "parameter", "displayName": "Match On Uri Prefix", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found." },
diff --git a/components/camel-platform-http-vertx/pom.xml b/components/camel-platform-http-vertx/pom.xml
index c48d0f6a7f1..80f5ae8b084 100644
--- a/components/camel-platform-http-vertx/pom.xml
+++ b/components/camel-platform-http-vertx/pom.xml
@@ -100,6 +100,12 @@
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.github.tomakehurst</groupId>
+ <artifactId>wiremock-jre8</artifactId>
+ <version>${wiremock-version}</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc b/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc
index ae087c7e51a..34c2cccfc53 100644
--- a/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc
+++ b/components/camel-platform-http-vertx/src/main/docs/platform-http-vertx.adoc
@@ -60,3 +60,17 @@ context.addRoutes(new RouteBuilder() {
context.start();
----
+
+== Implementing a reverse proxy
+
+Platform HTTP component can act as a reverse proxy, in that case `Exchange.HTTP_URI`, `Exchange.HTTP_HOST` headers are populated from the absolute URL received on the request line of the HTTP request.
+
+Here's an example of a HTTP proxy that simply redirects the Exchange to the origin server.
+
+[source,java]
+------------------------------------------------------------------------------------------
+from("platform-http:proxy")
+ .toD("http://"
+ + "${headers." + Exchange.HTTP_HOST + "}");
+
+-------------------------------------------------------------------------------------
\ No newline at end of file
diff --git a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
index 4a8072f8764..01d373d4e8a 100644
--- a/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
+++ b/components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java
@@ -40,6 +40,7 @@ import io.vertx.ext.web.impl.RouteImpl;
import org.apache.camel.Exchange;
import org.apache.camel.ExchangePattern;
import org.apache.camel.ExchangePropertyKey;
+import org.apache.camel.ExtendedExchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.attachment.AttachmentMessage;
@@ -181,6 +182,13 @@ public class VertxPlatformHttpConsumer extends DefaultConsumer {
// .removeHeaders("*", "CamelHttpPath")
// .to("rest:get:?bridgeEndpoint=true");
//
+
+ if (getEndpoint().isHttpProxy()) {
+ exchange.adapt(ExtendedExchange.class).setStreamCacheDisabled(true);
+ final MultiMap httpHeaders = ctx.request().headers();
+ exchange.getMessage().setHeader(Exchange.HTTP_HOST, httpHeaders.get("Host"));
+ exchange.getMessage().removeHeader("Proxy-Connection");
+ }
vertx.executeBlocking(
promise -> {
try {
diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpProxyTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpProxyTest.java
new file mode 100644
index 00000000000..df2a47cdc9d
--- /dev/null
+++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpProxyTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.platform.http.vertx;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.test.AvailablePortFinder;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.containsString;
+
+public class VertxPlatformHttpProxyTest {
+ private final int port = AvailablePortFinder.getNextAvailable();
+ private WireMockServer wireMockServer = new WireMockServer(options().port(port));
+
+ @BeforeEach
+ void before() {
+ wireMockServer.stubFor(get(urlPathEqualTo("/"))
+ .willReturn(aResponse()
+ .withBody(
+ "{\"message\": \"Hello World\"}")));
+
+ wireMockServer.start();
+ }
+
+ @AfterEach
+ void after() {
+ if (wireMockServer != null) {
+ wireMockServer.stop();
+ }
+ }
+
+ @Test
+ void testProxy() throws Exception {
+ final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+ try {
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("platform-http:proxy")
+ .toD("${headers." + Exchange.HTTP_URI + "}?bridgeEndpoint=true");
+ }
+ });
+
+ context.start();
+
+ // URI of proxy created with platform HTTP component
+ final var proxyURI = "http://localhost:" + RestAssured.port;
+
+ final var originURI = "http://localhost:" + wireMockServer.port();
+
+ given()
+ .proxy(proxyURI)
+ .contentType(ContentType.JSON)
+ .when().get(originURI)
+ .then()
+ .statusCode(200)
+ .body(containsString("{\"message\": \"Hello World\"}"));
+
+ } finally {
+ context.stop();
+ }
+ }
+
+}
diff --git a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpsProxyTest.java b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpsProxyTest.java
new file mode 100644
index 00000000000..79053d62d17
--- /dev/null
+++ b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpsProxyTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.platform.http.vertx;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import io.restassured.RestAssured;
+import io.restassured.http.ContentType;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.support.jsse.KeyManagersParameters;
+import org.apache.camel.support.jsse.KeyStoreParameters;
+import org.apache.camel.support.jsse.SSLContextParameters;
+import org.apache.camel.support.jsse.TrustManagersParameters;
+import org.apache.camel.test.AvailablePortFinder;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options;
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.containsString;
+
+public class VertxPlatformHttpsProxyTest {
+
+ private final int port = AvailablePortFinder.getNextAvailable();
+ private WireMockServer wireMockServer = new WireMockServer(
+ options().httpsPort(port)
+ .httpDisabled(true)
+ .keystorePath("proxy/keystore.p12")
+ .keystorePassword("changeit")
+ .keyManagerPassword("changeit"));
+
+ @BeforeEach
+ void before() {
+ wireMockServer.stubFor(get(urlPathEqualTo("/"))
+ .willReturn(aResponse()
+ .withBody(
+ "{\"message\": \"Hello World\"}")));
+
+ wireMockServer.start();
+ }
+
+ @AfterEach
+ void after() {
+ if (wireMockServer != null) {
+ wireMockServer.stop();
+ }
+ }
+
+ @Test
+ void testProxy() throws Exception {
+ final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
+
+ try {
+
+ context.getRegistry().bind("sslContextParameters", sslContextParameters());
+ context.getRegistry().bind("x509HostnameVerifier", x509HostnameVerifier());
+
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("platform-http:proxy")
+ .toD("https://${headers." + Exchange.HTTP_HOST
+ + "}?bridgeEndpoint=true&sslContextParameters=#sslContextParameters&x509HostnameVerifier=#x509HostnameVerifier");
+ }
+ });
+
+ context.start();
+
+ // URI of proxy created with platform HTTP component
+ final var proxyURI = "http://localhost:" + RestAssured.port;
+
+ // In order to make sure that RestAssured don't perform a CONNECT instead of a GET, we do trick with http
+ // if we want to do test manually from a terminal we use the real HTTPS address
+ final var originURI = "http://localhost:" + port;
+
+ given()
+ .proxy(proxyURI)
+ .contentType(ContentType.JSON)
+ .when().get(originURI)
+ .then()
+ .statusCode(200)
+ .body(containsString("{\"message\": \"Hello World\"}"));
+
+ } finally {
+ context.stop();
+ }
+ }
+
+ public SSLContextParameters sslContextParameters() {
+ SSLContextParameters sslContextParameters = new SSLContextParameters();
+
+ KeyManagersParameters keyManagersParameters = new KeyManagersParameters();
+ KeyStoreParameters keyStore = new KeyStoreParameters();
+ keyStore.setPassword("changeit");
+ keyStore.setResource("proxy/keystore.p12");
+ keyManagersParameters.setKeyPassword("changeit");
+ keyManagersParameters.setKeyStore(keyStore);
+ sslContextParameters.setKeyManagers(keyManagersParameters);
+
+ KeyStoreParameters truststoreParameters = new KeyStoreParameters();
+ truststoreParameters.setResource("proxy/keystore.p12");
+ truststoreParameters.setPassword("changeit");
+
+ TrustManagersParameters trustManagersParameters = new TrustManagersParameters();
+ trustManagersParameters.setKeyStore(truststoreParameters);
+ sslContextParameters.setTrustManagers(trustManagersParameters);
+
+ return sslContextParameters;
+ }
+
+ public NoopHostnameVerifier x509HostnameVerifier() {
+ return NoopHostnameVerifier.INSTANCE;
+ }
+
+}
diff --git a/components/camel-platform-http-vertx/src/test/resources/proxy/keystore.p12 b/components/camel-platform-http-vertx/src/test/resources/proxy/keystore.p12
new file mode 100644
index 00000000000..fadac3cb35b
Binary files /dev/null and b/components/camel-platform-http-vertx/src/test/resources/proxy/keystore.p12 differ
diff --git a/components/camel-platform-http/pom.xml b/components/camel-platform-http/pom.xml
index d9d2af60983..bfdb73f8ed8 100644
--- a/components/camel-platform-http/pom.xml
+++ b/components/camel-platform-http/pom.xml
@@ -67,6 +67,10 @@
<artifactId>log4j-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.camel</groupId>
+ <artifactId>camel-http</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
-
</project>
diff --git a/components/camel-platform-http/src/generated/resources/org/apache/camel/component/platform/http/platform-http.json b/components/camel-platform-http/src/generated/resources/org/apache/camel/component/platform/http/platform-http.json
index 805e0c10109..b48a5f2fa93 100644
--- a/components/camel-platform-http/src/generated/resources/org/apache/camel/component/platform/http/platform-http.json
+++ b/components/camel-platform-http/src/generated/resources/org/apache/camel/component/platform/http/platform-http.json
@@ -27,7 +27,7 @@
"engine": { "kind": "property", "displayName": "Engine", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "org.apache.camel.component.platform.http.spi.PlatformHttpEngine", "deprecated": false, "autowired": false, "secret": false, "description": "An HTTP Server engine implementation to serve the requests" }
},
"properties": {
- "path": { "kind": "path", "displayName": "Path", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The path under which this endpoint serves the HTTP requests" },
+ "path": { "kind": "path", "displayName": "Path", "group": "consumer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The path under which this endpoint serves the HTTP requests, for proxy use 'proxy'" },
"consumes": { "kind": "parameter", "displayName": "Consumes", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "The content type this endpoint accepts as an input, such as application\/xml or application\/json. null or *\/* mean no restriction." },
"httpMethodRestrict": { "kind": "parameter", "displayName": "Http Method Restrict", "group": "consumer", "label": "consumer", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "autowired": false, "secret": false, "description": "A comma separated list of HTTP methods to serve, e.g. GET,POST . If no methods are specified, all methods will be served." },
"matchOnUriPrefix": { "kind": "parameter", "displayName": "Match On Uri Prefix", "group": "consumer", "label": "consumer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether or not the consumer should try to find a target consumer by matching the URI prefix if no exact match is found." },
diff --git a/components/camel-platform-http/src/main/docs/platform-http-component.adoc b/components/camel-platform-http/src/main/docs/platform-http-component.adoc
index ae8b2041126..a73fed9d7be 100644
--- a/components/camel-platform-http/src/main/docs/platform-http-component.adoc
+++ b/components/camel-platform-http/src/main/docs/platform-http-component.adoc
@@ -61,3 +61,9 @@ include::partial$component-endpoint-options.adoc[]
// endpoint options: END
include::spring-boot:partial$starter.adoc[]
+
+== Implementing a reverse proxy
+
+Platform HTTP component can act as a reverse proxy, in that case some headers are populated from the absolute URL received on the request line of the HTTP request. Those headers are specific to the underlining platform.
+
+At this moment, this feature is only supported for Vert.x in `camel-platform-http-vertx` component.
\ No newline at end of file
diff --git a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java
index db5ca28e7fe..34db08833ef 100644
--- a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java
+++ b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpEndpoint.java
@@ -40,7 +40,9 @@ import org.apache.camel.support.service.ServiceHelper;
category = { Category.HTTP }, consumerOnly = true)
public class PlatformHttpEndpoint extends DefaultEndpoint implements AsyncEndpoint, HeaderFilterStrategyAware {
- @UriPath(description = "The path under which this endpoint serves the HTTP requests")
+ private static final String PROXY_PATH = "proxy";
+
+ @UriPath(description = "The path under which this endpoint serves the HTTP requests, for proxy use 'proxy'")
@Metadata(required = true)
private final String path;
@UriParam(label = "consumer", defaultValue = "false",
@@ -143,7 +145,7 @@ public class PlatformHttpEndpoint extends DefaultEndpoint implements AsyncEndpoi
}
public String getPath() {
- return path;
+ return isHttpProxy() ? "/" : path;
}
public PlatformHttpEngine getPlatformHttpEngine() {
@@ -207,4 +209,8 @@ public class PlatformHttpEndpoint extends DefaultEndpoint implements AsyncEndpoi
? platformHttpEngine
: getComponent().getOrCreateEngine();
}
+
+ public boolean isHttpProxy() {
+ return this.path.startsWith(PROXY_PATH);
+ }
}
diff --git a/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/JettyCustomPlatformHttpConsumer.java b/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/JettyCustomPlatformHttpConsumer.java
index f1bb46af1ff..cc8accecc5d 100644
--- a/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/JettyCustomPlatformHttpConsumer.java
+++ b/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/JettyCustomPlatformHttpConsumer.java
@@ -17,17 +17,23 @@
package org.apache.camel.component.platform.http;
import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.StringJoiner;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.camel.Exchange;
+import org.apache.camel.ExtendedExchange;
import org.apache.camel.Message;
import org.apache.camel.Processor;
import org.apache.camel.support.CamelContextHelper;
import org.apache.camel.support.DefaultConsumer;
import org.apache.camel.support.DefaultMessage;
+import org.apache.camel.util.IOHelper;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ContextHandler;
@@ -74,11 +80,26 @@ public class JettyCustomPlatformHttpConsumer extends DefaultConsumer {
bodyRequest += strCurrentLine;
}
final Exchange exchange = exchg = toExchange(request, bodyRequest);
+ if (getEndpoint().isHttpProxy()) {
+ exchange.getMessage().removeHeader("Proxy-Connection");
+ }
+ exchange.getMessage().setHeader(Exchange.HTTP_SCHEME, httpServletRequest.getScheme());
+ exchange.getMessage().setHeader(Exchange.HTTP_HOST, httpServletRequest.getServerName());
+ exchange.getMessage().setHeader(Exchange.HTTP_PORT, httpServletRequest.getServerPort());
+ exchange.getMessage().setHeader(Exchange.HTTP_PATH, httpServletRequest.getPathInfo());
+ if (getEndpoint().isHttpProxy()) {
+ exchange.adapt(ExtendedExchange.class).setStreamCacheDisabled(true);
+ }
createUoW(exchange);
- getProcessor().process(
- exchange);
+ getProcessor().process(exchange);
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
request.setHandled(true);
+ if (getEndpoint().isHttpProxy()) {
+ // extract response
+ InputStream response = exchange.getMessage().getBody(InputStream.class);
+ String body = JettyCustomPlatformHttpConsumer.toString(response);
+ exchange.getMessage().setBody(body);
+ }
httpServletResponse.getWriter().println(exchange.getMessage().getBody());
} catch (Exception e) {
getExceptionHandler().handleException("Failed handling platform-http endpoint " + endpoint.getPath(), exchg,
@@ -113,4 +134,16 @@ public class JettyCustomPlatformHttpConsumer extends DefaultConsumer {
return (PlatformHttpEndpoint) super.getEndpoint();
}
+ private static String toString(InputStream input) throws IOException {
+ BufferedReader reader = IOHelper.buffered(new InputStreamReader(input));
+ StringJoiner builder = new StringJoiner(" ");
+ while (true) {
+ String line = reader.readLine();
+ if (line == null) {
+ return builder.toString();
+ }
+ builder.add(line);
+ }
+ }
+
}
diff --git a/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/PlatformHttpProxyTest.java b/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/PlatformHttpProxyTest.java
new file mode 100644
index 00000000000..c25da3058cd
--- /dev/null
+++ b/components/camel-platform-http/src/test/java/org/apache/camel/component/platform/http/PlatformHttpProxyTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.platform.http;
+
+import io.restassured.http.ContentType;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.containsString;
+
+public class PlatformHttpProxyTest extends AbstractPlatformHttpTest {
+ @Test
+ void testProxy() {
+ given()
+ .body("hello")
+ .proxy("http://localhost:" + AbstractPlatformHttpTest.port)
+ .contentType(ContentType.HTML)
+ .when().get("http://neverssl.com:80")
+ .then()
+ .statusCode(200)
+ .body(containsString("<html>"));
+ }
+
+ @Override
+ protected RouteBuilder routes() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("platform-http:proxy")
+ .toD("${headers." + Exchange.HTTP_SCHEME + "}://" +
+ "${headers." + Exchange.HTTP_HOST + "}:" +
+ "${headers." + Exchange.HTTP_PORT + "}" +
+ "${headers." + Exchange.HTTP_PATH + "}?bridgeEndpoint=true");
+ }
+ };
+ }
+
+}
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
index 45a7d986cda..e219af622d8 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/StaticEndpointBuilders.java
@@ -11889,7 +11889,8 @@ public class StaticEndpointBuilders {
* Syntax: <code>platform-http:path</code>
*
* Path parameter: path (required)
- * The path under which this endpoint serves the HTTP requests
+ * The path under which this endpoint serves the HTTP requests, for proxy
+ * use 'proxy'
*
* @param path path
* @return the dsl builder
@@ -11910,7 +11911,8 @@ public class StaticEndpointBuilders {
* Syntax: <code>platform-http:path</code>
*
* Path parameter: path (required)
- * The path under which this endpoint serves the HTTP requests
+ * The path under which this endpoint serves the HTTP requests, for proxy
+ * use 'proxy'
*
* @param componentName to use a custom component name for the endpoint
* instead of the default name
diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PlatformHttpEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PlatformHttpEndpointBuilderFactory.java
index 222b8b34eb1..4160c2aae3f 100644
--- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PlatformHttpEndpointBuilderFactory.java
+++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/PlatformHttpEndpointBuilderFactory.java
@@ -387,7 +387,8 @@ public interface PlatformHttpEndpointBuilderFactory {
* Syntax: <code>platform-http:path</code>
*
* Path parameter: path (required)
- * The path under which this endpoint serves the HTTP requests
+ * The path under which this endpoint serves the HTTP requests, for
+ * proxy use 'proxy'
*
* @param path path
* @return the dsl builder
@@ -407,7 +408,8 @@ public interface PlatformHttpEndpointBuilderFactory {
* Syntax: <code>platform-http:path</code>
*
* Path parameter: path (required)
- * The path under which this endpoint serves the HTTP requests
+ * The path under which this endpoint serves the HTTP requests, for
+ * proxy use 'proxy'
*
* @param componentName to use a custom component name for the endpoint
* instead of the default name