Issue #4183 Handle null class location for ClasspathPattern. (#4197)

Signed-off-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
Jan Bartel 2019-10-16 14:14:49 +11:00 committed by GitHub
parent 73924d2774
commit 20e7aa01f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 80 additions and 7 deletions

View File

@ -71,7 +71,7 @@ public class ClasspathPattern extends AbstractSet<String>
{
private static final Logger LOG = Log.getLogger(ClasspathPattern.class);
private static class Entry
static class Entry
{
private final String _pattern;
private final String _name;
@ -727,21 +727,43 @@ public class ClasspathPattern extends AbstractSet<String>
});
}
private static boolean combine(IncludeExcludeSet<Entry, String> names, String name, IncludeExcludeSet<Entry, URI> locations, Supplier<URI> location)
/**
* Match a class against inclusions and exclusions by name and location.
* Name based checks are performed before location checks. For a class to match,
* it must not be excluded by either name or location, and must either be explicitly
* included, or for there to be no inclusions. In the case where the location
* of the class is null, it will match if it is included by name, or
* if there are no location exclusions.
*
* @param names configured inclusions and exclusions by name
* @param name the name to check
* @param locations configured inclusions and exclusions by location
* @param location the location of the class (can be null)
* @return true if the class is not excluded but is included, or there are
* no inclusions. False otherwise.
*/
static boolean combine(IncludeExcludeSet<Entry, String> names, String name, IncludeExcludeSet<Entry, URI> locations, Supplier<URI> location)
{
// check the name set
Boolean byName = names.isIncludedAndNotExcluded(name);
// If we excluded by name, then no match
if (Boolean.FALSE == byName)
return false;
// check the location set
URI uri = location.get();
if (uri == null)
return locations.isEmpty() || locations.hasExcludes() && !locations.hasIncludes();
Boolean byLocation = uri == null ? null : locations.isIncludedAndNotExcluded(uri);
Boolean byLocation = locations.isIncludedAndNotExcluded(uri);
if (Boolean.FALSE == byLocation)
// If we excluded by location or couldn't check location exclusion, then no match
if (Boolean.FALSE == byLocation || (locations.hasExcludes() && uri == null))
return false;
return Boolean.TRUE.equals(byName) || Boolean.TRUE.equals(byLocation) || !(names.hasIncludes() || locations.hasIncludes());
// If there are includes, then we must be included to match.
if (names.hasIncludes() || locations.hasIncludes())
return byName == Boolean.TRUE || byLocation == Boolean.TRUE;
// Otherwise there are no includes and it was not excluded, so match
return true;
}
}

View File

@ -20,8 +20,13 @@ package org.eclipse.jetty.webapp;
import java.net.URI;
import java.util.Arrays;
import java.util.function.Supplier;
import org.eclipse.jetty.util.IncludeExcludeSet;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.webapp.ClasspathPattern.ByLocationOrModule;
import org.eclipse.jetty.webapp.ClasspathPattern.ByPackageOrName;
import org.eclipse.jetty.webapp.ClasspathPattern.Entry;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -36,6 +41,14 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class ClasspathPatternTest
{
private final ClasspathPattern _pattern = new ClasspathPattern();
protected static Supplier<URI> NULL_SUPPLIER = new Supplier<URI>()
{
public URI get()
{
return null;
}
};
@BeforeEach
public void before()
@ -262,6 +275,44 @@ public class ClasspathPatternTest
assertThat(pattern.match(Test.class), Matchers.is(false));
assertThat(pattern.match(ClasspathPatternTest.class), Matchers.is(false));
}
@Test
public void testWithNullLocation() throws Exception
{
ClasspathPattern pattern = new ClasspathPattern();
IncludeExcludeSet<Entry, String> names = new IncludeExcludeSet<>(ByPackageOrName.class);
IncludeExcludeSet<Entry, URI> locations = new IncludeExcludeSet<>(ByLocationOrModule.class);
//Test no name or location includes or excludes - should match
assertThat(ClasspathPattern.combine(names, "a.b.c", locations, NULL_SUPPLIER), Matchers.is(true));
names.include(pattern.newEntry("a.b.", true));
names.exclude(pattern.newEntry("d.e.", false));
//Test explicit include by name no locations - should match
assertThat(ClasspathPattern.combine(names, "a.b.c", locations, NULL_SUPPLIER), Matchers.is(true));
//Test explicit exclude by name no locations - should not match
assertThat(ClasspathPattern.combine(names, "d.e.f", locations, NULL_SUPPLIER), Matchers.is(false));
//Test include by name with location includes - should match
locations.include(pattern.newEntry("file:/foo/bar", true));
assertThat(ClasspathPattern.combine(names, "a.b.c", locations, NULL_SUPPLIER), Matchers.is(true));
//Test include by name but with location exclusions - should not match
locations.clear();
locations.exclude(pattern.newEntry("file:/high/low", false));
assertThat(ClasspathPattern.combine(names, "a.b.c", locations, NULL_SUPPLIER), Matchers.is(false));
//Test neither included or excluded by name, but with location exclusions - should not match
assertThat(ClasspathPattern.combine(names, "g.b.r", locations, NULL_SUPPLIER), Matchers.is(false));
//Test neither included nor excluded by name, but with location inclusions - should not match
locations.clear();
locations.include(pattern.newEntry("file:/foo/bar", true));
assertThat(ClasspathPattern.combine(names, "g.b.r", locations, NULL_SUPPLIER), Matchers.is(false));
}
@Test
public void testLarge()