/* * Copyright (c) 2021, 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. * * 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. */ /* * @test * @summary Tests for SimpleFileServer with a root that is of a zip file system * @library /test/lib * @build jdk.test.lib.Platform jdk.test.lib.net.URIBuilder * @run testng/othervm ZipFileSystemTest */ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpRequest.BodyPublishers; import java.net.http.HttpResponse.BodyHandlers; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.Map; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.Logger; import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.SimpleFileServer; import com.sun.net.httpserver.SimpleFileServer.OutputLevel; import jdk.test.lib.net.URIBuilder; import jdk.test.lib.util.FileUtils; import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeTest; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; import static java.net.http.HttpClient.Builder.NO_PROXY; import static java.nio.charset.StandardCharsets.UTF_8; import static java.nio.file.StandardOpenOption.CREATE; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; public class ZipFileSystemTest { static final Path CWD = Path.of(".").toAbsolutePath(); static final Path TEST_DIR = CWD.resolve("ZipFileSystemTest"); static final InetSocketAddress LOOPBACK_ADDR = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0); static final boolean ENABLE_LOGGING = true; static final Logger LOGGER = Logger.getLogger("com.sun.net.httpserver"); @BeforeTest public void setup() throws Exception { if (ENABLE_LOGGING) { ConsoleHandler ch = new ConsoleHandler(); LOGGER.setLevel(Level.ALL); ch.setLevel(Level.ALL); LOGGER.addHandler(ch); } if (Files.exists(TEST_DIR)) { FileUtils.deleteFileTreeWithRetry(TEST_DIR); } Files.createDirectories(TEST_DIR); } @Test public void testFileGET() throws Exception { var root = createZipFs(TEST_DIR.resolve("testFileGET.zip")); var file = Files.writeString(root.resolve("aFile.txt"), "some text", CREATE); var lastModified = getLastModified(file); var expectedLength = Long.toString(Files.size(file)); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); try { var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); var request = HttpRequest.newBuilder(uri(server, "aFile.txt")).build(); var response = client.send(request, BodyHandlers.ofString()); assertEquals(response.statusCode(), 200); assertEquals(response.body(), "some text"); assertEquals(response.headers().firstValue("content-type").get(), "text/plain"); assertEquals(response.headers().firstValue("content-length").get(), expectedLength); assertEquals(response.headers().firstValue("last-modified").get(), lastModified); } finally { server.stop(0); root.getFileSystem().close(); Files.deleteIfExists(TEST_DIR.resolve("testFileGET.zip")); } } @Test public void testDirectoryGET() throws Exception { var expectedBody = openHTML + """
/aFile?#.txt
""" + closeHTML; var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); var root = createZipFs(TEST_DIR.resolve("testInvalidRequestURIGET.zip")); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); try { var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); var request = HttpRequest.newBuilder(uri(server, "aFile?#.txt")).build(); var response = client.send(request, BodyHandlers.ofString()); assertEquals(response.statusCode(), 404); assertEquals(response.headers().firstValue("content-length").get(), expectedLength); assertEquals(response.body(), expectedBody); } finally { server.stop(0); root.getFileSystem().close(); Files.deleteIfExists(TEST_DIR.resolve("testInvalidRequestURIGET.zip")); } } @Test public void testNotFoundGET() throws Exception { var expectedBody = openHTML + """/doesNotExist.txt
""" + closeHTML; var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); var root = createZipFs(TEST_DIR.resolve("testNotFoundGET.zip")); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); try { var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")).build(); var response = client.send(request, BodyHandlers.ofString()); assertEquals(response.statusCode(), 404); assertEquals(response.headers().firstValue("content-length").get(), expectedLength); assertEquals(response.body(), expectedBody); } finally { server.stop(0); root.getFileSystem().close(); Files.deleteIfExists(TEST_DIR.resolve("testNotFoundGET.zip")); } } @Test public void testNotFoundHEAD() throws Exception { var expectedBody = openHTML + """/doesNotExist.txt
""" + closeHTML; var expectedLength = Integer.toString(expectedBody.getBytes(UTF_8).length); var root = createZipFs(TEST_DIR.resolve("testNotFoundHEAD.zip")); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); try { var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); var request = HttpRequest.newBuilder(uri(server, "doesNotExist.txt")) .method("HEAD", BodyPublishers.noBody()).build(); var response = client.send(request, BodyHandlers.ofString()); assertEquals(response.statusCode(), 404); assertEquals(response.headers().firstValue("content-length").get(), expectedLength); assertEquals(response.body(), ""); } finally { server.stop(0); root.getFileSystem().close(); Files.deleteIfExists(TEST_DIR.resolve("testNotFoundHEAD.zip")); } } @Test public void testMovedPermanently() throws Exception { var root = createZipFs(TEST_DIR.resolve("testMovedPermanently.zip")); Files.createDirectory(root.resolve("aDirectory")); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); try { var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); var uri = uri(server, "aDirectory"); var request = HttpRequest.newBuilder(uri).build(); var response = client.send(request, BodyHandlers.ofString()); assertEquals(response.statusCode(), 301); assertEquals(response.headers().firstValue("content-length").get(), "0"); assertEquals(response.headers().firstValue("location").get(), "/aDirectory/"); } finally { server.stop(0); root.getFileSystem().close(); Files.deleteIfExists(TEST_DIR.resolve("testMovedPermanently.zip")); } } static Path createZipFs(Path zipFile) throws Exception { var p = zipFile.toAbsolutePath().normalize(); var fs = FileSystems.newFileSystem(p, Map.of("create", "true")); assert fs != FileSystems.getDefault(); return fs.getPath("/"); // root entry } @Test public void testXss() throws Exception { var root = createZipFs(TEST_DIR.resolve("testXss.zip")); var server = SimpleFileServer.createFileServer(LOOPBACK_ADDR, root, OutputLevel.VERBOSE); server.start(); try { var client = HttpClient.newBuilder().proxy(NO_PROXY).build(); var request = HttpRequest.newBuilder(uri(server, "beginDelim%3C%3EEndDelim")).build(); var response = client.send(request, BodyHandlers.ofString()); assertEquals(response.statusCode(), 404); assertTrue(response.body().contains("beginDelim%3C%3EEndDelim")); assertTrue(response.body().contains("File not found")); } finally { server.stop(0); root.getFileSystem().close(); Files.deleteIfExists(TEST_DIR.resolve("testXss.zip")); } } @AfterTest public void teardown() throws IOException { if (Files.exists(TEST_DIR)) { FileUtils.deleteFileTreeWithRetry(TEST_DIR); } } static final String openHTML = """ """; static final String closeHTML = """ """; static URI uri(HttpServer server, String path) { return URIBuilder.newBuilder() .host("localhost") .port(server.getAddress().getPort()) .scheme("http") .path("/" + path) .buildUnchecked(); } static String getLastModified(Path path) throws IOException { return Files.getLastModifiedTime(path).toInstant().atZone(ZoneId.of("GMT")) .format(DateTimeFormatter.RFC_1123_DATE_TIME); } }