From e9a8497936a8eaebe8f694988d03bc419922d52f Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Mon, 4 Nov 2019 17:53:05 +1100 Subject: [PATCH 1/8] Issue #4173 Avoid NPE generating name of tmp dir in WebInfConfiguration Signed-off-by: Jan Bartel --- .../jetty/webapp/WebInfConfiguration.java | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index aa8fe646814..c01e8caf62d 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -779,22 +779,25 @@ public class WebInfConfiguration extends AbstractConfiguration resource = context.newResource(context.getWar()); } - String tmp = URIUtil.decodePath(resource.getURI().getPath()); + String tmp = getResourceBasePath(resource); if (tmp.endsWith("/")) tmp = tmp.substring(0, tmp.length() - 1); if (tmp.endsWith("!")) tmp = tmp.substring(0, tmp.length() - 1); //get just the last part which is the filename int i = tmp.lastIndexOf("/"); - canonicalName.append(tmp.substring(i + 1)); + if (i > -1 && tmp.length() > 1) + { + canonicalName.append(tmp.substring(i + 1)); + } canonicalName.append("-"); } - catch (Exception e) + catch (IOException e) { - LOG.warn("Can't generate resourceBase as part of webapp tmp dir name: " + e); - LOG.debug(e); + LOG.warn("Can't get resource for resourceBase", e); + LOG.debug(e); } - + //Context name canonicalName.append(context.getContextPath()); @@ -810,6 +813,29 @@ public class WebInfConfiguration extends AbstractConfiguration return StringUtil.sanitizeFileSystemName(canonicalName.toString()); } + + private static String getResourceBasePath(Resource resource) + { + String tmp = ""; + try + { + tmp = URIUtil.decodePath(resource.getURI().getPath()); + } + catch (Exception e) + { + try + { + tmp = URIUtil.decodePath(resource.getURI().toURL().getPath()); + } + catch (Exception x) + { + LOG.warn("Can't get path for resource", x); + LOG.debug(e); + } + } + + return tmp; + } protected List findClassDirs(WebAppContext context) throws Exception From 2774533150bd7292cfca678f1114843ad5e85f87 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Mon, 4 Nov 2019 14:55:41 -0600 Subject: [PATCH 2/8] Issue #4173 - improved Base Resource Name resolution Signed-off-by: Joakim Erdfelt --- .../jetty/webapp/WebInfConfiguration.java | 93 ++++++++---- .../jetty/webapp/WebInfConfigurationTest.java | 139 ++++++++++++++++++ .../src/test/resources/test-base-resource.jar | Bin 0 -> 2126 bytes 3 files changed, 204 insertions(+), 28 deletions(-) create mode 100644 jetty-webapp/src/test/resources/test-base-resource.jar diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index c01e8caf62d..797e171531d 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -766,7 +766,7 @@ public class WebInfConfiguration extends AbstractConfiguration } } - //Resource base + // Resource base try { Resource resource = context.getBaseResource(); @@ -775,29 +775,20 @@ public class WebInfConfiguration extends AbstractConfiguration if (context.getWar() == null || context.getWar().length() == 0) throw new IllegalStateException("No resourceBase or war set for context"); - // Set dir or WAR + // Set dir or WAR to resource resource = context.newResource(context.getWar()); } - String tmp = getResourceBasePath(resource); - if (tmp.endsWith("/")) - tmp = tmp.substring(0, tmp.length() - 1); - if (tmp.endsWith("!")) - tmp = tmp.substring(0, tmp.length() - 1); - //get just the last part which is the filename - int i = tmp.lastIndexOf("/"); - if (i > -1 && tmp.length() > 1) - { - canonicalName.append(tmp.substring(i + 1)); - } + String resourceBaseName = getResourceBaseName(resource); + canonicalName.append(resourceBaseName); canonicalName.append("-"); } - catch (IOException e) + catch (Exception e) { LOG.warn("Can't get resource for resourceBase", e); - LOG.debug(e); + LOG.debug(e); } - + //Context name canonicalName.append(context.getContextPath()); @@ -813,28 +804,74 @@ public class WebInfConfiguration extends AbstractConfiguration return StringUtil.sanitizeFileSystemName(canonicalName.toString()); } - - private static String getResourceBasePath(Resource resource) + + protected static String getResourceBaseName(Resource resource) { - String tmp = ""; + // Use File System and File interface if present try { - tmp = URIUtil.decodePath(resource.getURI().getPath()); + File resourceFile = resource.getFile(); + if (resourceFile != null) + { + return resourceFile.getName(); + } } - catch (Exception e) + catch (IOException e) { - try + e.printStackTrace(); + } + + // Use URI itself. + URI uri = resource.getURI(); + if (uri == null) + { + throw new RuntimeException("Unable to produce URI from resource: " + resource); + } + return getUriLastPathSegment(uri); + } + + protected static String getUriLastPathSegment(URI uri) + { + String path = uri.getPath(); + + if ("jar".equalsIgnoreCase(uri.getScheme())) + { + String schemeSpecificPart = uri.getRawSchemeSpecificPart(); + URI inner = URI.create(schemeSpecificPart); + if ("file".equalsIgnoreCase(inner.getScheme())) { - tmp = URIUtil.decodePath(resource.getURI().toURL().getPath()); + path = inner.getRawPath(); + int idx = path.lastIndexOf("!/"); + if (idx >= 0) + { + String pathInJar = path.substring(idx + 2); + if (StringUtil.isNotBlank(pathInJar)) + { + URI pathInJarUri = URI.create(pathInJar); + return getUriLastPathSegment(pathInJarUri); + } + else + { + // Strip empty "!/" + path = path.substring(0, idx); + } + } + // if we reached here, we have "jar:file:" but no + // internal jar reference with "!/" present } - catch (Exception x) + else { - LOG.warn("Can't get path for resource", x); - LOG.debug(e); + // inner URI is not "file" + return getUriLastPathSegment(inner); } } - - return tmp; + + if (path.endsWith("/")) + path = path.substring(0, path.length() - 1); + // get just the last part which is the filename + int i = path.lastIndexOf("/"); + + return path.substring(i + 1); } protected List findClassDirs(WebAppContext context) diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java index 11b42a515cb..85c53dc90b7 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java @@ -18,27 +18,56 @@ package org.eclipse.jetty.webapp; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitOption; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.stream.Stream; +import org.eclipse.jetty.toolchain.test.FS; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; +import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; import org.eclipse.jetty.util.JavaVersion; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.PathResource; import org.eclipse.jetty.util.resource.Resource; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.DisabledOnJre; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.anyOf; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.endsWith; +import static org.hamcrest.Matchers.is; import static org.junit.jupiter.api.Assertions.assertEquals; /** * WebInfConfigurationTest */ +@ExtendWith(WorkDirExtension.class) public class WebInfConfigurationTest { + private static final Logger LOG = Log.getLogger(WebInfConfigurationTest.class); + private static final String TEST_RESOURCE_JAR = "test-base-resource.jar"; + + public WorkDir workDir; /** * Assume target < jdk9. In this case, we should be able to extract @@ -110,4 +139,114 @@ public class WebInfConfigurationTest assertEquals(1, containerResources.size()); assertThat(containerResources.get(0).toString(), containsString("jetty-util")); } + + public static Stream baseResourceNames() + { + return Stream.of( + Arguments.of("test.war", "test.war"), + Arguments.of("a/b/c/test.war", "test.war"), + Arguments.of("bar%2Fbaz/test.war", "test.war"), + Arguments.of("fizz buzz/test.war", "test.war"), + Arguments.of("another one/bites the dust/", "bites the dust"), + Arguments.of("another+one/bites+the+dust/", "bites+the+dust"), + Arguments.of("another%20one/bites%20the%20dust/", "bites%20the%20dust"), + Arguments.of("spanish/número.war", "número.war"), + Arguments.of("spanish/n\uC3BAmero.war", "n\uC3BAmero.war"), + Arguments.of("spanish/n%C3%BAmero.war", "n%C3%BAmero.war"), + Arguments.of("a/b!/", "b!"), + Arguments.of("a/b!/c/", "c"), + Arguments.of("a/b!/c/d/", "d"), + Arguments.of("a/b%21/", "b%21") + ); + } + + @ParameterizedTest + @MethodSource("baseResourceNames") + public void testPathGetResourceBaseName(String basePath, String expectedName) throws IOException + { + Path root = workDir.getPath(); + Path base = root.resolve(basePath); + if (basePath.endsWith("/")) + { + // we are working with a directory. + FS.ensureDirExists(base); + } + else + { + FS.ensureDirExists(base.getParent()); + FS.touch(base); + } + + Resource resource = new PathResource(base); + assertThat(WebInfConfiguration.getResourceBaseName(resource), is(expectedName)); + } + + /** + * Similar to testPathGetResourceBaseName, but with "file:" URIs + */ + @ParameterizedTest + @MethodSource("baseResourceNames") + public void testFileUriGetUriLastPathSegment(String basePath, String expectedName) throws IOException + { + Path root = workDir.getPath(); + Path base = root.resolve(basePath); + URI uri = base.toUri(); + assertThat(WebInfConfiguration.getUriLastPathSegment(uri), is(expectedName)); + } + + public static Stream jarFileBaseResourceNames() throws URISyntaxException, IOException + { + Path testJar = MavenTestingUtils.getTestResourcePathFile(TEST_RESOURCE_JAR); + URI uri = new URI("jar", testJar.toUri().toASCIIString(), null); + + Map env = new HashMap<>(); + env.put("multi-release", "runtime"); + + List arguments = new ArrayList<>(); + arguments.add(Arguments.of(uri, TEST_RESOURCE_JAR)); + try (FileSystem zipFs = FileSystems.newFileSystem(uri, env)) + { + FileVisitOption[] fileVisitOptions = new FileVisitOption[]{}; + + for (Path root : zipFs.getRootDirectories()) + { + Stream entryStream = Files.find(root, 10, (path, attrs) -> true, fileVisitOptions); + entryStream.forEach((path) -> + { + if (path.toString().endsWith("!/")) + { + // skip - JAR entry type not supported by Jetty + // TODO: re-enable once we start to use zipfs + LOG.warn("Skipping Unsupported entry: " + path.toUri()); + } + else + { + String lastPathSegment = TEST_RESOURCE_JAR; + if (path.getFileName() != null) + { + lastPathSegment = path.getFileName().toString(); + } + // Strip last '/' from directory entries + if (Files.isDirectory(path) && lastPathSegment.endsWith("/")) + { + lastPathSegment = lastPathSegment.substring(0, lastPathSegment.length() - 1); + } + arguments.add(Arguments.of(path.toUri(), lastPathSegment)); + } + }); + } + } + + return arguments.stream(); + } + + /** + * Tests of "jar:file:" based URIs + */ + @ParameterizedTest + @MethodSource("jarFileBaseResourceNames") + public void testJarFileUriGetUriLastPathSegment(URI uri, String expectedName) throws IOException + { + assertThat(WebInfConfiguration.getUriLastPathSegment(uri), is(expectedName)); + } } diff --git a/jetty-webapp/src/test/resources/test-base-resource.jar b/jetty-webapp/src/test/resources/test-base-resource.jar new file mode 100644 index 0000000000000000000000000000000000000000..aa3066909b36f5c46ef450143c03684ef11a17a7 GIT binary patch literal 2126 zcmaKtyH3ME5JfjH9uWcwMSxP7BBF>C=h0H|5)B2RrL*Ipq`(2&5t7Akz=u#GsM1mL z8I*vi05Q8Unc49=8!2*>d+u&_W^TGCg<@HVB_VbK?^KYrDvHAKN70}k)Y{FF-?x8X zgy?4KEns!MJB<1vuwVi2-Z+eq{<_w8gEI)%ft`+BC$_V7Ynl%HBO-ohrt2wja%16OX}_Ri;$;Xu&O7 z`W>FL9rBVRzGv+FqWaz?3XdsDO3~Y%BU${HctkYkB3ne(VB1x|E4lBM?N1)lm-xdf zD%<2@7{``7j%k~4ooo}-u{QZ;rm{_Rv0ljyc5G6~x?V}HB$ZT3RmnP3vOcY3E?*Ye z(+9^QOP{UjEN1f-A%$qdC!IIVCc2rX6AgWMq_djM$ui)&heza+q9AOVUW6wpcv>Xn zO-+dW2RxG5M$9zbh*fh0OU*jE@EMjpf~yNI`s`KBhE4p9kp!qlkJ_ zI-vel>19?RVM+@mJ{6&|BO8(Ffol^I%dr8GS%T2~Lhb@I3k`~y(gpYGQB2Dk+?c0` zOdDKx;D9kfcjlbl_RkuZYI{=};ihjXn72L89KG|Zg<0n%S%p8BlX~YJF_LFjX+fT{ N0 Date: Mon, 4 Nov 2019 15:52:22 -0600 Subject: [PATCH 3/8] Issue #4173 - Improve OSX test expectation (NFD form) Signed-off-by: Joakim Erdfelt --- .../eclipse/jetty/webapp/WebInfConfigurationTest.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java index 85c53dc90b7..74ad7061b29 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java @@ -26,6 +26,7 @@ import java.nio.file.FileSystems; import java.nio.file.FileVisitOption; import java.nio.file.Files; import java.nio.file.Path; +import java.text.Normalizer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -46,6 +47,7 @@ import org.junit.jupiter.api.condition.DisabledOnJre; import org.junit.jupiter.api.condition.EnabledIfSystemProperty; import org.junit.jupiter.api.condition.EnabledOnJre; import org.junit.jupiter.api.condition.JRE; +import org.junit.jupiter.api.condition.OS; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; @@ -150,8 +152,7 @@ public class WebInfConfigurationTest Arguments.of("another one/bites the dust/", "bites the dust"), Arguments.of("another+one/bites+the+dust/", "bites+the+dust"), Arguments.of("another%20one/bites%20the%20dust/", "bites%20the%20dust"), - Arguments.of("spanish/número.war", "número.war"), - Arguments.of("spanish/n\uC3BAmero.war", "n\uC3BAmero.war"), + Arguments.of("spanish/n\u00FAmero.war", "n\u00FAmero.war"), Arguments.of("spanish/n%C3%BAmero.war", "n%C3%BAmero.war"), Arguments.of("a/b!/", "b!"), Arguments.of("a/b!/c/", "c"), @@ -191,6 +192,11 @@ public class WebInfConfigurationTest Path root = workDir.getPath(); Path base = root.resolve(basePath); URI uri = base.toUri(); + if (OS.MAC.isCurrentOs()) + { + // Normalize Unicode to NFD form that OSX Path/FileSystem produces + expectedName = Normalizer.normalize(expectedName, Normalizer.Form.NFD); + } assertThat(WebInfConfiguration.getUriLastPathSegment(uri), is(expectedName)); } From 6ac925631cb342b8cfd0088155c49bb2bcd17e11 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Mon, 4 Nov 2019 16:01:43 -0600 Subject: [PATCH 4/8] Issue #4173 - Adding more testcases for raw root-ish Resources Signed-off-by: Joakim Erdfelt --- .../jetty/webapp/WebInfConfigurationTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java index 74ad7061b29..130de381851 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java @@ -142,6 +142,22 @@ public class WebInfConfigurationTest assertThat(containerResources.get(0).toString(), containsString("jetty-util")); } + public static Stream rawResourceNames() + { + return Stream.of( + Arguments.of("/", ""), + Arguments.of("/a", "a") + ); + } + + @ParameterizedTest + @MethodSource("rawResourceNames") + public void testTinyGetResourceBaseName(String rawPath, String expectedName) throws IOException + { + Resource resource = Resource.newResource(rawPath); + assertThat(WebInfConfiguration.getResourceBaseName(resource), is(expectedName)); + } + public static Stream baseResourceNames() { return Stream.of( From 68cf4f23f1ac8706e805085fa4cffdd4fcbb1e1e Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Mon, 4 Nov 2019 16:03:01 -0600 Subject: [PATCH 5/8] Issue #4173 - Ignore logging of failed Resource.getFile() Signed-off-by: Joakim Erdfelt --- .../main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 797e171531d..b8efd3fdfd9 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -818,7 +818,7 @@ public class WebInfConfiguration extends AbstractConfiguration } catch (IOException e) { - e.printStackTrace(); + LOG.ignore(e); } // Use URI itself. From 2d9f1284103fa7d769ad9bc18d7107acc59072ab Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 6 Nov 2019 16:02:00 -0600 Subject: [PATCH 6/8] Issue #4173 - simplify base name lookup + Some cleanup of logging + Exception during getResourceBaseName() results in empty canonical segment Signed-off-by: Joakim Erdfelt --- .../jetty/webapp/WebInfConfiguration.java | 73 +++++++++---------- .../jetty/webapp/WebInfConfigurationTest.java | 54 +++++++++----- 2 files changed, 69 insertions(+), 58 deletions(-) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index b8efd3fdfd9..08fcccbe4dc 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -785,8 +785,11 @@ public class WebInfConfiguration extends AbstractConfiguration } catch (Exception e) { - LOG.warn("Can't get resource for resourceBase", e); - LOG.debug(e); + if (LOG.isDebugEnabled()) + { + LOG.debug("Can't get resource base name", e); + } + canonicalName.append("-"); // empty resourceBaseName segment } //Context name @@ -818,60 +821,50 @@ public class WebInfConfiguration extends AbstractConfiguration } catch (IOException e) { - LOG.ignore(e); + if (LOG.isDebugEnabled()) + { + LOG.debug("Resource has no File reference: {}", resource); + } } // Use URI itself. URI uri = resource.getURI(); if (uri == null) { - throw new RuntimeException("Unable to produce URI from resource: " + resource); + if (LOG.isDebugEnabled()) + { + LOG.debug("Resource has no URI reference: {}", resource); + } + return ""; } + return getUriLastPathSegment(uri); } protected static String getUriLastPathSegment(URI uri) { - String path = uri.getPath(); - - if ("jar".equalsIgnoreCase(uri.getScheme())) + String ssp = uri.getSchemeSpecificPart(); + // strip off deep jar:file: reference information + int idx = ssp.indexOf("!/"); + if (idx != -1) { - String schemeSpecificPart = uri.getRawSchemeSpecificPart(); - URI inner = URI.create(schemeSpecificPart); - if ("file".equalsIgnoreCase(inner.getScheme())) - { - path = inner.getRawPath(); - int idx = path.lastIndexOf("!/"); - if (idx >= 0) - { - String pathInJar = path.substring(idx + 2); - if (StringUtil.isNotBlank(pathInJar)) - { - URI pathInJarUri = URI.create(pathInJar); - return getUriLastPathSegment(pathInJarUri); - } - else - { - // Strip empty "!/" - path = path.substring(0, idx); - } - } - // if we reached here, we have "jar:file:" but no - // internal jar reference with "!/" present - } - else - { - // inner URI is not "file" - return getUriLastPathSegment(inner); - } + ssp = ssp.substring(0, idx); } - if (path.endsWith("/")) - path = path.substring(0, path.length() - 1); - // get just the last part which is the filename - int i = path.lastIndexOf("/"); + // Strip off trailing '/' if present + if (ssp.endsWith("/")) + { + ssp = ssp.substring(0, ssp.length() - 1); + } - return path.substring(i + 1); + // Only interested in last segment + idx = ssp.lastIndexOf('/'); + if (idx != -1) + { + ssp = ssp.substring(idx + 1); + } + + return ssp; } protected List findClassDirs(WebAppContext context) diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java index 130de381851..28c1f5a0aa7 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebInfConfigurationTest.java @@ -158,7 +158,7 @@ public class WebInfConfigurationTest assertThat(WebInfConfiguration.getResourceBaseName(resource), is(expectedName)); } - public static Stream baseResourceNames() + public static Stream fileBaseResourceNames() { return Stream.of( Arguments.of("test.war", "test.war"), @@ -178,7 +178,7 @@ public class WebInfConfigurationTest } @ParameterizedTest - @MethodSource("baseResourceNames") + @MethodSource("fileBaseResourceNames") public void testPathGetResourceBaseName(String basePath, String expectedName) throws IOException { Path root = workDir.getPath(); @@ -198,15 +198,43 @@ public class WebInfConfigurationTest assertThat(WebInfConfiguration.getResourceBaseName(resource), is(expectedName)); } + public static Stream fileUriBaseResourceNames() + { + return Stream.of( + Arguments.of("test.war", "test.war"), + Arguments.of("a/b/c/test.war", "test.war"), + Arguments.of("bar%2Fbaz/test.war", "test.war"), + Arguments.of("fizz buzz/test.war", "test.war"), + Arguments.of("another one/bites the dust/", "bites the dust"), + Arguments.of("another+one/bites+the+dust/", "bites+the+dust"), + Arguments.of("another%20one/bites%20the%20dust/", "bites%20the%20dust"), + Arguments.of("spanish/n\u00FAmero.war", "n\u00FAmero.war"), + Arguments.of("spanish/n%C3%BAmero.war", "n%C3%BAmero.war"), + Arguments.of("a/b!/", "b"), + Arguments.of("a/b!/c/", "b"), + Arguments.of("a/b!/c/d/", "b"), + Arguments.of("a/b%21/", "b%21") + ); + } + /** * Similar to testPathGetResourceBaseName, but with "file:" URIs */ @ParameterizedTest - @MethodSource("baseResourceNames") + @MethodSource("fileUriBaseResourceNames") public void testFileUriGetUriLastPathSegment(String basePath, String expectedName) throws IOException { Path root = workDir.getPath(); Path base = root.resolve(basePath); + if (basePath.endsWith("/")) + { + FS.ensureDirExists(base); + } + else + { + FS.ensureDirExists(base.getParent()); + FS.touch(base); + } URI uri = base.toUri(); if (OS.MAC.isCurrentOs()) { @@ -216,7 +244,7 @@ public class WebInfConfigurationTest assertThat(WebInfConfiguration.getUriLastPathSegment(uri), is(expectedName)); } - public static Stream jarFileBaseResourceNames() throws URISyntaxException, IOException + public static Stream uriLastSegmentSource() throws URISyntaxException, IOException { Path testJar = MavenTestingUtils.getTestResourcePathFile(TEST_RESOURCE_JAR); URI uri = new URI("jar", testJar.toUri().toASCIIString(), null); @@ -243,17 +271,7 @@ public class WebInfConfigurationTest } else { - String lastPathSegment = TEST_RESOURCE_JAR; - if (path.getFileName() != null) - { - lastPathSegment = path.getFileName().toString(); - } - // Strip last '/' from directory entries - if (Files.isDirectory(path) && lastPathSegment.endsWith("/")) - { - lastPathSegment = lastPathSegment.substring(0, lastPathSegment.length() - 1); - } - arguments.add(Arguments.of(path.toUri(), lastPathSegment)); + arguments.add(Arguments.of(path.toUri(), TEST_RESOURCE_JAR)); } }); } @@ -263,11 +281,11 @@ public class WebInfConfigurationTest } /** - * Tests of "jar:file:" based URIs + * Tests of URIs last segment, including "jar:file:" based URIs. */ @ParameterizedTest - @MethodSource("jarFileBaseResourceNames") - public void testJarFileUriGetUriLastPathSegment(URI uri, String expectedName) throws IOException + @MethodSource("uriLastSegmentSource") + public void testGetUriLastPathSegment(URI uri, String expectedName) throws IOException { assertThat(WebInfConfiguration.getUriLastPathSegment(uri), is(expectedName)); } From 13a574557b994f1777ebe2fb83d8fa56d178865b Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Wed, 6 Nov 2019 16:09:54 -0600 Subject: [PATCH 7/8] JarFileResource.getFile() now returns the Jar's java.io.File object Signed-off-by: Joakim Erdfelt --- .../org/eclipse/jetty/util/resource/JarFileResource.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java index cf6252f6bc1..eea92e9f19d 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java @@ -404,4 +404,12 @@ public class JarFileResource extends JarResource URL url = new URL(string); return url.sameFile(resource.getURI().toURL()); } + + @Override + public File getFile() + { + if (_file != null) + return _file; + return null; + } } From 64a916e6eca54c1006079c194210bbe818a0c1a5 Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 7 Nov 2019 05:11:48 -0600 Subject: [PATCH 8/8] Issue #4173 - use JarFileResource's Jar java.io.File object if present Signed-off-by: Joakim Erdfelt --- .../org/eclipse/jetty/util/resource/JarFileResource.java | 3 +-- .../java/org/eclipse/jetty/webapp/WebInfConfiguration.java | 6 ++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java index eea92e9f19d..0e8b7c42d27 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarFileResource.java @@ -405,8 +405,7 @@ public class JarFileResource extends JarResource return url.sameFile(resource.getURI().toURL()); } - @Override - public File getFile() + public File getJarFile() { if (_file != null) return _file; diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java index 08fcccbe4dc..0d3205f5fed 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebInfConfiguration.java @@ -42,6 +42,7 @@ import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.JarFileResource; import org.eclipse.jetty.util.resource.JarResource; import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.ResourceCollection; @@ -814,6 +815,11 @@ public class WebInfConfiguration extends AbstractConfiguration try { File resourceFile = resource.getFile(); + if ((resourceFile != null) && (resource instanceof JarFileResource)) + { + resourceFile = ((JarFileResource)resource).getJarFile(); + } + if (resourceFile != null) { return resourceFile.getName();