This is an automated email from the ASF dual-hosted git repository. fmariani pushed a commit to branch camel-spring-boot-4.8.x in repository https://gitbox.apache.org/repos/asf/camel-spring-boot.git
commit dab7b32697e925da1524c3468acdb598411e3057 Author: Rinaldo Pitzer JĂșnior <[email protected]> AuthorDate: Fri Dec 6 05:27:17 2024 -0300 CAMEL-21461: platform-http - add CORS support (#1299) --- .../springboot/CamelRequestHandlerMapping.java | 107 ++++++++++- .../SpringBootPlatformHttpCorsCredentialsTest.java | 201 +++++++++++++++++++++ .../springboot/SpringBootPlatformHttpCorsTest.java | 173 ++++++++++++++++++ .../SpringBootPlatformHttpOptionsTest.java | 124 +++++++++++++ .../src/test/resources/application.properties | 22 ++- 5 files changed, 621 insertions(+), 6 deletions(-) diff --git a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/CamelRequestHandlerMapping.java b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/CamelRequestHandlerMapping.java index 91d84e4c4d8..380d69ce232 100644 --- a/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/CamelRequestHandlerMapping.java +++ b/components-starter/camel-platform-http-starter/src/main/java/org/apache/camel/component/platform/http/springboot/CamelRequestHandlerMapping.java @@ -23,8 +23,10 @@ import org.apache.camel.component.platform.http.PlatformHttpComponent; import org.apache.camel.component.platform.http.PlatformHttpEndpoint; import org.apache.camel.component.platform.http.PlatformHttpListener; import org.apache.camel.component.platform.http.spi.PlatformHttpEngine; +import org.apache.camel.spi.RestConfiguration; import org.apache.camel.util.ReflectionHelper; import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.mvc.method.RequestMappingInfo; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; @@ -32,13 +34,20 @@ import org.springframework.web.util.ServletRequestPathUtils; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; public class CamelRequestHandlerMapping extends RequestMappingHandlerMapping implements PlatformHttpListener { private final PlatformHttpComponent component; private final PlatformHttpEngine engine; + private CorsConfiguration corsConfiguration; + public CamelRequestHandlerMapping(PlatformHttpComponent component, PlatformHttpEngine engine) { this.component = component; this.engine = engine; @@ -67,6 +76,55 @@ public class CamelRequestHandlerMapping extends RequestMappingHandlerMapping imp return null; } + @Override + protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) { + RestConfiguration restConfiguration = component.getCamelContext().getRestConfiguration(); + + if (!restConfiguration.isEnableCORS()) { + // CORS disabled for camel + return null; + } + + if (corsConfiguration == null) { + Map<String, String> corsHeaders = restConfiguration.getCorsHeaders(); + corsConfiguration = createCorsConfiguration(corsHeaders != null ? corsHeaders : Collections.emptyMap()); + } + return corsConfiguration; + } + + @Override + protected CorsConfiguration getCorsConfiguration(Object handler, HttpServletRequest request) { + return super.getCorsConfiguration(handler, request); + } + + private CorsConfiguration createCorsConfiguration(Map<String, String> corsHeaders) { + CorsConfiguration config = new CorsConfiguration(); + + String allowedOrigin = corsHeaders.get("Access-Control-Allow-Origin"); + config.addAllowedOrigin(allowedOrigin != null ? allowedOrigin : RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_ORIGIN); + + String allowMethodsStr = corsHeaders.get("Access-Control-Allow-Methods"); + allowMethodsStr = allowMethodsStr != null ? allowMethodsStr : RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_METHODS; + for (String allowMethod : allowMethodsStr.split(",")) { + config.addAllowedMethod(allowMethod.trim()); + } + + String allowHeadersStr = corsHeaders.get("Access-Control-Allow-Headers"); + allowHeadersStr = allowHeadersStr != null ? allowHeadersStr : RestConfiguration.CORS_ACCESS_CONTROL_ALLOW_HEADERS; + for (String allowHeader : allowHeadersStr.split(",")) { + config.addAllowedHeader(allowHeader.trim()); + } + + String maxAgeStr = corsHeaders.get("Access-Control-Max-Age"); + Long maxAge = maxAgeStr != null ? Long.parseLong(maxAgeStr) : Long.parseLong(RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE); + config.setMaxAge(maxAge); + + String allowCredentials = corsHeaders.get("Access-Control-Allow-Credentials"); + config.setAllowCredentials(Boolean.parseBoolean(allowCredentials)); + + return config; + } + @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { ServletRequestPathUtils.parseAndCache(request); @@ -78,7 +136,11 @@ public class CamelRequestHandlerMapping extends RequestMappingHandlerMapping imp RequestMappingInfo info = asRequestMappingInfo(model); Method m = ReflectionHelper.findMethod(SpringBootPlatformHttpConsumer.class, "service", HttpServletRequest.class, HttpServletResponse.class); - registerMapping(info, model.getConsumer(), m); + for (RequestMappingInfo info : requestMappingInfos) { + // Needed in case of context reload + unregisterMapping(info); + registerMapping(info, model.getConsumer(), m); + } } @Override @@ -93,6 +155,9 @@ public class CamelRequestHandlerMapping extends RequestMappingHandlerMapping imp if (verbs == null && model.getConsumer() != null) { PlatformHttpEndpoint endpoint = (PlatformHttpEndpoint) model.getConsumer().getEndpoint(); verbs = endpoint.getHttpMethodRestrict(); + if (verbs == null) { + Collections.addAll(methods, RequestMethod.values()); + } } if (verbs != null) { for (String v : model.getVerbs().split(",")) { @@ -101,9 +166,43 @@ public class CamelRequestHandlerMapping extends RequestMappingHandlerMapping imp } } - RequestMappingInfo info = RequestMappingInfo.paths(model.getUri()) - .methods(methods.toArray(new RequestMethod[0])).options(this.getBuilderConfiguration()).build(); - return info; + if (component.getCamelContext().getRestConfiguration().isEnableCORS()) { + // when CORS is enabled Camel adds OPTIONS by default in httpMethodsRestrict + // which causes multiple registration of OPTIONS endpoints in spring. + // this causes issues when unregistering endpoints because others share + // the same handler (the consumer) so they get unregistered as well. + // removing the OPTIONS mappings maintains the intended behavior + // of this verb while avoiding this issue. + methods.remove(RequestMethod.OPTIONS); + } + + for (RequestMethod rm : methods) { + createRequestMappingInfo(model, rm, result); + } + + return result; + } + + private void createRequestMappingInfo(HttpEndpointModel model, RequestMethod rm, List<RequestMappingInfo> result) { + RequestMethod[] methods = new RequestMethod[]{}; + if (rm != null) { + methods = new RequestMethod[]{rm}; + } + + RequestMappingInfo.Builder info = RequestMappingInfo + .paths(model.getUri()) + .methods(methods) + .options(this.getBuilderConfiguration()); + + if (model.getConsumes() != null + && (RequestMethod.POST.name().equals(rm.name()) || RequestMethod.PUT.name().equals(rm.name()) || RequestMethod.PATCH.name().equals(rm.name()))) { + info.consumes(model.getConsumes().split(",")); + } + if (model.getProduces() != null) { + info.produces(model.getProduces().split(",")); + } + + result.add(info.build()); } } diff --git a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCorsCredentialsTest.java b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCorsCredentialsTest.java new file mode 100644 index 00000000000..b7a60072a3e --- /dev/null +++ b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCorsCredentialsTest.java @@ -0,0 +1,201 @@ +/* + * 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.springboot; + +import io.restassured.RestAssured; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.*; + +@EnableAutoConfiguration(exclude = {OAuth2ClientAutoConfiguration.class, SecurityAutoConfiguration.class}) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { CamelAutoConfiguration.class, + SpringBootPlatformHttpCorsCredentialsTest.class, SpringBootPlatformHttpCorsCredentialsTest.TestConfiguration.class, + PlatformHttpComponentAutoConfiguration.class, SpringBootPlatformHttpAutoConfiguration.class, }) +public class SpringBootPlatformHttpCorsCredentialsTest { + + @LocalServerPort + private Integer port; + + @BeforeEach + void setUp() { + RestAssured.port = port; + RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); + } + + @Configuration + public static class TestConfiguration { + @Bean + public RouteBuilder springBootPlatformHttpRestDSLRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + restConfiguration().component("platform-http") + .enableCORS(true) + .corsAllowCredentials(true) + .corsHeaderProperty("Access-Control-Allow-Origin", "http://custom.origin.springboot"); + + rest("/rest") + .get().to("direct:restGet") + .post().consumes("application/json").to("direct:restPost"); + + from("direct:restPost") + .transform().constant("corsPost"); + + from("direct:restGet") + .transform().constant("corsGet"); + } + }; + } + } + + @Test + public void get() { + given() + .when() + .get("/rest") + .then() + .statusCode(200) + .body(equalTo("corsGet")); + } + + @Test + public void post() { + given() + .header("Content-type","application/json") + .when() + .post("/rest") + .then() + .statusCode(200) + .body(equalTo("corsPost")); + } + + @Test + public void options() { + final String origin = "http://custom.origin.springboot"; + final String method = "POST"; + final String headers = "X-Requested-With"; + + given() + .header("Origin", origin) + .header("Access-Control-Request-Method", method) + .header("Access-Control-Request-Headers", headers) + .when() + .options("/rest") + .then() + .statusCode(200) + .header("Access-Control-Allow-Origin", origin) + .header("Access-Control-Allow-Methods", containsString(method)) + .header("Access-Control-Allow-Headers", containsString(headers)) + .header("Access-Control-Allow-Credentials", "true") + .header("Access-Control-Max-Age", RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE) + .body(emptyString()); + } + + @Test + public void getForbiddenOrigin() { + final String origin = "http://custom2.origin.springboot"; + + given() + .header("Origin", origin) + .when() + .get("/rest") + .then() + .statusCode(403); + } + + @Test + public void postForbiddenOrigin() { + final String origin = "http://custom2.origin.springboot"; + + given() + .header("Origin", origin) + .header("Content-type","application/json") + .when() + .post("/rest") + .then() + .statusCode(403); + } + + @Test + public void optionsForbiddenOrigin() { + final String origin = "http://custom2.origin.springboot"; + + given() + .header("Origin", origin) + .when() + .options("/rest") + .then() + .header("Access-Control-Allow-Origin", not(containsString(origin))); + } + + @Test + public void optionsForbiddenMethod() { + String method = "DELETE"; + + given() + .header("Access-Control-Request-Method", method) + .when() + .options("/rest") + .then() + .header("Access-Control-Allow-Methods", not(containsString(method))); + } + + @Test + public void optionsForbiddenHeader() { + String header = "X-Custom-Header"; + + given() + .header("Access-Control-Request-Headers", header) + .when() + .options("/rest") + .then() + .header("Access-Control-Allow-Headers", not(containsString(header))); + } + + @Test + public void optionNonCors() { + given() + .when() + .options("/rest") + .then() + .statusCode(200) + .header("Allow", containsString("OPTIONS")) + .header("Allow", containsString("GET")) + .header("Allow", containsString("POST")) + .header("Allow", containsString("HEAD")) + .header("Allow", not(containsString("PATCH"))) + .header("Allow", not(containsString("PUT"))) + .header("Allow", not(containsString("DELETE"))); + } + +} diff --git a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCorsTest.java b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCorsTest.java new file mode 100644 index 00000000000..fd7e3cd7f35 --- /dev/null +++ b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpCorsTest.java @@ -0,0 +1,173 @@ +/* + * 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.springboot; + +import io.restassured.RestAssured; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spi.RestConfiguration; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.not; + +@EnableAutoConfiguration(exclude = {OAuth2ClientAutoConfiguration.class, SecurityAutoConfiguration.class}) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { CamelAutoConfiguration.class, + SpringBootPlatformHttpCorsTest.class, SpringBootPlatformHttpCorsTest.TestConfiguration.class, + PlatformHttpComponentAutoConfiguration.class, SpringBootPlatformHttpAutoConfiguration.class, }) +public class SpringBootPlatformHttpCorsTest { + + @LocalServerPort + private Integer port; + + @BeforeEach + void setUp() { + RestAssured.port = port; + RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); + } + + @Configuration + public static class TestConfiguration { + @Bean + public RouteBuilder springBootPlatformHttpRestDSLRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + restConfiguration().component("platform-http").enableCORS(true); + + rest("/rest") + .post().consumes("application/json").to("direct:rest"); + + from("direct:rest") + .setBody(simple("Hello ${body}")); + + from("platform-http:/cors?httpMethodRestrict=GET,POST") + .transform().constant("cors"); + } + }; + } + } + + @Test + public void get() { + given() + .when() + .get("/cors") + .then() + .statusCode(200); + } + + @Test + public void post() { + given() + .header("Content-type","application/json") + .when() + .post("/rest") + .then() + .statusCode(200); + } + + @Test + public void options() { + final String origin = "http://custom.origin.springboot"; + final String method = "POST"; + final String headers = "X-Requested-With"; + + given() + .header("Origin", origin) + .header("Access-Control-Request-Method", method) + .header("Access-Control-Request-Headers", headers) + .when() + .options("/rest") + .then() + .statusCode(200) + .header("Access-Control-Allow-Origin", "*") + .header("Access-Control-Allow-Methods", containsString(method)) + .header("Access-Control-Allow-Headers", containsString(headers)) + .header("Access-Control-Max-Age", RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE) + .body(emptyString()); + } + + @Test + public void optionsSecondEndPoint() { + final String origin = "http://custom.origin.springboot"; + final String method = "POST"; + final String headers = "X-Requested-With"; + + given() + .header("Origin", origin) + .header("Access-Control-Request-Method", method) + .header("Access-Control-Request-Headers", headers) + .when() + .options("/cors") + .then() + .statusCode(200) + .header("Access-Control-Allow-Origin", "*") + .header("Access-Control-Allow-Methods", containsString(method)) + .header("Access-Control-Allow-Headers", containsString(headers)) + .header("Access-Control-Max-Age", RestConfiguration.CORS_ACCESS_CONTROL_MAX_AGE) + .body(emptyString()); + } + + @Test + public void optionNonCORS() { + given() + .when() + .options("/rest") + .then() + .statusCode(200) + .header("Allow", containsString("OPTIONS")) + .header("Allow", not(containsString("GET"))) + .header("Allow", containsString("POST")) + .header("Allow", not(containsString("HEAD"))) + .header("Allow", not(containsString("PATCH"))) + .header("Allow", not(containsString("PUT"))) + .header("Allow", not(containsString("DELETE"))); + } + + @Test + public void optionNonCorsSecondEndpoint() { + given() + .when() + .options("/cors") + .then() + .statusCode(200) + .header("Allow", containsString("OPTIONS")) + .header("Allow", containsString("GET")) + .header("Allow", containsString("POST")) + .header("Allow", containsString("HEAD")) + .header("Allow", not(containsString("PATCH"))) + .header("Allow", not(containsString("PUT"))) + .header("Allow", not(containsString("DELETE"))); + } + +} diff --git a/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpOptionsTest.java b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpOptionsTest.java new file mode 100644 index 00000000000..036dd359cf1 --- /dev/null +++ b/components-starter/camel-platform-http-starter/src/test/java/org/apache/camel/component/platform/http/springboot/SpringBootPlatformHttpOptionsTest.java @@ -0,0 +1,124 @@ +/* + * 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.springboot; + +import io.restassured.RestAssured; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.test.spring.junit5.CamelSpringBootTest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration; +import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.test.annotation.DirtiesContext; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.*; + +@EnableAutoConfiguration(exclude = {OAuth2ClientAutoConfiguration.class, SecurityAutoConfiguration.class}) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@CamelSpringBootTest +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { CamelAutoConfiguration.class, + SpringBootPlatformHttpOptionsTest.class, SpringBootPlatformHttpOptionsTest.TestConfiguration.class, + PlatformHttpComponentAutoConfiguration.class, SpringBootPlatformHttpAutoConfiguration.class, }) +public class SpringBootPlatformHttpOptionsTest { + + @LocalServerPort + private Integer port; + + @BeforeEach + void setUp() { + RestAssured.port = port; + RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); + } + + @Configuration + public static class TestConfiguration { + @Bean + public RouteBuilder springBootPlatformHttpRestDSLRouteBuilder() { + return new RouteBuilder() { + @Override + public void configure() { + restConfiguration().component("platform-http").enableCORS(false); + + rest("/rest") + .get().to("direct:get") + .post().to("direct:post"); + from("direct:get").transform().constant("get"); + from("direct:post").transform().constant("post"); + + from("platform-http:/restRestricted?httpMethodRestrict=GET,PUT").transform().constant("restricted"); + from("platform-http:/restDefault").transform().constant("default"); + } + }; + } + } + + @Test + public void optionsRest() { + given() + .when() + .options("/rest") + .then() + .statusCode(200) + .header("Allow", containsString("OPTIONS")) + .header("Allow", containsString("GET")) + .header("Allow", containsString("POST")) + .header("Allow", containsString("HEAD")) + .header("Allow", not(containsString("PATCH"))) + .header("Allow", not(containsString("PUT"))) + .header("Allow", not(containsString("DELETE"))); + } + + @Test + public void optionsRestRestricted() { + given() + .when() + .options("/restRestricted") + .then() + .statusCode(200) + .header("Allow", containsString("OPTIONS")) + .header("Allow", containsString("GET")) + .header("Allow", not(containsString("POST"))) + .header("Allow", containsString("HEAD")) + .header("Allow", not(containsString("PATCH"))) + .header("Allow", containsString("PUT")) + .header("Allow", not(containsString("DELETE"))); + } + + @Test + public void optionsRestDefault() { + given() + .when() + .options("/restDefault") + .then() + .statusCode(200) + .header("Allow", containsString("OPTIONS")) + .header("Allow", containsString("GET")) + .header("Allow", containsString("POST")) + .header("Allow", containsString("HEAD")) + .header("Allow", containsString("PATCH")) + .header("Allow", containsString("PUT")) + .header("Allow", containsString("DELETE")); + } + +} diff --git a/components-starter/camel-platform-http-starter/src/test/resources/application.properties b/components-starter/camel-platform-http-starter/src/test/resources/application.properties index 2a1a48d10d4..f3183eb5542 100644 --- a/components-starter/camel-platform-http-starter/src/test/resources/application.properties +++ b/components-starter/camel-platform-http-starter/src/test/resources/application.properties @@ -1,2 +1,20 @@ -#logging.level.org.springframework.web: DEBUG -#logging.level.org.springframework.boot.web: DEBUG \ No newline at end of file +## --------------------------------------------------------------------------- +## 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. +## --------------------------------------------------------------------------- + +#logging.level.org.springframework.web=TRACE +#logging.level.org.springframework.boot.web=TRACE +#spring.mvc.log-request-details=true
