Leverage PathPatternParser in CORS configuration source

Previously `UrlBasedCorsConfigurationSource` was relying on
`PathMatcher` implementations for matching incoming request lookup paths
with the configured path patterns for CORS configuration.

This commit replaces the use of `PathMatcher` with a `PathPatternParser`
that parses the string patterns into `PathPattenr` instances and allows
for faster matching against lookup paths.

Issue: SPR-15688
This commit is contained in:
Brian Clozel
2017-07-04 15:44:15 +02:00
parent fd1859c34c
commit 9c93521512
3 changed files with 26 additions and 46 deletions

View File

@@ -16,16 +16,14 @@
package org.springframework.web.cors.reactive;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.ParsingPathMatcher;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPatternParser;
/**
* Provide a per reactive request {@link CorsConfiguration} instance based on a
@@ -35,23 +33,18 @@ import org.springframework.web.util.pattern.ParsingPathMatcher;
* as well as Ant-style path patterns (such as {@code "/admin/**"}).
*
* @author Sebastien Deleuze
* @author Brian Clozel
* @since 5.0
*/
public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource {
private final Map<String, CorsConfiguration> corsConfigurations = new LinkedHashMap<>();
private final Map<PathPattern, CorsConfiguration> corsConfigurations;
private PathMatcher pathMatcher = new ParsingPathMatcher();
/**
* Set the PathMatcher implementation to use for matching URL paths
* against registered URL patterns. Default is ParsingPathMatcher.
* @see ParsingPathMatcher
*/
public void setPathMatcher(PathMatcher pathMatcher) {
Assert.notNull(pathMatcher, "PathMatcher must not be null");
this.pathMatcher = pathMatcher;
private final PathPatternParser patternParser;
public UrlBasedCorsConfigurationSource(PathPatternParser patternParser) {
this.corsConfigurations = new LinkedHashMap<>();
this.patternParser = patternParser;
}
/**
@@ -60,33 +53,25 @@ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource
public void setCorsConfigurations(@Nullable Map<String, CorsConfiguration> corsConfigurations) {
this.corsConfigurations.clear();
if (corsConfigurations != null) {
this.corsConfigurations.putAll(corsConfigurations);
corsConfigurations.forEach((path, config) -> registerCorsConfiguration(path, config));
}
}
/**
* Get the CORS configuration.
*/
public Map<String, CorsConfiguration> getCorsConfigurations() {
return Collections.unmodifiableMap(this.corsConfigurations);
}
/**
* Register a {@link CorsConfiguration} for the specified path pattern.
*/
public void registerCorsConfiguration(String path, CorsConfiguration config) {
this.corsConfigurations.put(path, config);
this.corsConfigurations.put(this.patternParser.parse(path), config);
}
@Override
public CorsConfiguration getCorsConfiguration(ServerWebExchange exchange) {
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
for (Map.Entry<String, CorsConfiguration> entry : this.corsConfigurations.entrySet()) {
if (this.pathMatcher.match(entry.getKey(), lookupPath)) {
return entry.getValue();
}
}
return null;
return this.corsConfigurations.entrySet().stream()
.filter(entry -> entry.getKey().matches(lookupPath))
.map(entry -> entry.getValue())
.findFirst()
.orElse(null);
}
}