Skip to content

Commit

Permalink
Return URL-decoded file name from UrlResource#getFilename()
Browse files Browse the repository at this point in the history
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
  • Loading branch information
sbrannen committed Oct 5, 2022
1 parent 084d7d1 commit 0aa9d9d
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -158,10 +158,11 @@ default ReadableByteChannel readableChannel() throws IOException {
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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
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;
Expand Down Expand Up @@ -316,12 +318,15 @@ protected URL createRelativeURL(String relativePath) throws MalformedURLExceptio
}

/**
* 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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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;
Expand Down Expand Up @@ -59,7 +60,6 @@
*/
class ResourceTests {


@ParameterizedTest(name = "{index}: {0}")
@MethodSource("resource")
void resourceIsValid(Resource resource) throws Exception {
Expand Down Expand Up @@ -272,6 +272,22 @@ void filenameIsExtractedFromFilePath() throws Exception {
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");
Expand Down

0 comments on commit 0aa9d9d

Please sign in to comment.