Correct path encoding/decoding in PathResourceResolver
Decoding is required for non-UrlResource when the HandlerMapping is not expected to decode the path. Encoding is the opposite. This commit ensures correct determination of whether the HandlerMapping is expected to have decoded the path or not that in turn depends on whether PathPattern or PathMatcher is in use. Closes gh-27791
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2021 the original author or authors.
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -260,36 +260,47 @@ public class PathResourceResolver extends AbstractResourceResolver {
|
||||
}
|
||||
|
||||
private String encodeOrDecodeIfNecessary(String path, @Nullable HttpServletRequest request, Resource location) {
|
||||
if (shouldDecodeRelativePath(location, request)) {
|
||||
return UriUtils.decode(path, StandardCharsets.UTF_8);
|
||||
}
|
||||
else if (shouldEncodeRelativePath(location) && request != null) {
|
||||
Charset charset = this.locationCharsets.getOrDefault(location, StandardCharsets.UTF_8);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringTokenizer tokenizer = new StringTokenizer(path, "/");
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String value = UriUtils.encode(tokenizer.nextToken(), charset);
|
||||
sb.append(value);
|
||||
sb.append('/');
|
||||
if (request != null) {
|
||||
boolean usesPathPattern = (
|
||||
ServletRequestPathUtils.hasCachedPath(request) &&
|
||||
ServletRequestPathUtils.getCachedPath(request) instanceof PathContainer);
|
||||
|
||||
if (shouldDecodeRelativePath(location, usesPathPattern)) {
|
||||
return UriUtils.decode(path, StandardCharsets.UTF_8);
|
||||
}
|
||||
if (!path.endsWith("/")) {
|
||||
sb.setLength(sb.length() - 1);
|
||||
else if (shouldEncodeRelativePath(location, usesPathPattern)) {
|
||||
Charset charset = this.locationCharsets.getOrDefault(location, StandardCharsets.UTF_8);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
StringTokenizer tokenizer = new StringTokenizer(path, "/");
|
||||
while (tokenizer.hasMoreTokens()) {
|
||||
String value = UriUtils.encode(tokenizer.nextToken(), charset);
|
||||
sb.append(value);
|
||||
sb.append('/');
|
||||
}
|
||||
if (!path.endsWith("/")) {
|
||||
sb.setLength(sb.length() - 1);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
else {
|
||||
return path;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
private boolean shouldDecodeRelativePath(Resource location, @Nullable HttpServletRequest request) {
|
||||
return (!(location instanceof UrlResource) && request != null &&
|
||||
ServletRequestPathUtils.hasCachedPath(request) &&
|
||||
ServletRequestPathUtils.getCachedPath(request) instanceof PathContainer);
|
||||
/**
|
||||
* When the {@code HandlerMapping} is set to not decode the URL path, the
|
||||
* path needs to be decoded for non-{@code UrlResource} locations.
|
||||
*/
|
||||
private boolean shouldDecodeRelativePath(Resource location, boolean usesPathPattern) {
|
||||
return (!(location instanceof UrlResource) &&
|
||||
(usesPathPattern || (this.urlPathHelper != null && !this.urlPathHelper.isUrlDecode())));
|
||||
}
|
||||
|
||||
private boolean shouldEncodeRelativePath(Resource location) {
|
||||
return (location instanceof UrlResource &&
|
||||
/**
|
||||
* When the {@code HandlerMapping} is set to decode the URL path, the path
|
||||
* needs to be encoded for {@code UrlResource} locations.
|
||||
*/
|
||||
private boolean shouldEncodeRelativePath(Resource location, boolean usesPathPattern) {
|
||||
return (location instanceof UrlResource && !usesPathPattern &&
|
||||
this.urlPathHelper != null && this.urlPathHelper.isUrlDecode());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user