* Fix #6305 Optimise isProtectedTarget Fix #6305 Optimise isProtectedTarget by using case insensitive Index. Signed-off-by: Greg Wilkins <gregw@webtide.com> * Fix #6305 Optimise isProtectedTarget updates from review Signed-off-by: Greg Wilkins <gregw@webtide.com> * Fix #6305 Optimise isProtectedTarget updates from review Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
parent
9e03775a7f
commit
0d71185e10
|
@ -73,6 +73,7 @@ import org.eclipse.jetty.server.Request;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.util.Attributes;
|
import org.eclipse.jetty.util.Attributes;
|
||||||
import org.eclipse.jetty.util.AttributesMap;
|
import org.eclipse.jetty.util.AttributesMap;
|
||||||
|
import org.eclipse.jetty.util.Index;
|
||||||
import org.eclipse.jetty.util.Loader;
|
import org.eclipse.jetty.util.Loader;
|
||||||
import org.eclipse.jetty.util.MultiException;
|
import org.eclipse.jetty.util.MultiException;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
@ -179,6 +180,16 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
DESTROYED
|
DESTROYED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of protected target match
|
||||||
|
* @see #_protectedTargets
|
||||||
|
*/
|
||||||
|
private enum ProtectedTargetType
|
||||||
|
{
|
||||||
|
EXACT,
|
||||||
|
PREFIX
|
||||||
|
}
|
||||||
|
|
||||||
protected ContextStatus _contextStatus = ContextStatus.NOTSET;
|
protected ContextStatus _contextStatus = ContextStatus.NOTSET;
|
||||||
protected Context _scontext;
|
protected Context _scontext;
|
||||||
private final AttributesMap _attributes;
|
private final AttributesMap _attributes;
|
||||||
|
@ -214,7 +225,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
private final List<ServletRequestAttributeListener> _servletRequestAttributeListeners = new CopyOnWriteArrayList<>();
|
private final List<ServletRequestAttributeListener> _servletRequestAttributeListeners = new CopyOnWriteArrayList<>();
|
||||||
private final List<ContextScopeListener> _contextListeners = new CopyOnWriteArrayList<>();
|
private final List<ContextScopeListener> _contextListeners = new CopyOnWriteArrayList<>();
|
||||||
private final Set<EventListener> _durableListeners = new HashSet<>();
|
private final Set<EventListener> _durableListeners = new HashSet<>();
|
||||||
private String[] _protectedTargets;
|
private Index<ProtectedTargetType> _protectedTargets = Index.empty(false);
|
||||||
private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<>();
|
private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
public enum Availability
|
public enum Availability
|
||||||
|
@ -1474,30 +1485,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
*/
|
*/
|
||||||
public boolean isProtectedTarget(String target)
|
public boolean isProtectedTarget(String target)
|
||||||
{
|
{
|
||||||
if (target == null || _protectedTargets == null)
|
if (target == null || _protectedTargets.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
while (target.startsWith("//"))
|
if (target.startsWith("//"))
|
||||||
{
|
// ignore empty segments which may be discard by file system
|
||||||
target = URIUtil.compactPath(target);
|
target = URIUtil.compactPath(target);
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < _protectedTargets.length; i++)
|
ProtectedTargetType type = _protectedTargets.getBest(target);
|
||||||
{
|
|
||||||
String t = _protectedTargets[i];
|
|
||||||
if (StringUtil.startsWithIgnoreCase(target, t))
|
|
||||||
{
|
|
||||||
if (target.length() == t.length())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Check that the target prefix really is a path segment, thus
|
return type == ProtectedTargetType.PREFIX ||
|
||||||
// it can end with /, a query, a target or a parameter
|
type == ProtectedTargetType.EXACT && _protectedTargets.get(target) == ProtectedTargetType.EXACT;
|
||||||
char c = target.charAt(t.length());
|
|
||||||
if (c == '/' || c == '?' || c == '#' || c == ';')
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1505,13 +1503,22 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
*/
|
*/
|
||||||
public void setProtectedTargets(String[] targets)
|
public void setProtectedTargets(String[] targets)
|
||||||
{
|
{
|
||||||
if (targets == null)
|
Index.Builder<ProtectedTargetType> builder = new Index.Builder<>();
|
||||||
|
if (targets != null)
|
||||||
{
|
{
|
||||||
_protectedTargets = null;
|
for (String t : targets)
|
||||||
return;
|
{
|
||||||
}
|
if (!t.startsWith("/"))
|
||||||
|
throw new IllegalArgumentException("Bad protected target: " + t);
|
||||||
|
|
||||||
_protectedTargets = Arrays.copyOf(targets, targets.length);
|
builder.with(t, ProtectedTargetType.EXACT);
|
||||||
|
builder.with(t + "/", ProtectedTargetType.PREFIX);
|
||||||
|
builder.with(t + "?", ProtectedTargetType.PREFIX);
|
||||||
|
builder.with(t + "#", ProtectedTargetType.PREFIX);
|
||||||
|
builder.with(t + ";", ProtectedTargetType.PREFIX);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_protectedTargets = builder.caseSensitive(false).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String[] getProtectedTargets()
|
public String[] getProtectedTargets()
|
||||||
|
@ -1519,7 +1526,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
||||||
if (_protectedTargets == null)
|
if (_protectedTargets == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return Arrays.copyOf(_protectedTargets, _protectedTargets.length);
|
return _protectedTargets.keySet().stream()
|
||||||
|
.filter(s -> _protectedTargets.get(s) == ProtectedTargetType.EXACT)
|
||||||
|
.toArray(String[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -646,9 +646,20 @@ public class ContextHandlerTest
|
||||||
String[] protectedTargets = {"/foo-inf", "/bar-inf"};
|
String[] protectedTargets = {"/foo-inf", "/bar-inf"};
|
||||||
handler.setProtectedTargets(protectedTargets);
|
handler.setProtectedTargets(protectedTargets);
|
||||||
|
|
||||||
|
assertTrue(handler.isProtectedTarget("/foo-inf"));
|
||||||
|
assertTrue(handler.isProtectedTarget("/Foo-Inf"));
|
||||||
|
assertTrue(handler.isProtectedTarget("/FOO-INF"));
|
||||||
|
assertTrue(handler.isProtectedTarget("/foo-inf/"));
|
||||||
|
assertTrue(handler.isProtectedTarget("/FOO-inf?"));
|
||||||
|
assertTrue(handler.isProtectedTarget("/FOO-INF;"));
|
||||||
|
assertTrue(handler.isProtectedTarget("/foo-INF#"));
|
||||||
|
assertTrue(handler.isProtectedTarget("//foo-inf"));
|
||||||
|
assertTrue(handler.isProtectedTarget("//foo-inf//some//path"));
|
||||||
|
assertTrue(handler.isProtectedTarget("///foo-inf"));
|
||||||
assertTrue(handler.isProtectedTarget("/foo-inf/x/y/z"));
|
assertTrue(handler.isProtectedTarget("/foo-inf/x/y/z"));
|
||||||
assertFalse(handler.isProtectedTarget("/foo/x/y/z"));
|
|
||||||
assertTrue(handler.isProtectedTarget("/foo-inf?x=y&z=1"));
|
assertTrue(handler.isProtectedTarget("/foo-inf?x=y&z=1"));
|
||||||
|
|
||||||
|
assertFalse(handler.isProtectedTarget("/foo/x/y/z"));
|
||||||
assertFalse(handler.isProtectedTarget("/foo-inf-bar"));
|
assertFalse(handler.isProtectedTarget("/foo-inf-bar"));
|
||||||
|
|
||||||
protectedTargets = new String[4];
|
protectedTargets = new String[4];
|
||||||
|
|
|
@ -73,7 +73,8 @@ public interface Index<V>
|
||||||
V getBest(String s, int offset, int len);
|
V getBest(String s, int offset, int len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the best match from key in a String.
|
* Get the best match from key in a String, which may be
|
||||||
|
* a prefix match or an exact match.
|
||||||
*
|
*
|
||||||
* @param s The string
|
* @param s The string
|
||||||
* @return The value or null if not found
|
* @return The value or null if not found
|
||||||
|
@ -267,6 +268,11 @@ public interface Index<V>
|
||||||
return new ArrayTrie<>(true, maxCapacity);
|
return new ArrayTrie<>(true, maxCapacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static <V> Index<V> empty(boolean caseSensitive)
|
||||||
|
{
|
||||||
|
return EmptyTrie.instance(caseSensitive);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builder of {@link Index} instances.
|
* Builder of {@link Index} instances.
|
||||||
* @param <V> the entry type
|
* @param <V> the entry type
|
||||||
|
|
Loading…
Reference in New Issue