Skip to content

Commit 57b680a

Browse files
authored
CAMEL-22798: camel-platform-http-vertx - VertX has hardcoded content-type validation (#20532)
1 parent f16cae2 commit 57b680a

File tree

7 files changed

+186
-15
lines changed

7 files changed

+186
-15
lines changed

catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/platform-http.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828
"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 likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." },
2929
"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 and store this on the Exchange, which allows onCompletion\/UnitOfWork to regard the Exchange as failed and have access to the caused exception from the HTTP server." },
3030
"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." },
31-
"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 type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." },
32-
"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" },
33-
"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." }
31+
"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 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." },
32+
"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 type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." },
33+
"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" },
34+
"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." }
3435
},
3536
"properties": {
3637
"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'" },

components/camel-platform-http-vertx/src/main/java/org/apache/camel/component/platform/http/vertx/VertxPlatformHttpConsumer.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -149,16 +149,18 @@ protected void doStart() throws Exception {
149149
methods.forEach(m -> newRoute.method(HttpMethod.valueOf(m.name())));
150150
}
151151

152-
if (getEndpoint().getConsumes() != null) {
153-
//comma separated contentTypes has to be registered one by one
154-
for (String c : getEndpoint().getConsumes().split(",")) {
155-
newRoute.consumes(c);
152+
if (getEndpoint().getComponent().isServerRequestValidation()) {
153+
if (getEndpoint().getConsumes() != null) {
154+
//comma separated contentTypes has to be registered one by one
155+
for (String c : getEndpoint().getConsumes().split(",")) {
156+
newRoute.consumes(c);
157+
}
156158
}
157-
}
158-
if (getEndpoint().getProduces() != null) {
159-
//comma separated contentTypes has to be registered one by one
160-
for (String p : getEndpoint().getProduces().split(",")) {
161-
newRoute.produces(p);
159+
if (getEndpoint().getProduces() != null) {
160+
//comma separated contentTypes has to be registered one by one
161+
for (String p : getEndpoint().getProduces().split(",")) {
162+
newRoute.produces(p);
163+
}
162164
}
163165
}
164166

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.component.platform.http.vertx;
18+
19+
import org.apache.camel.CamelContext;
20+
import org.apache.camel.builder.RouteBuilder;
21+
import org.apache.camel.component.platform.http.PlatformHttpComponent;
22+
import org.junit.jupiter.api.Test;
23+
24+
import static io.restassured.RestAssured.given;
25+
import static org.hamcrest.Matchers.is;
26+
27+
public class VertxPlatformServerRequestValidationTest {
28+
29+
@Test
30+
void testServerRequestFalse() throws Exception {
31+
final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
32+
33+
try {
34+
context.addRoutes(new RouteBuilder() {
35+
@Override
36+
public void configure() {
37+
PlatformHttpComponent phc = context.getComponent("platform-http", PlatformHttpComponent.class);
38+
phc.setServerRequestValidation(false);
39+
40+
restConfiguration().component("platform-http")
41+
.contextPath("/rest");
42+
43+
rest().post("/test")
44+
.consumes("application/json")
45+
.produces("application/json")
46+
.to("direct:rest");
47+
48+
from("direct:rest")
49+
.setBody(simple("Hello"));
50+
}
51+
});
52+
53+
context.start();
54+
55+
given()
56+
.body("<hello>World</hello>")
57+
.contentType("application/xml")
58+
.post("/rest/test")
59+
.then()
60+
.statusCode(200)
61+
.body(is("Hello"));
62+
63+
given()
64+
.body("{ \"name\": \"jack\" }")
65+
.contentType("application/json")
66+
.accept("application/xml")
67+
.post("/rest/test")
68+
.then()
69+
.statusCode(200)
70+
.body(is("Hello"));
71+
} finally {
72+
context.stop();
73+
}
74+
}
75+
76+
@Test
77+
void testServerRequestTrue() throws Exception {
78+
final CamelContext context = VertxPlatformHttpEngineTest.createCamelContext();
79+
80+
try {
81+
context.addRoutes(new RouteBuilder() {
82+
@Override
83+
public void configure() {
84+
PlatformHttpComponent phc = context.getComponent("platform-http", PlatformHttpComponent.class);
85+
phc.setServerRequestValidation(true);
86+
87+
restConfiguration().component("platform-http")
88+
.contextPath("/rest");
89+
90+
rest().post("/test")
91+
.consumes("application/json")
92+
.produces("application/json")
93+
.to("direct:rest");
94+
95+
from("direct:rest")
96+
.setBody(simple("Hello"));
97+
}
98+
});
99+
100+
context.start();
101+
102+
given()
103+
.body("<hello>World</hello>")
104+
.contentType("application/xml")
105+
.post("/rest/test")
106+
.then()
107+
.statusCode(415);
108+
109+
given()
110+
.body("{ \"name\": \"jack\" }")
111+
.contentType("application/json")
112+
.accept("application/xml")
113+
.post("/rest/test")
114+
.then()
115+
.statusCode(406);
116+
} finally {
117+
context.stop();
118+
}
119+
}
120+
121+
}

components/camel-platform-http/src/generated/java/org/apache/camel/component/platform/http/PlatformHttpComponentConfigurer.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj
3434
case "headerFilterStrategy": target.setHeaderFilterStrategy(property(camelContext, org.apache.camel.spi.HeaderFilterStrategy.class, value)); return true;
3535
case "requesttimeout":
3636
case "requestTimeout": target.setRequestTimeout(property(camelContext, long.class, value)); return true;
37+
case "serverrequestvalidation":
38+
case "serverRequestValidation": target.setServerRequestValidation(property(camelContext, boolean.class, value)); return true;
3739
default: return false;
3840
}
3941
}
@@ -52,6 +54,8 @@ public Class<?> getOptionType(String name, boolean ignoreCase) {
5254
case "headerFilterStrategy": return org.apache.camel.spi.HeaderFilterStrategy.class;
5355
case "requesttimeout":
5456
case "requestTimeout": return long.class;
57+
case "serverrequestvalidation":
58+
case "serverRequestValidation": return boolean.class;
5559
default: return null;
5660
}
5761
}
@@ -71,6 +75,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
7175
case "headerFilterStrategy": return target.getHeaderFilterStrategy();
7276
case "requesttimeout":
7377
case "requestTimeout": return target.getRequestTimeout();
78+
case "serverrequestvalidation":
79+
case "serverRequestValidation": return target.isServerRequestValidation();
7480
default: return null;
7581
}
7682
}

components/camel-platform-http/src/generated/resources/META-INF/org/apache/camel/component/platform/http/platform-http.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828
"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 likes, will now be processed as a message and handled by the routing Error Handler. Important: This is only possible if the 3rd party component allows Camel to be alerted if an exception was thrown. Some components handle this internally only, and therefore bridgeErrorHandler is not possible. In other situations we may improve the Camel component to hook into the 3rd party component and make this possible for future releases. By default the consumer will use the org.apache.camel.spi.ExceptionHandler to deal with exceptions, that will be logged at WARN or ERROR level and ignored." },
2929
"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 and store this on the Exchange, which allows onCompletion\/UnitOfWork to regard the Exchange as failed and have access to the caused exception from the HTTP server." },
3030
"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." },
31-
"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 type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." },
32-
"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" },
33-
"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." }
31+
"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 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." },
32+
"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 type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc." },
33+
"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" },
34+
"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." }
3435
},
3536
"properties": {
3637
"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'" },

0 commit comments

Comments
 (0)