Jetty 12 - General cleanup of URIUtil (#8861)
+ Removal of __CHARSET + Removal of unused methods + Using new switch/case concepts + cleanup of URIUtil constants + cleanup of URIUtil methods + collapse separate methods + simplify encodePath() * Javadoc updates * equalsIgnoreEncoding cleanup (no longer used by Resource layer)
This commit is contained in:
parent
41e9842921
commit
b3505ae687
|
@ -36,7 +36,6 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.Environment;
|
||||
|
@ -481,7 +480,7 @@ public class ContextProvider extends ScanningAppProvider
|
|||
// special case of archive (or dir) named "root" is / context
|
||||
if (contextPath.equalsIgnoreCase("root"))
|
||||
{
|
||||
contextPath = URIUtil.SLASH;
|
||||
contextPath = "/";
|
||||
}
|
||||
// handle root with virtual host form
|
||||
else if (StringUtil.startsWithIgnoreCase(contextPath, "root-"))
|
||||
|
@ -489,7 +488,7 @@ public class ContextProvider extends ScanningAppProvider
|
|||
int dash = contextPath.indexOf('-');
|
||||
String virtual = contextPath.substring(dash + 1);
|
||||
context.setVirtualHosts(Arrays.asList(virtual.split(",")));
|
||||
contextPath = URIUtil.SLASH;
|
||||
contextPath = "/";
|
||||
}
|
||||
|
||||
// Ensure "/" is Prepended to all context paths.
|
||||
|
|
|
@ -18,7 +18,6 @@ import java.nio.file.Path;
|
|||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.FileID;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.component.Environment;
|
||||
|
||||
|
@ -71,7 +70,7 @@ public class MockAppProvider extends AbstractLifeCycle implements AppProvider
|
|||
|
||||
// special case of archive (or dir) named "root" is / context
|
||||
if (path.equalsIgnoreCase("root") || path.equalsIgnoreCase("root/"))
|
||||
path = URIUtil.SLASH;
|
||||
path = "/";
|
||||
|
||||
// Ensure "/" is Prepended to all context paths.
|
||||
if (path.charAt(0) != '/')
|
||||
|
|
|
@ -177,15 +177,15 @@ public class ServletPathSpec extends AbstractPathSpec
|
|||
|
||||
if (info.startsWith("./"))
|
||||
info = info.substring(2);
|
||||
if (base.endsWith(URIUtil.SLASH))
|
||||
if (info.startsWith(URIUtil.SLASH))
|
||||
if (base.endsWith("/"))
|
||||
if (info.startsWith("/"))
|
||||
path = base + info.substring(1);
|
||||
else
|
||||
path = base + info;
|
||||
else if (info.startsWith(URIUtil.SLASH))
|
||||
else if (info.startsWith("/"))
|
||||
path = base + info;
|
||||
else
|
||||
path = base + URIUtil.SLASH + info;
|
||||
path = base + "/" + info;
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
@ -225,7 +225,7 @@ public class ResourceListing
|
|||
|
||||
// Ensure name has a slash if it's a directory
|
||||
if (item.isDirectory() && !name.endsWith("/"))
|
||||
name += URIUtil.SLASH;
|
||||
name += "/";
|
||||
|
||||
// Name
|
||||
buf.append("<tr><td class=\"name\"><a href=\"");
|
||||
|
|
|
@ -156,7 +156,7 @@ public class ResourceService
|
|||
// Is this a Range request?
|
||||
List<String> reqRanges = request.getHeaders().getValuesList(HttpHeader.RANGE.asString());
|
||||
|
||||
boolean endsWithSlash = pathInContext.endsWith(URIUtil.SLASH);
|
||||
boolean endsWithSlash = pathInContext.endsWith("/");
|
||||
boolean checkPrecompressedVariants = _precompressedFormats.size() > 0 && !endsWithSlash && reqRanges.isEmpty();
|
||||
|
||||
try
|
||||
|
@ -552,7 +552,7 @@ public class ResourceService
|
|||
return;
|
||||
}
|
||||
|
||||
String base = URIUtil.addEncodedPaths(request.getHttpURI().getPath(), URIUtil.SLASH);
|
||||
String base = URIUtil.addEncodedPaths(request.getHttpURI().getPath(), "/");
|
||||
String listing = ResourceListing.getAsXHTML(httpContent.getResource(), base, pathInContext.length() > 1, request.getHttpURI().getQuery());
|
||||
if (listing == null)
|
||||
{
|
||||
|
|
|
@ -18,7 +18,6 @@ import java.io.IOException;
|
|||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
@ -55,17 +54,10 @@ public final class URIUtil
|
|||
.with("jar:")
|
||||
.build();
|
||||
|
||||
public static final String SLASH = "/";
|
||||
public static final String HTTP = "http";
|
||||
public static final String HTTPS = "https";
|
||||
|
||||
// Use UTF-8 as per http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars
|
||||
public static final Charset __CHARSET = StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* The characters that are supported by the URI class and that can be decoded by {@link #canonicalPath(String)}
|
||||
*/
|
||||
public static final boolean[] __uriSupportedCharacters = new boolean[]
|
||||
private static final boolean[] URI_SUPPORTED_CHARACTERS = new boolean[]
|
||||
{
|
||||
false, // 0x00 is illegal
|
||||
false, // 0x01 is illegal
|
||||
|
@ -197,242 +189,102 @@ public final class URIUtil
|
|||
false, // 0x7f DEL is illegal
|
||||
};
|
||||
|
||||
private static final boolean[] ENCODE_PATH_NEEDS_ENCODING;
|
||||
|
||||
private URIUtil()
|
||||
{
|
||||
}
|
||||
|
||||
static
|
||||
{
|
||||
ENCODE_PATH_NEEDS_ENCODING = new boolean[128];
|
||||
// Special characters
|
||||
for (char c: "%?;#\"'<> [\\]^`{|}".toCharArray())
|
||||
ENCODE_PATH_NEEDS_ENCODING[c] = true;
|
||||
// control characters
|
||||
ENCODE_PATH_NEEDS_ENCODING[0x7f] = true;
|
||||
for (int i = 0; i < 0x20; i++)
|
||||
ENCODE_PATH_NEEDS_ENCODING[i] = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a URI path.
|
||||
* This is the same encoding offered by URLEncoder, except that
|
||||
* the '/' character is not encoded.
|
||||
* the '{@code /}' character is not encoded.
|
||||
*
|
||||
* @param path The path the encode
|
||||
* @param path The path to encode
|
||||
* @return The encoded path
|
||||
*/
|
||||
public static String encodePath(String path)
|
||||
{
|
||||
if (path == null || path.length() == 0)
|
||||
if (StringUtil.isEmpty(path))
|
||||
return path;
|
||||
|
||||
StringBuilder buf = encodePath(null, path, 0);
|
||||
return buf == null ? path : buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a URI path.
|
||||
*
|
||||
* @param path The path the encode
|
||||
* @param buf StringBuilder to encode path into (or null)
|
||||
* @return The StringBuilder or null if no substitutions required.
|
||||
*/
|
||||
public static StringBuilder encodePath(StringBuilder buf, String path)
|
||||
{
|
||||
return encodePath(buf, path, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a URI path.
|
||||
*
|
||||
* @param path The path the encode
|
||||
* @param buf StringBuilder to encode path into (or null)
|
||||
* @return The StringBuilder or null if no substitutions required.
|
||||
*/
|
||||
private static StringBuilder encodePath(StringBuilder buf, String path, int offset)
|
||||
{
|
||||
byte[] bytes = null;
|
||||
if (buf == null)
|
||||
{
|
||||
loop:
|
||||
for (int i = offset; i < path.length(); i++)
|
||||
{
|
||||
char c = path.charAt(i);
|
||||
switch (c)
|
||||
{
|
||||
case '%':
|
||||
case '?':
|
||||
case ';':
|
||||
case '#':
|
||||
case '"':
|
||||
case '\'':
|
||||
case '<':
|
||||
case '>':
|
||||
case ' ':
|
||||
case '[':
|
||||
case '\\':
|
||||
case ']':
|
||||
case '^':
|
||||
case '`':
|
||||
case '{':
|
||||
case '|':
|
||||
case '}':
|
||||
buf = new StringBuilder(path.length() * 2);
|
||||
break loop;
|
||||
default:
|
||||
if (c < 0x20 || c >= 0x7f)
|
||||
{
|
||||
bytes = path.getBytes(URIUtil.__CHARSET);
|
||||
buf = new StringBuilder(path.length() * 2);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buf == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
int i;
|
||||
|
||||
loop:
|
||||
for (i = offset; i < path.length(); i++)
|
||||
// byte encoding always wins and, if encountered, should be used.
|
||||
boolean needsByteEncoding = false;
|
||||
// string (char-by-char) encoding, but it could be followed by a need for byte encoding instead
|
||||
boolean needsEncoding = false;
|
||||
int length = path.length();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
char c = path.charAt(i);
|
||||
switch (c)
|
||||
if (c > 0x7F) // 8-bit +
|
||||
{
|
||||
case '%':
|
||||
buf.append("%25");
|
||||
continue;
|
||||
case '?':
|
||||
buf.append("%3F");
|
||||
continue;
|
||||
case ';':
|
||||
buf.append("%3B");
|
||||
continue;
|
||||
case '#':
|
||||
buf.append("%23");
|
||||
continue;
|
||||
case '"':
|
||||
buf.append("%22");
|
||||
continue;
|
||||
case '\'':
|
||||
buf.append("%27");
|
||||
continue;
|
||||
case '<':
|
||||
buf.append("%3C");
|
||||
continue;
|
||||
case '>':
|
||||
buf.append("%3E");
|
||||
continue;
|
||||
case ' ':
|
||||
buf.append("%20");
|
||||
continue;
|
||||
case '[':
|
||||
buf.append("%5B");
|
||||
continue;
|
||||
case '\\':
|
||||
buf.append("%5C");
|
||||
continue;
|
||||
case ']':
|
||||
buf.append("%5D");
|
||||
continue;
|
||||
case '^':
|
||||
buf.append("%5E");
|
||||
continue;
|
||||
case '`':
|
||||
buf.append("%60");
|
||||
continue;
|
||||
case '{':
|
||||
buf.append("%7B");
|
||||
continue;
|
||||
case '|':
|
||||
buf.append("%7C");
|
||||
continue;
|
||||
case '}':
|
||||
buf.append("%7D");
|
||||
continue;
|
||||
|
||||
default:
|
||||
if (c < 0x20 || c >= 0x7f)
|
||||
{
|
||||
bytes = path.getBytes(URIUtil.__CHARSET);
|
||||
break loop;
|
||||
}
|
||||
buf.append(c);
|
||||
needsByteEncoding = true;
|
||||
break; // have to encode byte by byte now
|
||||
}
|
||||
if (ENCODE_PATH_NEEDS_ENCODING[c])
|
||||
{
|
||||
// could be followed by a byte encoding, so no break
|
||||
needsEncoding = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes != null)
|
||||
{
|
||||
for (; i < bytes.length; i++)
|
||||
{
|
||||
byte c = bytes[i];
|
||||
switch (c)
|
||||
{
|
||||
case '%':
|
||||
buf.append("%25");
|
||||
continue;
|
||||
case '?':
|
||||
buf.append("%3F");
|
||||
continue;
|
||||
case ';':
|
||||
buf.append("%3B");
|
||||
continue;
|
||||
case '#':
|
||||
buf.append("%23");
|
||||
continue;
|
||||
case '"':
|
||||
buf.append("%22");
|
||||
continue;
|
||||
case '\'':
|
||||
buf.append("%27");
|
||||
continue;
|
||||
case '<':
|
||||
buf.append("%3C");
|
||||
continue;
|
||||
case '>':
|
||||
buf.append("%3E");
|
||||
continue;
|
||||
case ' ':
|
||||
buf.append("%20");
|
||||
continue;
|
||||
case '[':
|
||||
buf.append("%5B");
|
||||
continue;
|
||||
case '\\':
|
||||
buf.append("%5C");
|
||||
continue;
|
||||
case ']':
|
||||
buf.append("%5D");
|
||||
continue;
|
||||
case '^':
|
||||
buf.append("%5E");
|
||||
continue;
|
||||
case '`':
|
||||
buf.append("%60");
|
||||
continue;
|
||||
case '{':
|
||||
buf.append("%7B");
|
||||
continue;
|
||||
case '|':
|
||||
buf.append("%7C");
|
||||
continue;
|
||||
case '}':
|
||||
buf.append("%7D");
|
||||
continue;
|
||||
default:
|
||||
if (c < 0x20 || c >= 0x7f)
|
||||
{
|
||||
buf.append('%');
|
||||
TypeUtil.toHex(c, buf);
|
||||
}
|
||||
else
|
||||
buf.append((char)c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
if (needsByteEncoding)
|
||||
return encodePathBytes(path);
|
||||
else if (needsEncoding)
|
||||
return encodePathString(path);
|
||||
else
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a raw URI String and convert any raw spaces to
|
||||
* their "%20" equivalent.
|
||||
*
|
||||
* @param str input raw string
|
||||
* @return output with spaces converted to "%20"
|
||||
*/
|
||||
public static String encodeSpaces(String str)
|
||||
private static String encodePathString(String path)
|
||||
{
|
||||
return StringUtil.replace(str, " ", "%20");
|
||||
StringBuilder buf = new StringBuilder(path.length() * 2);
|
||||
int length = path.length();
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
char c = path.charAt(i);
|
||||
if (ENCODE_PATH_NEEDS_ENCODING[c])
|
||||
{
|
||||
buf.append('%');
|
||||
TypeUtil.toHex((byte)c, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
private static String encodePathBytes(String path)
|
||||
{
|
||||
StringBuilder buf = new StringBuilder(path.length() * 2);
|
||||
byte[] pathBytes = path.getBytes(StandardCharsets.UTF_8);
|
||||
for (byte b : pathBytes)
|
||||
{
|
||||
if (b < 0 || ENCODE_PATH_NEEDS_ENCODING[b])
|
||||
{
|
||||
buf.append('%');
|
||||
TypeUtil.toHex(b, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.append((char)b);
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,7 +335,7 @@ public final class URIUtil
|
|||
* Decode a raw String and convert any specific URI encoded sequences into characters.
|
||||
*
|
||||
* @param str input raw string
|
||||
* @param charsToDecode the list of raw characters that need to be decoded (if encountered), leaving all other encoded sequences alone.
|
||||
* @param charsToDecode the list of raw characters that need to be decoded (if encountered), leaving all the other encoded sequences alone.
|
||||
* @return output with specified characters decoded.
|
||||
*/
|
||||
@SuppressWarnings("Duplicates")
|
||||
|
@ -510,41 +362,40 @@ public final class URIUtil
|
|||
for (int i = idx; i < len; i++)
|
||||
{
|
||||
char c = str.charAt(i);
|
||||
switch (c)
|
||||
if (c == '%')
|
||||
{
|
||||
case '%':
|
||||
if ((i + 2) < len)
|
||||
if ((i + 2) < len)
|
||||
{
|
||||
char u = str.charAt(i + 1);
|
||||
char l = str.charAt(i + 2);
|
||||
char result = (char)(0xff & (TypeUtil.convertHexDigit(u) * 16 + TypeUtil.convertHexDigit(l)));
|
||||
boolean decoded = false;
|
||||
for (char f : find)
|
||||
{
|
||||
char u = str.charAt(i + 1);
|
||||
char l = str.charAt(i + 2);
|
||||
char result = (char)(0xff & (TypeUtil.convertHexDigit(u) * 16 + TypeUtil.convertHexDigit(l)));
|
||||
boolean decoded = false;
|
||||
for (char f : find)
|
||||
if (f == result)
|
||||
{
|
||||
if (f == result)
|
||||
{
|
||||
ret.append(result);
|
||||
decoded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (decoded)
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
ret.append(result);
|
||||
decoded = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (decoded)
|
||||
{
|
||||
i += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Bad URI % encoding");
|
||||
ret.append(c);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ret.append(c);
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Bad URI % encoding");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.append(c);
|
||||
}
|
||||
}
|
||||
return ret.toString();
|
||||
|
@ -553,11 +404,12 @@ public final class URIUtil
|
|||
/**
|
||||
* Encode a URI path.
|
||||
*
|
||||
* @param path The path the encode
|
||||
* @param path The path to encode
|
||||
* @param buf StringBuilder to encode path into (or null)
|
||||
* @param encode String of characters to encode. % is always encoded.
|
||||
* @param encode String of characters to encode. '{@code %}' is always encoded.
|
||||
* @return The StringBuilder or null if no substitutions required.
|
||||
*/
|
||||
// TODO: remove, only used in URIUtilTest?
|
||||
public static StringBuilder encodeString(StringBuilder buf,
|
||||
String path,
|
||||
String encode)
|
||||
|
@ -730,7 +582,7 @@ public final class URIUtil
|
|||
{
|
||||
// Allow any 8-bit character (as it's likely unicode).
|
||||
// or any character labeled with true in __uriSupportedCharacters static
|
||||
return (code >= __uriSupportedCharacters.length || __uriSupportedCharacters[code]);
|
||||
return (code >= URI_SUPPORTED_CHARACTERS.length || URI_SUPPORTED_CHARACTERS[code]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -784,11 +636,11 @@ public final class URIUtil
|
|||
* <p>
|
||||
* Decode only the safe characters in a URI path and strip parameters of UTF-8 path.
|
||||
* Safe characters are ones that are not special delimiters and that can be passed to the JVM {@link URI} class.
|
||||
* Unsafe characters, other than '/' will be encoded. Encodings will be uppercase hex.
|
||||
* Unsafe characters, other than '{@code /}' will be encoded. Encodings will be uppercase hex.
|
||||
* Canonical paths are also normalized and may be used in string comparisons with other canonical paths.
|
||||
* <p>
|
||||
* For example the path <code>/fo %2fo/b%61r</code> will be normalized to <code>/fo%20%2Fo/bar</code>,
|
||||
* whilst {@link #decodePath(String)} would result in the ambiguous and URI illegal <code>/fo /o/bar</code>.
|
||||
* For example the path {@code /fo %2fo/b%61r} will be normalized to {@code /fo%20%2Fo/bar},
|
||||
* whilst {@link #decodePath(String)} would result in the ambiguous and URI illegal {@code /fo /o/bar}.
|
||||
* @return the canonical path or null if it is non-normal
|
||||
* @see #decodePath(String)
|
||||
* @see #normalizePath(String)
|
||||
|
@ -917,7 +769,8 @@ public final class URIUtil
|
|||
}
|
||||
}
|
||||
|
||||
/* Decode a URI path and strip parameters of ISO-8859-1 path
|
||||
/**
|
||||
* Decode a URI path and strip parameters of ISO-8859-1 path
|
||||
*/
|
||||
private static String decodeISO88591Path(String path, int offset, int length)
|
||||
{
|
||||
|
@ -989,7 +842,7 @@ public final class URIUtil
|
|||
/**
|
||||
* Add two encoded URI path segments.
|
||||
* Handles null and empty paths, path and query params
|
||||
* (eg ?a=b or ;JSESSIONID=xxx) and avoids duplicate '/'
|
||||
* (e.g. {@code ?a=b} or {@code ;JSESSIONID=xxx}) and avoids duplicate '{@code /}'
|
||||
*
|
||||
* @param p1 URI path segment (should be encoded)
|
||||
* @param p2 URI path segment (should be encoded)
|
||||
|
@ -1019,7 +872,7 @@ public final class URIUtil
|
|||
|
||||
if (buf.charAt(split - 1) == '/')
|
||||
{
|
||||
if (p2.startsWith(URIUtil.SLASH))
|
||||
if (p2.startsWith("/"))
|
||||
{
|
||||
buf.deleteCharAt(split - 1);
|
||||
buf.insert(split - 1, p2);
|
||||
|
@ -1029,7 +882,7 @@ public final class URIUtil
|
|||
}
|
||||
else
|
||||
{
|
||||
if (p2.startsWith(URIUtil.SLASH))
|
||||
if (p2.startsWith("/"))
|
||||
buf.insert(split, p2);
|
||||
else
|
||||
{
|
||||
|
@ -1043,8 +896,10 @@ public final class URIUtil
|
|||
|
||||
/**
|
||||
* Add two Decoded URI path segments.
|
||||
* Handles null and empty paths. Path and query params (eg ?a=b or
|
||||
* ;JSESSIONID=xxx) are not handled
|
||||
* <p>
|
||||
* Handles null and empty paths.
|
||||
* Path and query params (e.g. {@code ?a=b} or {@code ;JSESSIONID=xxx}) are not handled
|
||||
* </p>
|
||||
*
|
||||
* @param p1 URI path segment (should be decoded)
|
||||
* @param p2 URI path segment (should be decoded)
|
||||
|
@ -1061,8 +916,8 @@ public final class URIUtil
|
|||
if (p2 == null || p2.length() == 0)
|
||||
return p1;
|
||||
|
||||
boolean p1EndsWithSlash = p1.endsWith(SLASH);
|
||||
boolean p2StartsWithSlash = p2.startsWith(SLASH);
|
||||
boolean p1EndsWithSlash = p1.endsWith("/");
|
||||
boolean p2StartsWithSlash = p2.startsWith("/");
|
||||
|
||||
if (p1EndsWithSlash && p2StartsWithSlash)
|
||||
{
|
||||
|
@ -1075,25 +930,27 @@ public final class URIUtil
|
|||
StringBuilder buf = new StringBuilder(p1.length() + p2.length() + 2);
|
||||
buf.append(p1);
|
||||
|
||||
if (p1.endsWith(SLASH))
|
||||
if (p1.endsWith("/"))
|
||||
{
|
||||
if (p2.startsWith(SLASH))
|
||||
if (p2.startsWith("/"))
|
||||
buf.setLength(buf.length() - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!p2.startsWith(SLASH))
|
||||
buf.append(SLASH);
|
||||
if (!p2.startsWith("/"))
|
||||
buf.append("/");
|
||||
}
|
||||
buf.append(p2);
|
||||
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
/** Add a path and a query string
|
||||
/**
|
||||
* Add a path and a query string
|
||||
*
|
||||
* @param path The path which may already contain a query
|
||||
* @param query The query string to add (if blank, no query is added)
|
||||
* @return The path with any non-blank query added after a '?' or '&' as appropriate.
|
||||
* @return The path with any non-blank query added after a '{@code ?}' or '{@code &}' as appropriate.
|
||||
*/
|
||||
public static String addPathQuery(String path, String query)
|
||||
{
|
||||
|
@ -1142,14 +999,16 @@ public final class URIUtil
|
|||
|
||||
/**
|
||||
* Return the parent Path.
|
||||
* <p>
|
||||
* Treat a URI like a directory path and return the parent directory.
|
||||
* </p>
|
||||
*
|
||||
* @param p the path to return a parent reference to
|
||||
* @return the parent path of the URI
|
||||
*/
|
||||
public static String parentPath(String p)
|
||||
{
|
||||
if (p == null || URIUtil.SLASH.equals(p))
|
||||
if (p == null || "/".equals(p))
|
||||
return null;
|
||||
int slash = p.lastIndexOf('/', p.length() - 2);
|
||||
if (slash >= 0)
|
||||
|
@ -1158,7 +1017,8 @@ public final class URIUtil
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Normalize a URI path and query by factoring out all segments of "." and ".."
|
||||
* <p>
|
||||
* Normalize a URI path and query by factoring out all segments of '{@code .}' and '{@code ..}'
|
||||
* up until any query or fragment.
|
||||
* Null is returned if the path is normalized above its root.
|
||||
* </p>
|
||||
|
@ -1189,7 +1049,6 @@ public final class URIUtil
|
|||
case '.':
|
||||
if (slash)
|
||||
break loop;
|
||||
slash = false;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
|
@ -1267,8 +1126,8 @@ public final class URIUtil
|
|||
|
||||
/**
|
||||
* <p>Check if a path would be normalized within itself. For example,
|
||||
* <code>/foo/../../bar</code> is normalized above its root and would
|
||||
* thus return false, whilst <code>/foo/./bar/..</code> is normal within itself
|
||||
* {@code /foo/../../bar} is normalized above its root and would
|
||||
* thus return false, whilst {@code /foo/./bar/..} is normal within itself
|
||||
* and would return true.
|
||||
* @param path The path to check
|
||||
* @return True if the normal form of the path is within the root of the path.
|
||||
|
@ -1280,11 +1139,11 @@ public final class URIUtil
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>Normalize a URI path by factoring out all segments of "." and "..".
|
||||
* <p>Normalize a URI path by factoring out all segments of {@code .} and {@code ..}.
|
||||
* Null is returned if the path is normalized above its root.
|
||||
* </p>
|
||||
*
|
||||
* @param path the decoded URI path to convert. Any special characters (e.g. '?', "#") are assumed to be part of
|
||||
* @param path the decoded URI path to convert. Any special characters (e.g. {@code ?}, {@code #}) are assumed to be part of
|
||||
* the path segments.
|
||||
* @return the normalized path, or null if path traversal above root.
|
||||
* @see #normalizePathQuery(String)
|
||||
|
@ -1306,18 +1165,13 @@ public final class URIUtil
|
|||
char c = path.charAt(i);
|
||||
switch (c)
|
||||
{
|
||||
case '/':
|
||||
slash = true;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
case '/' -> slash = true;
|
||||
case '.' ->
|
||||
{
|
||||
if (slash)
|
||||
break loop;
|
||||
slash = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
slash = false;
|
||||
}
|
||||
default -> slash = false;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
@ -1339,14 +1193,15 @@ public final class URIUtil
|
|||
char c = path.charAt(i);
|
||||
switch (c)
|
||||
{
|
||||
case '/':
|
||||
case '/' ->
|
||||
{
|
||||
if (doDotsSlash(canonical, dots))
|
||||
return null;
|
||||
slash = true;
|
||||
dots = 0;
|
||||
break;
|
||||
|
||||
case '.':
|
||||
}
|
||||
case '.' ->
|
||||
{
|
||||
// Count dots only if they are leading in the segment
|
||||
if (dots > 0)
|
||||
dots++;
|
||||
|
@ -1355,15 +1210,16 @@ public final class URIUtil
|
|||
else
|
||||
canonical.append('.');
|
||||
slash = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
}
|
||||
default ->
|
||||
{
|
||||
// Add leading dots to the path
|
||||
while (dots-- > 0)
|
||||
canonical.append('.');
|
||||
canonical.append(c);
|
||||
dots = 0;
|
||||
slash = false;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
@ -1420,7 +1276,7 @@ public final class URIUtil
|
|||
|
||||
/**
|
||||
* Convert a path to a compact form.
|
||||
* All instances of "//" and "///" etc. are factored out to single "/"
|
||||
* All instances of {@code //} and {@code ///} etc. are factored out to single {@code /}
|
||||
*
|
||||
* @param path the path to compact
|
||||
* @return the compacted path
|
||||
|
@ -1582,47 +1438,36 @@ public final class URIUtil
|
|||
*/
|
||||
public static void appendSchemeHostPort(StringBuffer url, String scheme, String server, int port)
|
||||
{
|
||||
synchronized (url)
|
||||
url.append(scheme).append("://").append(HostPort.normalizeHost(server));
|
||||
|
||||
if (port > 0)
|
||||
{
|
||||
url.append(scheme).append("://").append(HostPort.normalizeHost(server));
|
||||
|
||||
if (port > 0)
|
||||
switch (scheme)
|
||||
{
|
||||
switch (scheme)
|
||||
{
|
||||
case "http":
|
||||
if (port != 80)
|
||||
url.append(':').append(port);
|
||||
break;
|
||||
|
||||
case "https":
|
||||
if (port != 443)
|
||||
url.append(':').append(port);
|
||||
break;
|
||||
|
||||
default:
|
||||
case "http":
|
||||
if (port != 80)
|
||||
url.append(':').append(port);
|
||||
}
|
||||
break;
|
||||
|
||||
case "https":
|
||||
if (port != 443)
|
||||
url.append(':').append(port);
|
||||
break;
|
||||
|
||||
default:
|
||||
url.append(':').append(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only URIUtil is using this method
|
||||
static boolean equalsIgnoreEncodings(String uriA, String uriB)
|
||||
{
|
||||
try
|
||||
{
|
||||
String safeDecodedUriA = ensureSafeEncoding(uriA);
|
||||
String safeDecodedUriB = ensureSafeEncoding(uriB);
|
||||
return safeDecodedUriA.equals(safeDecodedUriB);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static String ensureSafeEncoding(String path)
|
||||
/**
|
||||
* Encode characters in a path to ensure they only contain safe encodings suitable for both
|
||||
* {@link URI} and {@link Paths#get(URI)} usage.
|
||||
*
|
||||
* @param path the path to encode
|
||||
* @return the returned path with only safe encodings
|
||||
*/
|
||||
public static String encodePathSafeEncoding(String path)
|
||||
{
|
||||
if (path == null)
|
||||
return null;
|
||||
|
@ -1762,42 +1607,6 @@ public final class URIUtil
|
|||
return ((codepoint == '?') || (codepoint == '#'));
|
||||
}
|
||||
|
||||
public static boolean equalsIgnoreEncodings(URI uriA, URI uriB)
|
||||
{
|
||||
if (uriA.equals(uriB))
|
||||
return true;
|
||||
|
||||
if (uriA.toASCIIString().equals(uriB.toASCIIString()))
|
||||
return true;
|
||||
|
||||
// TODO: this check occurs in uriA.equals(uriB)
|
||||
if (uriA.getScheme() == null)
|
||||
{
|
||||
if (uriB.getScheme() != null)
|
||||
return false;
|
||||
}
|
||||
else if (!uriA.getScheme().equalsIgnoreCase(uriB.getScheme()))
|
||||
return false;
|
||||
|
||||
if ("jar".equalsIgnoreCase(uriA.getScheme()))
|
||||
{
|
||||
// at this point we know that both uri's are "jar:"
|
||||
URI uriAssp = URI.create(uriA.getRawSchemeSpecificPart());
|
||||
URI uriBssp = URI.create(uriB.getRawSchemeSpecificPart());
|
||||
return equalsIgnoreEncodings(uriAssp, uriBssp);
|
||||
}
|
||||
|
||||
if (uriA.getAuthority() == null)
|
||||
{
|
||||
if (uriB.getAuthority() != null)
|
||||
return false;
|
||||
}
|
||||
else if (!uriA.getAuthority().equals(uriB.getAuthority()))
|
||||
return false;
|
||||
|
||||
return equalsIgnoreEncodings(uriA.getRawPath(), uriB.getRawPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a sub path to an existing URI.
|
||||
*
|
||||
|
@ -1828,7 +1637,7 @@ public final class URIUtil
|
|||
|
||||
// ensure that the base has a safe encoding suitable for both
|
||||
// URI and Paths.get(URI) later usage
|
||||
path = ensureSafeEncoding(path);
|
||||
path = encodePathSafeEncoding(path);
|
||||
pathLen = path.length();
|
||||
|
||||
if (base.length() == 0)
|
||||
|
@ -1847,8 +1656,8 @@ public final class URIUtil
|
|||
}
|
||||
|
||||
/**
|
||||
* Combine two query strings into one. Each query string should not contain the beginning '?' character, but
|
||||
* may contain multiple parameters separated by the '{@literal &}' character.
|
||||
* Combine two query strings into one. Each query string should not contain the beginning '{@code ?}' character, but
|
||||
* may contain multiple parameters separated by the '{@code &}' character.
|
||||
* @param query1 the first query string.
|
||||
* @param query2 the second query string.
|
||||
* @return the combination of the two query strings.
|
||||
|
@ -1911,12 +1720,12 @@ public final class URIUtil
|
|||
}
|
||||
|
||||
/**
|
||||
* Split a string of references, that may be split with {@code ,}, or {@code ;}, or {@code |} into URIs.
|
||||
* Split a string of references, that may be split with '{@code ,}', or '{@code ;}', or '{@code |}' into URIs.
|
||||
* <p>
|
||||
* Each part of the input string could be path references (unix or windows style), or string URI references.
|
||||
* </p>
|
||||
* <p>
|
||||
* If the result of processing the input segment is a java archive, then its resulting URI will be a mountable URI as `jar:file:...!/`.
|
||||
* If the result of processing the input segment is a java archive, then its resulting URI will be a mountable URI as {@code jar:file:...!/}
|
||||
* </p>
|
||||
*
|
||||
* @param str the input string of references
|
||||
|
@ -1973,12 +1782,15 @@ public final class URIUtil
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Take an arbitrary URI and provide a URI that is suitable for mounting the URI as a Java FileSystem.
|
||||
*
|
||||
* </p>
|
||||
* <p>
|
||||
* The resulting URI will point to the {@code jar:file://foo.jar!/} said Java Archive (jar, war, or zip)
|
||||
* </p>
|
||||
*
|
||||
* @param uri the URI to mutate to a {@code jar:file:...} URI.
|
||||
* @return the <code>jar:${uri_to_java_archive}!/${internal-reference}</code> URI or the unchanged URI if not a Java Archive.
|
||||
* @return the {@code jar:${uri_to_java_archive}!/${internal-reference}} URI or the unchanged URI if not a Java Archive.
|
||||
* @see FileID#isArchive(URI)
|
||||
*/
|
||||
public static URI toJarFileUri(URI uri)
|
||||
|
@ -2034,9 +1846,13 @@ public final class URIUtil
|
|||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Unwrap a URI to expose its container path reference.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Take out the container archive name URI from a {@code jar:file:${container-name}!/} URI.
|
||||
* </p>
|
||||
*
|
||||
* @param uri the input URI
|
||||
* @return the container String if a {@code jar} scheme, or just the URI untouched.
|
||||
|
|
|
@ -131,7 +131,7 @@ public class CombinedResource extends Resource
|
|||
if (URIUtil.isNotNormalWithinSelf(subUriPath))
|
||||
throw new IllegalArgumentException(subUriPath);
|
||||
|
||||
if (subUriPath.length() == 0 || URIUtil.SLASH.equals(subUriPath))
|
||||
if (subUriPath.length() == 0 || "/".equals(subUriPath))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -182,8 +182,8 @@ public class PathResource extends Resource
|
|||
if (Files.isDirectory(path))
|
||||
{
|
||||
String uriString = uri.toASCIIString();
|
||||
if (!uriString.endsWith(URIUtil.SLASH))
|
||||
uri = URIUtil.correctFileURI(URI.create(uriString + URIUtil.SLASH));
|
||||
if (!uriString.endsWith("/"))
|
||||
uri = URIUtil.correctFileURI(URI.create(uriString + "/"));
|
||||
}
|
||||
|
||||
this.path = path;
|
||||
|
@ -282,7 +282,7 @@ public class PathResource extends Resource
|
|||
if (URIUtil.isNotNormalWithinSelf(subUriPath))
|
||||
throw new IllegalArgumentException(subUriPath);
|
||||
|
||||
if (URIUtil.SLASH.equals(subUriPath))
|
||||
if ("/".equals(subUriPath))
|
||||
return this;
|
||||
|
||||
URI uri = getURI();
|
||||
|
|
|
@ -66,7 +66,9 @@ public class URIUtilTest
|
|||
Arguments.of("/context/'list'/\"me\"/;<script>window.alert('xss');</script>",
|
||||
"/context/%27list%27/%22me%22/%3B%3Cscript%3Ewindow.alert(%27xss%27)%3B%3C/script%3E"),
|
||||
Arguments.of("test\u00f6?\u00f6:\u00df", "test%C3%B6%3F%C3%B6:%C3%9F"),
|
||||
Arguments.of("test?\u00f6?\u00f6:\u00df", "test%3F%C3%B6%3F%C3%B6:%C3%9F")
|
||||
Arguments.of("test?\u00f6?\u00f6:\u00df", "test%3F%C3%B6%3F%C3%B6:%C3%9F"),
|
||||
Arguments.of("/test space/", "/test%20space/"),
|
||||
Arguments.of("/test\u007fdel/", "/test%7Fdel/")
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -75,10 +77,8 @@ public class URIUtilTest
|
|||
public void testEncodePath(String rawPath, String expectedEncoded)
|
||||
{
|
||||
// test basic encode/decode
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.setLength(0);
|
||||
URIUtil.encodePath(buf, rawPath);
|
||||
assertEquals(expectedEncoded, buf.toString());
|
||||
String result = URIUtil.encodePath(rawPath);
|
||||
assertEquals(expectedEncoded, result);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -565,7 +565,7 @@ public class URIUtilTest
|
|||
assertThat(actual, is(expected));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> ensureSafeEncodingSource()
|
||||
public static Stream<Arguments> encodePathSafeEncodingSource()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("/foo", "/foo"),
|
||||
|
@ -589,10 +589,10 @@ public class URIUtilTest
|
|||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("ensureSafeEncodingSource")
|
||||
public void testEnsureSafeEncoding(String input, String expected)
|
||||
@MethodSource("encodePathSafeEncodingSource")
|
||||
public void testEncodePathSafeEncoding(String input, String expected)
|
||||
{
|
||||
assertThat(URIUtil.ensureSafeEncoding(input), is(expected));
|
||||
assertThat(URIUtil.encodePathSafeEncoding(input), is(expected));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> compactPathSource()
|
||||
|
@ -637,139 +637,6 @@ public class URIUtilTest
|
|||
assertEquals(expectedPath, actual, String.format("parent %s", path));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> equalsIgnoreEncodingStringTrueSource()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of("http://example.com/foo/bar", "http://example.com/foo/bar"),
|
||||
Arguments.of("/barry%27s", "/barry%27s"),
|
||||
Arguments.of("/b rry%27s", "/b%20rry%27s"),
|
||||
Arguments.of("/barry's", "/barry%27s"),
|
||||
Arguments.of("/barry%27s", "/barry's"),
|
||||
Arguments.of("/b rry's", "/b%20rry%27s"),
|
||||
Arguments.of("/b rry%27s", "/b%20rry's"),
|
||||
Arguments.of("/re bar", "/re%20bar"),
|
||||
|
||||
Arguments.of("/foo%2fbar", "/foo%2fbar"),
|
||||
Arguments.of("/foo%2fbar", "/foo%2Fbar"),
|
||||
|
||||
// encoded vs not-encode ("%" symbol is encoded as "%25")
|
||||
Arguments.of("/abc%25xyz", "/abc%xyz"),
|
||||
Arguments.of("/abc%25xy", "/abc%xy"),
|
||||
Arguments.of("/abc%25x", "/abc%x"),
|
||||
Arguments.of("/zzz%25", "/zzz%"),
|
||||
|
||||
// unicode encoded vs not-encoded
|
||||
Arguments.of("/path/to/bä€ãm/", "/path/to/b%C3%A4%E2%82%AC%C3%A3m/")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("equalsIgnoreEncodingStringTrueSource")
|
||||
public void testEqualsIgnoreEncodingStringTrue(String uriA, String uriB)
|
||||
{
|
||||
assertTrue(URIUtil.equalsIgnoreEncodings(uriA, uriB));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> equalsIgnoreEncodingStringFalseSource()
|
||||
{
|
||||
return Stream.of(
|
||||
// case difference
|
||||
Arguments.of("ABC", "abc"),
|
||||
// Encoding difference ("'" is "%27")
|
||||
Arguments.of("/barry's", "/barry%26s"),
|
||||
// Never match on "%2f" differences - only intested in filename / directory name differences
|
||||
// This could be a directory called "foo" with a file called "bar" on the left, and just a file "foo%2fbar" on the right
|
||||
Arguments.of("/foo/bar", "/foo%2fbar"),
|
||||
// not actually encoded
|
||||
Arguments.of("/foo2fbar", "/foo/bar"),
|
||||
// path params
|
||||
Arguments.of("/path;a=b/to;x=y/foo/", "/path/to/foo"),
|
||||
// encoded vs not-encode ("%" symbol is encoded as "%25")
|
||||
Arguments.of("/yyy%25zzz", "/aaa%xxx"),
|
||||
Arguments.of("/zzz%25", "/aaa%"),
|
||||
// %2F then multi-byte unicode
|
||||
Arguments.of("/path/to/bãm/", "/path%2Fto/b%C3%A3m/"),
|
||||
// multi-byte unicode then %2F
|
||||
Arguments.of("/path/bãm/or/bust", "/path/b%C3%A3m/or%2Fbust"),
|
||||
// mix of %2F and multiple consecutive multi-byte unicode
|
||||
Arguments.of("/path/to/bä€ãm/", "/path%2Fto/b%C3%A4%E2%82%AC%C3%A3m/")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("equalsIgnoreEncodingStringFalseSource")
|
||||
public void testEqualsIgnoreEncodingStringFalse(String uriA, String uriB)
|
||||
{
|
||||
assertFalse(URIUtil.equalsIgnoreEncodings(uriA, uriB));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> equalsIgnoreEncodingURITrueSource()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of(
|
||||
URI.create("HTTP:/foo/b%61r"),
|
||||
URI.create("http:/f%6Fo/bar")
|
||||
),
|
||||
Arguments.of(
|
||||
URI.create("jar:file:/path/to/main.jar!/META-INF/versions/"),
|
||||
URI.create("jar:file:/path/to/main.jar!/META-INF/%76ersions/")
|
||||
),
|
||||
Arguments.of(
|
||||
URI.create("JAR:FILE:/path/to/main.jar!/META-INF/versions/"),
|
||||
URI.create("jar:file:/path/to/main.jar!/META-INF/versions/")
|
||||
),
|
||||
// unicode in opaque jar:file: URI
|
||||
Arguments.of(
|
||||
URI.create("jar:file:///path/to/test.jar!/bãm/"),
|
||||
URI.create("jar:file:///path/to/test.jar!/b%C3%A3m/")
|
||||
),
|
||||
// multiple consecutive unicode
|
||||
Arguments.of(
|
||||
URI.create("file:///path/to/bä€ãm/"),
|
||||
URI.create("file:///path/to/b%C3%A4%E2%82%AC%C3%A3m/")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("equalsIgnoreEncodingURITrueSource")
|
||||
public void testEqualsIgnoreEncodingURITrue(URI uriA, URI uriB)
|
||||
{
|
||||
assertTrue(URIUtil.equalsIgnoreEncodings(uriA, uriB));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> equalsIgnoreEncodingURIFalseSource()
|
||||
{
|
||||
return Stream.of(
|
||||
Arguments.of(
|
||||
URI.create("/foo%2Fbar"),
|
||||
URI.create("/foo/bar")
|
||||
),
|
||||
// %2F then unicode
|
||||
Arguments.of(
|
||||
URI.create("file:///path/to/bãm/"),
|
||||
URI.create("file:///path%2Fto/b%C3%A3m/")
|
||||
),
|
||||
// unicode then %2F
|
||||
Arguments.of(
|
||||
URI.create("file:///path/bãm/or/bust"),
|
||||
URI.create("file:///path/b%C3%A3m/or%2Fbust")
|
||||
),
|
||||
// mix of %2F and multiple consecutive unicode
|
||||
Arguments.of(
|
||||
URI.create("file:///path/to/bä€ãm/"),
|
||||
URI.create("file:///path%2Fto/b%C3%A4%E2%82%AC%C3%A3m/")
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("equalsIgnoreEncodingURIFalseSource")
|
||||
public void testEqualsIgnoreEncodingURIFalse(URI uriA, URI uriB)
|
||||
{
|
||||
assertFalse(URIUtil.equalsIgnoreEncodings(uriA, uriB));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> correctBadFileURICases()
|
||||
{
|
||||
return Stream.of(
|
||||
|
@ -811,17 +678,18 @@ public class URIUtilTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectBadFileURIActualFile() throws Exception
|
||||
public void testCorrectBadFileURIActualFile(WorkDir workDir) throws Exception
|
||||
{
|
||||
File file = MavenTestingUtils.getTargetFile("testCorrectBadFileURIActualFile.txt");
|
||||
FS.touch(file);
|
||||
Path testfile = workDir.getEmptyPathDir().resolve("testCorrectBadFileURIActualFile.txt");
|
||||
FS.touch(testfile);
|
||||
|
||||
URI expectedUri = file.toPath().toUri();
|
||||
URI expectedUri = testfile.toUri(); // correct URI with `://`
|
||||
|
||||
assertThat(expectedUri.toASCIIString(), containsString("://"));
|
||||
|
||||
URI fileUri = file.toURI();
|
||||
URI fileUrlUri = file.toURL().toURI();
|
||||
File file = testfile.toFile();
|
||||
URI fileUri = file.toURI(); // java produced bad format with only `:/` (not `://`)
|
||||
URI fileUrlUri = file.toURL().toURI(); // java produced bad format with only `:/` (not `://`)
|
||||
|
||||
// If these 2 tests start failing, that means Java itself has been fixed
|
||||
assertThat(fileUri.toASCIIString(), not(containsString("://")));
|
||||
|
@ -831,29 +699,6 @@ public class URIUtilTest
|
|||
assertThat(URIUtil.correctFileURI(fileUrlUri).toASCIIString(), is(expectedUri.toASCIIString()));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> encodeSpacesSource()
|
||||
{
|
||||
return Stream.of(
|
||||
// null
|
||||
Arguments.of(null, null),
|
||||
|
||||
// no spaces
|
||||
Arguments.of("abc", "abc"),
|
||||
|
||||
// match
|
||||
Arguments.of("a c", "a%20c"),
|
||||
Arguments.of(" ", "%20%20%20"),
|
||||
Arguments.of("a%20space", "a%20space")
|
||||
);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("encodeSpacesSource")
|
||||
public void testEncodeSpaces(String raw, String expected)
|
||||
{
|
||||
assertThat(URIUtil.encodeSpaces(raw), is(expected));
|
||||
}
|
||||
|
||||
public static Stream<Arguments> encodeSpecific()
|
||||
{
|
||||
return Stream.of(
|
||||
|
@ -1040,12 +885,12 @@ public class URIUtilTest
|
|||
builder.append(i);
|
||||
String path = builder.toString();
|
||||
String encoded = URIUtil.encodePath(path);
|
||||
// Check endoded is visible
|
||||
// Check encoded is visible
|
||||
for (char c : encoded.toCharArray())
|
||||
{
|
||||
assertTrue(c > 0x20 && c < 0x80);
|
||||
assertTrue(c > 0x20 && c < 0x7f);
|
||||
assertFalse(Character.isWhitespace(c));
|
||||
assertFalse(Character.isISOControl(c));
|
||||
assertFalse(Character.isISOControl(c), "isISOControl(0x%2x)".formatted((byte)c));
|
||||
}
|
||||
// check decode to original
|
||||
String decoded = URIUtil.decodePath(encoded);
|
||||
|
|
|
@ -389,7 +389,7 @@ public class OpenIdAuthenticator extends LoginAuthenticator
|
|||
|
||||
String uri = request.getRequestURI();
|
||||
if (uri == null)
|
||||
uri = URIUtil.SLASH;
|
||||
uri = "/";
|
||||
|
||||
mandatory |= isJSecurityCheck(uri);
|
||||
if (!mandatory)
|
||||
|
|
|
@ -786,7 +786,7 @@ public class ServletContextHandler extends ContextHandler implements Graceful
|
|||
*/
|
||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||
{
|
||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
||||
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||
throw new MalformedURLException(pathInContext);
|
||||
|
||||
Resource baseResource = getBaseResource();
|
||||
|
@ -838,8 +838,8 @@ public class ServletContextHandler extends ContextHandler implements Graceful
|
|||
{
|
||||
Resource resource = getResource(path);
|
||||
|
||||
if (!path.endsWith(URIUtil.SLASH))
|
||||
path = path + URIUtil.SLASH;
|
||||
if (!path.endsWith("/"))
|
||||
path = path + "/";
|
||||
|
||||
HashSet<String> set = new HashSet<>();
|
||||
for (Resource item: resource.list())
|
||||
|
@ -2889,9 +2889,9 @@ public class ServletContextHandler extends ContextHandler implements Graceful
|
|||
if (path == null)
|
||||
return null;
|
||||
if (path.length() == 0)
|
||||
path = URIUtil.SLASH;
|
||||
path = "/";
|
||||
else if (path.charAt(0) != '/')
|
||||
path = URIUtil.SLASH + path;
|
||||
path = "/" + path;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -253,7 +253,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
nuri = servletApiRequest.getContextPath();
|
||||
if (nuri.length() == 0)
|
||||
nuri = URIUtil.SLASH;
|
||||
nuri = "/";
|
||||
}
|
||||
else
|
||||
nuri = savedURI.asString();
|
||||
|
|
|
@ -378,7 +378,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
@Override
|
||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||
{
|
||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
||||
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||
throw new MalformedURLException(pathInContext);
|
||||
|
||||
MalformedURLException mue = null;
|
||||
|
|
|
@ -1384,7 +1384,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
*/
|
||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||
{
|
||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
||||
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||
throw new MalformedURLException(pathInContext);
|
||||
|
||||
Resource baseResource = _coreContextHandler.getBaseResource();
|
||||
|
@ -1476,8 +1476,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
{
|
||||
Resource resource = getResource(path);
|
||||
|
||||
if (!path.endsWith(URIUtil.SLASH))
|
||||
path = path + URIUtil.SLASH;
|
||||
if (!path.endsWith("/"))
|
||||
path = path + "/";
|
||||
|
||||
HashSet<String> set = new HashSet<>();
|
||||
|
||||
|
@ -1814,9 +1814,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
if (path == null)
|
||||
return null;
|
||||
if (path.length() == 0)
|
||||
path = URIUtil.SLASH;
|
||||
path = "/";
|
||||
else if (path.charAt(0) != '/')
|
||||
path = URIUtil.SLASH + path;
|
||||
path = "/" + path;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -233,7 +233,7 @@ public class ResourceService
|
|||
|
||||
String pathInContext = URIUtil.addPaths(servletPath, pathInfo);
|
||||
|
||||
boolean endsWithSlash = (pathInfo == null ? (_pathInfoOnly ? "" : servletPath) : pathInfo).endsWith(URIUtil.SLASH);
|
||||
boolean endsWithSlash = (pathInfo == null ? (_pathInfoOnly ? "" : servletPath) : pathInfo).endsWith("/");
|
||||
boolean checkPrecompressedVariants = _precompressedFormats.length > 0 && !endsWithSlash && !included && reqRanges == null;
|
||||
|
||||
HttpContent content = null;
|
||||
|
@ -650,7 +650,7 @@ public class ResourceService
|
|||
}
|
||||
|
||||
byte[] data = null;
|
||||
String base = URIUtil.addEncodedPaths(request.getRequestURI(), URIUtil.SLASH);
|
||||
String base = URIUtil.addEncodedPaths(request.getRequestURI(), "/");
|
||||
String dir = ResourceListing.getAsXHTML(resource, base, pathInContext.length() > 1, request.getQueryString());
|
||||
if (dir == null)
|
||||
{
|
||||
|
|
|
@ -378,7 +378,7 @@ public class OpenIdAuthenticator extends LoginAuthenticator
|
|||
|
||||
String uri = request.getRequestURI();
|
||||
if (uri == null)
|
||||
uri = URIUtil.SLASH;
|
||||
uri = "/";
|
||||
|
||||
mandatory |= isJSecurityCheck(uri);
|
||||
if (!mandatory)
|
||||
|
|
|
@ -242,7 +242,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
|
||||
String uri = request.getRequestURI();
|
||||
if (uri == null)
|
||||
uri = URIUtil.SLASH;
|
||||
uri = "/";
|
||||
|
||||
mandatory |= isJSecurityCheck(uri);
|
||||
if (!mandatory)
|
||||
|
@ -275,7 +275,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
|||
{
|
||||
nuri = request.getContextPath();
|
||||
if (nuri.length() == 0)
|
||||
nuri = URIUtil.SLASH;
|
||||
nuri = "/";
|
||||
}
|
||||
formAuth = new FormAuthentication(getAuthMethod(), user);
|
||||
}
|
||||
|
|
|
@ -387,7 +387,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
@Override
|
||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||
{
|
||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
||||
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||
throw new MalformedURLException(pathInContext);
|
||||
|
||||
MalformedURLException mue = null;
|
||||
|
|
Loading…
Reference in New Issue