Removing remaining use of PathPattern with String path
This commit is contained in:
@@ -60,7 +60,19 @@ public interface PathContainer {
|
||||
* @return the sub-path
|
||||
*/
|
||||
static PathContainer subPath(PathContainer path, int index) {
|
||||
return DefaultPathContainer.subPath(path, index, path.elements().size());
|
||||
return subPath(path, index, path.elements().size());
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a sub-path from the given start offset (inclusive) into the path
|
||||
* element list and to the end offset (exclusive).
|
||||
* @param path the path to extract from
|
||||
* @param startIndex the start element index (inclusive)
|
||||
* @param endIndex the end element index (exclusive)
|
||||
* @return the sub-path
|
||||
*/
|
||||
static PathContainer subPath(PathContainer path, int startIndex, int endIndex) {
|
||||
return DefaultPathContainer.subPath(path, startIndex, endIndex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ package org.springframework.web.cors.reactive;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
@@ -66,10 +67,10 @@ public class UrlBasedCorsConfigurationSource implements CorsConfigurationSource
|
||||
|
||||
@Override
|
||||
public CorsConfiguration getCorsConfiguration(ServerWebExchange exchange) {
|
||||
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||
PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
|
||||
return this.corsConfigurations.entrySet().stream()
|
||||
.filter(entry -> entry.getKey().matches(lookupPath))
|
||||
.map(entry -> entry.getValue())
|
||||
.map(Map.Entry::getValue)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@@ -73,7 +73,8 @@ public class ParsingPathMatcher implements PathMatcher {
|
||||
@Override
|
||||
public String extractPathWithinPattern(String pattern, String path) {
|
||||
PathPattern pathPattern = getPathPattern(pattern);
|
||||
return pathPattern.extractPathWithinPattern(path);
|
||||
PathContainer pathContainer = PathContainer.parse(path, StandardCharsets.UTF_8);
|
||||
return pathPattern.extractPathWithinPattern(pathContainer).value();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -158,22 +158,6 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
}
|
||||
|
||||
|
||||
// TODO: remove String-variants
|
||||
|
||||
public boolean matches(String path) {
|
||||
return matches(PathContainer.parse(path, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
public PathMatchResult matchAndExtract(String path) {
|
||||
return matchAndExtract(PathContainer.parse(path, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PathRemainingMatchInfo getPathRemaining(String path) {
|
||||
return getPathRemaining(PathContainer.parse(path, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param pathContainer the candidate path container to attempt to match against this pattern
|
||||
* @return true if the path matches this pattern
|
||||
@@ -262,13 +246,6 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: implement extractPathWithinPattern natively for PathContainer
|
||||
|
||||
public PathContainer extractPathWithinPattern(PathContainer path) {
|
||||
String result = extractPathWithinPattern(path.value());
|
||||
return PathContainer.parse(result, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a full path, determine the pattern-mapped part. <p>For example: <ul>
|
||||
* <li>'{@code /docs/cvs/commit.html}' and '{@code /docs/cvs/commit.html} -> ''</li>
|
||||
@@ -283,7 +260,14 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
* @param path a path that matches this pattern
|
||||
* @return the subset of the path that is matched by pattern or "" if none of it is matched by pattern elements
|
||||
*/
|
||||
public String extractPathWithinPattern(String path) {
|
||||
public PathContainer extractPathWithinPattern(PathContainer path) {
|
||||
String result = extractPathWithinPattern(path.value());
|
||||
return PathContainer.parse(result, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
// TODO: implement extractPathWithinPattern natively for PathContainer
|
||||
|
||||
private String extractPathWithinPattern(String path) {
|
||||
// assert this.matches(path)
|
||||
PathElement elem = head;
|
||||
int separatorCount = 0;
|
||||
@@ -517,7 +501,7 @@ public class PathPattern implements Comparable<PathPattern> {
|
||||
}
|
||||
|
||||
/**
|
||||
* A holder for the result of a {@link PathPattern#getPathRemaining(String)} call. Holds
|
||||
* A holder for the result of a {@link PathPattern#getPathRemaining} call.Holds
|
||||
* information on the path left after the first part has successfully matched a pattern
|
||||
* and any variables bound in that first part that matched.
|
||||
*/
|
||||
|
||||
@@ -36,8 +36,14 @@ import org.springframework.util.AntPathMatcher;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathMatchResult;
|
||||
import org.springframework.web.util.pattern.PathPattern.PathRemainingMatchInfo;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
/**
|
||||
* Exercise matching of {@link PathPattern} objects.
|
||||
@@ -1368,7 +1374,7 @@ public class PathPatternMatcherTests {
|
||||
private void checkExtractPathWithinPattern(String pattern, String path, String expected) {
|
||||
PathPatternParser ppp = new PathPatternParser();
|
||||
PathPattern pp = ppp.parse(pattern);
|
||||
String s = pp.extractPathWithinPattern(path);
|
||||
String s = pp.extractPathWithinPattern(toPathContainer(path)).value();
|
||||
assertEquals(expected, s);
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.UrlResource;
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
@@ -54,19 +55,18 @@ class PathResourceLookupFunction implements Function<ServerRequest, Mono<Resourc
|
||||
|
||||
@Override
|
||||
public Mono<Resource> apply(ServerRequest request) {
|
||||
String path = processPath(request.path());
|
||||
PathContainer pathContainer = request.pathContainer();
|
||||
if (!this.pattern.matches(pathContainer)) {
|
||||
return Mono.empty();
|
||||
}
|
||||
pathContainer = this.pattern.extractPathWithinPattern(pathContainer);
|
||||
String path = processPath(pathContainer.value());
|
||||
if (path.contains("%")) {
|
||||
path = StringUtils.uriDecode(path, StandardCharsets.UTF_8);
|
||||
}
|
||||
if (!StringUtils.hasLength(path) || isInvalidPath(path)) {
|
||||
return Mono.empty();
|
||||
}
|
||||
if (!this.pattern.matches(path)) {
|
||||
return Mono.empty();
|
||||
}
|
||||
else {
|
||||
path = this.pattern.extractPathWithinPattern(path);
|
||||
}
|
||||
try {
|
||||
Resource resource = this.location.createRelative(path);
|
||||
if (resource.exists() && resource.isReadable() && isResourceUnderLocation(resource)) {
|
||||
|
||||
@@ -341,10 +341,11 @@ public abstract class RequestPredicates {
|
||||
|
||||
@Override
|
||||
public boolean test(ServerRequest request) {
|
||||
boolean match = this.pattern.matches(request.pathContainer());
|
||||
PathContainer pathContainer = request.pathContainer();
|
||||
boolean match = this.pattern.matches(pathContainer);
|
||||
traceMatch("Pattern", this.pattern.getPatternString(), request.path(), match);
|
||||
if (match) {
|
||||
mergeTemplateVariables(request, this.pattern.matchAndExtract(request.path()).getUriVariables());
|
||||
mergeTemplateVariables(request, this.pattern.matchAndExtract(pathContainer).getUriVariables());
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -109,7 +109,7 @@ public class PathPatternRegistry<T> {
|
||||
* patterns first, according to the given {@code lookupPath}.
|
||||
* @param lookupPath the URL lookup path to be matched against
|
||||
*/
|
||||
public SortedSet<PathMatchResult<T>> findMatches(String lookupPath) {
|
||||
public SortedSet<PathMatchResult<T>> findMatches(PathContainer lookupPath) {
|
||||
return this.patternsMap.entrySet().stream()
|
||||
.filter(entry -> entry.getKey().matches(lookupPath))
|
||||
.sorted(Comparator.comparing(Map.Entry::getKey))
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.reactive.resource;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -30,6 +31,7 @@ import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.web.reactive.handler.PathMatchResult;
|
||||
@@ -136,8 +138,9 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
|
||||
}
|
||||
|
||||
/**
|
||||
* A variation on {@link #getForLookupPath(String)} that accepts a full request
|
||||
* URL path and returns the full request URL path to expose for public use.
|
||||
* A variation on {@link #getForLookupPath(PathContainer)} that accepts a
|
||||
* full request URL path and returns the full request URL path to expose
|
||||
* for public use.
|
||||
* @param exchange the current exchange
|
||||
* @param requestUrl the request URL path to resolve
|
||||
* @return the resolved public URL path, or empty if unresolved
|
||||
@@ -146,22 +149,16 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting resource URL for request URL \"" + requestUrl + "\"");
|
||||
}
|
||||
int prefixIndex = getLookupPathIndex(exchange);
|
||||
int suffixIndex = getEndPathIndex(requestUrl);
|
||||
String prefix = requestUrl.substring(0, prefixIndex);
|
||||
String suffix = requestUrl.substring(suffixIndex);
|
||||
String lookupPath = requestUrl.substring(prefixIndex, suffixIndex);
|
||||
return getForLookupPath(lookupPath).map(resolvedPath -> prefix + resolvedPath + suffix);
|
||||
}
|
||||
|
||||
private int getLookupPathIndex(ServerWebExchange exchange) {
|
||||
ServerHttpRequest request = exchange.getRequest();
|
||||
String requestPath = request.getURI().getPath();
|
||||
String lookupPath = exchange.getRequest().getPath().pathWithinApplication().value();
|
||||
return requestPath.indexOf(lookupPath);
|
||||
int queryIndex = getQueryIndex(requestUrl);
|
||||
String lookupPath = requestUrl.substring(0, queryIndex);
|
||||
String query = requestUrl.substring(queryIndex);
|
||||
PathContainer parsedLookupPath = PathContainer.parse(lookupPath, StandardCharsets.UTF_8);
|
||||
return getForLookupPath(parsedLookupPath).map(resolvedPath ->
|
||||
request.getPath().contextPath().value() + resolvedPath + query);
|
||||
}
|
||||
|
||||
private int getEndPathIndex(String lookupPath) {
|
||||
private int getQueryIndex(String lookupPath) {
|
||||
int suffixIndex = lookupPath.length();
|
||||
int queryIndex = lookupPath.indexOf("?");
|
||||
if (queryIndex > 0) {
|
||||
@@ -186,35 +183,33 @@ public class ResourceUrlProvider implements ApplicationListener<ContextRefreshed
|
||||
* @param lookupPath the lookup path to check
|
||||
* @return the resolved public URL path, or empty if unresolved
|
||||
*/
|
||||
public final Mono<String> getForLookupPath(String lookupPath) {
|
||||
public final Mono<String> getForLookupPath(PathContainer lookupPath) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Getting resource URL for lookup path \"" + lookupPath + "\"");
|
||||
}
|
||||
|
||||
Set<PathMatchResult<ResourceWebHandler>> matchResults = this.patternRegistry.findMatches(lookupPath);
|
||||
Set<PathMatchResult<ResourceWebHandler>> matches = this.patternRegistry.findMatches(lookupPath);
|
||||
|
||||
if (matchResults.isEmpty()) {
|
||||
return Mono.empty();
|
||||
}
|
||||
|
||||
return Flux.fromIterable(matchResults)
|
||||
.concatMap(result -> {
|
||||
String pathWithinMapping = result.getPattern().extractPathWithinPattern(lookupPath);
|
||||
String pathMapping = lookupPath.substring(0, lookupPath.indexOf(pathWithinMapping));
|
||||
return Flux.fromIterable(matches).next()
|
||||
.flatMap(result -> {
|
||||
PathContainer path = result.getPattern().extractPathWithinPattern(lookupPath);
|
||||
int endIndex = lookupPath.elements().size() - path.elements().size();
|
||||
PathContainer mapping = PathContainer.subPath(lookupPath, 0, endIndex);
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Invoking ResourceResolverChain for URL pattern \"" + result.getPattern() + "\"");
|
||||
logger.trace("Invoking ResourceResolverChain for URL pattern " +
|
||||
"\"" + result.getPattern() + "\"");
|
||||
}
|
||||
ResourceWebHandler handler = result.getHandler();
|
||||
ResourceResolverChain chain = new DefaultResourceResolverChain(handler.getResourceResolvers());
|
||||
return chain.resolveUrlPath(pathWithinMapping, handler.getLocations())
|
||||
List<ResourceResolver> resolvers = handler.getResourceResolvers();
|
||||
ResourceResolverChain chain = new DefaultResourceResolverChain(resolvers);
|
||||
return chain.resolveUrlPath(path.value(), handler.getLocations())
|
||||
.map(resolvedPath -> {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Resolved public resource URL path \"" + resolvedPath + "\"");
|
||||
}
|
||||
return pathMapping + resolvedPath;
|
||||
return mapping.value() + resolvedPath;
|
||||
});
|
||||
})
|
||||
.next();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.reactive.handler;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
@@ -28,6 +29,7 @@ import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.web.util.pattern.PathPattern;
|
||||
import org.springframework.web.util.pattern.PathPatternParser;
|
||||
import org.springframework.web.util.pattern.PatternParseException;
|
||||
@@ -73,14 +75,17 @@ public class PathPatternRegistryTests {
|
||||
|
||||
this.registry.register("/fo?", new Object());
|
||||
this.registry.register("/f?o", new Object());
|
||||
Set<PathMatchResult<Object>> matches = this.registry.findMatches("/foo");
|
||||
|
||||
PathContainer path = PathContainer.parse("/foo", StandardCharsets.UTF_8);
|
||||
Set<PathMatchResult<Object>> matches = this.registry.findMatches(path);
|
||||
assertThat(toPatterns(matches), contains(pattern("/f?o"), pattern("/fo?")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findNoMatch() {
|
||||
this.registry.register("/foo/{bar}", new Object());
|
||||
assertThat(this.registry.findMatches("/other"), hasSize(0));
|
||||
PathContainer path = PathContainer.parse("/other", StandardCharsets.UTF_8);
|
||||
assertThat(this.registry.findMatches(path), hasSize(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -88,7 +93,8 @@ public class PathPatternRegistryTests {
|
||||
this.registry.register("/foo/{*baz}", new Object());
|
||||
this.registry.register("/foo/bar/baz", new Object());
|
||||
this.registry.register("/foo/bar/{baz}", new Object());
|
||||
Set<PathMatchResult<Object>> matches = this.registry.findMatches("/foo/bar/baz");
|
||||
PathContainer path = PathContainer.parse("/foo/bar/baz", StandardCharsets.UTF_8);
|
||||
Set<PathMatchResult<Object>> matches = this.registry.findMatches(path);
|
||||
assertThat(toPatterns(matches), contains(pattern("/foo/bar/baz"), pattern("/foo/bar/{baz}"),
|
||||
pattern("/foo/{*baz}")));
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.reactive.resource;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.http.server.reactive.PathContainer;
|
||||
import org.springframework.mock.http.server.reactive.test.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.test.MockServletContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
@@ -73,7 +75,8 @@ public class ResourceUrlProviderTests {
|
||||
|
||||
@Test
|
||||
public void getStaticResourceUrl() {
|
||||
String url = this.urlProvider.getForLookupPath("/resources/foo.css").block(Duration.ofSeconds(5));
|
||||
PathContainer path = PathContainer.parse("/resources/foo.css", StandardCharsets.UTF_8);
|
||||
String url = this.urlProvider.getForLookupPath(path).block(Duration.ofSeconds(5));
|
||||
assertEquals("/resources/foo.css", url);
|
||||
}
|
||||
|
||||
@@ -102,7 +105,8 @@ public class ResourceUrlProviderTests {
|
||||
resolvers.add(new PathResourceResolver());
|
||||
this.handler.setResourceResolvers(resolvers);
|
||||
|
||||
String url = this.urlProvider.getForLookupPath("/resources/foo.css").block(Duration.ofSeconds(5));
|
||||
PathContainer path = PathContainer.parse("/resources/foo.css", StandardCharsets.UTF_8);
|
||||
String url = this.urlProvider.getForLookupPath(path).block(Duration.ofSeconds(5));
|
||||
assertEquals("/resources/foo-e36d2e05253c6c7085a91522ce43a0b4.css", url);
|
||||
}
|
||||
|
||||
@@ -123,7 +127,8 @@ public class ResourceUrlProviderTests {
|
||||
this.handlerMap.put("/resources/*.css", otherHandler);
|
||||
this.urlProvider.setHandlerMap(this.handlerMap);
|
||||
|
||||
String url = this.urlProvider.getForLookupPath("/resources/foo.css").block(Duration.ofSeconds(5));
|
||||
PathContainer path = PathContainer.parse("/resources/foo.css", StandardCharsets.UTF_8);
|
||||
String url = this.urlProvider.getForLookupPath(path).block(Duration.ofSeconds(5));
|
||||
assertEquals("/resources/foo-e36d2e05253c6c7085a91522ce43a0b4.css", url);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user