From d369adf55bcf0e1c6023a84c34b32abb71de3c97 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 27 Jul 2022 09:58:50 +1000 Subject: [PATCH] Jetty 12.0.x canonical uri (#8343) Somehow the URIUtil class had switched over the meaning of normal and canonical. This PR renames them to correct this: * canonical paths are always normal * Always canonicalize paths passed from the application * Switch the URIUtil names for canonical and normal --- .../java/org/eclipse/jetty/http/HttpURI.java | 9 +- .../org/eclipse/jetty/http/HttpURITest.java | 2 +- .../org/eclipse/jetty/server/Request.java | 4 +- .../java/org/eclipse/jetty/util/URIUtil.java | 174 ++++++++---------- .../eclipse/jetty/util/resource/Resource.java | 5 +- ...est.java => URIUtilNormalizePathTest.java} | 20 +- .../org/eclipse/jetty/util/URIUtilTest.java | 19 +- .../ee10/maven/plugin/MavenWebAppContext.java | 4 +- .../maven/plugin/SelectiveJarResource.java | 5 +- .../jetty/ee10/servlet/ServletChannel.java | 2 +- .../ee10/servlet/ServletContextHandler.java | 12 +- .../ee9/maven/plugin/MavenWebAppContext.java | 4 +- .../maven/plugin/SelectiveJarResource.java | 2 +- .../jetty/ee9/nested/ContextHandler.java | 16 +- .../eclipse/jetty/ee9/nested/Response.java | 4 +- 15 files changed, 137 insertions(+), 145 deletions(-) rename jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/{URIUtilCanonicalPathTest.java => URIUtilNormalizePathTest.java} (89%) diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java index e96f7ae9a5c..fe2d1cece9b 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpURI.java @@ -381,7 +381,7 @@ public interface HttpURI public String getCanonicalPath() { if (_canonicalPath == null && _path != null) - _canonicalPath = URIUtil.canonicalPath(URIUtil.normalizePath(_path)); + _canonicalPath = URIUtil.canonicalPath(_path); return _canonicalPath; } @@ -532,7 +532,7 @@ public interface HttpURI * Remove Dot Segments * algorithm. This results in some ambiguity as dot segments can result from later * parameter removal or % encoding expansion, that are not removed from the URI - * by {@link URIUtil#canonicalPath(String)}. Thus this class flags such ambiguous + * by {@link URIUtil#normalizePath(String)}. Thus this class flags such ambiguous * path segments, so that they may be rejected by the server if so configured. */ private static final Index __ambiguousSegments = new Index.Builder() @@ -750,7 +750,7 @@ public interface HttpURI public String getCanonicalPath() { if (_canonicalPath == null && _path != null) - _canonicalPath = URIUtil.canonicalPath(URIUtil.normalizePath(_path)); + _canonicalPath = URIUtil.canonicalPath(_path); return _canonicalPath; } @@ -1412,8 +1412,7 @@ public interface HttpURI { // The RFC requires this to be canonical before decoding, but this can leave dot segments and dot dot segments // which are not canonicalized and could be used in an attempt to bypass security checks. - String decodedNonCanonical = URIUtil.normalizePath(_path); - _canonicalPath = URIUtil.canonicalPath(decodedNonCanonical); + _canonicalPath = URIUtil.canonicalPath(_path); if (_canonicalPath == null) throw new IllegalArgumentException("Bad URI"); } diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java index 3a7094d0e59..ab873e62344 100644 --- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java +++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpURITest.java @@ -487,8 +487,8 @@ public class HttpURITest try { HttpURI uri = HttpURI.from(input); - assertThat(uri.getCanonicalPath(), is(canonicalPath)); assertThat(uri.getDecodedPath(), is(decodedPath)); + EnumSet ambiguous = EnumSet.copyOf(expected); ambiguous.retainAll(EnumSet.complementOf(EnumSet.of(Violation.UTF16_ENCODINGS))); diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 528e0e7dc45..3d0bd354315 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -393,14 +393,14 @@ public interface Request extends Attributes, Content.Source if (location.startsWith("/")) { // absolute in context - location = URIUtil.canonicalURI(location); + location = URIUtil.normalizePathQuery(location); } else { // relative to request String path = uri.getPath(); String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path); - location = URIUtil.canonicalURI(URIUtil.addEncodedPaths(parent, location)); + location = URIUtil.normalizePathQuery(URIUtil.addEncodedPaths(parent, location)); if (location != null && !location.startsWith("/")) url.append('/'); } diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java index f8a5417f89a..18045f18bdb 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/URIUtil.java @@ -45,7 +45,7 @@ public class URIUtil public static final Charset __CHARSET = StandardCharsets.UTF_8; /** - * The characters that are supported by the URI class and that can be decoded by {@link #normalizePath(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[] { @@ -81,12 +81,12 @@ public class URIUtil false, // 0x1d is illegal false, // 0x1e is illegal false, // 0x1f is illegal - false, // 0x20 is illegal + false, // 0x20 space is illegal true, // 0x21 - false, // 0x22 is illegal - false, // # is special + false, // 0x22 " is illegal + false, // 0x23 # is special true, // 0x24 - false, // % must remain encoded + false, // 0x25 % must remain encoded true, // 0x26 true, // 0x27 true, // 0x28 @@ -96,7 +96,7 @@ public class URIUtil true, // 0x2c true, // 0x2d true, // 0x2e - false, // / is a delimiter + false, // 0x2f / is a delimiter true, // 0x30 true, // 0x31 true, // 0x32 @@ -108,11 +108,11 @@ public class URIUtil true, // 0x38 true, // 0x39 true, // 0x3a - false, // ; is path parameter - false, // 0x3c is illegal + false, // 0x3b ; is path parameter + false, // 0x3c < is illegal true, // 0x3d - false, // 0x3e is illegal - false, // ? is special + false, // 0x3e > is illegal + false, // 0x3f ? is special true, // 0x40 true, // 0x41 true, // 0x42 @@ -140,12 +140,12 @@ public class URIUtil true, // 0x58 true, // 0x59 true, // 0x5a - false, // 0x5b is illegal - false, // 0x5c is illegal - false, // 0x5d is illegal - false, // 0x5e is illegal + false, // 0x5b [ is illegal + false, // 0x5c \ is illegal + false, // 0x5d ] is illegal + false, // 0x5e ^ is illegal true, // 0x5f - false, // 0x60 is illegal + false, // 0x60 ` is illegal true, // 0x61 true, // 0x62 true, // 0x63 @@ -172,11 +172,11 @@ public class URIUtil true, // 0x78 true, // 0x79 true, // 0x7a - false, // 0x7b is illegal - false, // 0x7c is illegal - false, // 0x7d is illegal + false, // 0x7b { is illegal + false, // 0x7c | is illegal + false, // 0x7d } is illegal true, // 0x7e - false, // 0x7f is illegal + false, // 0x7f DEL is illegal }; private URIUtil() @@ -576,8 +576,8 @@ public class URIUtil /** * Decode a URI path and strip parameters - * @see #normalizePath(String) * @see #canonicalPath(String) + * @see #normalizePath(String) */ public static String decodePath(String path) { @@ -586,8 +586,8 @@ public class URIUtil /** * Decode a URI path and strip parameters of UTF-8 path - * @see #normalizePath(String, int, int) * @see #canonicalPath(String) + * @see #normalizePath(String) */ public static String decodePath(String path, int offset, int length) { @@ -700,47 +700,32 @@ public class URIUtil } /** - * Normalize a URI path to a form that is unambiguous and safe to use with the JVM {@link URI} class. + * Canonicalize a URI path to a form that is unambiguous and safe to use with the JVM {@link URI} class. *

* 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. - * The resulting URI path may be used in string comparisons with other normalized paths. + * Canonical paths are also normalized and may be used in string comparisons with other canonical paths. *

* For example the path /fo %2fo/b%61r will be normalized to /fo%20%2Fo/bar, * whilst {@link #decodePath(String)} would result in the ambiguous and URI illegal /fo /o/bar. - * + * @return the canonical path or null if it is non-normal * @see #decodePath(String) - * @see #canonicalPath(String) + * @see #normalizePath(String) * @see URI */ - public static String normalizePath(String path) - { - return normalizePath(path, 0, path.length()); - } - - /** - * Normalize a URI path to a form that is unambiguous and safe to use with the JVM {@link URI} class. - *

- * 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. - * The resulting URI path may be used in string comparisons with other normalized paths. - *

- * For example the path /fo %2fo/b%61r will be normalized to /fo%20%2Fo/bar, - * whilst {@link #decodePath(String)} would result in the ambiguous and URI illegal /fo /o/bar. - * - * @see #decodePath(String, int, int) - * @see #canonicalPath(String) - * @see URI - */ - public static String normalizePath(String path, int offset, int length) + public static String canonicalPath(String path) { + if (path == null) + return null; try { + Utf8StringBuilder builder = null; - int end = offset + length; - for (int i = offset; i < end; i++) + int end = path.length(); + boolean slash = true; + boolean normal = true; + for (int i = 0; i < end; i++) { char c = path.charAt(i); switch (c) @@ -749,7 +734,7 @@ public class URIUtil if (builder == null) { builder = new Utf8StringBuilder(path.length()); - builder.append(path, offset, i - offset); + builder.append(path, 0, i); } if ((i + 2) < end) { @@ -762,7 +747,12 @@ public class URIUtil { char[] chars = Character.toChars(code); for (char ch : chars) + { builder.append(ch); + if (slash && ch == '.') + normal = false; + slash = false; + } } i += 5; } @@ -770,7 +760,11 @@ public class URIUtil { int code = TypeUtil.convertHexDigit(u) * 16 + TypeUtil.convertHexDigit(path.charAt(i + 2)); if (isSafeElseEncode(code, builder)) + { builder.append((byte)(0xff & code)); + if (slash && code == '.') + normal = false; + } i += 2; } } @@ -784,7 +778,7 @@ public class URIUtil if (builder == null) { builder = new Utf8StringBuilder(path.length()); - builder.append(path, offset, i - offset); + builder.append(path, 0, i); } while (++i < end) @@ -802,29 +796,35 @@ public class URIUtil builder.append(c); break; + case '.': + if (slash) + normal = false; + if (builder != null) + builder.append(c); + break; + default: if (builder == null && !isSafe(c)) { builder = new Utf8StringBuilder(path.length()); - builder.append(path, offset, i - offset); + builder.append(path, 0, i); } if (builder != null && isSafeElseEncode(c, builder)) builder.append(c); break; } + + slash = c == '/'; } - if (builder != null) - return builder.toString(); - if (offset == 0 && length == path.length()) - return path; - return path.substring(offset, end); + String canonical = (builder != null) ? builder.toString() : path; + return normal ? canonical : normalizePath(canonical); } catch (NotUtf8Exception e) { if (LOG.isDebugEnabled()) - LOG.debug("{} {}", path.substring(offset, offset + length), e.toString()); + LOG.debug("{} {}", path, e.toString()); throw e; } catch (IllegalArgumentException e) @@ -1078,29 +1078,28 @@ public class URIUtil } /** - * Convert a partial URI to a canonical form. - *

- * All segments of "." and ".." are factored out. - * Null is returned if the path tries to .. above its root. + *

Normalize a URI path and query by factoring out all segments of "." and ".." + * up until any query or fragment. + * Null is returned if the path is normalized above its root. *

* - * @param uri the encoded URI from the path onwards, which may contain query strings and/or fragments - * @return the canonical path, or null if path traversal above root. - * @see #canonicalPath(String) + * @param pathQuery the encoded URI from the path onwards, which may contain query strings and/or fragments + * @return the normalized path, or null if path traversal above root. + * @see #normalizePath(String) */ - public static String canonicalURI(String uri) + public static String normalizePathQuery(String pathQuery) { - if (uri == null || uri.isEmpty()) - return uri; + if (pathQuery == null || pathQuery.isEmpty()) + return pathQuery; boolean slash = true; - int end = uri.length(); + int end = pathQuery.length(); int i = 0; // Initially just loop looking if we may need to normalize loop: while (i < end) { - char c = uri.charAt(i); + char c = pathQuery.charAt(i); switch (c) { case '/': @@ -1116,7 +1115,7 @@ public class URIUtil case '?': case '#': // Nothing to normalize so return original path - return uri; + return pathQuery; default: slash = false; @@ -1127,18 +1126,18 @@ public class URIUtil // Nothing to normalize so return original path if (i == end) - return uri; + return pathQuery; // We probably need to normalize, so copy to path so far into builder - StringBuilder canonical = new StringBuilder(uri.length()); - canonical.append(uri, 0, i); + StringBuilder canonical = new StringBuilder(pathQuery.length()); + canonical.append(pathQuery, 0, i); // Loop looking for single and double dot segments int dots = 1; i++; loop : while (i < end) { - char c = uri.charAt(i); + char c = pathQuery.charAt(i); switch (c) { case '/': @@ -1181,37 +1180,24 @@ public class URIUtil // append any query if (i < end) - canonical.append(uri, i, end); + canonical.append(pathQuery, i, end); return canonical.toString(); } /** - * @param path the encoded URI from the path onwards, which may contain query strings and/or fragments - * @return the canonical path, or null if path traversal above root. - * @deprecated Use {@link #canonicalURI(String)} - */ - @Deprecated - public static String canonicalEncodedPath(String path) - { - return canonicalURI(path); - } - - /** - * Convert a decoded URI path to a canonical form. - *

- * All segments of "." and ".." are factored out. - * Null is returned if the path tries to .. above its root. + *

Normalize a URI path by factoring out all segments of "." and "..". + * Null is returned if the path is normalized above its root. *

* * @param path the decoded URI path to convert. Any special characters (e.g. '?', "#") are assumed to be part of * the path segments. - * @return the canonical path, or null if path traversal above root. - * @see #canonicalURI(String) - * @see #normalizePath(String) + * @return the normalized path, or null if path traversal above root. + * @see #normalizePathQuery(String) + * @see #canonicalPath(String) * @see #decodePath(String) */ - public static String canonicalPath(String path) + public static String normalizePath(String path) { if (path == null || path.isEmpty()) return path; diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java index 6c1518a1800..93bbc75ab6d 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/resource/Resource.java @@ -606,7 +606,8 @@ public abstract class Resource implements ResourceFactory // Check that the path is within the root, // but use the original path to create the // resource, to preserve aliasing. - if (URIUtil.canonicalPath(subUriPath) == null) + // TODO should we canonicalize here? Or perhaps just do a URI safe encoding + if (URIUtil.normalizePath(subUriPath) == null) throw new IOException(subUriPath); if (URIUtil.SLASH.equals(subUriPath)) @@ -687,7 +688,7 @@ public abstract class Resource implements ResourceFactory public String getListHTML(String base, boolean parent, String query) throws IOException { // This method doesn't check aliases, so it is OK to canonicalize here. - base = URIUtil.canonicalPath(base); + base = URIUtil.normalizePath(base); if (base == null || !isDirectory()) return null; diff --git a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilCanonicalPathTest.java b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilNormalizePathTest.java similarity index 89% rename from jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilCanonicalPathTest.java rename to jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilNormalizePathTest.java index 8442fee8eeb..828704940bb 100644 --- a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilCanonicalPathTest.java +++ b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilNormalizePathTest.java @@ -24,11 +24,11 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; -public class URIUtilCanonicalPathTest +public class URIUtilNormalizePathTest { public static Stream paths() { - String[][] canonical = + String[][] unNormalAndNormal = { // Examples from RFC {"/a/b/c/./../../g", "/a/g"}, @@ -130,7 +130,7 @@ public class URIUtilCanonicalPathTest }; ArrayList ret = new ArrayList<>(); - for (String[] args : canonical) + for (String[] args : unNormalAndNormal) { ret.add(Arguments.of((Object[])args)); } @@ -139,23 +139,23 @@ public class URIUtilCanonicalPathTest @ParameterizedTest @MethodSource("paths") - public void testCanonicalPath(String input, String expectedResult) + public void testNormalizePath(String input, String expectedResult) { // Check canonicalPath - assertThat(URIUtil.canonicalPath(input), is(expectedResult)); + assertThat(URIUtil.normalizePath(input), is(expectedResult)); // Check canonicalURI if (expectedResult == null) { - assertThat(URIUtil.canonicalURI(input), nullValue()); + assertThat(URIUtil.normalizePathQuery(input), nullValue()); } else { // mostly encodedURI will be the same - assertThat(URIUtil.canonicalURI(input), is(expectedResult)); + assertThat(URIUtil.normalizePathQuery(input), is(expectedResult)); // but will terminate on fragments and queries - assertThat(URIUtil.canonicalURI(input + "?/foo/../bar/."), is(expectedResult + "?/foo/../bar/.")); - assertThat(URIUtil.canonicalURI(input + "#/foo/../bar/."), is(expectedResult + "#/foo/../bar/.")); + assertThat(URIUtil.normalizePathQuery(input + "?/foo/../bar/."), is(expectedResult + "?/foo/../bar/.")); + assertThat(URIUtil.normalizePathQuery(input + "#/foo/../bar/."), is(expectedResult + "#/foo/../bar/.")); } } @@ -174,7 +174,7 @@ public class URIUtilCanonicalPathTest @MethodSource("queries") public void testQuery(String input, String expectedPath) { - String actual = URIUtil.canonicalURI(input); + String actual = URIUtil.normalizePathQuery(input); assertThat(actual, is(expectedPath)); } } diff --git a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java index ebc123cbabe..e75607cefeb 100644 --- a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java +++ b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/URIUtilTest.java @@ -136,20 +136,31 @@ public class URIUtilTest // Deprecated Microsoft Percent-U encoding arguments.add(Arguments.of("abc%u3040", "abc\u3040", "abc\u3040")); + + // Canonical paths are also normalized + arguments.add(Arguments.of("./bar", "bar", "./bar")); + arguments.add(Arguments.of("/foo/./bar", "/foo/bar", "/foo/./bar")); + arguments.add(Arguments.of("/foo/../bar", "/bar", "/foo/../bar")); + arguments.add(Arguments.of("/foo/.../bar", "/foo/.../bar", "/foo/.../bar")); + arguments.add(Arguments.of("/foo/%2e/bar", "/foo/bar", "/foo/./bar")); // Not by the RFC, but safer + arguments.add(Arguments.of("/foo/%2e%2e/bar", "/bar", "/foo/../bar")); // Not by the RFC, but safer + arguments.add(Arguments.of("/foo/%2e%2e%2e/bar", "/foo/.../bar", "/foo/.../bar")); + return arguments.stream(); + } @ParameterizedTest(name = "[{index}] {0}") @MethodSource("decodePathSource") - public void testNormalizePath(String encodedPath, String safePath, String decodedPath) + public void testCanonicalEncodedPath(String encodedPath, String canonicalPath, String decodedPath) { - String path = URIUtil.normalizePath(encodedPath); - assertEquals(safePath, path); + String path = URIUtil.canonicalPath(encodedPath); + assertEquals(canonicalPath, path); } @ParameterizedTest(name = "[{index}] {0}") @MethodSource("decodePathSource") - public void testDecodePath(String encodedPath, String safePath, String decodedPath) + public void testDecodePath(String encodedPath, String canonicalPath, String decodedPath) { String path = URIUtil.decodePath(encodedPath); assertEquals(decodedPath, path); diff --git a/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/MavenWebAppContext.java b/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/MavenWebAppContext.java index 9fa4561c318..31b52108822 100644 --- a/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/MavenWebAppContext.java +++ b/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/MavenWebAppContext.java @@ -361,8 +361,8 @@ public class MavenWebAppContext extends WebAppContext // /WEB-INF/classes if ((resource == null || !resource.exists()) && pathInContext != null && _classes != null) { - // Canonicalize again to look for the resource inside /WEB-INF subdirectories. - String uri = URIUtil.canonicalPath(pathInContext); + // Normalize again to look for the resource inside /WEB-INF subdirectories. + String uri = URIUtil.normalizePath(pathInContext); if (uri == null) return null; diff --git a/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/SelectiveJarResource.java b/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/SelectiveJarResource.java index 6034564685b..6021f1918fd 100644 --- a/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/SelectiveJarResource.java +++ b/jetty-ee10/jetty-ee10-maven-plugin/src/main/java/org/eclipse/jetty/ee10/maven/plugin/SelectiveJarResource.java @@ -13,12 +13,9 @@ package org.eclipse.jetty.ee10.maven.plugin; -import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.nio.file.Files; @@ -165,7 +162,7 @@ public class SelectiveJarResource extends Resource LOG.debug("Looking at {}", entryName); // make sure no access out of the root entry is present - String dotCheck = URIUtil.canonicalPath(entryName); + String dotCheck = URIUtil.normalizePath(entryName); if (dotCheck == null) { LOG.info("Invalid entry: {}", entryName); diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletChannel.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletChannel.java index 73d26609e26..ec98dc26181 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletChannel.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletChannel.java @@ -398,7 +398,7 @@ public class ServletChannel implements Runnable { String contextPath = _request.getContext().getContextPath(); HttpURI.Immutable dispatchUri = HttpURI.from(dispatchString); - pathInContext = URIUtil.normalizePath(dispatchUri.getPath()); + pathInContext = URIUtil.canonicalPath(dispatchUri.getPath()); uri = HttpURI.build(_request.getHttpURI()) .path(URIUtil.addPaths(contextPath, pathInContext)) .query(dispatchUri.getQuery()); diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java index e736c3eeffe..d5660b2deae 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java @@ -3066,8 +3066,8 @@ public class ServletContextHandler extends ContextHandler implements Graceful @Override public String getRealPath(String path) { - // This is an API call from the application which may have arbitrary non canonical paths passed - // Thus we canonicalize here, to avoid the enforcement of only canonical paths in + // This is an API call from the application which may pass non-canonical paths. + // Thus, we canonicalize here, to avoid the enforcement of canonical paths in // ContextHandler.this.getResource(path). path = URIUtil.canonicalPath(path); if (path == null) @@ -3098,8 +3098,8 @@ public class ServletContextHandler extends ContextHandler implements Graceful @Override public URL getResource(String path) throws MalformedURLException { - // This is an API call from the application which may have arbitrary non canonical paths passed - // Thus we canonicalize here, to avoid the enforcement of only canonical paths in + // This is an API call from the application which may pass non-canonical paths. + // Thus, we canonicalize here, to avoid the enforcement of canonical paths in // ContextHandler.this.getResource(path). path = URIUtil.canonicalPath(path); if (path == null) @@ -3134,8 +3134,8 @@ public class ServletContextHandler extends ContextHandler implements Graceful @Override public Set getResourcePaths(String path) { - // This is an API call from the application which may have arbitrary non canonical paths passed - // Thus we canonicalize here, to avoid the enforcement of only canonical paths in + // This is an API call from the application which may pass non-canonical paths. + // Thus, we canonicalize here, to avoid the enforcement of canonical paths in // ContextHandler.this.getResource(path). path = URIUtil.canonicalPath(path); if (path == null) diff --git a/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/MavenWebAppContext.java b/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/MavenWebAppContext.java index 24ca19a3650..2cf9edf01ea 100644 --- a/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/MavenWebAppContext.java +++ b/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/MavenWebAppContext.java @@ -361,8 +361,8 @@ public class MavenWebAppContext extends WebAppContext // /WEB-INF/classes if ((resource == null || !resource.exists()) && pathInContext != null && _classes != null) { - // Canonicalize again to look for the resource inside /WEB-INF subdirectories. - String uri = URIUtil.canonicalPath(pathInContext); + // Normalize again to look for the resource inside /WEB-INF subdirectories. + String uri = URIUtil.normalizePath(pathInContext); if (uri == null) return null; diff --git a/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/SelectiveJarResource.java b/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/SelectiveJarResource.java index 2f6dcdb7b96..6126b5d9b5e 100644 --- a/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/SelectiveJarResource.java +++ b/jetty-ee9/jetty-ee9-maven-plugin/src/main/java/org/eclipse/jetty/ee9/maven/plugin/SelectiveJarResource.java @@ -162,7 +162,7 @@ public class SelectiveJarResource extends Resource LOG.debug("Looking at {}", entryName); // make sure no access out of the root entry is present - String dotCheck = URIUtil.canonicalPath(entryName); + String dotCheck = URIUtil.normalizePath(entryName); if (dotCheck == null) { LOG.info("Invalid entry: {}", entryName); diff --git a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java index 51784ae97be..c7e7fe6c469 100644 --- a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java +++ b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java @@ -68,12 +68,10 @@ import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.server.Context; import org.eclipse.jetty.server.Handler; -import org.eclipse.jetty.server.Handler.Nested; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextRequest; -import org.eclipse.jetty.server.handler.gzip.GzipHandler; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Index; @@ -1660,7 +1658,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu : URIUtil.encodePath(servletContext.getContextPath()); if (!StringUtil.isEmpty(encodedContextPath)) { - encodedPathQuery = URIUtil.canonicalPath(URIUtil.addEncodedPaths(encodedContextPath, encodedPathQuery)); + encodedPathQuery = URIUtil.normalizePath(URIUtil.addEncodedPaths(encodedContextPath, encodedPathQuery)); if (encodedPathQuery == null) throw new BadMessageException(500, "Bad dispatch path"); } @@ -1832,8 +1830,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu @Override public String getRealPath(String path) { - // This is an API call from the application which may have arbitrary non canonical paths passed - // Thus we canonicalize here, to avoid the enforcement of only canonical paths in + // This is an API call from the application which may pass non-canonical paths. + // Thus, we canonicalize here, to avoid the enforcement of canonical paths in // ContextHandler.this.getResource(path). path = URIUtil.canonicalPath(path); if (path == null) @@ -1864,8 +1862,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu @Override public URL getResource(String path) throws MalformedURLException { - // This is an API call from the application which may have arbitrary non canonical paths passed - // Thus we canonicalize here, to avoid the enforcement of only canonical paths in + // This is an API call from the application which may pass non-canonical paths. + // Thus, we canonicalize here, to avoid the enforcement of canonical paths in // ContextHandler.this.getResource(path). path = URIUtil.canonicalPath(path); if (path == null) @@ -1900,8 +1898,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu @Override public Set getResourcePaths(String path) { - // This is an API call from the application which may have arbitrary non canonical paths passed - // Thus we canonicalize here, to avoid the enforcement of only canonical paths in + // This is an API call from the application which may pass non-canonical paths. + // Thus, we canonicalize here, to avoid the enforcement of canonical paths in // ContextHandler.this.getResource(path). path = URIUtil.canonicalPath(path); if (path == null) diff --git a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/Response.java b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/Response.java index 5d7e3754086..6155043c0c5 100644 --- a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/Response.java +++ b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/Response.java @@ -588,14 +588,14 @@ public class Response implements HttpServletResponse if (location.startsWith("/")) { // absolute in context - location = URIUtil.canonicalURI(location); + location = URIUtil.normalizePathQuery(location); } else { // relative to request String path = _channel.getRequest().getRequestURI(); String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path); - location = URIUtil.canonicalURI(URIUtil.addEncodedPaths(parent, location)); + location = URIUtil.normalizePathQuery(URIUtil.addEncodedPaths(parent, location)); if (location != null && !location.startsWith("/")) buf.append('/'); }