8281305: Test com/sun/net/httpserver/simpleserver/MapToPathTest.java fails on Windows 11

Reviewed-by: dfuchs
This commit is contained in:
Julia Boes 2022-02-17 10:35:05 +00:00
parent b4900b1298
commit 9ca435b4c0
4 changed files with 138 additions and 7 deletions

View File

@ -227,9 +227,12 @@ public final class FileServerHandler implements HttpHandler {
// resolve each path segment against the root
Path path = root;
for (var segment : pathSegment) {
if (!URIPathSegment.isSupported(segment)) {
return null; // stop resolution, null results in 404 response
}
path = path.resolve(segment);
if (!Files.isReadable(path) || isHiddenOrSymLink(path)) {
return null; // stop resolution, null results in 404 response
return null; // stop resolution
}
}
path = path.normalize();

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver.simpleserver;
/**
* A class that represents a URI path segment.
*/
final class URIPathSegment {
private URIPathSegment() { throw new AssertionError(); }
/**
* Checks if the segment of a URI path is supported.
*
* @param segment the segment string
* @return true
*/
static boolean isSupported(String segment) {
return true;
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.net.httpserver.simpleserver;
/**
* A class that represents a URI path segment.
*/
final class URIPathSegment {
private URIPathSegment() { throw new AssertionError(); }
/**
* Checks if the segment of a URI path is supported. For example,
* "C:" is supported as a drive on Windows only.
*
* @param segment the segment string
* @return true if the segment is supported
*/
static boolean isSupported(String segment) {
// apply same logic as WindowsPathParser
if (segment.length() >= 2 && isLetter(segment.charAt(0)) && segment.charAt(1) == ':') {
return false;
}
return true;
}
private static boolean isLetter(char c) {
return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
}
}

View File

@ -137,19 +137,27 @@ public class MapToPathTest {
var res3 = client.send(req3, BodyHandlers.ofString());
assertEquals(res3.statusCode(), 404); // not found
var req4 = HttpRequest.newBuilder(uri(server, "/foo/file:" + TEST_DIR.getParent())).build();
var req4 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/c:.//")).build();
var res4 = client.send(req4, BodyHandlers.ofString());
assertEquals(res4.statusCode(), 404); // not found
var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar/\\..\\../")).build();
var req5 = HttpRequest.newBuilder(uri(server, "/foo/bar/baz/c:..//")).build();
var res5 = client.send(req5, BodyHandlers.ofString());
assertEquals(res5.statusCode(), 404); // not found
var req6 = HttpRequest.newBuilder(uri(server, "/foo")).build();
var req6 = HttpRequest.newBuilder(uri(server, "/foo/file:" + TEST_DIR.getParent())).build();
var res6 = client.send(req6, BodyHandlers.ofString());
assertEquals(res6.statusCode(), 301); // redirect
assertEquals(res6.headers().firstValue("content-length").get(), "0");
assertEquals(res6.headers().firstValue("location").get(), "/foo/");
assertEquals(res6.statusCode(), 404); // not found
var req7 = HttpRequest.newBuilder(uri(server, "/foo/bar/\\..\\../")).build();
var res7 = client.send(req7, BodyHandlers.ofString());
assertEquals(res7.statusCode(), 404); // not found
var req8 = HttpRequest.newBuilder(uri(server, "/foo")).build();
var res8 = client.send(req8, BodyHandlers.ofString());
assertEquals(res8.statusCode(), 301); // redirect
assertEquals(res8.headers().firstValue("content-length").get(), "0");
assertEquals(res8.headers().firstValue("location").get(), "/foo/");
} finally {
server.stop(0);
}
@ -250,6 +258,29 @@ public class MapToPathTest {
server.stop(0);
}
}
{
// Test that a request path segment that is a Windows root drive
// does not circumvent access restrictions.
//
// For example, given the test directory tree:
//
// |-- TEST_DIR
// |-- foo
// |-- bar ----->>> if hidden, itself and any of its subdirectories are not accessible
// |-- baz
// |-- file.txt
// ...
var handler = SimpleFileServer.createFileHandler(TEST_DIR);
var server = HttpServer.create(LOOPBACK_ADDR, 10, "/", handler, OUTPUT_FILTER);
server.start();
try {
var req1 = HttpRequest.newBuilder(uri(server, "/foo/bar/c:/baz/")).build();
var res1 = client.send(req1, BodyHandlers.ofString());
assertEquals(res1.statusCode(), 404); // not found
} finally {
server.stop(0);
}
}
}
// Tests with a mixture of in-memory and file handlers.