|
|
|
@ -31,6 +31,7 @@ import java.nio.charset.StandardCharsets; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.lang.Nullable; |
|
|
|
import org.springframework.lang.Nullable; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
import org.springframework.util.Assert; |
|
|
|
|
|
|
|
import org.springframework.util.ResourceUtils; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -57,10 +58,10 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
private final URL url; |
|
|
|
private final URL url; |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Cleaned URL (with normalized path), used for comparisons. |
|
|
|
* Cleaned URL String (with normalized path), used for comparisons. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Nullable |
|
|
|
@Nullable |
|
|
|
private volatile URL cleanedUrl; |
|
|
|
private volatile String cleanedUrl; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -97,8 +98,8 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
public UrlResource(String path) throws MalformedURLException { |
|
|
|
public UrlResource(String path) throws MalformedURLException { |
|
|
|
Assert.notNull(path, "Path must not be null"); |
|
|
|
Assert.notNull(path, "Path must not be null"); |
|
|
|
this.uri = null; |
|
|
|
this.uri = null; |
|
|
|
this.url = new URL(path); |
|
|
|
this.url = ResourceUtils.toURL(path); |
|
|
|
this.cleanedUrl = getCleanedUrl(this.url, path); |
|
|
|
this.cleanedUrl = StringUtils.cleanPath(path); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -144,7 +145,7 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
* Create a new {@code UrlResource} from the given {@link URI}. |
|
|
|
* Create a new {@code UrlResource} from the given {@link URI}. |
|
|
|
* <p>This factory method is a convenience for {@link #UrlResource(URI)} that |
|
|
|
* <p>This factory method is a convenience for {@link #UrlResource(URI)} that |
|
|
|
* catches any {@link MalformedURLException} and rethrows it wrapped in an |
|
|
|
* catches any {@link MalformedURLException} and rethrows it wrapped in an |
|
|
|
* {@link UncheckedIOException}; suitable for use in {@link java.util.Stream} |
|
|
|
* {@link UncheckedIOException}; suitable for use in {@link java.util.stream.Stream} |
|
|
|
* and {@link java.util.Optional} APIs or other scenarios when a checked |
|
|
|
* and {@link java.util.Optional} APIs or other scenarios when a checked |
|
|
|
* {@link IOException} is undesirable. |
|
|
|
* {@link IOException} is undesirable. |
|
|
|
* @param uri a URI |
|
|
|
* @param uri a URI |
|
|
|
@ -165,7 +166,7 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
* Create a new {@code UrlResource} from the given URL path. |
|
|
|
* Create a new {@code UrlResource} from the given URL path. |
|
|
|
* <p>This factory method is a convenience for {@link #UrlResource(String)} |
|
|
|
* <p>This factory method is a convenience for {@link #UrlResource(String)} |
|
|
|
* that catches any {@link MalformedURLException} and rethrows it wrapped in an |
|
|
|
* that catches any {@link MalformedURLException} and rethrows it wrapped in an |
|
|
|
* {@link UncheckedIOException}; suitable for use in {@link java.util.Stream} |
|
|
|
* {@link UncheckedIOException}; suitable for use in {@link java.util.stream.Stream} |
|
|
|
* and {@link java.util.Optional} APIs or other scenarios when a checked |
|
|
|
* and {@link java.util.Optional} APIs or other scenarios when a checked |
|
|
|
* {@link IOException} is undesirable. |
|
|
|
* {@link IOException} is undesirable. |
|
|
|
* @param path a URL path |
|
|
|
* @param path a URL path |
|
|
|
@ -183,36 +184,16 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Determine a cleaned URL for the given original URL. |
|
|
|
|
|
|
|
* @param originalUrl the original URL |
|
|
|
|
|
|
|
* @param originalPath the original URL path |
|
|
|
|
|
|
|
* @return the cleaned URL (possibly the original URL as-is) |
|
|
|
|
|
|
|
* @see org.springframework.util.StringUtils#cleanPath |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static URL getCleanedUrl(URL originalUrl, String originalPath) { |
|
|
|
|
|
|
|
String cleanedPath = StringUtils.cleanPath(originalPath); |
|
|
|
|
|
|
|
if (!cleanedPath.equals(originalPath)) { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
return new URL(cleanedPath); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
catch (MalformedURLException ex) { |
|
|
|
|
|
|
|
// Cleaned URL path cannot be converted to URL -> take original URL.
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return originalUrl; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Lazily determine a cleaned URL for the given original URL. |
|
|
|
* Lazily determine a cleaned URL for the given original URL. |
|
|
|
* @see #getCleanedUrl(URL, String) |
|
|
|
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private URL getCleanedUrl() { |
|
|
|
private String getCleanedUrl() { |
|
|
|
URL cleanedUrl = this.cleanedUrl; |
|
|
|
String cleanedUrl = this.cleanedUrl; |
|
|
|
if (cleanedUrl != null) { |
|
|
|
if (cleanedUrl != null) { |
|
|
|
return cleanedUrl; |
|
|
|
return cleanedUrl; |
|
|
|
} |
|
|
|
} |
|
|
|
cleanedUrl = getCleanedUrl(this.url, (this.uri != null ? this.uri : this.url).toString()); |
|
|
|
String originalPath = (this.uri != null ? this.uri : this.url).toString(); |
|
|
|
|
|
|
|
cleanedUrl = StringUtils.cleanPath(originalPath); |
|
|
|
this.cleanedUrl = cleanedUrl; |
|
|
|
this.cleanedUrl = cleanedUrl; |
|
|
|
return cleanedUrl; |
|
|
|
return cleanedUrl; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -305,16 +286,13 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
* A leading slash will get dropped; a "#" symbol will get encoded. |
|
|
|
* A leading slash will get dropped; a "#" symbol will get encoded. |
|
|
|
* @since 5.2 |
|
|
|
* @since 5.2 |
|
|
|
* @see #createRelative(String) |
|
|
|
* @see #createRelative(String) |
|
|
|
* @see java.net.URL#URL(java.net.URL, String) |
|
|
|
* @see ResourceUtils#toRelativeURL(URL, String) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected URL createRelativeURL(String relativePath) throws MalformedURLException { |
|
|
|
protected URL createRelativeURL(String relativePath) throws MalformedURLException { |
|
|
|
if (relativePath.startsWith("/")) { |
|
|
|
if (relativePath.startsWith("/")) { |
|
|
|
relativePath = relativePath.substring(1); |
|
|
|
relativePath = relativePath.substring(1); |
|
|
|
} |
|
|
|
} |
|
|
|
// # can appear in filenames, java.net.URL should not treat it as a fragment
|
|
|
|
return ResourceUtils.toRelativeURL(this.url, relativePath); |
|
|
|
relativePath = StringUtils.replace(relativePath, "#", "%23"); |
|
|
|
|
|
|
|
// Use the URL constructor for applying the relative path as a URL spec
|
|
|
|
|
|
|
|
return new URL(this.url, relativePath); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -324,9 +302,10 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
* @see java.net.URLDecoder#decode(String, java.nio.charset.Charset) |
|
|
|
* @see java.net.URLDecoder#decode(String, java.nio.charset.Charset) |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
|
|
|
|
@Nullable |
|
|
|
public String getFilename() { |
|
|
|
public String getFilename() { |
|
|
|
String filename = StringUtils.getFilename(getCleanedUrl().getPath()); |
|
|
|
String filename = StringUtils.getFilename(this.uri != null ? this.uri.getPath() : this.url.getPath()); |
|
|
|
return URLDecoder.decode(filename, StandardCharsets.UTF_8); |
|
|
|
return (filename != null ? URLDecoder.decode(filename, StandardCharsets.UTF_8) : null); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -334,7 +313,7 @@ public class UrlResource extends AbstractFileResolvingResource { |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public String getDescription() { |
|
|
|
public String getDescription() { |
|
|
|
return "URL [" + this.url + "]"; |
|
|
|
return "URL [" + (this.uri != null ? this.uri : this.url) + "]"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|