This is an automated email from the ASF dual-hosted git repository.
lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k-runtime.git
The following commit(s) were added to refs/heads/master by this push:
new 5b18aac Add support for cors in platfomr http vertx
5b18aac is described below
commit 5b18aacf70bd2fcc63cb8a0f57c112758bf88a33
Author: lburgazzoli <[email protected]>
AuthorDate: Thu Apr 16 17:38:13 2020 +0200
Add support for cors in platfomr http vertx
---
.../apache/camel/k/http/PlatformHttpServer.java | 4 +
.../k/http/PlatformHttpServiceConfiguration.java | 87 +++++++++++--
.../http/PlatformHttpServiceContextCustomizer.java | 9 ++
.../apache/camel/k/http/support/CorsHandler.java | 136 +++++++++++++++++++++
.../k/http/PlatformHttpServiceCustomizerTest.java | 43 +++++++
5 files changed, 270 insertions(+), 9 deletions(-)
diff --git
a/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServer.java
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServer.java
index 62cd280..8076157 100644
---
a/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServer.java
+++
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServer.java
@@ -83,6 +83,10 @@ public final class PlatformHttpServer extends ServiceSupport
{
final Router router = Router.router(vertx);
final Router subRouter = Router.router(vertx);
+ if (configuration.getCors().isEnabled()) {
+ subRouter.route().handler(new
org.apache.camel.k.http.support.CorsHandler(configuration));
+ }
+
router.mountSubRouter(configuration.getPath(), subRouter);
context.getRegistry().bind(
diff --git
a/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceConfiguration.java
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceConfiguration.java
index 2180e7d..9001d2d 100644
---
a/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceConfiguration.java
+++
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceConfiguration.java
@@ -17,6 +17,8 @@
package org.apache.camel.k.http;
import java.math.BigInteger;
+import java.time.Duration;
+import java.util.List;
import org.apache.camel.support.jsse.SSLContextParameters;
@@ -30,10 +32,12 @@ public class PlatformHttpServiceConfiguration {
private String path = DEFAULT_PATH;
private BigInteger maxBodySize;
- private BodyHandlerConfiguration bodyHandlerConfiguration = new
BodyHandlerConfiguration();
private SSLContextParameters sslContextParameters;
private boolean useGlobalSslContextParameters;
+ private CorsConfiguration corsConfiguration = new CorsConfiguration();
+ private BodyHandlerConfiguration bodyHandlerConfiguration = new
BodyHandlerConfiguration();
+
public String getBindHost() {
return bindHost;
}
@@ -66,14 +70,6 @@ public class PlatformHttpServiceConfiguration {
this.maxBodySize = maxBodySize;
}
- public BodyHandlerConfiguration getBodyHandler() {
- return bodyHandlerConfiguration;
- }
-
- public void setBodyHandler(BodyHandlerConfiguration bodyHandler) {
- this.bodyHandlerConfiguration = bodyHandler;
- }
-
public SSLContextParameters getSslContextParameters() {
return sslContextParameters;
}
@@ -90,6 +86,79 @@ public class PlatformHttpServiceConfiguration {
this.useGlobalSslContextParameters = useGlobalSslContextParameters;
}
+ public CorsConfiguration getCors() {
+ return corsConfiguration;
+ }
+
+ public void setCors(CorsConfiguration corsConfiguration) {
+ this.corsConfiguration = corsConfiguration;
+ }
+
+ public BodyHandlerConfiguration getBodyHandler() {
+ return bodyHandlerConfiguration;
+ }
+
+ public void setBodyHandler(BodyHandlerConfiguration bodyHandler) {
+ this.bodyHandlerConfiguration = bodyHandler;
+ }
+
+ public static class CorsConfiguration {
+ private boolean enabled;
+ private List<String> origins;
+ private List<String> methods;
+ private List<String> headers;
+ private List<String> exposedHeaders;
+ private Duration accessControlMaxAge;
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public List<String> getOrigins() {
+ return origins;
+ }
+
+ public void setOrigins(List<String> origins) {
+ this.origins = origins;
+ }
+
+ public List<String> getMethods() {
+ return methods;
+ }
+
+ public void setMethods(List<String> methods) {
+ this.methods = methods;
+ }
+
+ public List<String> getHeaders() {
+ return headers;
+ }
+
+ public List<String> getExposedHeaders() {
+ return exposedHeaders;
+ }
+
+ public void setExposedHeaders(List<String> exposedHeaders) {
+ this.exposedHeaders = exposedHeaders;
+ }
+
+ public void setHeaders(List<String> headers) {
+ this.headers = headers;
+ }
+
+ public Duration getAccessControlMaxAge() {
+ return accessControlMaxAge;
+ }
+
+ public void setAccessControlMaxAge(Duration accessControlMaxAge) {
+ this.accessControlMaxAge = accessControlMaxAge;
+ }
+ }
+
public static class BodyHandlerConfiguration {
private boolean handleFileUploads = true;
private String uploadsDirectory = "file-uploads";
diff --git
a/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceContextCustomizer.java
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceContextCustomizer.java
index f46139e..634e06e 100644
---
a/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceContextCustomizer.java
+++
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/PlatformHttpServiceContextCustomizer.java
@@ -29,6 +29,9 @@ import
org.apache.camel.k.http.engine.RuntimePlatformHttpEngine;
public class PlatformHttpServiceContextCustomizer extends
PlatformHttpServiceConfiguration implements ContextCustomizer {
private PlatformHttpServiceEndpoint endpoint;
+ public PlatformHttpServiceContextCustomizer() {
+ }
+
@Override
public int getOrder() {
return Ordered.HIGHEST;
@@ -54,6 +57,12 @@ public class PlatformHttpServiceContextCustomizer extends
PlatformHttpServiceCon
// TODO: remove once migrating to camel 3.2
parameters.remove("matchOnUriPrefix");
+ // the PlatformHttpComponent set this value but it is not
handled which cause the
+ // context to fail as the property cannot be bound to the
enpoint.
+ //
+ // TODO: fix upstream
+ parameters.remove("optionsEnabled");
+
// let the original component to create the endpoint
return super.createEndpoint(uri, remaining, parameters);
}
diff --git
a/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/support/CorsHandler.java
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/support/CorsHandler.java
new file mode 100644
index 0000000..f206b3f
--- /dev/null
+++
b/camel-k-runtime-http/src/main/java/org/apache/camel/k/http/support/CorsHandler.java
@@ -0,0 +1,136 @@
+/*
+ * 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.k.http.support;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import io.vertx.core.Handler;
+import io.vertx.core.http.HttpHeaders;
+import io.vertx.core.http.HttpMethod;
+import io.vertx.core.http.HttpServerRequest;
+import io.vertx.core.http.HttpServerResponse;
+import io.vertx.ext.web.RoutingContext;
+import org.apache.camel.k.http.PlatformHttpServiceConfiguration;
+import org.apache.camel.util.ObjectHelper;
+
+public class CorsHandler implements Handler<RoutingContext> {
+
+ private static final Pattern COMMA_SEPARATED_SPLIT_REGEX =
Pattern.compile("\\s*,\\s*");
+
+ // This is set in the recorder at runtime.
+ // Must be static because the filter is created(deployed) at build time
and runtime config is still not available
+ final PlatformHttpServiceConfiguration.CorsConfiguration corsConfig;
+
+ public CorsHandler(PlatformHttpServiceConfiguration configuration) {
+ this.corsConfig = ObjectHelper.notNull(configuration.getCors(),
"config");
+ }
+
+ private void processRequestedHeaders(HttpServerResponse response, String
allowHeadersValue) {
+ if (ObjectHelper.isEmpty(corsConfig.getHeaders())) {
+ response.headers().set(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
allowHeadersValue);
+ } else {
+ List<String> requestedHeaders = new ArrayList<>();
+ for (String requestedHeader :
COMMA_SEPARATED_SPLIT_REGEX.split(allowHeadersValue)) {
+ requestedHeaders.add(requestedHeader.toLowerCase());
+ }
+
+ List<String> validRequestedHeaders = new ArrayList<>();
+ for (String configHeader : corsConfig.getHeaders()) {
+ if (requestedHeaders.contains(configHeader.toLowerCase())) {
+ validRequestedHeaders.add(configHeader);
+ }
+ }
+
+ if (!validRequestedHeaders.isEmpty()) {
+
response.headers().set(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
String.join(",", validRequestedHeaders));
+ }
+ }
+ }
+
+ private void processMethods(HttpServerResponse response, String
allowMethodsValue) {
+ if (ObjectHelper.isEmpty(corsConfig.getMethods())) {
+ response.headers().set(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,
allowMethodsValue);
+ } else {
+ List<String> requestedMethods = new ArrayList<>();
+ for (String requestedMethod :
COMMA_SEPARATED_SPLIT_REGEX.split(allowMethodsValue)) {
+ requestedMethods.add(requestedMethod.toLowerCase());
+ }
+
+ List<String> validRequestedMethods = new ArrayList<>();
+ for (String configMethod : corsConfig.getMethods()) {
+ if (requestedMethods.contains(configMethod.toLowerCase())) {
+ validRequestedMethods.add(configMethod);
+ }
+ }
+
+ if (!validRequestedMethods.isEmpty()) {
+
response.headers().set(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS,
String.join(",", validRequestedMethods));
+ }
+ }
+ }
+
+ @Override
+ public void handle(RoutingContext event) {
+ final HttpServerRequest request = event.request();
+ final HttpServerResponse response = event.response();
+ final String origin = request.getHeader(HttpHeaders.ORIGIN);
+
+ if (origin == null) {
+ event.next();
+ } else {
+ final String requestedMethods =
request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD);
+
+ if (requestedMethods != null) {
+ processMethods(response, requestedMethods);
+ }
+
+ final String requestedHeaders =
request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
+
+ if (requestedHeaders != null) {
+ processRequestedHeaders(response, requestedHeaders);
+ }
+
+ boolean allowsOrigin =
ObjectHelper.isEmpty(corsConfig.getOrigins()) ||
corsConfig.getOrigins().contains(origin);
+
+ if (allowsOrigin) {
+
response.headers().set(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
+ }
+
+
response.headers().set(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
+
+
+ if (ObjectHelper.isNotEmpty(corsConfig.getExposedHeaders())) {
+ response.headers().set(
+ HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS,
+ String.join(",", corsConfig.getExposedHeaders()));
+ }
+
+ if (request.method().equals(HttpMethod.OPTIONS)) {
+ if ((requestedHeaders != null || requestedMethods != null) &&
corsConfig.getAccessControlMaxAge() != null) {
+ response.putHeader(
+ HttpHeaders.ACCESS_CONTROL_MAX_AGE,
+
String.valueOf(corsConfig.getAccessControlMaxAge().getSeconds()));
+ }
+ response.end();
+ } else {
+ event.next();
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git
a/camel-k-runtime-http/src/test/java/org/apache/camel/k/http/PlatformHttpServiceCustomizerTest.java
b/camel-k-runtime-http/src/test/java/org/apache/camel/k/http/PlatformHttpServiceCustomizerTest.java
index 044292a..421d63e 100644
---
a/camel-k-runtime-http/src/test/java/org/apache/camel/k/http/PlatformHttpServiceCustomizerTest.java
+++
b/camel-k-runtime-http/src/test/java/org/apache/camel/k/http/PlatformHttpServiceCustomizerTest.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.k.http;
+import java.util.Arrays;
+
import io.vertx.core.http.HttpMethod;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonObject;
@@ -274,4 +276,45 @@ public class PlatformHttpServiceCustomizerTest {
context.stop();
}
}
+
+ @Test
+ public void testPlatformHttpComponentCORS() throws Exception {
+ CamelContext context = new DefaultCamelContext();
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() throws Exception {
+ fromF("platform-http:/")
+ .transform().constant("cors");
+ }
+ });
+
+ PlatformHttpServiceContextCustomizer httpService = new
PlatformHttpServiceContextCustomizer();
+ httpService.setBindPort(AvailablePortFinder.getNextAvailable());
+ httpService.getCors().setEnabled(true);
+ httpService.getCors().setMethods(Arrays.asList("GET", "POST"));
+ httpService.apply(context);
+
+ try {
+ context.start();
+
+ String origin = "http://custom.origin.quarkus";
+ String methods = "GET,POST";
+ String headers = "X-Custom";
+
+ given()
+ .port(httpService.getBindPort())
+ .header("Origin", origin)
+ .header("Access-Control-Request-Method", methods)
+ .header("Access-Control-Request-Headers", headers)
+ .when()
+ .get("/")
+ .then()
+ .statusCode(200)
+ .header("Access-Control-Allow-Origin", origin)
+ .header("Access-Control-Allow-Methods", methods)
+ .header("Access-Control-Allow-Headers", headers);
+ } finally {
+ context.stop();
+ }
+ }
}