Return URL-decoded file name from UrlResource#getFilename()
Prior to this commit, UrlResource#getFilename() returned the filename of the resource URL-encoded which is in contrast to what FileSystemResource#getFilename() returns for an equivalent resource. In addition, users most likely expect that a filename returned from a method defined in the Resource interface is unencoded. This commit therefore revises UrlResource#getFilename() so that it always returns the filename URL-decoded. Closes gh-29261
This commit is contained in:
@@ -158,10 +158,11 @@ public interface Resource extends InputStreamSource {
|
||||
Resource createRelative(String relativePath) throws IOException;
|
||||
|
||||
/**
|
||||
* Determine a filename for this resource, i.e. typically the last
|
||||
* part of the path: for example, "myfile.txt".
|
||||
* Determine the filename for this resource — typically the last
|
||||
* part of the path — for example, {@code "myfile.txt"}.
|
||||
* <p>Returns {@code null} if this type of resource does not
|
||||
* have a filename.
|
||||
* <p>Implementations are encouraged to return the filename unencoded.
|
||||
*/
|
||||
@Nullable
|
||||
String getFilename();
|
||||
|
||||
@@ -26,6 +26,8 @@ import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -316,12 +318,15 @@ public class UrlResource extends AbstractFileResolvingResource {
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation returns the name of the file that this URL refers to.
|
||||
* This implementation returns the URL-decoded name of the file that this URL
|
||||
* refers to.
|
||||
* @see java.net.URL#getPath()
|
||||
* @see java.net.URLDecoder#decode(String, java.nio.charset.Charset)
|
||||
*/
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return StringUtils.getFilename(getCleanedUrl().getPath());
|
||||
String filename = StringUtils.getFilename(getCleanedUrl().getPath());
|
||||
return URLDecoder.decode(filename, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
@@ -59,7 +60,6 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
*/
|
||||
class ResourceTests {
|
||||
|
||||
|
||||
@ParameterizedTest(name = "{index}: {0}")
|
||||
@MethodSource("resource")
|
||||
void resourceIsValid(Resource resource) throws Exception {
|
||||
@@ -272,6 +272,22 @@ class ResourceTests {
|
||||
assertThat(new UrlResource("file:\\dir/test.txt?argh").getFilename()).isEqualTo("test.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
void filenameContainingHashTagIsExtractedFromFilePathUnencoded() throws Exception {
|
||||
String unencodedPath = "/dir/test#1.txt";
|
||||
String encodedPath = "/dir/test%231.txt";
|
||||
|
||||
URI uri = new URI("file", unencodedPath, null);
|
||||
URL url = uri.toURL();
|
||||
assertThat(uri.getPath()).isEqualTo(unencodedPath);
|
||||
assertThat(uri.getRawPath()).isEqualTo(encodedPath);
|
||||
assertThat(url.getPath()).isEqualTo(encodedPath);
|
||||
|
||||
UrlResource urlResource = new UrlResource(url);
|
||||
assertThat(urlResource.getURI().getPath()).isEqualTo(unencodedPath);
|
||||
assertThat(urlResource.getFilename()).isEqualTo("test#1.txt");
|
||||
}
|
||||
|
||||
@Test
|
||||
void factoryMethodsProduceEqualResources() throws Exception {
|
||||
Resource resource1 = new UrlResource("file:core/io/Resource.class");
|
||||
|
||||
Reference in New Issue
Block a user