// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.util; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; import java.util.Arrays; import java.util.List; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) public class URIUtilCanonicalPathTest { @Parameterized.Parameters(name = "{0}") public static List<String[]> data() { String[][] canonical = { // Basic examples (no changes expected) {"/hello.html", "/hello.html"}, {"/css/main.css", "/css/main.css"}, {"/", "/"}, {"", ""}, {"/aaa/bbb/", "/aaa/bbb/"}, {"/aaa/bbb", "/aaa/bbb"}, {"aaa/bbb", "aaa/bbb"}, {"aaa/", "aaa/"}, {"aaa", "aaa"}, {"a", "a"}, {"a/", "a/"}, // Extra slashes {"/aaa//bbb/", "/aaa//bbb/"}, {"/aaa//bbb", "/aaa//bbb"}, {"/aaa///bbb/", "/aaa///bbb/"}, // Path traversal with current references "./" {"/aaa/./bbb/", "/aaa/bbb/"}, {"/aaa/./bbb", "/aaa/bbb"}, {"./bbb/", "bbb/"}, {"./aaa/../bbb/", "bbb/"}, {"/foo/.", "/foo/"}, {"./", ""}, {".", ""}, {".//", "/"}, {".///", "//"}, {"/.", "/"}, {"//.", "//"}, {"///.", "///"}, // Path traversal directory (but not past root) {"/aaa/../bbb/", "/bbb/"}, {"/aaa/../bbb", "/bbb"}, {"/aaa..bbb/", "/aaa..bbb/"}, {"/aaa..bbb", "/aaa..bbb"}, {"/aaa/..bbb/", "/aaa/..bbb/"}, {"/aaa/..bbb", "/aaa/..bbb"}, {"/aaa/./../bbb/", "/bbb/"}, {"/aaa/./../bbb", "/bbb"}, {"/aaa/bbb/ccc/../../ddd/", "/aaa/ddd/"}, {"/aaa/bbb/ccc/../../ddd", "/aaa/ddd"}, {"/foo/../bar//", "/bar//"}, {"/ctx/../bar/../ctx/all/index.txt", "/ctx/all/index.txt"}, {"/down/.././index.html", "/index.html"}, // Path traversal up past root {"..", null}, {"./..", null}, {"aaa/../..", null}, {"/foo/bar/../../..", null}, {"/../foo", null}, {"a/.", "a/"}, {"a/..", ""}, {"a/../..", null}, {"/foo/../../bar", null}, // Query parameter specifics {"/ctx/dir?/../index.html", "/ctx/index.html"}, {"/get-files?file=/etc/passwd", "/get-files?file=/etc/passwd"}, {"/get-files?file=../../../../../passwd", null}, // Known windows shell quirks {"file.txt ", "file.txt "}, // with spaces {"file.txt...", "file.txt..."}, // extra dots ignored by windows // BREAKS Jenkins: {"file.txt\u0000", "file.txt\u0000"}, // null terminated is ignored by windows {"file.txt\r", "file.txt\r"}, // CR terminated is ignored by windows {"file.txt\n", "file.txt\n"}, // LF terminated is ignored by windows {"file.txt\"\"\"\"", "file.txt\"\"\"\""}, // extra quotes ignored by windows {"file.txt<<<>>><", "file.txt<<<>>><"}, // angle brackets at end of path ignored by windows {"././././././file.txt", "file.txt"}, // Oddball requests that look like path traversal, but are not {"/....", "/...."}, {"/..../ctx/..../blah/logo.jpg", "/..../ctx/..../blah/logo.jpg"}, // paths with encoded segments should remain encoded // canonicalPath() is not responsible for decoding characters {"%2e%2e/", "%2e%2e/"}, }; return Arrays.asList(canonical); } @Parameterized.Parameter(0) public String input; @Parameterized.Parameter(1) public String expectedResult; @Test public void testCanonicalPath() { assertThat("Canonical", URIUtil.canonicalPath(input), is(expectedResult)); } }