Discovered whilst working on https://github.com/spring-projects/spring-boot/issues/24645. Running CorsSampleActuatorApplicationTests.preflightRequestToEndpointShouldReturnOk from this branch should replicate the problem.

This issue is a quite subtle and hard to replicate. I've found it to cause problems for CorsFilter as well as MvcRequestMatcher in Spring Security. It appears that HandlerMappingIntrospector can fail to find mappings if they are configured with a PathPattern.

In AbstractHandlerMapping.initLookupPath there's the following branch:

if (usesPathPatterns()) {
    request.removeAttribute(UrlPathHelper.PATH_ATTRIBUTE);
    RequestPath requestPath = ServletRequestPathUtils.getParsedRequestPath(request);
    String lookupPath = requestPath.pathWithinApplication().value();
    return UrlPathHelper.defaultInstance.removeSemicolonContent(lookupPath);
}
else {
    return getUrlPathHelper().resolveAndCacheLookupPath(request);
}

This means that ServletRequestPathUtils.getParsedRequestPath(request) is called when a PathPattern is set. That code will fail if request.getAttribute(PATH_ATTRIBUTE) is null.

Usually HandlerMappers are only called from the DispatcherServlet which has the following logic:

RequestPath previousRequestPath = null;
if (this.parseRequestPath) {
    previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
    ServletRequestPathUtils.parseAndCache(request);
}

The problem is that HandlerMappingIntrospector is designed to be called from a Filter which means that it can be executed before the DisatcherServlet runs.

Comment From: rstoyanchev

It looks like the original intent was that Spring Security might configure ServletRequestPathFilter in its filter chain. However, when the solution was refined so that its Spring Security can remain unaware of the kind of patterns used, the HandlerMappingIntrospector was never updated. I will fix that.

I'm not sure what the issue is for CorsFilter, I presume that is a variation of the same issue when Spring Security calls HandlerMappingIntrospector#getCorsConfiguration?

Comment From: philwebb

Yes, it's this line when configSource is a HandlerMappingIntrospector. The CorsConfiguration is never returned because this line catches and swallows this exception.

Comment From: rstoyanchev

Okay thanks for confirming.