Suppress PREFLIGHT_AMBIGUOUS_MATCH if matches have no CORS config
Closes gh-26490
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,12 +28,19 @@ import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.server.PathContainer;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.CrossOrigin;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.web.testfixture.http.server.reactive.MockServerHttpResponse;
|
||||
import org.springframework.web.testfixture.server.MockServerWebExchange;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
@@ -105,6 +112,39 @@ public class HandlerMethodMappingTests {
|
||||
StepVerifier.create(result).expectError(IllegalStateException.class).verify();
|
||||
}
|
||||
|
||||
@Test // gh-26490
|
||||
public void ambiguousMatchOnPreFlightRequestWithoutCorsConfig() throws Exception {
|
||||
this.mapping.registerMapping("/f?o", this.handler, this.method1);
|
||||
this.mapping.registerMapping("/fo?", this.handler, this.method2);
|
||||
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(
|
||||
MockServerHttpRequest.options("http://example.org/foo")
|
||||
.header(HttpHeaders.ORIGIN, "https://domain.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET"));
|
||||
|
||||
this.mapping.getHandler(exchange).block();
|
||||
|
||||
assertThat(exchange.getResponse().getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test // gh-26490
|
||||
public void ambiguousMatchOnPreFlightRequestWithCorsConfig() throws Exception {
|
||||
this.mapping.registerMapping("/f?o", this.handler, this.method1);
|
||||
this.mapping.registerMapping("/fo?", this.handler, this.handler.getClass().getMethod("corsHandlerMethod"));
|
||||
|
||||
MockServerWebExchange exchange = MockServerWebExchange.from(
|
||||
MockServerHttpRequest.options("http://example.org/foo")
|
||||
.header(HttpHeaders.ORIGIN, "https://domain.com")
|
||||
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET"));
|
||||
|
||||
this.mapping.getHandler(exchange).block();
|
||||
|
||||
MockServerHttpResponse response = exchange.getResponse();
|
||||
assertThat(response.getStatusCode()).isNull();
|
||||
assertThat(response.getHeaders().getAccessControlAllowOrigin()).isEqualTo("https://domain.com");
|
||||
assertThat(response.getHeaders().getAccessControlAllowMethods()).containsExactly(HttpMethod.GET);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerMapping() {
|
||||
String key1 = "/foo";
|
||||
@@ -171,6 +211,17 @@ public class HandlerMethodMappingTests {
|
||||
Collections.emptySet() : Collections.singleton(mapping));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CorsConfiguration initCorsConfiguration(Object handler, Method method, String mapping) {
|
||||
CrossOrigin crossOrigin = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class);
|
||||
if (crossOrigin != null) {
|
||||
CorsConfiguration corsConfig = new CorsConfiguration();
|
||||
corsConfig.setAllowedOrigins(Collections.singletonList("http://domain.com"));
|
||||
return corsConfig;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getMatchingMapping(String pattern, ServerWebExchange exchange) {
|
||||
PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
|
||||
@@ -200,6 +251,11 @@ public class HandlerMethodMappingTests {
|
||||
@SuppressWarnings("unused")
|
||||
public void handlerMethod2() {
|
||||
}
|
||||
|
||||
@RequestMapping
|
||||
@CrossOrigin(originPatterns = "*")
|
||||
public void corsHandlerMethod() {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -160,9 +160,9 @@ class GlobalCorsConfigIntegrationTests extends AbstractRequestMappingIntegration
|
||||
this.headers.add(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET");
|
||||
ResponseEntity<String> entity = performOptions("/ambiguous", this.headers, String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getHeaders().getAccessControlAllowOrigin()).isEqualTo("http://localhost:9000");
|
||||
assertThat(entity.getHeaders().getAccessControlAllowMethods()).containsExactly(HttpMethod.GET);
|
||||
assertThat(entity.getHeaders().getAccessControlAllowCredentials()).isEqualTo(true);
|
||||
assertThat(entity.getHeaders().getAccessControlAllowOrigin()).isEqualTo("*");
|
||||
assertThat(entity.getHeaders().getAccessControlAllowMethods()).containsExactly(HttpMethod.GET, HttpMethod.POST);
|
||||
assertThat(entity.getHeaders().getAccessControlAllowCredentials()).isEqualTo(false);
|
||||
assertThat(entity.getHeaders().get(HttpHeaders.VARY))
|
||||
.containsExactly(HttpHeaders.ORIGIN, HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD,
|
||||
HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
|
||||
|
||||
Reference in New Issue
Block a user