Skip to content

Commit 3a166ea

Browse files
committed
Add efficient existence check to ClassPathResource.isReadable()
Includes reduced isReadable() check in PathResourceLookupFunction, aligned with PathResourceResolver. Closes gh-27538 See gh-21372
1 parent 6d4dfed commit 3a166ea

File tree

4 files changed

+29
-14
lines changed

4 files changed

+29
-14
lines changed

spring-core/src/main/java/org/springframework/core/io/AbstractFileResolvingResource.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -88,7 +88,15 @@ else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
8888
@Override
8989
public boolean isReadable() {
9090
try {
91-
URL url = getURL();
91+
return checkReadable(getURL());
92+
}
93+
catch (IOException ex) {
94+
return false;
95+
}
96+
}
97+
98+
boolean checkReadable(URL url) {
99+
try {
92100
if (ResourceUtils.isFileURL(url)) {
93101
// Proceed with file system resolution
94102
File file = getFile();

spring-core/src/main/java/org/springframework/core/io/ClassPathResource.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ public boolean exists() {
142142
return (resolveURL() != null);
143143
}
144144

145+
/**
146+
* This implementation checks for the resolution of a resource URL upfront,
147+
* then proceeding with {@link AbstractFileResolvingResource}'s length check.
148+
* @see java.lang.ClassLoader#getResource(String)
149+
* @see java.lang.Class#getResource(String)
150+
*/
151+
@Override
152+
public boolean isReadable() {
153+
URL url = resolveURL();
154+
return (url != null && checkReadable(url));
155+
}
156+
145157
/**
146158
* Resolves a URL for the underlying class path resource.
147159
* @return the resolved URL, or {@code null} if not resolvable

spring-webflux/src/main/java/org/springframework/web/reactive/function/server/PathResourceLookupFunction.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -72,7 +72,7 @@ public Mono<Resource> apply(ServerRequest request) {
7272

7373
try {
7474
Resource resource = this.location.createRelative(path);
75-
if (resource.exists() && resource.isReadable() && isResourceUnderLocation(resource)) {
75+
if (resource.isReadable() && isResourceUnderLocation(resource)) {
7676
return Mono.just(resource);
7777
}
7878
else {

spring-webmvc/src/main/java/org/springframework/web/servlet/function/PathResourceLookupFunction.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -71,7 +71,7 @@ public Optional<Resource> apply(ServerRequest request) {
7171

7272
try {
7373
Resource resource = this.location.createRelative(path);
74-
if (resource.exists() && resource.isReadable() && isResourceUnderLocation(resource)) {
74+
if (resource.isReadable() && isResourceUnderLocation(resource)) {
7575
return Optional.of(resource);
7676
}
7777
else {
@@ -110,10 +110,7 @@ private boolean isInvalidPath(String path) {
110110
return true;
111111
}
112112
}
113-
if (path.contains("..") && StringUtils.cleanPath(path).contains("../")) {
114-
return true;
115-
}
116-
return false;
113+
return path.contains("..") && StringUtils.cleanPath(path).contains("../");
117114
}
118115

119116
private boolean isResourceUnderLocation(Resource resource) throws IOException {
@@ -144,10 +141,8 @@ else if (resource instanceof ClassPathResource) {
144141
if (!resourcePath.startsWith(locationPath)) {
145142
return false;
146143
}
147-
if (resourcePath.contains("%") && StringUtils.uriDecode(resourcePath, StandardCharsets.UTF_8).contains("../")) {
148-
return false;
149-
}
150-
return true;
144+
return !resourcePath.contains("%") ||
145+
!StringUtils.uriDecode(resourcePath, StandardCharsets.UTF_8).contains("../");
151146
}
152147

153148

0 commit comments

Comments
 (0)