11/*
2- * Copyright 2002-2018 the original author or authors.
2+ * Copyright 2002-2020 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.
@@ -56,7 +56,8 @@ public class UrlResource extends AbstractFileResolvingResource {
5656 /**
5757 * Cleaned URL (with normalized path), used for comparisons.
5858 */
59- private final URL cleanedUrl ;
59+ @ Nullable
60+ private volatile URL cleanedUrl ;
6061
6162
6263 /**
@@ -69,7 +70,6 @@ public UrlResource(URI uri) throws MalformedURLException {
6970 Assert .notNull (uri , "URI must not be null" );
7071 this .uri = uri ;
7172 this .url = uri .toURL ();
72- this .cleanedUrl = getCleanedUrl (this .url , uri .toString ());
7373 }
7474
7575 /**
@@ -78,9 +78,8 @@ public UrlResource(URI uri) throws MalformedURLException {
7878 */
7979 public UrlResource (URL url ) {
8080 Assert .notNull (url , "URL must not be null" );
81- this .url = url ;
82- this .cleanedUrl = getCleanedUrl (this .url , url .toString ());
8381 this .uri = null ;
82+ this .url = url ;
8483 }
8584
8685 /**
@@ -127,7 +126,6 @@ public UrlResource(String protocol, String location, @Nullable String fragment)
127126 try {
128127 this .uri = new URI (protocol , location , fragment );
129128 this .url = this .uri .toURL ();
130- this .cleanedUrl = getCleanedUrl (this .url , this .uri .toString ());
131129 }
132130 catch (URISyntaxException ex ) {
133131 MalformedURLException exToThrow = new MalformedURLException (ex .getMessage ());
@@ -144,17 +142,34 @@ public UrlResource(String protocol, String location, @Nullable String fragment)
144142 * @return the cleaned URL
145143 * @see org.springframework.util.StringUtils#cleanPath
146144 */
147- private URL getCleanedUrl (URL originalUrl , String originalPath ) {
148- try {
149- return new URL (StringUtils .cleanPath (originalPath ));
145+ private static URL getCleanedUrl (URL originalUrl , String originalPath ) {
146+ String cleanedPath = StringUtils .cleanPath (originalPath );
147+ if (!cleanedPath .equals (originalPath )) {
148+ try {
149+ return new URL (cleanedPath );
150+ }
151+ catch (MalformedURLException ex ) {
152+ // Cleaned URL path cannot be converted to URL -> take original URL.
153+ }
150154 }
151- catch (MalformedURLException ex ) {
152- // Cleaned URL path cannot be converted to URL
153- // -> take original URL.
154- return originalUrl ;
155+ return originalUrl ;
156+ }
157+
158+ /**
159+ * Lazily determine a cleaned URL for the given original URL.
160+ * @see #getCleanedUrl(URL, String)
161+ */
162+ private URL getCleanedUrl () {
163+ URL cleanedUrl = this .cleanedUrl ;
164+ if (cleanedUrl != null ) {
165+ return cleanedUrl ;
155166 }
167+ cleanedUrl = getCleanedUrl (this .url , (this .uri != null ? this .uri : this .url ).toString ());
168+ this .cleanedUrl = cleanedUrl ;
169+ return cleanedUrl ;
156170 }
157171
172+
158173 /**
159174 * This implementation opens an InputStream for the given URL.
160175 * <p>It sets the {@code useCaches} flag to {@code false},
@@ -245,7 +260,7 @@ public Resource createRelative(String relativePath) throws MalformedURLException
245260 */
246261 @ Override
247262 public String getFilename () {
248- return StringUtils .getFilename (this . cleanedUrl .getPath ());
263+ return StringUtils .getFilename (getCleanedUrl () .getPath ());
249264 }
250265
251266 /**
@@ -263,15 +278,15 @@ public String getDescription() {
263278 @ Override
264279 public boolean equals (Object other ) {
265280 return (this == other || (other instanceof UrlResource &&
266- this . cleanedUrl . equals (((UrlResource ) other ).cleanedUrl )));
281+ getCleanedUrl (). equals (((UrlResource ) other ).getCleanedUrl () )));
267282 }
268283
269284 /**
270285 * This implementation returns the hash code of the underlying URL reference.
271286 */
272287 @ Override
273288 public int hashCode () {
274- return this . cleanedUrl .hashCode ();
289+ return getCleanedUrl () .hashCode ();
275290 }
276291
277292}
0 commit comments