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 57b680a70082 CAMEL-22798: camel-platform-http-vertx - VertX has
hardcoded content-type validation (#20532)
57b680a70082 is described below
commit 57b680a70082b901f3345927ced16f1877c64dad
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun Dec 21 12:54:52 2025 +0100
CAMEL-22798: camel-platform-http-vertx - VertX has hardcoded content-type
validation (#20532)
---
.../camel/catalog/components/platform-http.json | 7 +-
.../http/vertx/VertxPlatformHttpConsumer.java | 20 ++--
.../VertxPlatformServerRequestValidationTest.java | 121 +++++++++++++++++++++
.../http/PlatformHttpComponentConfigurer.java | 6 +
.../component/platform/http/platform-http.json | 7 +-
.../platform/http/PlatformHttpComponent.java | 15 +++
.../dsl/PlatformHttpComponentBuilderFactory.java | 25 +++++
7 files changed, 186 insertions(+), 15 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 970d47bf17ab..9de65466be58 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
@@ -28,9 +28,10 @@
"bridgeErrorHandler": { "index": 0, "kind": "property", "displayName":
"Bridge Error Handler", "group": "consumer", "label": "consumer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Allows for bridging the consumer to the Camel routing Error Handler, which
mean any exceptions (if possible) occurred while the Camel consumer is trying
to pickup incoming messages, or the like [...]
"handleWriteResponseError": { "index": 1, "kind": "property",
"displayName": "Handle Write Response Error", "group": "consumer", "label":
"advanced,consumer", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "When Camel is complete processing the
message, and the HTTP server is writing response. This option controls whether
Camel should catch any failure during writing response [...]
"requestTimeout": { "index": 2, "kind": "property", "displayName":
"Request Timeout", "group": "consumer", "label": "advanced,consumer",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "description": "The period in milliseconds
after which the request should be timed out." },
- "autowiredEnabled": { "index": 3, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
- "engine": { "index": 4, "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" },
- "headerFilterStrategy": { "index": 5, "kind": "property", "displayName":
"Header Filter Strategy", "group": "filter", "label": "filter", "required":
false, "type": "object", "javaType":
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired":
false, "secret": false, "description": "To use a custom
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel
message." }
+ "serverRequestValidation": { "index": 3, "kind": "property",
"displayName": "Server Request Validation", "group": "consumer", "label":
"advanced,consumer", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": true, "description": "Whether HTTP server should do preliminary
validation of incoming requests, validating if Content-Type\/Accept header,
matches what is allowed according to consumes\/produces c [...]
+ "autowiredEnabled": { "index": 4, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
+ "engine": { "index": 5, "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" },
+ "headerFilterStrategy": { "index": 6, "kind": "property", "displayName":
"Header Filter Strategy", "group": "filter", "label": "filter", "required":
false, "type": "object", "javaType":
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired":
false, "secret": false, "description": "To use a custom
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel
message." }
},
"properties": {
"path": { "index": 0, "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'" },
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 324650f84605..fd088b7f2a03 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
@@ -149,16 +149,18 @@ public class VertxPlatformHttpConsumer extends
DefaultConsumer
methods.forEach(m ->
newRoute.method(HttpMethod.valueOf(m.name())));
}
- if (getEndpoint().getConsumes() != null) {
- //comma separated contentTypes has to be registered one by one
- for (String c : getEndpoint().getConsumes().split(",")) {
- newRoute.consumes(c);
+ if (getEndpoint().getComponent().isServerRequestValidation()) {
+ if (getEndpoint().getConsumes() != null) {
+ //comma separated contentTypes has to be registered one by one
+ for (String c : getEndpoint().getConsumes().split(",")) {
+ newRoute.consumes(c);
+ }
}
- }
- if (getEndpoint().getProduces() != null) {
- //comma separated contentTypes has to be registered one by one
- for (String p : getEndpoint().getProduces().split(",")) {
- newRoute.produces(p);
+ if (getEndpoint().getProduces() != null) {
+ //comma separated contentTypes has to be registered one by one
+ for (String p : getEndpoint().getProduces().split(",")) {
+ newRoute.produces(p);
+ }
}
}
diff --git
a/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformServerRequestValidationTest.java
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformServerRequestValidationTest.java
new file mode 100644
index 000000000000..deca3af3c4ef
--- /dev/null
+++
b/components/camel-platform-http-vertx/src/test/java/org/apache/camel/component/platform/http/vertx/VertxPlatformServerRequestValidationTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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 org.apache.camel.CamelContext;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.platform.http.PlatformHttpComponent;
+import org.junit.jupiter.api.Test;
+
+import static io.restassured.RestAssured.given;
+import static org.hamcrest.Matchers.is;
+
+public class VertxPlatformServerRequestValidationTest {
+
+ @Test
+ void testServerRequestFalse() throws Exception {
+ final CamelContext context =
VertxPlatformHttpEngineTest.createCamelContext();
+
+ try {
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ PlatformHttpComponent phc =
context.getComponent("platform-http", PlatformHttpComponent.class);
+ phc.setServerRequestValidation(false);
+
+ restConfiguration().component("platform-http")
+ .contextPath("/rest");
+
+ rest().post("/test")
+ .consumes("application/json")
+ .produces("application/json")
+ .to("direct:rest");
+
+ from("direct:rest")
+ .setBody(simple("Hello"));
+ }
+ });
+
+ context.start();
+
+ given()
+ .body("<hello>World</hello>")
+ .contentType("application/xml")
+ .post("/rest/test")
+ .then()
+ .statusCode(200)
+ .body(is("Hello"));
+
+ given()
+ .body("{ \"name\": \"jack\" }")
+ .contentType("application/json")
+ .accept("application/xml")
+ .post("/rest/test")
+ .then()
+ .statusCode(200)
+ .body(is("Hello"));
+ } finally {
+ context.stop();
+ }
+ }
+
+ @Test
+ void testServerRequestTrue() throws Exception {
+ final CamelContext context =
VertxPlatformHttpEngineTest.createCamelContext();
+
+ try {
+ context.addRoutes(new RouteBuilder() {
+ @Override
+ public void configure() {
+ PlatformHttpComponent phc =
context.getComponent("platform-http", PlatformHttpComponent.class);
+ phc.setServerRequestValidation(true);
+
+ restConfiguration().component("platform-http")
+ .contextPath("/rest");
+
+ rest().post("/test")
+ .consumes("application/json")
+ .produces("application/json")
+ .to("direct:rest");
+
+ from("direct:rest")
+ .setBody(simple("Hello"));
+ }
+ });
+
+ context.start();
+
+ given()
+ .body("<hello>World</hello>")
+ .contentType("application/xml")
+ .post("/rest/test")
+ .then()
+ .statusCode(415);
+
+ given()
+ .body("{ \"name\": \"jack\" }")
+ .contentType("application/json")
+ .accept("application/xml")
+ .post("/rest/test")
+ .then()
+ .statusCode(406);
+ } finally {
+ context.stop();
+ }
+ }
+
+}
diff --git
a/components/camel-platform-http/src/generated/java/org/apache/camel/component/platform/http/PlatformHttpComponentConfigurer.java
b/components/camel-platform-http/src/generated/java/org/apache/camel/component/platform/http/PlatformHttpComponentConfigurer.java
index 72a4a7d45dc0..c0beb64b8244 100644
---
a/components/camel-platform-http/src/generated/java/org/apache/camel/component/platform/http/PlatformHttpComponentConfigurer.java
+++
b/components/camel-platform-http/src/generated/java/org/apache/camel/component/platform/http/PlatformHttpComponentConfigurer.java
@@ -34,6 +34,8 @@ public class PlatformHttpComponentConfigurer extends
PropertyConfigurerSupport i
case "headerFilterStrategy":
target.setHeaderFilterStrategy(property(camelContext,
org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true;
case "requesttimeout":
case "requestTimeout": target.setRequestTimeout(property(camelContext,
long.class, value)); return true;
+ case "serverrequestvalidation":
+ case "serverRequestValidation":
target.setServerRequestValidation(property(camelContext, boolean.class,
value)); return true;
default: return false;
}
}
@@ -52,6 +54,8 @@ public class PlatformHttpComponentConfigurer extends
PropertyConfigurerSupport i
case "headerFilterStrategy": return
org.apache.camel.spi.HeaderFilterStrategy.class;
case "requesttimeout":
case "requestTimeout": return long.class;
+ case "serverrequestvalidation":
+ case "serverRequestValidation": return boolean.class;
default: return null;
}
}
@@ -71,6 +75,8 @@ public class PlatformHttpComponentConfigurer extends
PropertyConfigurerSupport i
case "headerFilterStrategy": return target.getHeaderFilterStrategy();
case "requesttimeout":
case "requestTimeout": return target.getRequestTimeout();
+ case "serverrequestvalidation":
+ case "serverRequestValidation": return
target.isServerRequestValidation();
default: return null;
}
}
diff --git
a/components/camel-platform-http/src/generated/resources/META-INF/org/apache/camel/component/platform/http/platform-http.json
b/components/camel-platform-http/src/generated/resources/META-INF/org/apache/camel/component/platform/http/platform-http.json
index 970d47bf17ab..9de65466be58 100644
---
a/components/camel-platform-http/src/generated/resources/META-INF/org/apache/camel/component/platform/http/platform-http.json
+++
b/components/camel-platform-http/src/generated/resources/META-INF/org/apache/camel/component/platform/http/platform-http.json
@@ -28,9 +28,10 @@
"bridgeErrorHandler": { "index": 0, "kind": "property", "displayName":
"Bridge Error Handler", "group": "consumer", "label": "consumer", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": false, "description":
"Allows for bridging the consumer to the Camel routing Error Handler, which
mean any exceptions (if possible) occurred while the Camel consumer is trying
to pickup incoming messages, or the like [...]
"handleWriteResponseError": { "index": 1, "kind": "property",
"displayName": "Handle Write Response Error", "group": "consumer", "label":
"advanced,consumer", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": false, "description": "When Camel is complete processing the
message, and the HTTP server is writing response. This option controls whether
Camel should catch any failure during writing response [...]
"requestTimeout": { "index": 2, "kind": "property", "displayName":
"Request Timeout", "group": "consumer", "label": "advanced,consumer",
"required": false, "type": "integer", "javaType": "long", "deprecated": false,
"autowired": false, "secret": false, "description": "The period in milliseconds
after which the request should be timed out." },
- "autowiredEnabled": { "index": 3, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
- "engine": { "index": 4, "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" },
- "headerFilterStrategy": { "index": 5, "kind": "property", "displayName":
"Header Filter Strategy", "group": "filter", "label": "filter", "required":
false, "type": "object", "javaType":
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired":
false, "secret": false, "description": "To use a custom
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel
message." }
+ "serverRequestValidation": { "index": 3, "kind": "property",
"displayName": "Server Request Validation", "group": "consumer", "label":
"advanced,consumer", "required": false, "type": "boolean", "javaType":
"boolean", "deprecated": false, "autowired": false, "secret": false,
"defaultValue": true, "description": "Whether HTTP server should do preliminary
validation of incoming requests, validating if Content-Type\/Accept header,
matches what is allowed according to consumes\/produces c [...]
+ "autowiredEnabled": { "index": 4, "kind": "property", "displayName":
"Autowired Enabled", "group": "advanced", "label": "advanced", "required":
false, "type": "boolean", "javaType": "boolean", "deprecated": false,
"autowired": false, "secret": false, "defaultValue": true, "description":
"Whether autowiring is enabled. This is used for automatic autowiring options
(the option must be marked as autowired) by looking up in the registry to find
if there is a single instance of matching t [...]
+ "engine": { "index": 5, "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" },
+ "headerFilterStrategy": { "index": 6, "kind": "property", "displayName":
"Header Filter Strategy", "group": "filter", "label": "filter", "required":
false, "type": "object", "javaType":
"org.apache.camel.spi.HeaderFilterStrategy", "deprecated": false, "autowired":
false, "secret": false, "description": "To use a custom
org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel
message." }
},
"properties": {
"path": { "index": 0, "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'" },
diff --git
a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpComponent.java
b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpComponent.java
index 00abe1cf0f4b..c272ac263a08 100644
---
a/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpComponent.java
+++
b/components/camel-platform-http/src/main/java/org/apache/camel/component/platform/http/PlatformHttpComponent.java
@@ -64,6 +64,13 @@ public class PlatformHttpComponent extends
HeaderFilterStrategyComponent
@Metadata(label = "advanced,consumer",
description = "The period in milliseconds after which the
request should be timed out.")
private long requestTimeout;
+ @Metadata(label = "advanced,consumer", defaultValue = "true",
+ description = "Whether HTTP server should do preliminary
validation of incoming requests, validating if Content-Type/Accept header,
matches what"
+ + " is allowed according to consumes/produces
configuration (if set). If validation fails HTTP Status 415/406 is returned."
+ + " The HTTP server performs this validation
before Camel is involved, and as such if validation fails then Camel is never
activated."
+ + " Setting this option to false, allows Camel to
process any incoming requests such as to do custom validation"
+ + " or all requests must be handled by Camel.")
+ private boolean serverRequestValidation = true;
private final Set<HttpEndpointModel> httpEndpoints = new TreeSet<>();
private final Set<HttpEndpointModel> httpManagementEndpoints = new
TreeSet<>();
@@ -248,6 +255,14 @@ public class PlatformHttpComponent extends
HeaderFilterStrategyComponent
this.requestTimeout = requestTimeout;
}
+ public boolean isServerRequestValidation() {
+ return serverRequestValidation;
+ }
+
+ public void setServerRequestValidation(boolean serverRequestValidation) {
+ this.serverRequestValidation = serverRequestValidation;
+ }
+
private Consumer doCreateConsumer(
CamelContext camelContext, Processor processor, String verb,
String basePath,
String uriTemplate,
diff --git
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PlatformHttpComponentBuilderFactory.java
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PlatformHttpComponentBuilderFactory.java
index 0bbda8aae1a8..f981332b2d0b 100644
---
a/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PlatformHttpComponentBuilderFactory.java
+++
b/dsl/camel-componentdsl/src/generated/java/org/apache/camel/builder/component/dsl/PlatformHttpComponentBuilderFactory.java
@@ -118,6 +118,30 @@ public interface PlatformHttpComponentBuilderFactory {
}
+ /**
+ * Whether HTTP server should do preliminary validation of incoming
+ * requests, validating if Content-Type/Accept header, matches what is
+ * allowed according to consumes/produces configuration (if set). If
+ * validation fails HTTP Status 415/406 is returned. The HTTP server
+ * performs this validation before Camel is involved, and as such if
+ * validation fails then Camel is never activated. Setting this option
+ * to false, allows Camel to process any incoming requests such as to
do
+ * custom validation or all requests must be handled by Camel.
+ *
+ * The option is a: <code>boolean</code> type.
+ *
+ * Default: true
+ * Group: consumer
+ *
+ * @param serverRequestValidation the value to set
+ * @return the dsl builder
+ */
+ default PlatformHttpComponentBuilder serverRequestValidation(boolean
serverRequestValidation) {
+ doSetProperty("serverRequestValidation", serverRequestValidation);
+ return this;
+ }
+
+
/**
* Whether autowiring is enabled. This is used for automatic autowiring
* options (the option must be marked as autowired) by looking up in
the
@@ -190,6 +214,7 @@ public interface PlatformHttpComponentBuilderFactory {
case "bridgeErrorHandler": ((PlatformHttpComponent)
component).setBridgeErrorHandler((boolean) value); return true;
case "handleWriteResponseError": ((PlatformHttpComponent)
component).setHandleWriteResponseError((boolean) value); return true;
case "requestTimeout": ((PlatformHttpComponent)
component).setRequestTimeout((long) value); return true;
+ case "serverRequestValidation": ((PlatformHttpComponent)
component).setServerRequestValidation((boolean) value); return true;
case "autowiredEnabled": ((PlatformHttpComponent)
component).setAutowiredEnabled((boolean) value); return true;
case "engine": ((PlatformHttpComponent)
component).setEngine((org.apache.camel.component.platform.http.spi.PlatformHttpEngine)
value); return true;
case "headerFilterStrategy": ((PlatformHttpComponent)
component).setHeaderFilterStrategy((org.apache.camel.spi.HeaderFilterStrategy)
value); return true;