Spring MVC supports CORS with simple and pre-flight requests.

Spring MVC provides support for global CORS handling with a filter, but also local support with @CorsMapping annotations or a CorsConfiguration instance, which is provided to AbstractHandlerMapping implementations.

In the case of Servlet Functional Endpoints, the provided CorsConfiguration has no effect on pre-flight requests.

Here is a sample application:

@Configuration
public class SampleRouterConfig {

    @Bean
    public RouterFunction<ServerResponse> router() {
        return RouterFunctions.route()
                .POST("/function", (req) -> ServerResponse.ok().body("Hello"))
                .build();
    }
}

We can also set a custom CorsConfiguration on the RouterFunctionMapping.

In this case, the following request will not match any handler, and other HandlerMapping later in the chain will handle this:

OPTIONS http://localhost:8080/function
Origin: https://spring.io
Access-Control-Request-Method: POST

Other HandlerMapping implementations have additional checks in the request matching infrastructure to check requests with CorstUtils.isPreFlightRequest(request). See implementations of AbstractRequestCondition and also AbstractHandlerMethodMapping itself.

I'm wondering if we should have here additional RequestPredicates to locally manage CORS requests, or if existing predicates should look for pre-flight requests and match anyway.

Comment From: poutsma

I was under the impression that since the RouterFunctionMapping extends from AbstractHandlerMapping, we get CORS for free? Is there more we can do?

Comment From: bclozel

We're getting most of it for free, expect for the pre-flight requests. We need in that case to match OPTIONS requests that qualify as pre-flight requests and make sure to match to the corresponding handler.

Could you take a look at AbstractRequestCondition and AbstractHandlerMethodMapping? In those classes we're making sure to match pre-flight requests. We might have to do something like this for RequestPredicates.

Comment From: rstoyanchev

@poutsma, notice how RequestMethodsRequestCondition makes a special check for pre-flight requests. Rather than matching the actual method which is HTTP OPTIONS, it matches the HTTP method specified in the Access-Control-Request-Method header. This is necessary to ensure we can correctly identify that there is a match for the would-be, "actual" request.

From there AbstractHandlerMapping will use a PreFlightHandlerInterceptor to handle the request without ever calling the identified handler. The main purpose of finding that handler then was a) to ensure there is a match and b) to check if that handler implements CorsConfigurationSource. The latter could be used for example if the functional model added some equivalent to @CorsConfiguration for specific route(s) but it's not the only way.

One option could be to change the HTTP method of the request before trying to find a route. That would be an easy way to support course with RouterFunctionMapping. Another approach would be to consider the CORS support needed for route functions first, even if used independent of the HandlerMapping hierarchy.

Comment From: poutsma

Thanks for the pointer, @rstoyanchev!

I think it should be possible to get this into the HttpMethodPredicate for 5.2.5.

Comment From: poutsma

Initial testing by @bclozel shows that there is more that needs to be done.