|
@@ -1,5 +1,5 @@
|
|
/*
|
|
/*
|
|
- * Copyright 2002-2023 the original author or authors.
|
|
|
|
|
|
+ * Copyright 2002-2024 the original author or authors.
|
|
*
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* you may not use this file except in compliance with the License.
|
|
@@ -22,6 +22,7 @@ import java.util.Collection;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Map;
|
|
|
|
+import java.util.concurrent.ConcurrentHashMap;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
import java.util.function.Function;
|
|
import java.util.function.Function;
|
|
|
|
|
|
@@ -322,36 +323,15 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
|
if (servletContext == null) {
|
|
if (servletContext == null) {
|
|
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
|
return requestMatchers(RequestMatchers.antMatchersAsArray(method, patterns));
|
|
}
|
|
}
|
|
- boolean isProgrammaticApiAvailable = isProgrammaticApiAvailable(servletContext);
|
|
|
|
List<RequestMatcher> matchers = new ArrayList<>();
|
|
List<RequestMatcher> matchers = new ArrayList<>();
|
|
for (String pattern : patterns) {
|
|
for (String pattern : patterns) {
|
|
AntPathRequestMatcher ant = new AntPathRequestMatcher(pattern, (method != null) ? method.name() : null);
|
|
AntPathRequestMatcher ant = new AntPathRequestMatcher(pattern, (method != null) ? method.name() : null);
|
|
MvcRequestMatcher mvc = createMvcMatchers(method, pattern).get(0);
|
|
MvcRequestMatcher mvc = createMvcMatchers(method, pattern).get(0);
|
|
- if (isProgrammaticApiAvailable) {
|
|
|
|
- matchers.add(resolve(ant, mvc, servletContext));
|
|
|
|
- }
|
|
|
|
- else {
|
|
|
|
- this.logger
|
|
|
|
- .warn("The ServletRegistration API was not available at startup time. This may be due to a misconfiguration; "
|
|
|
|
- + "if you are using AbstractSecurityWebApplicationInitializer, please double-check the recommendations outlined in "
|
|
|
|
- + "https://docs.spring.io/spring-security/reference/servlet/configuration/java.html#abstractsecuritywebapplicationinitializer-with-spring-mvc");
|
|
|
|
- matchers.add(new DeferredRequestMatcher((request) -> resolve(ant, mvc, request.getServletContext()),
|
|
|
|
- mvc, ant));
|
|
|
|
- }
|
|
|
|
|
|
+ matchers.add(new DeferredRequestMatcher((c) -> resolve(ant, mvc, c), mvc, ant));
|
|
}
|
|
}
|
|
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
|
|
return requestMatchers(matchers.toArray(new RequestMatcher[0]));
|
|
}
|
|
}
|
|
|
|
|
|
- private static boolean isProgrammaticApiAvailable(ServletContext servletContext) {
|
|
|
|
- try {
|
|
|
|
- servletContext.getServletRegistrations();
|
|
|
|
- return true;
|
|
|
|
- }
|
|
|
|
- catch (UnsupportedOperationException ex) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
|
|
private RequestMatcher resolve(AntPathRequestMatcher ant, MvcRequestMatcher mvc, ServletContext servletContext) {
|
|
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
|
|
Map<String, ? extends ServletRegistration> registrations = mappableServletRegistrations(servletContext);
|
|
if (registrations.isEmpty()) {
|
|
if (registrations.isEmpty()) {
|
|
@@ -593,34 +573,29 @@ public abstract class AbstractRequestMatcherRegistry<C> {
|
|
|
|
|
|
static class DeferredRequestMatcher implements RequestMatcher {
|
|
static class DeferredRequestMatcher implements RequestMatcher {
|
|
|
|
|
|
- final Function<HttpServletRequest, RequestMatcher> requestMatcherFactory;
|
|
|
|
|
|
+ final Function<ServletContext, RequestMatcher> requestMatcherFactory;
|
|
|
|
|
|
final AtomicReference<String> description = new AtomicReference<>();
|
|
final AtomicReference<String> description = new AtomicReference<>();
|
|
|
|
|
|
- volatile RequestMatcher requestMatcher;
|
|
|
|
-
|
|
|
|
- DeferredRequestMatcher(Function<HttpServletRequest, RequestMatcher> resolver, RequestMatcher... candidates) {
|
|
|
|
- this.requestMatcherFactory = (request) -> {
|
|
|
|
- if (this.requestMatcher == null) {
|
|
|
|
- synchronized (this) {
|
|
|
|
- if (this.requestMatcher == null) {
|
|
|
|
- this.requestMatcher = resolver.apply(request);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- return this.requestMatcher;
|
|
|
|
- };
|
|
|
|
|
|
+ final Map<ServletContext, RequestMatcher> requestMatchers = new ConcurrentHashMap<>();
|
|
|
|
+
|
|
|
|
+ DeferredRequestMatcher(Function<ServletContext, RequestMatcher> resolver, RequestMatcher... candidates) {
|
|
|
|
+ this.requestMatcherFactory = (sc) -> this.requestMatchers.computeIfAbsent(sc, resolver);
|
|
this.description.set("Deferred " + Arrays.toString(candidates));
|
|
this.description.set("Deferred " + Arrays.toString(candidates));
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ RequestMatcher requestMatcher(ServletContext servletContext) {
|
|
|
|
+ return this.requestMatcherFactory.apply(servletContext);
|
|
|
|
+ }
|
|
|
|
+
|
|
@Override
|
|
@Override
|
|
public boolean matches(HttpServletRequest request) {
|
|
public boolean matches(HttpServletRequest request) {
|
|
- return this.requestMatcherFactory.apply(request).matches(request);
|
|
|
|
|
|
+ return this.requestMatcherFactory.apply(request.getServletContext()).matches(request);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
public MatchResult matcher(HttpServletRequest request) {
|
|
public MatchResult matcher(HttpServletRequest request) {
|
|
- return this.requestMatcherFactory.apply(request).matcher(request);
|
|
|
|
|
|
+ return this.requestMatcherFactory.apply(request.getServletContext()).matcher(request);
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|