Skip to content

Commit

Permalink
Merge pull request #1151 from fl4via/UNDERTOW-1886_master
Browse files Browse the repository at this point in the history
[UNDERTOW-1886] Add back non-null option to CanonicalPathUtils, while…
  • Loading branch information
fl4via authored May 25, 2021
2 parents 0559617 + 55c6ccf commit 8fa3c17
Show file tree
Hide file tree
Showing 3 changed files with 24 additions and 16 deletions.
22 changes: 13 additions & 9 deletions core/src/main/java/io/undertow/util/CanonicalPathUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,21 @@ public class CanonicalPathUtils {


public static String canonicalize(final String path) {
return canonicalize(path, false);
}

public static String canonicalize(final String path, final boolean nullAllowed) {
int state = START;
for (int i = path.length() - 1; i >= 0; --i) {
final char c = path.charAt(i);
switch (c) {
case '/':
if (state == FIRST_SLASH) {
return realCanonicalize(path, i + 1, FIRST_SLASH);
return realCanonicalize(path, i + 1, FIRST_SLASH, nullAllowed);
} else if (state == ONE_DOT) {
return realCanonicalize(path, i + 2, FIRST_SLASH);
return realCanonicalize(path, i + 2, FIRST_SLASH, nullAllowed);
} else if (state == TWO_DOT) {
return realCanonicalize(path, i + 3, FIRST_SLASH);
return realCanonicalize(path, i + 3, FIRST_SLASH, nullAllowed);
}
state = FIRST_SLASH;
break;
Expand All @@ -59,11 +63,11 @@ public static String canonicalize(final String path) {
case '\\':
if(!DONT_CANONICALIZE_BACKSLASH) {
if (state == FIRST_BACKSLASH) {
return realCanonicalize(path, i + 1, FIRST_BACKSLASH);
return realCanonicalize(path, i + 1, FIRST_BACKSLASH, nullAllowed);
} else if (state == ONE_DOT) {
return realCanonicalize(path, i + 2, FIRST_BACKSLASH);
return realCanonicalize(path, i + 2, FIRST_BACKSLASH, nullAllowed);
} else if (state == TWO_DOT) {
return realCanonicalize(path, i + 3, FIRST_BACKSLASH);
return realCanonicalize(path, i + 3, FIRST_BACKSLASH, nullAllowed);
}
state = FIRST_BACKSLASH;
break;
Expand All @@ -85,7 +89,7 @@ public static String canonicalize(final String path) {
static final int FIRST_BACKSLASH = 4;


private static String realCanonicalize(final String path, final int lastDot, final int initialState) {
private static String realCanonicalize(final String path, final int lastDot, final int initialState, final boolean nullAllowed) {
int state = initialState;
int eatCount = 0;
int tokenEnd = path.length();
Expand Down Expand Up @@ -170,8 +174,8 @@ private static String realCanonicalize(final String path, final int lastDot, fin
}
}
}
if (eatCount > 0) {
// the relative path is outside the context
if (eatCount > 0 && nullAllowed) {
// the relative path is outside the context and null allowed
return null;
}
final StringBuilder result = new StringBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ public void testCanonicalization() {
Assert.assertEquals("/b", CanonicalPathUtils.canonicalize("/a/c/../../b"));

// out of servlet context
Assert.assertNull(CanonicalPathUtils.canonicalize("/a/../.."));
Assert.assertNull(CanonicalPathUtils.canonicalize("/a/../../foo"));
Assert.assertNull(CanonicalPathUtils.canonicalize("/../../a/b/bar"));
Assert.assertNull(CanonicalPathUtils.canonicalize("/a/../..", true));
Assert.assertNull(CanonicalPathUtils.canonicalize("/a/../../foo", true));
Assert.assertNull(CanonicalPathUtils.canonicalize("/../../a/b/bar", true));
Assert.assertEquals("/", CanonicalPathUtils.canonicalize("/a/../.."));
Assert.assertEquals("/foo", CanonicalPathUtils.canonicalize("/a/../../foo"));

//preserve (single) trailing /
Assert.assertEquals("/a/", CanonicalPathUtils.canonicalize("/a/"));
Expand Down Expand Up @@ -106,9 +108,11 @@ public void testCanonicalizationBackslash() {
Assert.assertEquals("\\b", CanonicalPathUtils.canonicalize("\\a\\c\\..\\..\\b"));

// out of servlet context
Assert.assertNull(CanonicalPathUtils.canonicalize("\\a\\..\\.."));
Assert.assertNull(CanonicalPathUtils.canonicalize("\\a\\..\\..\\foo"));
Assert.assertNull(CanonicalPathUtils.canonicalize("\\..\\..\\a\\b\\bar"));
Assert.assertNull(CanonicalPathUtils.canonicalize("\\a\\..\\..", true));
Assert.assertNull(CanonicalPathUtils.canonicalize("\\a\\..\\..\\foo", true));
Assert.assertNull(CanonicalPathUtils.canonicalize("\\..\\..\\a\\b\\bar", true));
Assert.assertEquals("/", CanonicalPathUtils.canonicalize("\\a\\..\\.."));
Assert.assertEquals("\\foo", CanonicalPathUtils.canonicalize("\\a\\..\\..\\foo"));

//preserve (single) trailing \
Assert.assertEquals("\\a\\", CanonicalPathUtils.canonicalize("\\a\\"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ public RequestDispatcher getRequestDispatcher(final String path) {
if (!path.startsWith("/")) {
throw UndertowServletMessages.MESSAGES.pathMustStartWithSlashForRequestDispatcher(path);
}
final String realPath = CanonicalPathUtils.canonicalize(path);
final String realPath = CanonicalPathUtils.canonicalize(path, true);
if (realPath == null) {
// path is outside the servlet context, return null per spec
return null;
Expand Down

0 comments on commit 8fa3c17

Please sign in to comment.