Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[UNDERTOW-1886] Add back non-null option to CanonicalPathUtils, while… #1151

Merged
merged 1 commit into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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