diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index 122641b2c6a..0d696db8950 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -71,6 +71,11 @@ + + org.eclipse.jetty.toolchain + jetty-test-helper + test + org.eclipse.jetty.toolchain jetty-test-helper diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index daab4099616..261badb7c4d 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -753,7 +753,7 @@ public class AnnotationParser public void parseDir (Resource dir, ClassNameResolver resolver) throws Exception { - if (!dir.isDirectory() || !dir.exists()) + if (!dir.isDirectory() || !dir.exists() || dir.getName().startsWith(".")) return; if (LOG.isDebugEnabled()) {LOG.debug("Scanning dir {}", dir);}; @@ -767,7 +767,7 @@ public class AnnotationParser if (res.isDirectory()) parseDir(res, resolver); String name = res.getName(); - if (name.endsWith(".class")) + if (isValidClassFileName(name)) { if ((resolver == null)|| (!resolver.isExcluded(name) && (!isParsed(name) || resolver.shouldOverride(name)))) { @@ -812,8 +812,12 @@ public class AnnotationParser { try { + //skip directories + if (entry.isDirectory()) + return; + String name = entry.getName(); - if (name.toLowerCase(Locale.ENGLISH).endsWith(".class")) + if (isValidClassFileName(name)) { String shortName = name.replace('/', '.').substring(0,name.length()-6); if ((resolver == null) @@ -930,28 +934,33 @@ public class AnnotationParser JarEntry entry = jar_in.getNextJarEntry(); while (entry!=null) { - try + //skip directories + if (!entry.isDirectory()) { - String name = entry.getName(); - if (name.toLowerCase(Locale.ENGLISH).endsWith(".class")) + try { - String shortName = name.replace('/', '.').substring(0,name.length()-6); + String name = entry.getName(); - if ((resolver == null) - || - (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName)))) + //skip any class files that are in a hidden directory (ie dirname starts with .) + if (isValidClassFileName(name)) { - Resource clazz = Resource.newResource("jar:"+uri+"!/"+name); - if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);}; - scanClass(clazz.getInputStream()); + String shortName = name.replace('/', '.').substring(0,name.length()-6); + + if ((resolver == null) + || + (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName)))) + { + Resource clazz = Resource.newResource("jar:"+uri+"!/"+name); + if (LOG.isDebugEnabled()) {LOG.debug("Scanning class from jar {}", clazz);}; + scanClass(clazz.getInputStream()); + } } } + catch (Exception e) + { + LOG.warn("Problem processing jar entry "+entry, e); + } } - catch (Exception e) - { - LOG.warn("Problem processing jar entry "+entry, e); - } - entry = jar_in.getNextJarEntry(); } } @@ -975,5 +984,37 @@ public class AnnotationParser ClassReader reader = new ClassReader(is); reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES); } + + /** + * Check that the given path represents a valid class file name. + * The check is fairly cursory, checking that: + * + * @param path + * @return + */ + private boolean isValidClassFileName (String path) + { + //skip anything that is not a class file + if (!path.toLowerCase(Locale.ENGLISH).endsWith(".class")) + return false; + + //skip any classfiles that are not a valid name + int c0 = 0; + int ldir = path.lastIndexOf('/', path.length()-6); + c0 = (ldir > -1 ? ldir+1 : c0); + + if (!Character.isJavaIdentifierStart(path.charAt(c0))) + return false; + + //skip any classfiles that are in a hidden directory + if (path.startsWith(".") || path.contains("/.")) + return false; + + return true; + } } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java index 4e95a026501..8deecacef4c 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationParser.java @@ -22,11 +22,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import java.io.File; import java.util.Arrays; import java.util.List; import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.junit.Test; public class TestAnnotationParser @@ -162,4 +164,14 @@ public class TestAnnotationParser parser.registerHandler(new MultiAnnotationHandler()); parser.parse(classNames, null); } + + + @Test + public void testHiddenFilesInJar () throws Exception + { + File badClassesJar = MavenTestingUtils.getTestResourceFile("bad-classes.jar"); + AnnotationParser parser = new AnnotationParser(); + parser.parse(badClassesJar.toURI(), null); + //only the valid classes inside bad-classes.jar should be parsed. If any invalid classes are parsed and exception would be thrown here + } } diff --git a/jetty-annotations/src/test/resources/bad-classes.jar b/jetty-annotations/src/test/resources/bad-classes.jar new file mode 100644 index 00000000000..5538c18b552 Binary files /dev/null and b/jetty-annotations/src/test/resources/bad-classes.jar differ