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.FileID;
|
||||||
import org.eclipse.jetty.util.Loader;
|
import org.eclipse.jetty.util.Loader;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
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.ManagedAttribute;
|
||||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||||
import org.eclipse.jetty.util.component.Environment;
|
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
|
// special case of archive (or dir) named "root" is / context
|
||||||
if (contextPath.equalsIgnoreCase("root"))
|
if (contextPath.equalsIgnoreCase("root"))
|
||||||
{
|
{
|
||||||
contextPath = URIUtil.SLASH;
|
contextPath = "/";
|
||||||
}
|
}
|
||||||
// handle root with virtual host form
|
// handle root with virtual host form
|
||||||
else if (StringUtil.startsWithIgnoreCase(contextPath, "root-"))
|
else if (StringUtil.startsWithIgnoreCase(contextPath, "root-"))
|
||||||
|
@ -489,7 +488,7 @@ public class ContextProvider extends ScanningAppProvider
|
||||||
int dash = contextPath.indexOf('-');
|
int dash = contextPath.indexOf('-');
|
||||||
String virtual = contextPath.substring(dash + 1);
|
String virtual = contextPath.substring(dash + 1);
|
||||||
context.setVirtualHosts(Arrays.asList(virtual.split(",")));
|
context.setVirtualHosts(Arrays.asList(virtual.split(",")));
|
||||||
contextPath = URIUtil.SLASH;
|
contextPath = "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure "/" is Prepended to all context paths.
|
// 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.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.eclipse.jetty.util.FileID;
|
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.AbstractLifeCycle;
|
||||||
import org.eclipse.jetty.util.component.Environment;
|
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
|
// special case of archive (or dir) named "root" is / context
|
||||||
if (path.equalsIgnoreCase("root") || path.equalsIgnoreCase("root/"))
|
if (path.equalsIgnoreCase("root") || path.equalsIgnoreCase("root/"))
|
||||||
path = URIUtil.SLASH;
|
path = "/";
|
||||||
|
|
||||||
// Ensure "/" is Prepended to all context paths.
|
// Ensure "/" is Prepended to all context paths.
|
||||||
if (path.charAt(0) != '/')
|
if (path.charAt(0) != '/')
|
||||||
|
|
|
@ -177,15 +177,15 @@ public class ServletPathSpec extends AbstractPathSpec
|
||||||
|
|
||||||
if (info.startsWith("./"))
|
if (info.startsWith("./"))
|
||||||
info = info.substring(2);
|
info = info.substring(2);
|
||||||
if (base.endsWith(URIUtil.SLASH))
|
if (base.endsWith("/"))
|
||||||
if (info.startsWith(URIUtil.SLASH))
|
if (info.startsWith("/"))
|
||||||
path = base + info.substring(1);
|
path = base + info.substring(1);
|
||||||
else
|
else
|
||||||
path = base + info;
|
path = base + info;
|
||||||
else if (info.startsWith(URIUtil.SLASH))
|
else if (info.startsWith("/"))
|
||||||
path = base + info;
|
path = base + info;
|
||||||
else
|
else
|
||||||
path = base + URIUtil.SLASH + info;
|
path = base + "/" + info;
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -225,7 +225,7 @@ public class ResourceListing
|
||||||
|
|
||||||
// Ensure name has a slash if it's a directory
|
// Ensure name has a slash if it's a directory
|
||||||
if (item.isDirectory() && !name.endsWith("/"))
|
if (item.isDirectory() && !name.endsWith("/"))
|
||||||
name += URIUtil.SLASH;
|
name += "/";
|
||||||
|
|
||||||
// Name
|
// Name
|
||||||
buf.append("<tr><td class=\"name\"><a href=\"");
|
buf.append("<tr><td class=\"name\"><a href=\"");
|
||||||
|
|
|
@ -156,7 +156,7 @@ public class ResourceService
|
||||||
// Is this a Range request?
|
// Is this a Range request?
|
||||||
List<String> reqRanges = request.getHeaders().getValuesList(HttpHeader.RANGE.asString());
|
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();
|
boolean checkPrecompressedVariants = _precompressedFormats.size() > 0 && !endsWithSlash && reqRanges.isEmpty();
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -552,7 +552,7 @@ public class ResourceService
|
||||||
return;
|
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());
|
String listing = ResourceListing.getAsXHTML(httpContent.getResource(), base, pathInContext.length() > 1, request.getHttpURI().getQuery());
|
||||||
if (listing == null)
|
if (listing == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,7 +18,6 @@ import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -55,17 +54,10 @@ public final class URIUtil
|
||||||
.with("jar:")
|
.with("jar:")
|
||||||
.build();
|
.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)}
|
* 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, // 0x00 is illegal
|
||||||
false, // 0x01 is illegal
|
false, // 0x01 is illegal
|
||||||
|
@ -197,242 +189,102 @@ public final class URIUtil
|
||||||
false, // 0x7f DEL is illegal
|
false, // 0x7f DEL is illegal
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private static final boolean[] ENCODE_PATH_NEEDS_ENCODING;
|
||||||
|
|
||||||
private URIUtil()
|
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.
|
* Encode a URI path.
|
||||||
* This is the same encoding offered by URLEncoder, except that
|
* 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
|
* @return The encoded path
|
||||||
*/
|
*/
|
||||||
public static String encodePath(String path)
|
public static String encodePath(String path)
|
||||||
{
|
{
|
||||||
if (path == null || path.length() == 0)
|
if (StringUtil.isEmpty(path))
|
||||||
return path;
|
return path;
|
||||||
|
|
||||||
StringBuilder buf = encodePath(null, path, 0);
|
// byte encoding always wins and, if encountered, should be used.
|
||||||
return buf == null ? path : buf.toString();
|
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();
|
||||||
* Encode a URI path.
|
for (int i = 0; i < length; i++)
|
||||||
*
|
|
||||||
* @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++)
|
|
||||||
{
|
{
|
||||||
char c = path.charAt(i);
|
char c = path.charAt(i);
|
||||||
switch (c)
|
if (c > 0x7F) // 8-bit +
|
||||||
{
|
{
|
||||||
case '%':
|
needsByteEncoding = true;
|
||||||
buf.append("%25");
|
break; // have to encode byte by byte now
|
||||||
continue;
|
}
|
||||||
case '?':
|
if (ENCODE_PATH_NEEDS_ENCODING[c])
|
||||||
buf.append("%3F");
|
{
|
||||||
continue;
|
// could be followed by a byte encoding, so no break
|
||||||
case ';':
|
needsEncoding = true;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bytes != null)
|
if (needsByteEncoding)
|
||||||
{
|
return encodePathBytes(path);
|
||||||
for (; i < bytes.length; i++)
|
else if (needsEncoding)
|
||||||
{
|
return encodePathString(path);
|
||||||
byte c = bytes[i];
|
else
|
||||||
switch (c)
|
return path;
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private static String encodePathString(String 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)
|
|
||||||
{
|
{
|
||||||
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.
|
* Decode a raw String and convert any specific URI encoded sequences into characters.
|
||||||
*
|
*
|
||||||
* @param str input raw string
|
* @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.
|
* @return output with specified characters decoded.
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
|
@ -510,41 +362,40 @@ public final class URIUtil
|
||||||
for (int i = idx; i < len; i++)
|
for (int i = idx; i < len; i++)
|
||||||
{
|
{
|
||||||
char c = str.charAt(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);
|
if (f == result)
|
||||||
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)
|
ret.append(result);
|
||||||
{
|
decoded = true;
|
||||||
ret.append(result);
|
break;
|
||||||
decoded = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (decoded)
|
|
||||||
{
|
|
||||||
i += 2;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret.append(c);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (decoded)
|
||||||
|
{
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new IllegalArgumentException("Bad URI % encoding");
|
ret.append(c);
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
default:
|
else
|
||||||
ret.append(c);
|
{
|
||||||
break;
|
throw new IllegalArgumentException("Bad URI % encoding");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.append(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret.toString();
|
return ret.toString();
|
||||||
|
@ -553,11 +404,12 @@ public final class URIUtil
|
||||||
/**
|
/**
|
||||||
* Encode a URI path.
|
* 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 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.
|
* @return The StringBuilder or null if no substitutions required.
|
||||||
*/
|
*/
|
||||||
|
// TODO: remove, only used in URIUtilTest?
|
||||||
public static StringBuilder encodeString(StringBuilder buf,
|
public static StringBuilder encodeString(StringBuilder buf,
|
||||||
String path,
|
String path,
|
||||||
String encode)
|
String encode)
|
||||||
|
@ -730,7 +582,7 @@ public final class URIUtil
|
||||||
{
|
{
|
||||||
// Allow any 8-bit character (as it's likely unicode).
|
// Allow any 8-bit character (as it's likely unicode).
|
||||||
// or any character labeled with true in __uriSupportedCharacters static
|
// 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>
|
* <p>
|
||||||
* Decode only the safe characters in a URI path and strip parameters of UTF-8 path.
|
* 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.
|
* 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.
|
* Canonical paths are also normalized and may be used in string comparisons with other canonical paths.
|
||||||
* <p>
|
* <p>
|
||||||
* For example the path <code>/fo %2fo/b%61r</code> will be normalized to <code>/fo%20%2Fo/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</code>.
|
* 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
|
* @return the canonical path or null if it is non-normal
|
||||||
* @see #decodePath(String)
|
* @see #decodePath(String)
|
||||||
* @see #normalizePath(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)
|
private static String decodeISO88591Path(String path, int offset, int length)
|
||||||
{
|
{
|
||||||
|
@ -989,7 +842,7 @@ public final class URIUtil
|
||||||
/**
|
/**
|
||||||
* Add two encoded URI path segments.
|
* Add two encoded URI path segments.
|
||||||
* Handles null and empty paths, path and query params
|
* 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 p1 URI path segment (should be encoded)
|
||||||
* @param p2 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 (buf.charAt(split - 1) == '/')
|
||||||
{
|
{
|
||||||
if (p2.startsWith(URIUtil.SLASH))
|
if (p2.startsWith("/"))
|
||||||
{
|
{
|
||||||
buf.deleteCharAt(split - 1);
|
buf.deleteCharAt(split - 1);
|
||||||
buf.insert(split - 1, p2);
|
buf.insert(split - 1, p2);
|
||||||
|
@ -1029,7 +882,7 @@ public final class URIUtil
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (p2.startsWith(URIUtil.SLASH))
|
if (p2.startsWith("/"))
|
||||||
buf.insert(split, p2);
|
buf.insert(split, p2);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1043,8 +896,10 @@ public final class URIUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add two Decoded URI path segments.
|
* Add two Decoded URI path segments.
|
||||||
* Handles null and empty paths. Path and query params (eg ?a=b or
|
* <p>
|
||||||
* ;JSESSIONID=xxx) are not handled
|
* 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 p1 URI path segment (should be decoded)
|
||||||
* @param p2 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)
|
if (p2 == null || p2.length() == 0)
|
||||||
return p1;
|
return p1;
|
||||||
|
|
||||||
boolean p1EndsWithSlash = p1.endsWith(SLASH);
|
boolean p1EndsWithSlash = p1.endsWith("/");
|
||||||
boolean p2StartsWithSlash = p2.startsWith(SLASH);
|
boolean p2StartsWithSlash = p2.startsWith("/");
|
||||||
|
|
||||||
if (p1EndsWithSlash && p2StartsWithSlash)
|
if (p1EndsWithSlash && p2StartsWithSlash)
|
||||||
{
|
{
|
||||||
|
@ -1075,25 +930,27 @@ public final class URIUtil
|
||||||
StringBuilder buf = new StringBuilder(p1.length() + p2.length() + 2);
|
StringBuilder buf = new StringBuilder(p1.length() + p2.length() + 2);
|
||||||
buf.append(p1);
|
buf.append(p1);
|
||||||
|
|
||||||
if (p1.endsWith(SLASH))
|
if (p1.endsWith("/"))
|
||||||
{
|
{
|
||||||
if (p2.startsWith(SLASH))
|
if (p2.startsWith("/"))
|
||||||
buf.setLength(buf.length() - 1);
|
buf.setLength(buf.length() - 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!p2.startsWith(SLASH))
|
if (!p2.startsWith("/"))
|
||||||
buf.append(SLASH);
|
buf.append("/");
|
||||||
}
|
}
|
||||||
buf.append(p2);
|
buf.append(p2);
|
||||||
|
|
||||||
return buf.toString();
|
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 path The path which may already contain a query
|
||||||
* @param query The query string to add (if blank, no query is added)
|
* @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)
|
public static String addPathQuery(String path, String query)
|
||||||
{
|
{
|
||||||
|
@ -1142,14 +999,16 @@ public final class URIUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the parent Path.
|
* Return the parent Path.
|
||||||
|
* <p>
|
||||||
* Treat a URI like a directory path and return the parent directory.
|
* Treat a URI like a directory path and return the parent directory.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param p the path to return a parent reference to
|
* @param p the path to return a parent reference to
|
||||||
* @return the parent path of the URI
|
* @return the parent path of the URI
|
||||||
*/
|
*/
|
||||||
public static String parentPath(String p)
|
public static String parentPath(String p)
|
||||||
{
|
{
|
||||||
if (p == null || URIUtil.SLASH.equals(p))
|
if (p == null || "/".equals(p))
|
||||||
return null;
|
return null;
|
||||||
int slash = p.lastIndexOf('/', p.length() - 2);
|
int slash = p.lastIndexOf('/', p.length() - 2);
|
||||||
if (slash >= 0)
|
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.
|
* up until any query or fragment.
|
||||||
* Null is returned if the path is normalized above its root.
|
* Null is returned if the path is normalized above its root.
|
||||||
* </p>
|
* </p>
|
||||||
|
@ -1189,7 +1049,6 @@ public final class URIUtil
|
||||||
case '.':
|
case '.':
|
||||||
if (slash)
|
if (slash)
|
||||||
break loop;
|
break loop;
|
||||||
slash = false;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '?':
|
case '?':
|
||||||
|
@ -1267,8 +1126,8 @@ public final class URIUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Check if a path would be normalized within itself. For example,
|
* <p>Check if a path would be normalized within itself. For example,
|
||||||
* <code>/foo/../../bar</code> is normalized above its root and would
|
* {@code /foo/../../bar} is normalized above its root and would
|
||||||
* thus return false, whilst <code>/foo/./bar/..</code> is normal within itself
|
* thus return false, whilst {@code /foo/./bar/..} is normal within itself
|
||||||
* and would return true.
|
* and would return true.
|
||||||
* @param path The path to check
|
* @param path The path to check
|
||||||
* @return True if the normal form of the path is within the root of the path.
|
* @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.
|
* Null is returned if the path is normalized above its root.
|
||||||
* </p>
|
* </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.
|
* the path segments.
|
||||||
* @return the normalized path, or null if path traversal above root.
|
* @return the normalized path, or null if path traversal above root.
|
||||||
* @see #normalizePathQuery(String)
|
* @see #normalizePathQuery(String)
|
||||||
|
@ -1306,18 +1165,13 @@ public final class URIUtil
|
||||||
char c = path.charAt(i);
|
char c = path.charAt(i);
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '/':
|
case '/' -> slash = true;
|
||||||
slash = true;
|
case '.' ->
|
||||||
break;
|
{
|
||||||
|
|
||||||
case '.':
|
|
||||||
if (slash)
|
if (slash)
|
||||||
break loop;
|
break loop;
|
||||||
slash = false;
|
}
|
||||||
break;
|
default -> slash = false;
|
||||||
|
|
||||||
default:
|
|
||||||
slash = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
@ -1339,14 +1193,15 @@ public final class URIUtil
|
||||||
char c = path.charAt(i);
|
char c = path.charAt(i);
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '/':
|
case '/' ->
|
||||||
|
{
|
||||||
if (doDotsSlash(canonical, dots))
|
if (doDotsSlash(canonical, dots))
|
||||||
return null;
|
return null;
|
||||||
slash = true;
|
slash = true;
|
||||||
dots = 0;
|
dots = 0;
|
||||||
break;
|
}
|
||||||
|
case '.' ->
|
||||||
case '.':
|
{
|
||||||
// Count dots only if they are leading in the segment
|
// Count dots only if they are leading in the segment
|
||||||
if (dots > 0)
|
if (dots > 0)
|
||||||
dots++;
|
dots++;
|
||||||
|
@ -1355,15 +1210,16 @@ public final class URIUtil
|
||||||
else
|
else
|
||||||
canonical.append('.');
|
canonical.append('.');
|
||||||
slash = false;
|
slash = false;
|
||||||
break;
|
}
|
||||||
|
default ->
|
||||||
default:
|
{
|
||||||
// Add leading dots to the path
|
// Add leading dots to the path
|
||||||
while (dots-- > 0)
|
while (dots-- > 0)
|
||||||
canonical.append('.');
|
canonical.append('.');
|
||||||
canonical.append(c);
|
canonical.append(c);
|
||||||
dots = 0;
|
dots = 0;
|
||||||
slash = false;
|
slash = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
@ -1420,7 +1276,7 @@ public final class URIUtil
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert a path to a compact form.
|
* 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
|
* @param path the path to compact
|
||||||
* @return the compacted path
|
* @return the compacted path
|
||||||
|
@ -1582,47 +1438,36 @@ public final class URIUtil
|
||||||
*/
|
*/
|
||||||
public static void appendSchemeHostPort(StringBuffer url, String scheme, String server, int port)
|
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));
|
switch (scheme)
|
||||||
|
|
||||||
if (port > 0)
|
|
||||||
{
|
{
|
||||||
switch (scheme)
|
case "http":
|
||||||
{
|
if (port != 80)
|
||||||
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);
|
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)
|
* Encode characters in a path to ensure they only contain safe encodings suitable for both
|
||||||
{
|
* {@link URI} and {@link Paths#get(URI)} usage.
|
||||||
try
|
*
|
||||||
{
|
* @param path the path to encode
|
||||||
String safeDecodedUriA = ensureSafeEncoding(uriA);
|
* @return the returned path with only safe encodings
|
||||||
String safeDecodedUriB = ensureSafeEncoding(uriB);
|
*/
|
||||||
return safeDecodedUriA.equals(safeDecodedUriB);
|
public static String encodePathSafeEncoding(String path)
|
||||||
}
|
|
||||||
catch (IllegalArgumentException e)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static String ensureSafeEncoding(String path)
|
|
||||||
{
|
{
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return null;
|
return null;
|
||||||
|
@ -1762,42 +1607,6 @@ public final class URIUtil
|
||||||
return ((codepoint == '?') || (codepoint == '#'));
|
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.
|
* 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
|
// ensure that the base has a safe encoding suitable for both
|
||||||
// URI and Paths.get(URI) later usage
|
// URI and Paths.get(URI) later usage
|
||||||
path = ensureSafeEncoding(path);
|
path = encodePathSafeEncoding(path);
|
||||||
pathLen = path.length();
|
pathLen = path.length();
|
||||||
|
|
||||||
if (base.length() == 0)
|
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
|
* Combine two query strings into one. Each query string should not contain the beginning '{@code ?}' character, but
|
||||||
* may contain multiple parameters separated by the '{@literal &}' character.
|
* may contain multiple parameters separated by the '{@code &}' character.
|
||||||
* @param query1 the first query string.
|
* @param query1 the first query string.
|
||||||
* @param query2 the second query string.
|
* @param query2 the second query string.
|
||||||
* @return the combination of the two query strings.
|
* @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>
|
* <p>
|
||||||
* Each part of the input string could be path references (unix or windows style), or string URI references.
|
* Each part of the input string could be path references (unix or windows style), or string URI references.
|
||||||
* </p>
|
* </p>
|
||||||
* <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>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param str the input string of references
|
* @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.
|
* 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)
|
* 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.
|
* @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)
|
* @see FileID#isArchive(URI)
|
||||||
*/
|
*/
|
||||||
public static URI toJarFileUri(URI 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.
|
* 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.
|
* Take out the container archive name URI from a {@code jar:file:${container-name}!/} URI.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param uri the input URI
|
* @param uri the input URI
|
||||||
* @return the container String if a {@code jar} scheme, or just the URI untouched.
|
* @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))
|
if (URIUtil.isNotNormalWithinSelf(subUriPath))
|
||||||
throw new IllegalArgumentException(subUriPath);
|
throw new IllegalArgumentException(subUriPath);
|
||||||
|
|
||||||
if (subUriPath.length() == 0 || URIUtil.SLASH.equals(subUriPath))
|
if (subUriPath.length() == 0 || "/".equals(subUriPath))
|
||||||
{
|
{
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,8 +182,8 @@ public class PathResource extends Resource
|
||||||
if (Files.isDirectory(path))
|
if (Files.isDirectory(path))
|
||||||
{
|
{
|
||||||
String uriString = uri.toASCIIString();
|
String uriString = uri.toASCIIString();
|
||||||
if (!uriString.endsWith(URIUtil.SLASH))
|
if (!uriString.endsWith("/"))
|
||||||
uri = URIUtil.correctFileURI(URI.create(uriString + URIUtil.SLASH));
|
uri = URIUtil.correctFileURI(URI.create(uriString + "/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.path = path;
|
this.path = path;
|
||||||
|
@ -282,7 +282,7 @@ public class PathResource extends Resource
|
||||||
if (URIUtil.isNotNormalWithinSelf(subUriPath))
|
if (URIUtil.isNotNormalWithinSelf(subUriPath))
|
||||||
throw new IllegalArgumentException(subUriPath);
|
throw new IllegalArgumentException(subUriPath);
|
||||||
|
|
||||||
if (URIUtil.SLASH.equals(subUriPath))
|
if ("/".equals(subUriPath))
|
||||||
return this;
|
return this;
|
||||||
|
|
||||||
URI uri = getURI();
|
URI uri = getURI();
|
||||||
|
|
|
@ -66,7 +66,9 @@ public class URIUtilTest
|
||||||
Arguments.of("/context/'list'/\"me\"/;<script>window.alert('xss');</script>",
|
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"),
|
"/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%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)
|
public void testEncodePath(String rawPath, String expectedEncoded)
|
||||||
{
|
{
|
||||||
// test basic encode/decode
|
// test basic encode/decode
|
||||||
StringBuilder buf = new StringBuilder();
|
String result = URIUtil.encodePath(rawPath);
|
||||||
buf.setLength(0);
|
assertEquals(expectedEncoded, result);
|
||||||
URIUtil.encodePath(buf, rawPath);
|
|
||||||
assertEquals(expectedEncoded, buf.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -565,7 +565,7 @@ public class URIUtilTest
|
||||||
assertThat(actual, is(expected));
|
assertThat(actual, is(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<Arguments> ensureSafeEncodingSource()
|
public static Stream<Arguments> encodePathSafeEncodingSource()
|
||||||
{
|
{
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
Arguments.of("/foo", "/foo"),
|
Arguments.of("/foo", "/foo"),
|
||||||
|
@ -589,10 +589,10 @@ public class URIUtilTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("ensureSafeEncodingSource")
|
@MethodSource("encodePathSafeEncodingSource")
|
||||||
public void testEnsureSafeEncoding(String input, String expected)
|
public void testEncodePathSafeEncoding(String input, String expected)
|
||||||
{
|
{
|
||||||
assertThat(URIUtil.ensureSafeEncoding(input), is(expected));
|
assertThat(URIUtil.encodePathSafeEncoding(input), is(expected));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Stream<Arguments> compactPathSource()
|
public static Stream<Arguments> compactPathSource()
|
||||||
|
@ -637,139 +637,6 @@ public class URIUtilTest
|
||||||
assertEquals(expectedPath, actual, String.format("parent %s", path));
|
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()
|
public static Stream<Arguments> correctBadFileURICases()
|
||||||
{
|
{
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
|
@ -811,17 +678,18 @@ public class URIUtilTest
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCorrectBadFileURIActualFile() throws Exception
|
public void testCorrectBadFileURIActualFile(WorkDir workDir) throws Exception
|
||||||
{
|
{
|
||||||
File file = MavenTestingUtils.getTargetFile("testCorrectBadFileURIActualFile.txt");
|
Path testfile = workDir.getEmptyPathDir().resolve("testCorrectBadFileURIActualFile.txt");
|
||||||
FS.touch(file);
|
FS.touch(testfile);
|
||||||
|
|
||||||
URI expectedUri = file.toPath().toUri();
|
URI expectedUri = testfile.toUri(); // correct URI with `://`
|
||||||
|
|
||||||
assertThat(expectedUri.toASCIIString(), containsString("://"));
|
assertThat(expectedUri.toASCIIString(), containsString("://"));
|
||||||
|
|
||||||
URI fileUri = file.toURI();
|
File file = testfile.toFile();
|
||||||
URI fileUrlUri = file.toURL().toURI();
|
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
|
// If these 2 tests start failing, that means Java itself has been fixed
|
||||||
assertThat(fileUri.toASCIIString(), not(containsString("://")));
|
assertThat(fileUri.toASCIIString(), not(containsString("://")));
|
||||||
|
@ -831,29 +699,6 @@ public class URIUtilTest
|
||||||
assertThat(URIUtil.correctFileURI(fileUrlUri).toASCIIString(), is(expectedUri.toASCIIString()));
|
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()
|
public static Stream<Arguments> encodeSpecific()
|
||||||
{
|
{
|
||||||
return Stream.of(
|
return Stream.of(
|
||||||
|
@ -1040,12 +885,12 @@ public class URIUtilTest
|
||||||
builder.append(i);
|
builder.append(i);
|
||||||
String path = builder.toString();
|
String path = builder.toString();
|
||||||
String encoded = URIUtil.encodePath(path);
|
String encoded = URIUtil.encodePath(path);
|
||||||
// Check endoded is visible
|
// Check encoded is visible
|
||||||
for (char c : encoded.toCharArray())
|
for (char c : encoded.toCharArray())
|
||||||
{
|
{
|
||||||
assertTrue(c > 0x20 && c < 0x80);
|
assertTrue(c > 0x20 && c < 0x7f);
|
||||||
assertFalse(Character.isWhitespace(c));
|
assertFalse(Character.isWhitespace(c));
|
||||||
assertFalse(Character.isISOControl(c));
|
assertFalse(Character.isISOControl(c), "isISOControl(0x%2x)".formatted((byte)c));
|
||||||
}
|
}
|
||||||
// check decode to original
|
// check decode to original
|
||||||
String decoded = URIUtil.decodePath(encoded);
|
String decoded = URIUtil.decodePath(encoded);
|
||||||
|
|
|
@ -389,7 +389,7 @@ public class OpenIdAuthenticator extends LoginAuthenticator
|
||||||
|
|
||||||
String uri = request.getRequestURI();
|
String uri = request.getRequestURI();
|
||||||
if (uri == null)
|
if (uri == null)
|
||||||
uri = URIUtil.SLASH;
|
uri = "/";
|
||||||
|
|
||||||
mandatory |= isJSecurityCheck(uri);
|
mandatory |= isJSecurityCheck(uri);
|
||||||
if (!mandatory)
|
if (!mandatory)
|
||||||
|
|
|
@ -786,7 +786,7 @@ public class ServletContextHandler extends ContextHandler implements Graceful
|
||||||
*/
|
*/
|
||||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||||
{
|
{
|
||||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||||
throw new MalformedURLException(pathInContext);
|
throw new MalformedURLException(pathInContext);
|
||||||
|
|
||||||
Resource baseResource = getBaseResource();
|
Resource baseResource = getBaseResource();
|
||||||
|
@ -838,8 +838,8 @@ public class ServletContextHandler extends ContextHandler implements Graceful
|
||||||
{
|
{
|
||||||
Resource resource = getResource(path);
|
Resource resource = getResource(path);
|
||||||
|
|
||||||
if (!path.endsWith(URIUtil.SLASH))
|
if (!path.endsWith("/"))
|
||||||
path = path + URIUtil.SLASH;
|
path = path + "/";
|
||||||
|
|
||||||
HashSet<String> set = new HashSet<>();
|
HashSet<String> set = new HashSet<>();
|
||||||
for (Resource item: resource.list())
|
for (Resource item: resource.list())
|
||||||
|
@ -2889,9 +2889,9 @@ public class ServletContextHandler extends ContextHandler implements Graceful
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return null;
|
return null;
|
||||||
if (path.length() == 0)
|
if (path.length() == 0)
|
||||||
path = URIUtil.SLASH;
|
path = "/";
|
||||||
else if (path.charAt(0) != '/')
|
else if (path.charAt(0) != '/')
|
||||||
path = URIUtil.SLASH + path;
|
path = "/" + path;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -253,7 +253,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
||||||
{
|
{
|
||||||
nuri = servletApiRequest.getContextPath();
|
nuri = servletApiRequest.getContextPath();
|
||||||
if (nuri.length() == 0)
|
if (nuri.length() == 0)
|
||||||
nuri = URIUtil.SLASH;
|
nuri = "/";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
nuri = savedURI.asString();
|
nuri = savedURI.asString();
|
||||||
|
|
|
@ -378,7 +378,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
@Override
|
@Override
|
||||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||||
{
|
{
|
||||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||||
throw new MalformedURLException(pathInContext);
|
throw new MalformedURLException(pathInContext);
|
||||||
|
|
||||||
MalformedURLException mue = null;
|
MalformedURLException mue = null;
|
||||||
|
|
|
@ -1384,7 +1384,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
*/
|
*/
|
||||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||||
{
|
{
|
||||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||||
throw new MalformedURLException(pathInContext);
|
throw new MalformedURLException(pathInContext);
|
||||||
|
|
||||||
Resource baseResource = _coreContextHandler.getBaseResource();
|
Resource baseResource = _coreContextHandler.getBaseResource();
|
||||||
|
@ -1476,8 +1476,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
{
|
{
|
||||||
Resource resource = getResource(path);
|
Resource resource = getResource(path);
|
||||||
|
|
||||||
if (!path.endsWith(URIUtil.SLASH))
|
if (!path.endsWith("/"))
|
||||||
path = path + URIUtil.SLASH;
|
path = path + "/";
|
||||||
|
|
||||||
HashSet<String> set = new HashSet<>();
|
HashSet<String> set = new HashSet<>();
|
||||||
|
|
||||||
|
@ -1814,9 +1814,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return null;
|
return null;
|
||||||
if (path.length() == 0)
|
if (path.length() == 0)
|
||||||
path = URIUtil.SLASH;
|
path = "/";
|
||||||
else if (path.charAt(0) != '/')
|
else if (path.charAt(0) != '/')
|
||||||
path = URIUtil.SLASH + path;
|
path = "/" + path;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
|
@ -233,7 +233,7 @@ public class ResourceService
|
||||||
|
|
||||||
String pathInContext = URIUtil.addPaths(servletPath, pathInfo);
|
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;
|
boolean checkPrecompressedVariants = _precompressedFormats.length > 0 && !endsWithSlash && !included && reqRanges == null;
|
||||||
|
|
||||||
HttpContent content = null;
|
HttpContent content = null;
|
||||||
|
@ -650,7 +650,7 @@ public class ResourceService
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data = null;
|
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());
|
String dir = ResourceListing.getAsXHTML(resource, base, pathInContext.length() > 1, request.getQueryString());
|
||||||
if (dir == null)
|
if (dir == null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -378,7 +378,7 @@ public class OpenIdAuthenticator extends LoginAuthenticator
|
||||||
|
|
||||||
String uri = request.getRequestURI();
|
String uri = request.getRequestURI();
|
||||||
if (uri == null)
|
if (uri == null)
|
||||||
uri = URIUtil.SLASH;
|
uri = "/";
|
||||||
|
|
||||||
mandatory |= isJSecurityCheck(uri);
|
mandatory |= isJSecurityCheck(uri);
|
||||||
if (!mandatory)
|
if (!mandatory)
|
||||||
|
|
|
@ -242,7 +242,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
||||||
|
|
||||||
String uri = request.getRequestURI();
|
String uri = request.getRequestURI();
|
||||||
if (uri == null)
|
if (uri == null)
|
||||||
uri = URIUtil.SLASH;
|
uri = "/";
|
||||||
|
|
||||||
mandatory |= isJSecurityCheck(uri);
|
mandatory |= isJSecurityCheck(uri);
|
||||||
if (!mandatory)
|
if (!mandatory)
|
||||||
|
@ -275,7 +275,7 @@ public class FormAuthenticator extends LoginAuthenticator
|
||||||
{
|
{
|
||||||
nuri = request.getContextPath();
|
nuri = request.getContextPath();
|
||||||
if (nuri.length() == 0)
|
if (nuri.length() == 0)
|
||||||
nuri = URIUtil.SLASH;
|
nuri = "/";
|
||||||
}
|
}
|
||||||
formAuth = new FormAuthentication(getAuthMethod(), user);
|
formAuth = new FormAuthentication(getAuthMethod(), user);
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,7 +387,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
@Override
|
@Override
|
||||||
public Resource getResource(String pathInContext) throws MalformedURLException
|
public Resource getResource(String pathInContext) throws MalformedURLException
|
||||||
{
|
{
|
||||||
if (pathInContext == null || !pathInContext.startsWith(URIUtil.SLASH))
|
if (pathInContext == null || !pathInContext.startsWith("/"))
|
||||||
throw new MalformedURLException(pathInContext);
|
throw new MalformedURLException(pathInContext);
|
||||||
|
|
||||||
MalformedURLException mue = null;
|
MalformedURLException mue = null;
|
||||||
|
|
Loading…
Reference in New Issue