diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java index 60873cea20f2..6878a249e616 100644 --- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java +++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/AllowSymLinkAliasCheckerTest.java @@ -27,12 +27,13 @@ import org.eclipse.jetty.http.HttpTester; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.SymlinkAllowedResourceAliasChecker; import org.eclipse.jetty.toolchain.test.FS; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.resource.ResourceFactory; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -44,7 +45,6 @@ import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively; -@Disabled // TODO public class AllowSymLinkAliasCheckerTest { public static Stream params() @@ -177,12 +177,12 @@ private void setupServer() throws Exception fileResourceContext.setContextPath("/"); fileResourceContext.setAllowNullPathInContext(true); fileResourceContext.setHandler(fileResourceHandler); - /* TODO - fileResourceContext.setBaseResource(new PathResource(rootPath)); + + fileResourceContext.setBaseResource(ResourceFactory.of(fileResourceContext).newResource(rootPath)); fileResourceContext.clearAliasChecks(); fileResourceContext.addAliasCheck(new SymlinkAllowedResourceAliasChecker(fileResourceContext)); - */ + server.setHandler(fileResourceContext); server.start(); } diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java deleted file mode 100644 index ebd355bf369b..000000000000 --- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerGetResourceTest.java +++ /dev/null @@ -1,431 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License v. 2.0 which is available at -// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 -// which is available at https://www.apache.org/licenses/LICENSE-2.0. -// -// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 -// ======================================================================== -// - -package org.eclipse.jetty.server.handler; - -import java.io.File; -import java.nio.file.Files; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.toolchain.test.FS; -import org.eclipse.jetty.toolchain.test.MavenTestingUtils; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.condition.OS; - -@Disabled // TODO -public class ContextHandlerGetResourceTest -{ - private static boolean OS_ALIAS_SUPPORTED; - private static Server server; - private static ContextHandler context; - private static File docroot; - private static File otherroot; - private static final AtomicBoolean allowAliases = new AtomicBoolean(false); - private static final AtomicBoolean allowSymlinks = new AtomicBoolean(false); - - @BeforeAll - public static void beforeClass() throws Exception - { - File testRoot = MavenTestingUtils.getTargetTestingDir(ContextHandlerGetResourceTest.class.getSimpleName()); - FS.ensureEmpty(testRoot); - docroot = new File(testRoot, "docroot").getCanonicalFile().getAbsoluteFile(); - FS.ensureEmpty(docroot); - File index = new File(docroot, "index.html"); - index.createNewFile(); - File sub = new File(docroot, "subdir"); - sub.mkdir(); - File data = new File(sub, "data.txt"); - data.createNewFile(); - File verylong = new File(sub, "TextFile.Long.txt"); - verylong.createNewFile(); - - otherroot = new File(testRoot, "otherroot").getCanonicalFile().getAbsoluteFile(); - FS.ensureEmpty(otherroot); - File other = new File(otherroot, "other.txt"); - other.createNewFile(); - - File transit = new File(docroot.getParentFile(), "transit"); - transit.delete(); - - if (!OS.WINDOWS.isCurrentOs()) - { - // Create alias as 8.3 name so same test will produce an alias on both windows an unix/normal systems - File eightDotThree = new File(sub, "TEXTFI~1.TXT"); - Files.createSymbolicLink(eightDotThree.toPath(), verylong.toPath()); - - Files.createSymbolicLink(new File(docroot, "other").toPath(), new File("../transit").toPath()); - Files.createSymbolicLink(transit.toPath(), otherroot.toPath()); - - // /web/logs -> /var/logs -> /media/internal/logs - // where /media/internal -> /media/internal-physical/ - new File(docroot, "media/internal-physical/logs").mkdirs(); - Files.createSymbolicLink(new File(docroot, "media/internal").toPath(), new File(docroot, "media/internal-physical").toPath()); - new File(docroot, "var").mkdir(); - Files.createSymbolicLink(new File(docroot, "var/logs").toPath(), new File(docroot, "media/internal/logs").toPath()); - new File(docroot, "web").mkdir(); - Files.createSymbolicLink(new File(docroot, "web/logs").toPath(), new File(docroot, "var/logs").toPath()); - new File(docroot, "media/internal-physical/logs/file.log").createNewFile(); - - System.err.println("docroot=" + docroot); - } - - OS_ALIAS_SUPPORTED = new File(sub, "TEXTFI~1.TXT").exists(); - - server = new Server(); - context = new ContextHandler("/"); - /* TODO - context.clearAliasChecks(); - context.setBaseResource(Resource.newResource(docroot)); - context.addAliasCheck(new ContextHandler.AliasCheck() - { - final SymlinkAllowedResourceAliasChecker symlinkcheck = new SymlinkAllowedResourceAliasChecker(context); - { - context.addBean(symlinkcheck); - } - - @Override - public boolean check(String pathInContext, Resource resource) - { - if (allowAliases.get()) - return true; - if (allowSymlinks.get()) - return symlinkcheck.check(pathInContext, resource); - return allowAliases.get(); - } - }); - - */ - - server.setHandler(context); - server.start(); - } - - @AfterAll - public static void afterClass() throws Exception - { - server.stop(); - } - - /* TODO - @Test - public void testBadPath() throws Exception - { - final String path = "bad"; - assertThrows(MalformedURLException.class, () -> context.getResource(path)); - assertThrows(MalformedURLException.class, () -> context.getServletContext().getResource(path)); - } - - @Test - public void testGetUnknown() throws Exception - { - final String path = "/unknown.txt"; - Resource resource = context.getResource(path); - assertEquals("unknown.txt", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile()); - assertFalse(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - - @Test - public void testGetUnknownDir() throws Exception - { - final String path = "/unknown/"; - Resource resource = context.getResource(path); - assertEquals("unknown", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile()); - assertFalse(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - - @Test - public void testRoot() throws Exception - { - final String path = "/"; - Resource resource = context.getResource(path); - assertEquals(docroot, resource.getFile()); - assertTrue(resource.exists()); - assertTrue(resource.isDirectory()); - - URL url = context.getServletContext().getResource(path); - assertEquals(docroot, new File(url.toURI())); - } - - @Test - public void testSubdir() throws Exception - { - final String path = "/subdir"; - Resource resource = context.getResource(path); - assertEquals(docroot, resource.getFile().getParentFile()); - assertTrue(resource.exists()); - assertTrue(resource.isDirectory()); - assertTrue(resource.toString().endsWith("/")); - - URL url = context.getServletContext().getResource(path); - assertEquals(docroot, new File(url.toURI()).getParentFile()); - } - - @Test - public void testSubdirSlash() throws Exception - { - final String path = "/subdir/"; - Resource resource = context.getResource(path); - assertEquals(docroot, resource.getFile().getParentFile()); - assertTrue(resource.exists()); - assertTrue(resource.isDirectory()); - assertTrue(resource.toString().endsWith("/")); - - URL url = context.getServletContext().getResource(path); - assertEquals(docroot, new File(url.toURI()).getParentFile()); - } - - @Test - public void testGetKnown() throws Exception - { - final String path = "/index.html"; - Resource resource = context.getResource(path); - assertEquals("index.html", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile()); - assertTrue(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertEquals(docroot, new File(url.toURI()).getParentFile()); - } - - @Test - public void testDoesNotExistResource() throws Exception - { - Resource resource = context.getResource("/doesNotExist.html"); - assertNotNull(resource); - assertFalse(resource.exists()); - } - - @Test - public void testAlias() throws Exception - { - String path = "/./index.html"; - Resource resource = context.getResource(path); - assertNull(resource); - URL resourceURL = context.getServletContext().getResource(path); - assertFalse(resourceURL.getPath().contains("/./")); - - path = "/down/../index.html"; - resource = context.getResource(path); - assertNull(resource); - resourceURL = context.getServletContext().getResource(path); - assertFalse(resourceURL.getPath().contains("/../")); - - path = "//index.html"; - resource = context.getResource(path); - assertNull(resource); - resourceURL = context.getServletContext().getResource(path); - assertNull(resourceURL); - } - - @ParameterizedTest - @ValueSource(strings = {"/down/.././../", "/../down/"}) - public void testNormalize(String path) throws Exception - { - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - - @Test - public void testDeep() throws Exception - { - final String path = "/subdir/data.txt"; - Resource resource = context.getResource(path); - assertEquals("data.txt", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile().getParentFile()); - assertTrue(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertEquals(docroot, new File(url.toURI()).getParentFile().getParentFile()); - } - - @Test - public void testEncodedSlash() throws Exception - { - final String path = "/subdir%2Fdata.txt"; - - Resource resource = context.getResource(path); - assertEquals("subdir%2Fdata.txt", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile()); - assertFalse(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - - @Test - public void testEncodedSlosh() throws Exception - { - final String path = "/subdir%5Cdata.txt"; - - Resource resource = context.getResource(path); - assertEquals("subdir%5Cdata.txt", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile()); - assertFalse(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - - @Test - public void testEncodedNull() throws Exception - { - final String path = "/subdir/data.txt%00"; - - Resource resource = context.getResource(path); - assertEquals("data.txt%00", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile().getParentFile()); - assertFalse(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - - @Test - public void testSlashSlash() throws Exception - { - File expected = new File(docroot, FS.separators("subdir/data.txt")); - URL expectedUrl = expected.toURI().toURL(); - - String path = "//subdir/data.txt"; - Resource resource = context.getResource(path); - assertThat("Resource: " + resource, resource, nullValue()); - URL url = context.getServletContext().getResource(path); - assertThat("Resource: " + url, url, nullValue()); - - path = "/subdir//data.txt"; - resource = context.getResource(path); - assertThat("Resource: " + resource, resource, nullValue()); - url = context.getServletContext().getResource(path); - assertThat("Resource: " + url, url, nullValue()); - } - - @Test - public void testAliasedFile() throws Exception - { - assumeTrue(OS_ALIAS_SUPPORTED, "OS Supports 8.3 Aliased / Alternate References"); - final String path = "/subdir/TEXTFI~1.TXT"; - - Resource resource = context.getResource(path); - assertNull(resource); - - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - - @Test - public void testAliasedFileAllowed() throws Exception - { - assumeTrue(OS_ALIAS_SUPPORTED, "OS Supports 8.3 Aliased / Alternate References"); - try - { - allowAliases.set(true); - final String path = "/subdir/TEXTFI~1.TXT"; - - Resource resource = context.getResource(path); - assertNotNull(resource); - assertEquals(context.getResource("/subdir/TextFile.Long.txt").getURI(), resource.getRealURI()); - - URL url = context.getServletContext().getResource(path); - assertNotNull(url); - assertEquals(docroot, new File(url.toURI()).getParentFile().getParentFile()); - } - finally - { - allowAliases.set(false); - } - } - - @Test - @EnabledOnOs({LINUX, MAC}) - public void testSymlinkKnown() throws Exception - { - try - { - allowSymlinks.set(true); - - final String path = "/other/other.txt"; - - Resource resource = context.getResource(path); - assertNotNull(resource); - assertEquals("other.txt", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile().getParentFile()); - assertTrue(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertEquals(docroot, new File(url.toURI()).getParentFile().getParentFile()); - } - finally - { - allowSymlinks.set(false); - } - } - - @Test - @EnabledOnOs({LINUX, MAC}) - public void testSymlinkNested() throws Exception - { - try - { - allowSymlinks.set(true); - - final String path = "/web/logs/file.log"; - - Resource resource = context.getResource(path); - assertNotNull(resource); - assertEquals("file.log", resource.getFile().getName()); - assertTrue(resource.exists()); - } - finally - { - allowSymlinks.set(false); - } - } - - @Test - @EnabledOnOs({LINUX, MAC}) - public void testSymlinkUnknown() throws Exception - { - try - { - allowSymlinks.set(true); - - final String path = "/other/unknown.txt"; - - Resource resource = context.getResource(path); - assertNotNull(resource); - assertEquals("unknown.txt", resource.getFile().getName()); - assertEquals(docroot, resource.getFile().getParentFile().getParentFile()); - assertFalse(resource.exists()); - - URL url = context.getServletContext().getResource(path); - assertNull(url); - } - finally - { - allowSymlinks.set(false); - } - } - - */ -} diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java index b102e5909f05..6e152a972dd9 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletContextHandler.java @@ -765,7 +765,16 @@ public Resource getResource(String pathInContext) throws MalformedURLException if (baseResource == null) return null; - return baseResource.resolve(pathInContext); + try + { + return baseResource.resolve(pathInContext); + } + catch (Exception e) + { + LOG.trace("IGNORED", e); + } + + return null; } /** diff --git a/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/ServletContextHandlerTest.java b/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/ServletContextHandlerTest.java index 83a96c69fba0..8adc90a1e667 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/ServletContextHandlerTest.java +++ b/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/ServletContextHandlerTest.java @@ -13,8 +13,12 @@ package org.eclipse.jetty.ee10.servlet; +import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; @@ -84,6 +88,8 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ResourceHandler; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.Decorator; @@ -94,6 +100,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; @@ -117,6 +124,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.condition.OS.LINUX; +import static org.junit.jupiter.api.condition.OS.MAC; public class ServletContextHandlerTest { @@ -2662,4 +2671,40 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws HttpTester.Response response = HttpTester.parseResponse(rawResponse); assertThat(response.getContent(), containsString("OK2")); } + + @Test + @EnabledOnOs({LINUX, MAC}) + public void testGetResource() throws Exception + { + File baseDir = MavenTestingUtils.getTargetTestingDir(ServletContextHandlerTest.class.getSimpleName()); + FS.ensureEmpty(baseDir); + File index = new File(baseDir, "index.html"); + index.createNewFile(); + File sub = new File(baseDir, "subdir"); + sub.mkdir(); + File data = new File(sub, "data.txt"); + data.createNewFile(); + + ServletContextHandler context = new ServletContextHandler("/c1", ServletContextHandler.NO_SESSIONS); + context.setBaseResourceAsPath(baseDir.toPath()); + _server.setHandler(context); + + assertThat(context.getServletContext().getResource("/"), notNullValue()); + assertThat(context.getServletContext().getResource("/index.html"), notNullValue()); + assertThat(context.getServletContext().getResource("/doesnotexist.html"), nullValue()); + assertThat(context.getServletContext().getResource("/unknowndir/"), nullValue()); + assertThat(context.getServletContext().getResource("/subdir/data.txt"), notNullValue()); + assertThat(context.getServletContext().getResource("/subdir%5Cdata.txt"), nullValue()); //encoded slosh + assertThat(context.getServletContext().getResource("/subdir/data.txt%00"), nullValue()); //encoded null + //NOTE that these tests return a resource whereas major versions of jetty before 12 did not + assertThat(context.getServletContext().getResource("//subdir/data.txt"), notNullValue()); + assertThat(context.getServletContext().getResource("/subdir//data.txt"), notNullValue()); + assertThat(context.getServletContext().getResource("/subdir%2Fdata.txt"), notNullValue()); //encoded slash + URL subdir = context.getServletContext().getResource("/subdir/"); + assertThat(subdir, notNullValue()); + assertEquals(baseDir, new File(subdir.toURI()).getParentFile()); + assertThrows(MalformedURLException.class, () -> context.getResource("badpath")); + assertThat(context.getServletContext().getResource("/../down/"), nullValue()); + assertThat(context.getServletContext().getResource("/down/.././../"), nullValue()); + } } diff --git a/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java b/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java index 23bca7f6a9e8..984a058736c9 100644 --- a/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java +++ b/jetty-ee11/jetty-ee11-servlet/src/main/java/org/eclipse/jetty/ee11/servlet/ServletContextHandler.java @@ -764,7 +764,15 @@ public Resource getResource(String pathInContext) throws MalformedURLException if (baseResource == null) return null; - return baseResource.resolve(pathInContext); + try + { + return baseResource.resolve(pathInContext); + } + catch (Exception e) + { + LOG.trace("IGNORE", e); + } + return null; } /** diff --git a/jetty-ee11/jetty-ee11-servlet/src/test/java/org/eclipse/jetty/ee11/servlet/ServletContextHandlerTest.java b/jetty-ee11/jetty-ee11-servlet/src/test/java/org/eclipse/jetty/ee11/servlet/ServletContextHandlerTest.java index ef7ca5011473..36d5e9e1aee8 100644 --- a/jetty-ee11/jetty-ee11-servlet/src/test/java/org/eclipse/jetty/ee11/servlet/ServletContextHandlerTest.java +++ b/jetty-ee11/jetty-ee11-servlet/src/test/java/org/eclipse/jetty/ee11/servlet/ServletContextHandlerTest.java @@ -13,8 +13,11 @@ package org.eclipse.jetty.ee11.servlet; +import java.io.File; import java.io.IOException; import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.net.URL; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; @@ -84,6 +87,8 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ResourceHandler; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.DecoratedObjectFactory; import org.eclipse.jetty.util.Decorator; @@ -94,6 +99,7 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; @@ -117,6 +123,8 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.condition.OS.LINUX; +import static org.junit.jupiter.api.condition.OS.MAC; public class ServletContextHandlerTest { @@ -2662,4 +2670,40 @@ protected void service(HttpServletRequest req, HttpServletResponse resp) throws HttpTester.Response response = HttpTester.parseResponse(rawResponse); assertThat(response.getContent(), containsString("OK2")); } + + @Test + @EnabledOnOs({LINUX, MAC}) + public void testGetResource() throws Exception + { + File baseDir = MavenTestingUtils.getTargetTestingDir(ServletContextHandlerTest.class.getSimpleName()); + FS.ensureEmpty(baseDir); + File index = new File(baseDir, "index.html"); + index.createNewFile(); + File sub = new File(baseDir, "subdir"); + sub.mkdir(); + File data = new File(sub, "data.txt"); + data.createNewFile(); + + ServletContextHandler context = new ServletContextHandler("/c1", ServletContextHandler.NO_SESSIONS); + context.setBaseResourceAsPath(baseDir.toPath()); + _server.setHandler(context); + + assertThat(context.getServletContext().getResource("/"), notNullValue()); + assertThat(context.getServletContext().getResource("/index.html"), notNullValue()); + assertThat(context.getServletContext().getResource("/doesnotexist.html"), nullValue()); + assertThat(context.getServletContext().getResource("/unknowndir/"), nullValue()); + assertThat(context.getServletContext().getResource("/subdir/data.txt"), notNullValue()); + assertThat(context.getServletContext().getResource("/subdir%5Cdata.txt"), nullValue()); //encoded slosh + assertThat(context.getServletContext().getResource("/subdir/data.txt%00"), nullValue()); //encoded null + //NOTE that these tests return a value, whereas in versions prior to 12 they did not + assertThat(context.getServletContext().getResource("//subdir/data.txt"), notNullValue()); + assertThat(context.getServletContext().getResource("/subdir//data.txt"), notNullValue()); + assertThat(context.getServletContext().getResource("/subdir%2Fdata.txt"), notNullValue()); //encoded slash + URL subdir = context.getServletContext().getResource("/subdir/"); + assertThat(subdir, notNullValue()); + assertEquals(baseDir, new File(subdir.toURI()).getParentFile()); + assertThrows(MalformedURLException.class, () -> context.getResource("badpath")); + assertThat(context.getServletContext().getResource("/../down/"), nullValue()); + assertThat(context.getServletContext().getResource("/down/.././../"), nullValue()); + } } diff --git a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java index 0a50e42e7287..8ab6cee3cea7 100644 --- a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java +++ b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/ContextHandler.java @@ -1520,9 +1520,6 @@ public Resource getResource(String pathInContext) throws MalformedURLException try { - // addPath with accept non-canonical paths that don't go above the root, - // but will treat them as aliases. So unless allowed by an AliasChecker - // they will be rejected below. return baseResource.resolve(pathInContext); } catch (Exception e) diff --git a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/ContextHandlerTest.java b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/ContextHandlerTest.java index e9286c5eda65..61acab502517 100644 --- a/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/ContextHandlerTest.java +++ b/jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/ContextHandlerTest.java @@ -13,8 +13,11 @@ package org.eclipse.jetty.ee9.nested; +import java.io.File; import java.io.IOException; import java.io.StringReader; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Properties; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; @@ -37,11 +40,14 @@ import org.eclipse.jetty.server.Response; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.util.Callback; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; @@ -51,22 +57,38 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.condition.OS.LINUX; +import static org.junit.jupiter.api.condition.OS.MAC; public class ContextHandlerTest { Server _server; ContextHandler _contextHandler; LocalConnector _connector; + File _testRoot; @BeforeEach public void before() throws Exception { + _testRoot = MavenTestingUtils.getTargetTestingDir(ContextHandlerTest.class.getSimpleName()); + FS.ensureEmpty(_testRoot); + File index = new File(_testRoot, "index.html"); + index.createNewFile(); + File sub = new File(_testRoot, "subdir"); + sub.mkdir(); + File data = new File(sub, "data.txt"); + data.createNewFile(); + _server = new Server(); _connector = new LocalConnector(_server); _server.addConnector(_connector); _contextHandler = new ContextHandler(); + _contextHandler.setBaseResourceAsPath(_testRoot.toPath()); _server.setHandler(_contextHandler); } @@ -863,6 +885,29 @@ public void handle(String target, Request baseRequest, HttpServletRequest reques assertThat(response.get("Nested"), is("Inserted")); } + @Test + @EnabledOnOs({LINUX, MAC}) + public void testGetResource() throws Exception + { + assertThat(_contextHandler.getServletContext().getResource("/"), notNullValue()); + assertThat(_contextHandler.getServletContext().getResource("/index.html"), notNullValue()); + assertThat(_contextHandler.getServletContext().getResource("/doesnotexist.html"), nullValue()); + assertThat(_contextHandler.getServletContext().getResource("/unknowndir/"), nullValue()); + assertThat(_contextHandler.getServletContext().getResource("/subdir/data.txt"), notNullValue()); + assertThat(_contextHandler.getServletContext().getResource("/subdir/data.txt%00"), nullValue()); //encoded null + assertThat(_contextHandler.getServletContext().getResource("/subdir%5Cdata.txt"), nullValue()); //encoded slosh + //NOTE that these tests return a value, whereas in versions prior to 12 they did not + assertThat(_contextHandler.getServletContext().getResource("//subdir/data.txt"), notNullValue()); + assertThat(_contextHandler.getServletContext().getResource("/subdir//data.txt"), notNullValue()); + assertThat(_contextHandler.getServletContext().getResource("/subdir%2Fdata.txt"), notNullValue()); //encoded slash + URL subdir = _contextHandler.getServletContext().getResource("/subdir/"); + assertThat(subdir, notNullValue()); + assertEquals(_testRoot, new File(subdir.toURI()).getParentFile()); + assertThrows(MalformedURLException.class, () -> _contextHandler.getResource("badpath")); + assertThat(_contextHandler.getServletContext().getResource("/../down/"), nullValue()); + assertThat(_contextHandler.getServletContext().getResource("/down/.././../"), nullValue()); + } + private static class TestErrorHandler extends ErrorHandler implements ErrorHandler.ErrorPageMapper { @Override