replace Trie interface and impls usage with new *Index interfaces and Builders

Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
Ludovic Orban 2020-11-23 14:56:54 +01:00
parent df5622ecfc
commit aa8bd5d820
30 changed files with 1363 additions and 1045 deletions

View File

@ -26,10 +26,9 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -92,13 +91,11 @@ public class HttpGenerator
private final int _send;
private static final int SEND_SERVER = 0x01;
private static final int SEND_XPOWEREDBY = 0x02;
private static final Trie<Boolean> ASSUMED_CONTENT_METHODS = new ArrayTrie<>(8);
static
{
ASSUMED_CONTENT_METHODS.put(HttpMethod.POST.asString(), Boolean.TRUE);
ASSUMED_CONTENT_METHODS.put(HttpMethod.PUT.asString(), Boolean.TRUE);
}
private static final Index<Boolean> ASSUMED_CONTENT_METHODS = new Index.Builder<Boolean>()
.caseSensitive(false)
.with(HttpMethod.POST.asString(), Boolean.TRUE)
.with(HttpMethod.PUT.asString(), Boolean.TRUE)
.build();
public static void setJettyVersion(String serverVersion)
{
@ -679,7 +676,7 @@ public class HttpGenerator
// Calculate how to end _content and connection, _content length and transfer encoding
// settings from http://tools.ietf.org/html/rfc7230#section-3.3.3
boolean assumedContentRequest = request != null && Boolean.TRUE.equals(ASSUMED_CONTENT_METHODS.get(request.getMethod()));
boolean assumedContentRequest = request != null && ASSUMED_CONTENT_METHODS.get(request.getMethod()) != null;
boolean assumedContent = assumedContentRequest || contentType || chunkedHint;
boolean noContentRequest = request != null && contentLength <= 0 && !assumedContent;

View File

@ -20,9 +20,8 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
public enum HttpHeader
{
@ -133,21 +132,12 @@ public enum HttpHeader
C_AUTHORITY(":authority", true),
C_PATH(":path", true),
C_STATUS(":status", true),
C_PROTOCOL(":protocol"),
C_PROTOCOL(":protocol");
UNKNOWN("::UNKNOWN::", true);
public static final Trie<HttpHeader> CACHE = new ArrayTrie<>(630);
static
{
for (HttpHeader header : HttpHeader.values())
{
if (header != UNKNOWN)
if (!CACHE.put(header.toString(), header))
throw new IllegalStateException();
}
}
public static final Index<HttpHeader> CACHE = new Index.Builder<HttpHeader>()
.caseSensitive(false)
.withAll(HttpHeader.values(), HttpHeader::toString)
.build();
private final String _string;
private final String _lowerCase;

View File

@ -21,9 +21,8 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.util.EnumSet;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Index;
/**
*
@ -40,19 +39,12 @@ public enum HttpHeaderValue
TE("TE"),
BYTES("bytes"),
NO_CACHE("no-cache"),
UPGRADE("Upgrade"),
UNKNOWN("::UNKNOWN::");
UPGRADE("Upgrade");
public static final Trie<HttpHeaderValue> CACHE = new ArrayTrie<HttpHeaderValue>();
static
{
for (HttpHeaderValue value : HttpHeaderValue.values())
{
if (value != UNKNOWN)
CACHE.put(value.toString(), value);
}
}
public static final Index<HttpHeaderValue> CACHE = new Index.Builder<HttpHeaderValue>()
.caseSensitive(false)
.withAll(HttpHeaderValue.values(), HttpHeaderValue::toString)
.build();
private final String _string;
private final ByteBuffer _buffer;

View File

@ -20,10 +20,8 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
/**
* Known HTTP Methods
@ -142,29 +140,24 @@ public enum HttpMethod
return _method;
}
public static final Trie<HttpMethod> INSENSITIVE_CACHE = new ArrayTrie<>(252);
public static final Trie<HttpMethod> CACHE = new ArrayTernaryTrie<>(false, 300);
public static final Trie<HttpMethod> LOOK_AHEAD = new ArrayTernaryTrie<>(false, 330);
public static final Index<HttpMethod> INSENSITIVE_CACHE = new Index.Builder<HttpMethod>()
.caseSensitive(false)
.withAll(HttpMethod.values(), HttpMethod::asString)
.build();
public static final Index<HttpMethod> CACHE = new Index.Builder<HttpMethod>()
.caseSensitive(true)
.withAll(HttpMethod.values(), HttpMethod::asString)
.build();
public static final Index<HttpMethod> LOOK_AHEAD = new Index.Builder<HttpMethod>()
.caseSensitive(true)
.withAll(HttpMethod.values(), httpMethod -> httpMethod.asString() + ' ')
.build();
public static final int ACL_AS_INT = ('A' & 0xff) << 24 | ('C' & 0xFF) << 16 | ('L' & 0xFF) << 8 | (' ' & 0xFF);
public static final int GET_AS_INT = ('G' & 0xff) << 24 | ('E' & 0xFF) << 16 | ('T' & 0xFF) << 8 | (' ' & 0xFF);
public static final int PRI_AS_INT = ('P' & 0xff) << 24 | ('R' & 0xFF) << 16 | ('I' & 0xFF) << 8 | (' ' & 0xFF);
public static final int PUT_AS_INT = ('P' & 0xff) << 24 | ('U' & 0xFF) << 16 | ('T' & 0xFF) << 8 | (' ' & 0xFF);
public static final int POST_AS_INT = ('P' & 0xff) << 24 | ('O' & 0xFF) << 16 | ('S' & 0xFF) << 8 | ('T' & 0xFF);
public static final int HEAD_AS_INT = ('H' & 0xff) << 24 | ('E' & 0xFF) << 16 | ('A' & 0xFF) << 8 | ('D' & 0xFF);
static
{
for (HttpMethod method : HttpMethod.values())
{
if (!INSENSITIVE_CACHE.put(method.asString(), method))
throw new IllegalStateException("INSENSITIVE_CACHE too small: " + method);
if (!CACHE.put(method.asString(), method))
throw new IllegalStateException("CACHE too small: " + method);
if (!LOOK_AHEAD.put(method.asString() + ' ', method))
throw new IllegalStateException("LOOK_AHEAD too small: " + method);
}
}
/**
* Optimized lookup to find a method name and trailing space in a byte array.

View File

@ -21,15 +21,15 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.EnumSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.eclipse.jetty.http.HttpTokens.EndOfContent;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -67,7 +67,7 @@ import static org.eclipse.jetty.http.HttpCompliance.Violation.WHITESPACE_AFTER_F
* </p>
* <p>
* For performance, the parse is heavily dependent on the
* {@link Trie#getBest(ByteBuffer, int, int)} method to look ahead in a
* {@link Index#getBest(ByteBuffer, int, int)} method to look ahead in a
* single pass for both the structure ( : and CRLF ) and semantic (which
* header and value) of a header. Specifically the static {@link HttpHeader#CACHE}
* is used to lookup common combinations of headers and values
@ -106,8 +106,74 @@ public class HttpParser
* determine the header name even if the name:value combination is not cached
* </ul>
*/
public static final Trie<HttpField> CACHE = new ArrayTrie<>(2048);
private static final Trie<HttpField> NO_CACHE = Trie.empty(true);
public static final Index<HttpField> CACHE = new Index.Builder<HttpField>()
.caseSensitive(false)
.with(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE))
.with(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE))
.with(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.UPGRADE))
.with(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip"))
.with(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip, deflate"))
.with(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip, deflate, br"))
.with(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip,deflate,sdch"))
.with(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-US,enq=0.5"))
.with(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-GB,en-USq=0.8,enq=0.6"))
.with(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-AU,enq=0.9,it-ITq=0.8,itq=0.7,en-GBq=0.6,en-USq=0.5"))
.with(new HttpField(HttpHeader.ACCEPT_CHARSET, "ISO-8859-1,utf-8q=0.7,*q=0.3"))
.with(new HttpField(HttpHeader.ACCEPT, "*/*"))
.with(new HttpField(HttpHeader.ACCEPT, "image/png,image/*q=0.8,*/*q=0.5"))
.with(new HttpField(HttpHeader.ACCEPT, "text/html,application/xhtml+xml,application/xmlq=0.9,*/*q=0.8"))
.with(new HttpField(HttpHeader.ACCEPT, "text/html,application/xhtml+xml,application/xmlq=0.9,image/webp,image/apng,*/*q=0.8"))
.with(new HttpField(HttpHeader.ACCEPT_RANGES, HttpHeaderValue.BYTES))
.with(new HttpField(HttpHeader.PRAGMA, "no-cache"))
.with(new HttpField(HttpHeader.CACHE_CONTROL, "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"))
.with(new HttpField(HttpHeader.CACHE_CONTROL, "no-cache"))
.with(new HttpField(HttpHeader.CACHE_CONTROL, "max-age=0"))
.with(new HttpField(HttpHeader.CONTENT_LENGTH, "0"))
.with(new HttpField(HttpHeader.CONTENT_ENCODING, "gzip"))
.with(new HttpField(HttpHeader.CONTENT_ENCODING, "deflate"))
.with(new HttpField(HttpHeader.TRANSFER_ENCODING, "chunked"))
.with(new HttpField(HttpHeader.EXPIRES, "Fri, 01 Jan 1990 00:00:00 GMT"))
.withAll(() ->
{
Map<String, HttpField> map = new LinkedHashMap<>();
// Add common Content types as fields
for (String type : new String[]{
"text/plain", "text/html", "text/xml", "text/json", "application/json", "application/x-www-form-urlencoded"
})
{
HttpField field = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type);
map.put(field.toString(), field);
for (String charset : new String[]{"utf-8", "iso-8859-1"})
{
PreEncodedHttpField field1 = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + ";charset=" + charset);
map.put(field1.toString(), field1);
PreEncodedHttpField field2 = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + "; charset=" + charset);
map.put(field2.toString(), field2);
PreEncodedHttpField field3 = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + ";charset=" + charset.toUpperCase(Locale.ENGLISH));
map.put(field3.toString(), field3);
PreEncodedHttpField field4 = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + "; charset=" + charset.toUpperCase(Locale.ENGLISH));
map.put(field4.toString(), field4);
}
}
return map;
})
.withAll(() ->
{
Map<String, HttpField> map = new LinkedHashMap<>();
for (HttpHeader h : HttpHeader.values())
{
HttpField httpField = new HttpField(h, (String)null);
map.put(httpField.toString(), httpField);
}
return map;
})
.build();
private static final Index.Mutable<HttpField> NO_CACHE = new Index.Builder<HttpField>()
.caseSensitive(false)
.mutable()
.maxCapacity(0)
.build();
// States
public enum FieldState
@ -181,65 +247,12 @@ public class HttpParser
private boolean _headResponse;
private boolean _cr;
private ByteBuffer _contentChunk;
private Trie<HttpField> _fieldCache;
private Index.Mutable<HttpField> _fieldCache;
private int _length;
private final StringBuilder _string = new StringBuilder();
private int _headerCacheSize = 1024;
private boolean _headerCacheCaseSensitive;
static
{
CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE));
CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE));
CACHE.put(new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.UPGRADE));
CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip, deflate"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip, deflate, br"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING, "gzip,deflate,sdch"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-US,en;q=0.5"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-GB,en-US;q=0.8,en;q=0.6"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE, "en-AU,en;q=0.9,it-IT;q=0.8,it;q=0.7,en-GB;q=0.6,en-US;q=0.5"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET, "ISO-8859-1,utf-8;q=0.7,*;q=0.3"));
CACHE.put(new HttpField(HttpHeader.ACCEPT, "*/*"));
CACHE.put(new HttpField(HttpHeader.ACCEPT, "image/png,image/*;q=0.8,*/*;q=0.5"));
CACHE.put(new HttpField(HttpHeader.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"));
CACHE.put(new HttpField(HttpHeader.ACCEPT, "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"));
CACHE.put(new HttpField(HttpHeader.ACCEPT_RANGES, HttpHeaderValue.BYTES));
CACHE.put(new HttpField(HttpHeader.PRAGMA, "no-cache"));
CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL, "private, no-cache, no-cache=Set-Cookie, proxy-revalidate"));
CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL, "no-cache"));
CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL, "max-age=0"));
CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH, "0"));
CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING, "gzip"));
CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING, "deflate"));
CACHE.put(new HttpField(HttpHeader.TRANSFER_ENCODING, "chunked"));
CACHE.put(new HttpField(HttpHeader.EXPIRES, "Fri, 01 Jan 1990 00:00:00 GMT"));
// Add common Content types as fields
for (String type : new String[]{
"text/plain", "text/html", "text/xml", "text/json", "application/json", "application/x-www-form-urlencoded"
})
{
HttpField field = new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type);
CACHE.put(field);
for (String charset : new String[]{"utf-8", "iso-8859-1"})
{
CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + ";charset=" + charset));
CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + "; charset=" + charset));
CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + ";charset=" + charset.toUpperCase(Locale.ENGLISH)));
CACHE.put(new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, type + "; charset=" + charset.toUpperCase(Locale.ENGLISH)));
}
}
// Add headers with null values so HttpParser can avoid looking up name again for unknown values
for (HttpHeader h : HttpHeader.values())
{
if (!h.isPseudo() && !CACHE.put(new HttpField(h, (String)null)))
throw new IllegalStateException("CACHE FULL");
}
}
private static HttpCompliance compliance()
{
return RFC7230;
@ -1052,14 +1065,19 @@ public class HttpParser
if (_fieldCache == null)
{
_fieldCache = (getHeaderCacheSize() > 0 && (_version != null && _version == HttpVersion.HTTP_1_1))
? new ArrayTernaryTrie<>(getHeaderCacheSize())
? new Index.Builder<HttpField>()
.caseSensitive(false)
.mutable()
.maxCapacity(getHeaderCacheSize())
.build()
: NO_CACHE;
}
if (!_fieldCache.isFull())
if (_field == null)
_field = new HttpField(_header, caseInsensitiveHeader(_headerString, _header.asString()), _valueString);
if (!_fieldCache.put(_field))
{
if (_field == null)
_field = new HttpField(_header, caseInsensitiveHeader(_headerString, _header.asString()), _valueString);
_fieldCache.clear();
_fieldCache.put(_field);
}
}
@ -1898,7 +1916,7 @@ public class HttpParser
_fieldState = state;
}
public Trie<HttpField> getFieldCache()
public Index<HttpField> getFieldCache()
{
return _fieldCache;
}

View File

@ -20,9 +20,8 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Index;
/**
* HTTP and WebSocket Schemes
@ -34,15 +33,10 @@ public enum HttpScheme
WS("ws", 80),
WSS("wss", 443);
public static final Trie<HttpScheme> CACHE = new ArrayTrie<HttpScheme>();
static
{
for (HttpScheme version : HttpScheme.values())
{
CACHE.put(version.asString(), version);
}
}
public static final Index<HttpScheme> CACHE = new Index.Builder<HttpScheme>()
.caseSensitive(false)
.withAll(HttpScheme.values(), HttpScheme::asString)
.build();
private final String _string;
private final ByteBuffer _buffer;

View File

@ -20,9 +20,8 @@ package org.eclipse.jetty.http;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
public enum HttpVersion
{
@ -31,15 +30,10 @@ public enum HttpVersion
HTTP_1_1("HTTP/1.1", 11),
HTTP_2("HTTP/2.0", 20);
public static final Trie<HttpVersion> CACHE = new ArrayTrie<HttpVersion>();
static
{
for (HttpVersion version : HttpVersion.values())
{
CACHE.put(version.toString(), version);
}
}
public static final Index<HttpVersion> CACHE = new Index.Builder<HttpVersion>()
.caseSensitive(false)
.withAll(HttpVersion.values(), HttpVersion::toString)
.build();
/**
* Optimised lookup to find an Http Version and whitespace in a byte array.

View File

@ -32,10 +32,9 @@ import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -46,7 +45,6 @@ public class MimeTypes
{
private static final Logger LOG = LoggerFactory.getLogger(MimeTypes.class);
private static final Trie<ByteBuffer> TYPES = new ArrayTrie<ByteBuffer>(512);
private static final Map<String, String> __dftMimeMap = new HashMap<String, String>();
private static final Map<String, String> __inferredEncodings = new HashMap<String, String>();
private static final Map<String, String> __assumedEncodings = new HashMap<String, String>();
@ -168,23 +166,30 @@ public class MimeTypes
}
}
public static final Trie<MimeTypes.Type> CACHE = new ArrayTrie<>(512);
public static final Index<Type> CACHE = new Index.Builder<Type>()
.caseSensitive(false)
.withAll(() ->
{
Map<String, Type> result = new HashMap<>();
for (Type type : Type.values())
{
String key1 = type.toString();
result.put(key1, type);
if (key1.indexOf(";charset=") > 0)
{
String key2 = StringUtil.replace(key1, ";charset=", "; charset=");
result.put(key2, type);
}
}
return result;
})
.build();
static
{
for (MimeTypes.Type type : MimeTypes.Type.values())
{
CACHE.put(type.toString(), type);
TYPES.put(type.toString(), type.asBuffer());
int charset = type.toString().indexOf(";charset=");
if (charset > 0)
{
String alt = StringUtil.replace(type.toString(), ";charset=", "; charset=");
CACHE.put(alt, type);
TYPES.put(alt, type.asBuffer());
}
if (type.isCharsetAssumed())
__assumedEncodings.put(type.asString(), type.getCharsetString());
}

View File

@ -28,8 +28,7 @@ import java.util.Set;
import java.util.TreeSet;
import java.util.function.Predicate;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.Dumpable;
@ -49,9 +48,18 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
private static final Logger LOG = LoggerFactory.getLogger(PathMappings.class);
private final Set<MappedResource<E>> _mappings = new TreeSet<>(Comparator.comparing(MappedResource::getPathSpec));
private Trie<MappedResource<E>> _exactMap = new ArrayTernaryTrie<>(false);
private Trie<MappedResource<E>> _prefixMap = new ArrayTernaryTrie<>(false);
private Trie<MappedResource<E>> _suffixMap = new ArrayTernaryTrie<>(false);
private final Index.Mutable<MappedResource<E>> _exactMap = new Index.Builder<MappedResource<E>>()
.caseSensitive(true)
.mutable()
.build();
private final Index.Mutable<MappedResource<E>> _prefixMap = new Index.Builder<MappedResource<E>>()
.caseSensitive(true)
.mutable()
.build();
private final Index.Mutable<MappedResource<E>> _suffixMap = new Index.Builder<MappedResource<E>>()
.caseSensitive(true)
.mutable()
.build();
@Override
public String dump()
@ -136,10 +144,9 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
case EXACT:
{
int i = path.length();
final Trie<MappedResource<E>> exact_map = _exactMap;
while (i >= 0)
{
MappedResource<E> candidate = exact_map.getBest(path, 0, i);
MappedResource<E> candidate = _exactMap.getBest(path, 0, i);
if (candidate == null)
break;
if (candidate.getPathSpec().matches(path))
@ -152,10 +159,9 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
case PREFIX_GLOB:
{
int i = path.length();
final Trie<MappedResource<E>> prefix_map = _prefixMap;
while (i >= 0)
{
MappedResource<E> candidate = prefix_map.getBest(path, 0, i);
MappedResource<E> candidate = _prefixMap.getBest(path, 0, i);
if (candidate == null)
break;
if (candidate.getPathSpec().matches(path))
@ -168,10 +174,9 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
case SUFFIX_GLOB:
{
int i = 0;
final Trie<MappedResource<E>> suffix_map = _suffixMap;
while ((i = path.indexOf('.', i + 1)) > 0)
{
MappedResource<E> candidate = suffix_map.get(path, i + 1, path.length() - i - 1);
MappedResource<E> candidate = _suffixMap.get(path, i + 1, path.length() - i - 1);
if (candidate != null && candidate.getPathSpec().matches(path))
return candidate;
}
@ -230,24 +235,18 @@ public class PathMappings<E> implements Iterable<MappedResource<E>>, Dumpable
{
case EXACT:
String exact = pathSpec.getPrefix();
while (exact != null && !_exactMap.put(exact, entry))
{
_exactMap = new ArrayTernaryTrie<>((ArrayTernaryTrie<MappedResource<E>>)_exactMap, 1.5);
}
if (exact != null)
_exactMap.put(exact, entry);
break;
case PREFIX_GLOB:
String prefix = pathSpec.getPrefix();
while (prefix != null && !_prefixMap.put(prefix, entry))
{
_prefixMap = new ArrayTernaryTrie<>((ArrayTernaryTrie<MappedResource<E>>)_prefixMap, 1.5);
}
if (prefix != null)
_prefixMap.put(prefix, entry);
break;
case SUFFIX_GLOB:
String suffix = pathSpec.getSuffix();
while (suffix != null && !_suffixMap.put(suffix, entry))
{
_suffixMap = new ArrayTernaryTrie<>((ArrayTernaryTrie<MappedResource<E>>)_prefixMap, 1.5);
}
if (suffix != null)
_suffixMap.put(suffix, entry);
break;
default:
}

View File

@ -20,319 +20,310 @@ package org.eclipse.jetty.http2;
import java.util.Comparator;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Index;
public class HTTP2Cipher
{
public static final Comparator<String> COMPARATOR = new CipherComparator();
private static final Trie<Boolean> __blackProtocols = new ArrayTrie<>(6 * 5);
private static final Trie<Boolean> __blackCiphers = new ArrayTrie<>(275 * 40);
private static final Index<Boolean> __blackProtocols = new Index.Builder<Boolean>()
.caseSensitive(false)
.with("TLSv1.2", Boolean.TRUE)
.with("TLSv1.1", Boolean.TRUE)
.with("TLSv1", Boolean.TRUE)
.with("SSL", Boolean.TRUE)
.with("SSLv2", Boolean.TRUE)
.with("SSLv3", Boolean.TRUE)
.build();
static
{
String[] protocols = {"TLSv1.2", "TLSv1.1", "TLSv1", "SSL", "SSLv2", "SSLv3"};
for (String p : protocols)
{
__blackProtocols.put(p, Boolean.TRUE);
}
String[] ciphers =
{
"TLS_NULL_WITH_NULL_NULL",
"TLS_RSA_WITH_NULL_MD5",
"TLS_RSA_WITH_NULL_SHA",
"TLS_RSA_EXPORT_WITH_RC4_40_MD5",
"TLS_RSA_WITH_RC4_128_MD5",
"TLS_RSA_WITH_RC4_128_SHA",
"TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_RSA_WITH_IDEA_CBC_SHA",
"TLS_RSA_EXPORT_WITH_DES40_CBC_SHA",
"TLS_RSA_WITH_DES_CBC_SHA",
"TLS_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DH_DSS_WITH_DES_CBC_SHA",
"TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA",
"TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DH_RSA_WITH_DES_CBC_SHA",
"TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DHE_DSS_WITH_DES_CBC_SHA",
"TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DHE_RSA_WITH_DES_CBC_SHA",
"TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_DH_anon_EXPORT_WITH_RC4_40_MD5",
"TLS_DH_anon_WITH_RC4_128_MD5",
"TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA",
"TLS_DH_anon_WITH_DES_CBC_SHA",
"TLS_DH_anon_WITH_3DES_EDE_CBC_SHA",
"TLS_KRB5_WITH_DES_CBC_SHA",
"TLS_KRB5_WITH_3DES_EDE_CBC_SHA",
"TLS_KRB5_WITH_RC4_128_SHA",
"TLS_KRB5_WITH_IDEA_CBC_SHA",
"TLS_KRB5_WITH_DES_CBC_MD5",
"TLS_KRB5_WITH_3DES_EDE_CBC_MD5",
"TLS_KRB5_WITH_RC4_128_MD5",
"TLS_KRB5_WITH_IDEA_CBC_MD5",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA",
"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA",
"TLS_KRB5_EXPORT_WITH_RC4_40_SHA",
"TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5",
"TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5",
"TLS_KRB5_EXPORT_WITH_RC4_40_MD5",
"TLS_PSK_WITH_NULL_SHA",
"TLS_DHE_PSK_WITH_NULL_SHA",
"TLS_RSA_PSK_WITH_NULL_SHA",
"TLS_RSA_WITH_AES_128_CBC_SHA",
"TLS_DH_DSS_WITH_AES_128_CBC_SHA",
"TLS_DH_RSA_WITH_AES_128_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_DH_anon_WITH_AES_128_CBC_SHA",
"TLS_RSA_WITH_AES_256_CBC_SHA",
"TLS_DH_DSS_WITH_AES_256_CBC_SHA",
"TLS_DH_RSA_WITH_AES_256_CBC_SHA",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_DH_anon_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_NULL_SHA256",
"TLS_RSA_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DH_DSS_WITH_AES_128_CBC_SHA256",
"TLS_DH_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_128_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA",
"TLS_DHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_DH_DSS_WITH_AES_256_CBC_SHA256",
"TLS_DH_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_AES_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_AES_256_CBC_SHA256",
"TLS_DH_anon_WITH_AES_128_CBC_SHA256",
"TLS_DH_anon_WITH_AES_256_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA",
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA",
"TLS_PSK_WITH_RC4_128_SHA",
"TLS_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_PSK_WITH_AES_128_CBC_SHA",
"TLS_PSK_WITH_AES_256_CBC_SHA",
"TLS_DHE_PSK_WITH_RC4_128_SHA",
"TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_RSA_PSK_WITH_RC4_128_SHA",
"TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_RSA_PSK_WITH_AES_128_CBC_SHA",
"TLS_RSA_PSK_WITH_AES_256_CBC_SHA",
"TLS_RSA_WITH_SEED_CBC_SHA",
"TLS_DH_DSS_WITH_SEED_CBC_SHA",
"TLS_DH_RSA_WITH_SEED_CBC_SHA",
"TLS_DHE_DSS_WITH_SEED_CBC_SHA",
"TLS_DHE_RSA_WITH_SEED_CBC_SHA",
"TLS_DH_anon_WITH_SEED_CBC_SHA",
"TLS_RSA_WITH_AES_128_GCM_SHA256",
"TLS_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DH_RSA_WITH_AES_128_GCM_SHA256",
"TLS_DH_RSA_WITH_AES_256_GCM_SHA384",
"TLS_DH_DSS_WITH_AES_128_GCM_SHA256",
"TLS_DH_DSS_WITH_AES_256_GCM_SHA384",
"TLS_DH_anon_WITH_AES_128_GCM_SHA256",
"TLS_DH_anon_WITH_AES_256_GCM_SHA384",
"TLS_PSK_WITH_AES_128_GCM_SHA256",
"TLS_PSK_WITH_AES_256_GCM_SHA384",
"TLS_RSA_PSK_WITH_AES_128_GCM_SHA256",
"TLS_RSA_PSK_WITH_AES_256_GCM_SHA384",
"TLS_PSK_WITH_AES_128_CBC_SHA256",
"TLS_PSK_WITH_AES_256_CBC_SHA384",
"TLS_PSK_WITH_NULL_SHA256",
"TLS_PSK_WITH_NULL_SHA384",
"TLS_DHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_DHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_DHE_PSK_WITH_NULL_SHA256",
"TLS_DHE_PSK_WITH_NULL_SHA384",
"TLS_RSA_PSK_WITH_AES_128_CBC_SHA256",
"TLS_RSA_PSK_WITH_AES_256_CBC_SHA384",
"TLS_RSA_PSK_WITH_NULL_SHA256",
"TLS_RSA_PSK_WITH_NULL_SHA384",
"TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256",
"TLS_EMPTY_RENEGOTIATION_INFO_SCSV",
"TLS_ECDH_ECDSA_WITH_NULL_SHA",
"TLS_ECDH_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_NULL_SHA",
"TLS_ECDHE_ECDSA_WITH_RC4_128_SHA",
"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_RSA_WITH_NULL_SHA",
"TLS_ECDH_RSA_WITH_RC4_128_SHA",
"TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_RSA_WITH_NULL_SHA",
"TLS_ECDHE_RSA_WITH_RC4_128_SHA",
"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA",
"TLS_ECDH_anon_WITH_NULL_SHA",
"TLS_ECDH_anon_WITH_RC4_128_SHA",
"TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_128_CBC_SHA",
"TLS_ECDH_anon_WITH_AES_256_CBC_SHA",
"TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA",
"TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA",
"TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA",
"TLS_SRP_SHA_WITH_AES_128_CBC_SHA",
"TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA",
"TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA",
"TLS_SRP_SHA_WITH_AES_256_CBC_SHA",
"TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA",
"TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256",
"TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256",
"TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_PSK_WITH_RC4_128_SHA",
"TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA",
"TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384",
"TLS_ECDHE_PSK_WITH_NULL_SHA",
"TLS_ECDHE_PSK_WITH_NULL_SHA256",
"TLS_ECDHE_PSK_WITH_NULL_SHA384",
"TLS_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256",
"TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384",
"TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256",
"TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384",
"TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_DH_anon_WITH_ARIA_128_CBC_SHA256",
"TLS_DH_anon_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384",
"TLS_RSA_WITH_ARIA_128_GCM_SHA256",
"TLS_RSA_WITH_ARIA_256_GCM_SHA384",
"TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256",
"TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384",
"TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256",
"TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384",
"TLS_DH_anon_WITH_ARIA_128_GCM_SHA256",
"TLS_DH_anon_WITH_ARIA_256_GCM_SHA384",
"TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256",
"TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384",
"TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256",
"TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384",
"TLS_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_PSK_WITH_ARIA_128_GCM_SHA256",
"TLS_PSK_WITH_ARIA_256_GCM_SHA384",
"TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256",
"TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384",
"TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384",
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256",
"TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384",
"TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256",
"TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384",
"TLS_RSA_WITH_AES_128_CCM",
"TLS_RSA_WITH_AES_256_CCM",
"TLS_RSA_WITH_AES_128_CCM_8",
"TLS_RSA_WITH_AES_256_CCM_8",
"TLS_PSK_WITH_AES_128_CCM",
"TLS_PSK_WITH_AES_256_CCM",
"TLS_PSK_WITH_AES_128_CCM_8",
"TLS_PSK_WITH_AES_256_CCM_8"
};
for (String c : ciphers)
{
__blackCiphers.put(c, Boolean.TRUE);
}
}
private static final Index<Boolean> __blackCiphers = new Index.Builder<Boolean>()
.caseSensitive(false)
.with("TLS_NULL_WITH_NULL_NULL", Boolean.TRUE)
.with("TLS_RSA_WITH_NULL_MD5", Boolean.TRUE)
.with("TLS_RSA_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_RSA_EXPORT_WITH_RC4_40_MD5", Boolean.TRUE)
.with("TLS_RSA_WITH_RC4_128_MD5", Boolean.TRUE)
.with("TLS_RSA_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5", Boolean.TRUE)
.with("TLS_RSA_WITH_IDEA_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_EXPORT_WITH_DES40_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_WITH_DES_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_DES_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_DES_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_DES_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_DES_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_EXPORT_WITH_RC4_40_MD5", Boolean.TRUE)
.with("TLS_DH_anon_WITH_RC4_128_MD5", Boolean.TRUE)
.with("TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_WITH_DES_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_KRB5_WITH_DES_CBC_SHA", Boolean.TRUE)
.with("TLS_KRB5_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_KRB5_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_KRB5_WITH_IDEA_CBC_SHA", Boolean.TRUE)
.with("TLS_KRB5_WITH_DES_CBC_MD5", Boolean.TRUE)
.with("TLS_KRB5_WITH_3DES_EDE_CBC_MD5", Boolean.TRUE)
.with("TLS_KRB5_WITH_RC4_128_MD5", Boolean.TRUE)
.with("TLS_KRB5_WITH_IDEA_CBC_MD5", Boolean.TRUE)
.with("TLS_KRB5_EXPORT_WITH_DES_CBC_40_SHA", Boolean.TRUE)
.with("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_SHA", Boolean.TRUE)
.with("TLS_KRB5_EXPORT_WITH_RC4_40_SHA", Boolean.TRUE)
.with("TLS_KRB5_EXPORT_WITH_DES_CBC_40_MD5", Boolean.TRUE)
.with("TLS_KRB5_EXPORT_WITH_RC2_CBC_40_MD5", Boolean.TRUE)
.with("TLS_KRB5_EXPORT_WITH_RC4_40_MD5", Boolean.TRUE)
.with("TLS_PSK_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_WITH_NULL_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_AES_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_AES_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_AES_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA", Boolean.TRUE)
.with("TLS_PSK_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_PSK_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_WITH_SEED_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_SEED_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_SEED_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_SEED_CBC_SHA", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_SEED_CBC_SHA", Boolean.TRUE)
.with("TLS_DH_anon_WITH_SEED_CBC_SHA", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_anon_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_PSK_WITH_NULL_SHA256", Boolean.TRUE)
.with("TLS_PSK_WITH_NULL_SHA384", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_NULL_SHA256", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_NULL_SHA384", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_NULL_SHA256", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_NULL_SHA384", Boolean.TRUE)
.with("TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256", Boolean.TRUE)
.with("TLS_EMPTY_RENEGOTIATION_INFO_SCSV", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_anon_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_ECDH_anon_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_anon_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDH_anon_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_RSA_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_RSA_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_RC4_128_SHA", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_3DES_EDE_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_NULL_SHA", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_NULL_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_NULL_SHA384", Boolean.TRUE)
.with("TLS_RSA_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_DSS_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_RSA_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DH_anon_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_RSA_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_anon_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_PSK_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_PSK_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_PSK_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_PSK_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_ARIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_ARIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_ARIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_ARIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_PSK_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_PSK_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_CAMELLIA_128_GCM_SHA256", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_CAMELLIA_256_GCM_SHA384", Boolean.TRUE)
.with("TLS_PSK_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_PSK_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_DHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_RSA_PSK_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_CAMELLIA_128_CBC_SHA256", Boolean.TRUE)
.with("TLS_ECDHE_PSK_WITH_CAMELLIA_256_CBC_SHA384", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_128_CCM", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_256_CCM", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_128_CCM_8", Boolean.TRUE)
.with("TLS_RSA_WITH_AES_256_CCM_8", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_128_CCM", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_256_CCM", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_128_CCM_8", Boolean.TRUE)
.with("TLS_PSK_WITH_AES_256_CCM_8", Boolean.TRUE)
.build();
public static boolean isBlackListProtocol(String tlsProtocol)
{
Boolean b = __blackProtocols.get(tlsProtocol);
return b != null && b;
return __blackProtocols.get(tlsProtocol) != null;
}
public static boolean isBlackListCipher(String tlsCipher)
{
Boolean b = __blackCiphers.get(tlsCipher);
return b != null && b;
return __blackCiphers.get(tlsCipher) != null;
}
/**

View File

@ -29,9 +29,8 @@ import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -114,13 +113,14 @@ public class HpackContext
};
private static final Map<HttpField, Entry> __staticFieldMap = new HashMap<>();
private static final Trie<StaticEntry> __staticNameMap = new ArrayTernaryTrie<>(true, 512);
private static final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.UNKNOWN.ordinal()];
private static final Index<StaticEntry> __staticNameMap;
private static final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.values().length];
private static final StaticEntry[] __staticTable = new StaticEntry[STATIC_TABLE.length];
public static final int STATIC_SIZE = STATIC_TABLE.length - 1;
static
{
Index.Builder<StaticEntry> staticNameMapBuilder = new Index.Builder<StaticEntry>().caseSensitive(false);
Set<String> added = new HashSet<>();
for (int i = 1; i < STATIC_TABLE.length; i++)
{
@ -173,11 +173,10 @@ public class HpackContext
if (!added.contains(entry._field.getName()))
{
added.add(entry._field.getName());
__staticNameMap.put(entry._field.getName(), entry);
if (__staticNameMap.get(entry._field.getName()) == null)
throw new IllegalStateException("name trie too small");
staticNameMapBuilder.with(entry._field.getName(), entry);
}
}
__staticNameMap = staticNameMapBuilder.build();
for (HttpHeader h : HttpHeader.values())
{

View File

@ -28,8 +28,7 @@ import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Index;
/**
* Special handling for MSIE (Microsoft Internet Explorer).
@ -42,21 +41,19 @@ public class MsieRule extends Rule
{
private static final int IEv5 = '5';
private static final int IEv6 = '6';
private static final Trie<Boolean> __IE6_BadOS = new ArrayTernaryTrie<>();
private static final Index<Boolean> __IE6_BadOS = new Index.Builder<Boolean>()
.caseSensitive(false)
.with("NT 5.01", Boolean.TRUE)
.with("NT 5.0", Boolean.TRUE)
.with("NT 4.0", Boolean.TRUE)
.with("98", Boolean.TRUE)
.with("98; Win 9x 4.90", Boolean.TRUE)
.with("95", Boolean.TRUE)
.with("CE", Boolean.TRUE)
.build();
private static final HttpField CONNECTION_CLOSE = new HttpField(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE);
private static final HttpField VARY_USER_AGENT = new PreEncodedHttpField(HttpHeader.VARY, HttpHeader.USER_AGENT.asString());
static
{
__IE6_BadOS.put("NT 5.01", Boolean.TRUE);
__IE6_BadOS.put("NT 5.0", Boolean.TRUE);
__IE6_BadOS.put("NT 4.0", Boolean.TRUE);
__IE6_BadOS.put("98", Boolean.TRUE);
__IE6_BadOS.put("98; Win 9x 4.90", Boolean.TRUE);
__IE6_BadOS.put("95", Boolean.TRUE);
__IE6_BadOS.put("CE", Boolean.TRUE);
}
public MsieRule()
{
_handling = false;

View File

@ -24,8 +24,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Index;
/**
* MSIE (Microsoft Internet Explorer) SSL Rule.
@ -37,17 +36,16 @@ public class MsieSslRule extends Rule
{
private static final int IEv5 = '5';
private static final int IEv6 = '6';
private static Trie<Boolean> __IE6_BadOS = new ArrayTernaryTrie<>();
{
__IE6_BadOS.put("NT 5.01", Boolean.TRUE);
__IE6_BadOS.put("NT 5.0", Boolean.TRUE);
__IE6_BadOS.put("NT 4.0", Boolean.TRUE);
__IE6_BadOS.put("98", Boolean.TRUE);
__IE6_BadOS.put("98; Win 9x 4.90", Boolean.TRUE);
__IE6_BadOS.put("95", Boolean.TRUE);
__IE6_BadOS.put("CE", Boolean.TRUE);
}
private static final Index<Boolean> __IE6_BadOS = new Index.Builder<Boolean>()
.caseSensitive(false)
.with("NT 5.01", Boolean.TRUE)
.with("NT 5.0", Boolean.TRUE)
.with("NT 4.0", Boolean.TRUE)
.with("98", Boolean.TRUE)
.with("98; Win 9x 4.90", Boolean.TRUE)
.with("95", Boolean.TRUE)
.with("CE", Boolean.TRUE)
.build();
public MsieSslRule()
{

View File

@ -33,10 +33,9 @@ import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.QuotedCSVParser;
import org.eclipse.jetty.server.HttpConfiguration.Customizer;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.HostPort;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
import static java.lang.invoke.MethodType.methodType;
@ -159,7 +158,10 @@ public class ForwardedRequestCustomizer implements Customizer
private String _forwardedCipherSuiteHeader = "Proxy-auth-cert";
private String _forwardedSslSessionIdHeader = "Proxy-ssl-id";
private boolean _sslIsSecure = true;
private Trie<MethodHandle> _handles;
private final Index.Mutable<MethodHandle> _handles = new Index.Builder<MethodHandle>()
.caseSensitive(false)
.mutable()
.build();
public ForwardedRequestCustomizer()
{
@ -596,52 +598,33 @@ public class ForwardedRequestCustomizer implements Customizer
private void updateHandles()
{
int size = 0;
MethodHandles.Lookup lookup = MethodHandles.lookup();
// Loop to grow capacity of ArrayTrie for all headers
while (true)
try
{
try
{
size += 128; // experimented good baseline size
_handles = new ArrayTrie<>(size);
if (updateForwardedHandle(lookup, getForwardedHeader(), "handleRFC7239"))
continue;
if (updateForwardedHandle(lookup, getForwardedHostHeader(), "handleForwardedHost"))
continue;
if (updateForwardedHandle(lookup, getForwardedForHeader(), "handleForwardedFor"))
continue;
if (updateForwardedHandle(lookup, getForwardedPortHeader(), "handleForwardedPort"))
continue;
if (updateForwardedHandle(lookup, getForwardedProtoHeader(), "handleProto"))
continue;
if (updateForwardedHandle(lookup, getForwardedHttpsHeader(), "handleHttps"))
continue;
if (updateForwardedHandle(lookup, getForwardedServerHeader(), "handleForwardedServer"))
continue;
if (updateForwardedHandle(lookup, getForwardedCipherSuiteHeader(), "handleCipherSuite"))
continue;
if (updateForwardedHandle(lookup, getForwardedSslSessionIdHeader(), "handleSslSessionId"))
continue;
break;
}
catch (NoSuchMethodException | IllegalAccessException e)
{
throw new IllegalStateException(e);
}
updateForwardedHandle(lookup, getForwardedHeader(), "handleRFC7239");
updateForwardedHandle(lookup, getForwardedHostHeader(), "handleForwardedHost");
updateForwardedHandle(lookup, getForwardedForHeader(), "handleForwardedFor");
updateForwardedHandle(lookup, getForwardedPortHeader(), "handleForwardedPort");
updateForwardedHandle(lookup, getForwardedProtoHeader(), "handleProto");
updateForwardedHandle(lookup, getForwardedHttpsHeader(), "handleHttps");
updateForwardedHandle(lookup, getForwardedServerHeader(), "handleForwardedServer");
updateForwardedHandle(lookup, getForwardedCipherSuiteHeader(), "handleCipherSuite");
updateForwardedHandle(lookup, getForwardedSslSessionIdHeader(), "handleSslSessionId");
}
catch (NoSuchMethodException | IllegalAccessException e)
{
throw new IllegalStateException(e);
}
}
private boolean updateForwardedHandle(MethodHandles.Lookup lookup, String headerName, String forwardedMethodName) throws NoSuchMethodException, IllegalAccessException
private void updateForwardedHandle(MethodHandles.Lookup lookup, String headerName, String forwardedMethodName) throws NoSuchMethodException, IllegalAccessException
{
final MethodType type = methodType(void.class, HttpField.class);
if (StringUtil.isBlank(headerName))
return false;
return;
return !_handles.put(headerName, lookup.findVirtual(Forwarded.class, forwardedMethodName, type));
_handles.put(headerName, lookup.findVirtual(Forwarded.class, forwardedMethodName, type));
}
private static class MutableHostPort

View File

@ -508,38 +508,27 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque
if (HttpVersion.HTTP_1_1.equals(_requestBuilder.version()))
{
HttpHeaderValue expect = HttpHeaderValue.CACHE.get(value);
switch (expect == null ? HttpHeaderValue.UNKNOWN : expect)
if (expect == HttpHeaderValue.CONTINUE)
{
case CONTINUE:
_expect100Continue = true;
break;
case PROCESSING:
_expect102Processing = true;
break;
default:
String[] values = field.getValues();
for (int i = 0; values != null && i < values.length; i++)
{
expect = HttpHeaderValue.CACHE.get(values[i].trim());
if (expect == null)
_unknownExpectation = true;
else
{
switch (expect)
{
case CONTINUE:
_expect100Continue = true;
break;
case PROCESSING:
_expect102Processing = true;
break;
default:
_unknownExpectation = true;
}
}
}
_expect100Continue = true;
}
else if (expect == HttpHeaderValue.PROCESSING)
{
_expect102Processing = true;
}
else
{
String[] values = field.getValues();
for (int i = 0; values != null && i < values.length; i++)
{
expect = HttpHeaderValue.CACHE.get(values[i].trim());
if (expect == HttpHeaderValue.CONTINUE)
_expect100Continue = true;
else if (expect == HttpHeaderValue.PROCESSING)
_expect102Processing = true;
else
_unknownExpectation = true;
}
}
}
break;

View File

@ -27,9 +27,8 @@ import org.eclipse.jetty.http.CookieCompliance;
import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.Jetty;
import org.eclipse.jetty.util.TreeTrie;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.Dumpable;
@ -51,7 +50,10 @@ public class HttpConfiguration implements Dumpable
{
public static final String SERVER_VERSION = "Jetty(" + Jetty.VERSION + ")";
private final List<Customizer> _customizers = new CopyOnWriteArrayList<>();
private final Trie<Boolean> _formEncodedMethods = new TreeTrie<>();
private final Index.Mutable<Boolean> _formEncodedMethods = new Index.Builder<Boolean>()
.caseSensitive(false)
.mutable()
.build();
private int _outputBufferSize = 32 * 1024;
private int _outputAggregationSize = _outputBufferSize / 4;
private int _requestHeaderSize = 8 * 1024;
@ -424,7 +426,7 @@ public class HttpConfiguration implements Dumpable
/**
* @param headerCacheSize The size of the header field cache, in terms of unique characters branches
* in the lookup {@link Trie} and associated data structures.
* in the lookup {@link Index.Mutable} and associated data structures.
*/
public void setHeaderCacheSize(int headerCacheSize)
{
@ -491,7 +493,7 @@ public class HttpConfiguration implements Dumpable
*/
public void addFormEncodedMethod(String method)
{
_formEncodedMethods.put(method, Boolean.TRUE);
_formEncodedMethods.put(method,Boolean.TRUE);
}
/**
@ -504,7 +506,7 @@ public class HttpConfiguration implements Dumpable
*/
public boolean isFormEncodedMethod(String method)
{
return Boolean.TRUE.equals(_formEncodedMethods.get(method));
return _formEncodedMethods.get(method) != null;
}
/**

View File

@ -20,8 +20,10 @@ package org.eclipse.jetty.server.handler;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
@ -32,10 +34,9 @@ import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HandlerContainer;
import org.eclipse.jetty.server.HttpChannelState;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.ArrayUtil;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.thread.SerializedExecutor;
@ -129,44 +130,9 @@ public class ContextHandlerCollection extends HandlerCollection
entry.setValue(sorted);
}
// Loop until we have a big enough trie to hold all the context paths
int capacity = 512;
Mapping mapping;
loop:
while (true)
{
mapping = new Mapping(handlers, capacity);
for (Map.Entry<String, Branch[]> entry : path2Branches.entrySet())
{
if (!mapping._pathBranches.put(entry.getKey().substring(1), entry))
{
capacity += 512;
continue loop;
}
}
break;
}
Mapping mapping = new Mapping(handlers, path2Branches);
if (LOG.isDebugEnabled())
{
for (String ctx : mapping._pathBranches.keySet())
{
LOG.debug("{}->{}", ctx, Arrays.asList(mapping._pathBranches.get(ctx).getValue()));
}
}
// add new context branches to concurrent map
for (Branch[] branches : path2Branches.values())
{
for (Branch branch : branches)
{
for (ContextHandler context : branch.getContextHandlers())
{
mapping._contextBranches.put(context, branch.getHandler());
}
}
}
LOG.debug("{}", mapping._pathBranches);
return mapping;
}
@ -209,7 +175,7 @@ public class ContextHandlerCollection extends HandlerCollection
// handle many contexts
if (target.startsWith("/"))
{
Trie<Map.Entry<String, Branch[]>> pathBranches = mapping._pathBranches;
Index<Map.Entry<String, Branch[]>> pathBranches = mapping._pathBranches;
if (pathBranches == null)
return;
@ -377,13 +343,38 @@ public class ContextHandlerCollection extends HandlerCollection
private static class Mapping extends Handlers
{
private final Map<ContextHandler, Handler> _contextBranches = new HashMap<>();
private final Trie<Map.Entry<String, Branch[]>> _pathBranches;
private final Map<ContextHandler, Handler> _contextBranches;
private final Index<Map.Entry<String, Branch[]>> _pathBranches;
private Mapping(Handler[] handlers, int capacity)
private Mapping(Handler[] handlers, Map<String, Branch[]> path2Branches)
{
super(handlers);
_pathBranches = new ArrayTernaryTrie<>(false, capacity);
_pathBranches = new Index.Builder<Map.Entry<String, Branch[]>>()
.caseSensitive(true)
.withAll(() ->
{
Map<String, Map.Entry<String, Branch[]>> result = new LinkedHashMap<>();
for (Map.Entry<String, Branch[]> entry : path2Branches.entrySet())
{
result.put(entry.getKey().substring(1), entry);
}
return result;
})
.build();
// add new context branches to map
Map<ContextHandler, Handler> contextBranches = new HashMap<>();
for (Branch[] branches : path2Branches.values())
{
for (Branch branch : branches)
{
for (ContextHandler context : branch.getContextHandlers())
{
contextBranches.put(context, branch.getHandler());
}
}
}
_contextBranches = Collections.unmodifiableMap(contextBranches);
}
}
}

View File

@ -26,10 +26,9 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.Utf8StringBuilder;
import org.eclipse.jetty.util.ajax.JSON.Convertible;
@ -79,7 +78,7 @@ public class AsyncJSON
*/
public static class Factory
{
private Trie<CachedString> cache;
private Index.Mutable<CachedString> cache;
private Map<String, Convertor> convertors;
private boolean detailedParseException;
@ -106,7 +105,10 @@ public class AsyncJSON
public boolean cache(String value)
{
if (cache == null)
cache = new ArrayTernaryTrie.Growing<>(false, 64, 64);
cache = new Index.Builder<CachedString>()
.caseSensitive(true)
.mutable()
.build();
CachedString cached = new CachedString(value);
if (cached.isCacheable())

View File

@ -20,6 +20,11 @@ package org.eclipse.jetty.util;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
* Abstract Trie implementation.
@ -29,7 +34,7 @@ import java.nio.charset.StandardCharsets;
*
* @param <V> the type of object that the Trie holds
*/
public abstract class AbstractTrie<V> implements Trie<V>
abstract class AbstractTrie<V> implements Index.Mutable<V>
{
final boolean _caseInsensitive;
@ -38,13 +43,16 @@ public abstract class AbstractTrie<V> implements Trie<V>
_caseInsensitive = insensitive;
}
@Override
public boolean isCaseInsensitive()
{
return _caseInsensitive;
}
public boolean put(V v)
{
return put(v.toString(), v);
}
@Override
public V remove(String s)
{
V o = get(s);
@ -52,33 +60,109 @@ public abstract class AbstractTrie<V> implements Trie<V>
return o;
}
@Override
public V get(String s)
{
return get(s, 0, s.length());
}
@Override
public V get(ByteBuffer b)
{
return get(b, 0, b.remaining());
}
@Override
public V getBest(String s)
{
return getBest(s, 0, s.length());
}
@Override
public V getBest(byte[] b, int offset, int len)
{
return getBest(new String(b, offset, len, StandardCharsets.ISO_8859_1));
}
@Override
public boolean isCaseInsensitive()
/**
* Calculate required Trie capacity in nodes of a tree decomposition of the keys.
* For example given the keys:
* <ul>
* <li>utf_16</li>
* <li>utf_8</li>
* <li>utf16</li>
* <li>utf8</li>
* </ul>
* The tree has 10 nodes as follows:
* <pre>
* 1 - 6
* /
* _ - 8
* /
* u - t - f - 1 - 6
* \
* 8
* </pre>
* @param keys The keys to be put in a Trie
* @param caseSensitive true if the capacity should be calculated with case-sensitive keys
* @return The capacity in nodes of a tree decomposition
*/
protected static int requiredCapacity(Set<String> keys, boolean caseSensitive)
{
return _caseInsensitive;
List<String> list = caseSensitive
? new ArrayList<>(keys)
: keys.stream().map(String::toLowerCase).collect(Collectors.toList());
Collections.sort(list);
return AbstractTrie.requiredCapacity(list, 0, list.size(), 0);
}
/**
* Calculate required Trie capacity in nodes of a sub-tree decomposition of the keys.
* @param keys The keys to calculate the capacity for
* @param offset The offset of the first key to be considered
* @param length The number of keys to be considered
* @param index The character to be considered
* @return The capacity in tree nodes of the substree
*/
private static int requiredCapacity(List<String> keys, int offset, int length, int index)
{
int required = 0;
// Examine all the keys in the subtree
Character nodeChar = null;
for (int i = 0; i < length; i++)
{
String k = keys.get(offset + i);
// If the key is shorter than our current index then ignore it
if (k.length() <= index)
continue;
// Get the character at the index of the current key
char c = k.charAt(index);
// If the character is the same as the current node, then we are
// still in the current node and need to continue searching for the
// next node or the end of the keys
if (nodeChar != null && c == nodeChar)
continue;
// The character is a new node, so increase required by 1
required++;
// if we had a previous node, then add the required nodes for the subtree under it.
if (nodeChar != null)
required += AbstractTrie.requiredCapacity(keys, offset, i, index + 1);
// set the char for the new node
nodeChar = c;
// reset the offset, length and index to continue iteration from the start of the new node
offset += i;
length -= i;
i = 0;
}
// If we finish the iteration with a nodeChar, then we must add the required nodes for the subtree under it.
if (nodeChar != null)
required += AbstractTrie.requiredCapacity(keys, offset, length, index + 1);
return required;
}
}

View File

@ -23,6 +23,7 @@ import java.util.AbstractMap;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
/**
@ -57,11 +58,11 @@ import java.util.Set;
*
* @param <V> the Entry type
*/
public class ArrayTernaryTrie<V> extends AbstractTrie<V>
class ArrayTernaryTrie<V> extends AbstractTrie<V>
{
private static int LO = 1;
private static int EQ = 2;
private static int HI = 3;
private static final int LO = 1;
private static final int EQ = 2;
private static final int HI = 3;
/**
* The Size of a Trie row is the char, and the low, equal and high
@ -69,6 +70,13 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
*/
private static final int ROW_SIZE = 4;
/**
* The maximum capacity of the implementation. Over that,
* the 16 bit indexes can overflow and the trie
* cannot find existing entries anymore.
*/
private static final int MAX_CAPACITY = 21_000;
/**
* The Trie rows in a single array which allows a lookup of row,character
* to the next row in the Trie. This is actually a 2 dimensional
@ -93,39 +101,6 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
*/
private char _rows;
/**
* Create a case insensitive Trie of default capacity.
*/
public ArrayTernaryTrie()
{
this(128);
}
/**
* Create a Trie of default capacity
*
* @param insensitive true if the Trie is insensitive to the case of the key.
*/
public ArrayTernaryTrie(boolean insensitive)
{
this(insensitive, 128);
}
/**
* Create a case insensitive Trie
*
* @param capacity The capacity of the Trie, which is in the worst case
* is the total number of characters of all keys stored in the Trie.
* The capacity needed is dependent of the shared prefixes of the keys.
* For example, a capacity of 6 nodes is required to store keys "foo"
* and "bar", but a capacity of only 4 is required to
* store "bar" and "bat".
*/
public ArrayTernaryTrie(int capacity)
{
this(true, capacity);
}
/**
* Create a Trie
*
@ -137,28 +112,37 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
* and "bar", but a capacity of only 4 is required to
* store "bar" and "bat".
*/
public ArrayTernaryTrie(boolean insensitive, int capacity)
@SuppressWarnings("unchecked")
ArrayTernaryTrie(boolean insensitive, int capacity)
{
super(insensitive);
if (capacity > MAX_CAPACITY)
throw new IllegalArgumentException("ArrayTernaryTrie maximum capacity overflow (" + capacity + " > " + MAX_CAPACITY + ")");
_value = (V[])new Object[capacity];
_tree = new char[capacity * ROW_SIZE];
_key = new String[capacity];
}
/**
* Copy Trie and change capacity by a factor
*
* @param trie the trie to copy from
* @param factor the factor to grow the capacity by
*/
public ArrayTernaryTrie(ArrayTernaryTrie<V> trie, double factor)
@SuppressWarnings("unchecked")
ArrayTernaryTrie(boolean insensitive, Map<String, V> initialValues)
{
super(trie.isCaseInsensitive());
int capacity = (int)(trie._value.length * factor);
_rows = trie._rows;
_value = Arrays.copyOf(trie._value, capacity);
_tree = Arrays.copyOf(trie._tree, capacity * ROW_SIZE);
_key = Arrays.copyOf(trie._key, capacity);
super(insensitive);
// The calculated requiredCapacity does not take into account the
// extra reserved slot for the empty string key, nor the slots
// required for 'terminating' the entry (1 slot per key) so we
// have to add those.
Set<String> keys = initialValues.keySet();
int capacity = AbstractTrie.requiredCapacity(keys, !insensitive) + keys.size() + 1;
if (capacity > MAX_CAPACITY)
throw new IllegalArgumentException("ArrayTernaryTrie maximum capacity overflow (" + capacity + " > " + MAX_CAPACITY + ")");
_value = (V[])new Object[capacity];
_tree = new char[capacity * ROW_SIZE];
_key = new String[capacity];
for (Map.Entry<String, V> entry : initialValues.entrySet())
{
if (!put(entry.getKey(), entry.getValue()))
throw new AssertionError("Invalid capacity calculated (" + capacity + ") at '" + entry + "' for " + initialValues);
}
}
@Override
@ -527,12 +511,6 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
return entries;
}
@Override
public boolean isFull()
{
return _rows + 1 == _key.length;
}
public static int hilo(int diff)
{
// branchless equivalent to return ((diff<0)?LO:HI);
@ -556,24 +534,14 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
}
}
public static class Growing<V> implements Trie<V>
static class Growing<V> extends AbstractTrie<V>
{
private final int _growby;
private ArrayTernaryTrie<V> _trie;
public Growing()
{
this(1024, 1024);
}
public Growing(int capacity, int growby)
{
_growby = growby;
_trie = new ArrayTernaryTrie<>(capacity);
}
public Growing(boolean insensitive, int capacity, int growby)
Growing(boolean insensitive, int capacity, int growby)
{
super(insensitive);
_growby = growby;
_trie = new ArrayTernaryTrie<>(insensitive, capacity);
}
@ -591,15 +559,14 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
}
@Override
public boolean isCaseInsensitive()
public boolean equals(Object o)
{
return _trie.isCaseInsensitive();
}
@Override
public boolean equals(Object obj)
{
return _trie.equals(obj);
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
Growing<?> growing = (Growing<?>)o;
return Objects.equals(_trie, growing._trie);
}
@Override
@ -692,12 +659,6 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
return _trie.keySet();
}
@Override
public boolean isFull()
{
return false;
}
public void dump()
{
_trie.dump();

View File

@ -22,6 +22,7 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
@ -47,7 +48,7 @@ import java.util.Set;
*
* @param <V> the entry type
*/
public class ArrayTrie<V> extends AbstractTrie<V>
class ArrayTrie<V> extends AbstractTrie<V>
{
/**
* The Size of a Trie row is how many characters can be looked
@ -112,11 +113,6 @@ public class ArrayTrie<V> extends AbstractTrie<V>
*/
private char _rows;
public ArrayTrie()
{
this(128);
}
/**
* @param capacity The capacity of the trie, which at the worst case
* is the total number of characters of all keys stored in the Trie.
@ -126,14 +122,32 @@ public class ArrayTrie<V> extends AbstractTrie<V>
* store "bar" and "bat".
*/
@SuppressWarnings("unchecked")
public ArrayTrie(int capacity)
ArrayTrie(int capacity)
{
super(true);
capacity++;
_value = (V[])new Object[capacity];
_rowIndex = new char[capacity * 32];
_rowIndex = new char[capacity * ROW_SIZE];
_key = new String[capacity];
}
@SuppressWarnings("unchecked")
ArrayTrie(Map<String, V> initialValues)
{
super(true);
// The calculated requiredCapacity does not take into account the
// extra reserved slot for the empty string key, so we have to add 1.
int capacity = requiredCapacity(initialValues.keySet(), false) + 1;
_value = (V[])new Object[capacity];
_rowIndex = new char[capacity * ROW_SIZE];
_key = new String[capacity];
for (Map.Entry<String, V> entry : initialValues.entrySet())
{
if (!put(entry.getKey(), entry.getValue()))
throw new AssertionError("Invalid capacity calculated (" + capacity + ") at '" + entry + "' for " + initialValues);
}
}
@Override
public void clear()
{
@ -446,6 +460,18 @@ public class ArrayTrie<V> extends AbstractTrie<V>
return keys;
}
@Override
public int size()
{
return keySet().size();
}
@Override
public boolean isEmpty()
{
return keySet().isEmpty();
}
private void keySet(Set<String> set, int t)
{
if (t < _value.length && _value[t] != null)
@ -468,10 +494,4 @@ public class ArrayTrie<V> extends AbstractTrie<V>
}
}
}
@Override
public boolean isFull()
{
return _rows + 1 >= _key.length;
}
}

View File

@ -0,0 +1,99 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.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.util;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Set;
/**
* An empty trie implementation that never contains anything and never accepts new entries.
* @param <V> the entry type
*/
class EmptyTrie<V> extends AbstractTrie<V>
{
@SuppressWarnings("rawtypes")
private static final EmptyTrie SENSITIVE = new EmptyTrie<>(false);
@SuppressWarnings("rawtypes")
private static final EmptyTrie INSENSITIVE = new EmptyTrie<>(true);
@SuppressWarnings("unchecked")
public static <V> EmptyTrie<V> instance(boolean caseSensitive)
{
return caseSensitive ? SENSITIVE : INSENSITIVE;
}
private EmptyTrie(boolean insensitive)
{
super(insensitive);
}
@Override
public boolean put(String s, V v)
{
return false;
}
@Override
public V get(String s, int offset, int len)
{
return null;
}
@Override
public V get(ByteBuffer b, int offset, int len)
{
return null;
}
@Override
public V getBest(String s, int offset, int len)
{
return null;
}
@Override
public V getBest(ByteBuffer b, int offset, int len)
{
return null;
}
@Override
public boolean isEmpty()
{
return true;
}
@Override
public Set<String> keySet()
{
return Collections.emptySet();
}
@Override
public int size()
{
return 0;
}
@Override
public void clear()
{
}
}

View File

@ -0,0 +1,364 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.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.util;
import java.nio.ByteBuffer;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
/**
* An immutable String lookup data structure.
* @param <V> the entry type
*/
public interface Index<V>
{
/**
* Get an exact match from a String key
*
* @param s The key
* @return the value for the string key
*/
V get(String s);
/**
* Get an exact match from a segment of a ByteBuufer as key
*
* @param b The buffer
* @return The value or null if not found
*/
V get(ByteBuffer b);
/**
* Get an exact match from a String key
*
* @param s The key
* @param offset The offset within the string of the key
* @param len the length of the key
* @return the value for the string / offset / length
*/
V get(String s, int offset, int len);
/**
* Get an exact match from a segment of a ByteBuufer as key
*
* @param b The buffer
* @param offset The offset within the buffer of the key
* @param len the length of the key
* @return The value or null if not found
*/
V get(ByteBuffer b, int offset, int len);
/**
* Get the best match from key in a String.
*
* @param s The string
* @param offset The offset within the string of the key
* @param len the length of the key
* @return The value or null if not found
*/
V getBest(String s, int offset, int len);
/**
* Get the best match from key in a byte buffer.
* The key is assumed to by ISO_8859_1 characters.
*
* @param b The buffer
* @param offset The offset within the buffer of the key
* @param len the length of the key
* @return The value or null if not found
*/
V getBest(ByteBuffer b, int offset, int len);
/**
* Get the best match from key in a String.
*
* @param s The string
* @return The value or null if not found
*/
V getBest(String s);
/**
* Get the best match from key in a byte array.
* The key is assumed to by ISO_8859_1 characters.
*
* @param b The buffer
* @param offset The offset within the array of the key
* @param len the length of the key
* @return The value or null if not found
*/
V getBest(byte[] b, int offset, int len);
/**
* Check if the index contains any entry.
*
* @return true if the index does not contain any entry.
*/
boolean isEmpty();
/**
* Get the number of entries in the index.
*
* @return the index' entries count.
*/
int size();
/**
* Get a {@link Set} of the keys contained in this index.
*
* @return a {@link Set} of the keys contained in this index.
*/
Set<String> keySet();
/**
* A mutable String lookup data structure.
* Implementations are not thread-safe.
* @param <V> the entry type
*/
interface Mutable<V> extends Index<V>
{
/**
* Put an entry into the index.
*
* @param s The key for the entry
* @param v The value of the entry
* @return True if the index had capacity to add the field.
*/
boolean put(String s, V v);
/**
* Put a value as both a key and a value.
*
* @param v The value and key
* @return True if the Trie had capacity to add the field.
*/
boolean put(V v);
/**
* Remove an entry from the index.
*
* @param s The key for the entry
* @return The removed value of the entry
*/
V remove(String s);
/**
* Remove all entries from the index.
*/
void clear();
/**
* Builder of {@link Index.Mutable} instances. Such builder cannot be
* directly created, it is instead returned by calling {@link Index.Builder#mutable()}.
* @param <V> the entry type
*/
class Builder<V> extends Index.Builder<V>
{
private int maxCapacity = -1;
Builder(boolean caseSensitive, Map<String, V> contents)
{
super(caseSensitive, contents);
}
/**
* Configure a maximum capacity for the mutable index.
* A negative value means there is no capacity limit and
* the index can grow without limits.
* The default value is -1.
* @param capacity the maximum capacity of the index.
* @return this
*/
public Builder<V> maxCapacity(int capacity)
{
this.maxCapacity = capacity;
return this;
}
/**
* Build a {@link Mutable} instance.
* @return a {@link Mutable} instance.
*/
public Mutable<V> build()
{
if (contents != null && maxCapacity == 0)
throw new IllegalStateException("Cannot create a mutable index with maxCapacity=0 and some contents");
// TODO we need to consider large size and alphabet when picking a trie impl
Mutable<V> result;
if (maxCapacity > 0)
{
result = new ArrayTernaryTrie<>(!caseSensitive, maxCapacity);
}
else if (maxCapacity < 0)
{
if (caseSensitive)
result = new ArrayTernaryTrie.Growing<>(false, 512, 512);
else
result = new TreeTrie<>();
}
else
{
result = EmptyTrie.instance(caseSensitive);
}
if (contents != null)
{
for (Map.Entry<String, V> entry : contents.entrySet())
{
if (!result.put(entry.getKey(), entry.getValue()))
throw new AssertionError("Index capacity exceeded at " + entry.getKey());
}
}
return result;
}
}
}
/**
* Builder of {@link Index} instances.
* @param <V> the entry type
*/
class Builder<V>
{
Map<String, V> contents;
boolean caseSensitive;
/**
* Create a new index builder instance.
*/
public Builder()
{
this(false, null);
}
Builder(boolean caseSensitive, Map<String, V> contents)
{
this.caseSensitive = caseSensitive;
this.contents = contents;
}
private Map<String, V> contents()
{
if (contents == null)
contents = new LinkedHashMap<>();
return contents;
}
/**
* Configure the index to be either case-sensitive or not.
* Default value is false.
*
* @param caseSensitive true if the index has to be case-sensitive
* @return this
*/
public Builder<V> caseSensitive(boolean caseSensitive)
{
this.caseSensitive = caseSensitive;
return this;
}
/**
* Configure some pre-existing entries.
*
* @param values an array of values
* @param keyFunction a {@link Function} that generates the key of each
* entry of the values array
* @return this
*/
public Builder<V> withAll(V[] values, Function<V, String> keyFunction)
{
for (V value : values)
{
String key = keyFunction.apply(value);
contents().put(key, value);
}
return this;
}
/**
* Configure some pre-existing entries.
*
* @param entriesSupplier a {@link Map} {@link Supplier} of entries
* @return this
*/
public Builder<V> withAll(Supplier<Map<String, V>> entriesSupplier)
{
Map<String, V> map = entriesSupplier.get();
contents().putAll(map);
return this;
}
/**
* Configure a pre-existing entry with a key
* that is the {@link #toString()} representation
* of the value.
*
* @param value The value
* @return this
*/
public Builder<V> with(V value)
{
contents().put(value.toString(), value);
return this;
}
/**
* Configure a pre-existing entry.
*
* @param key The key
* @param value The value for the key string
* @return this
*/
public Builder<V> with(String key, V value)
{
contents().put(key, value);
return this;
}
/**
* Configure the index to be mutable.
*
* @return a {@link Mutable.Builder} configured like this builder.
*/
public Mutable.Builder<V> mutable()
{
return new Mutable.Builder<>(caseSensitive, contents);
}
/**
* Build a {@link Index} instance.
*
* @return a {@link Index} instance.
*/
public Index<V> build()
{
if (contents == null)
return EmptyTrie.instance(caseSensitive);
// TODO we need to consider large size and alphabet when picking a trie impl
if (caseSensitive)
return new ArrayTernaryTrie<>(false, contents);
else
return new ArrayTrie<>(contents);
}
}
}

View File

@ -33,8 +33,6 @@ import java.util.List;
*/
public class StringUtil
{
private static final Trie<String> CHARSETS = new ArrayTrie<>(256);
public static final String ALL_INTERFACES = "0.0.0.0";
public static final String CRLF = "\r\n";
public static final String DEFAULT_DELIMS = ",;";
@ -43,15 +41,15 @@ public class StringUtil
public static final String __UTF8 = "utf-8";
public static final String __UTF16 = "utf-16";
static
{
CHARSETS.put("utf-8", __UTF8);
CHARSETS.put("utf8", __UTF8);
CHARSETS.put("utf-16", __UTF16);
CHARSETS.put("utf16", __UTF16);
CHARSETS.put("iso-8859-1", __ISO_8859_1);
CHARSETS.put("iso_8859_1", __ISO_8859_1);
}
private static final Index<String> CHARSETS = new Index.Builder<String>()
.caseSensitive(false)
.with("utf-8", __UTF8)
.with("utf8", __UTF8)
.with("utf-16", __UTF16)
.with("utf16", __UTF16)
.with("iso-8859-1", __ISO_8859_1)
.with("iso_8859_1", __ISO_8859_1)
.build();
/**
* Convert alternate charset names (eg utf8) to normalized

View File

@ -42,7 +42,7 @@ import java.util.Set;
*
* @param <V> the entry type
*/
public class TreeTrie<V> extends AbstractTrie<V>
class TreeTrie<V> extends AbstractTrie<V>
{
private static final int[] LOOKUP =
{
@ -63,13 +63,15 @@ public class TreeTrie<V> extends AbstractTrie<V>
private String _key;
private V _value;
public TreeTrie()
@SuppressWarnings("unchecked")
TreeTrie()
{
super(true);
_nextIndex = new TreeTrie[INDEX];
_c = 0;
}
@SuppressWarnings("unchecked")
private TreeTrie(char c)
{
super(true);
@ -231,6 +233,18 @@ public class TreeTrie<V> extends AbstractTrie<V>
return t._value;
}
@Override
public boolean isEmpty()
{
return keySet().isEmpty();
}
@Override
public int size()
{
return keySet().size();
}
@Override
public V getBest(String s, int offset, int len)
{
@ -394,10 +408,4 @@ public class TreeTrie<V> extends AbstractTrie<V>
}
}
}
@Override
public boolean isFull()
{
return false;
}
}

View File

@ -1,230 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.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.util;
import java.nio.ByteBuffer;
import java.util.Collections;
import java.util.Set;
/**
* A Trie String lookup data structure.
*
* @param <V> the Trie entry type
*/
public interface Trie<V>
{
/**
* Put an entry into the Trie
*
* @param s The key for the entry
* @param v The value of the entry
* @return True if the Trie had capacity to add the field.
*/
public boolean put(String s, V v);
/**
* Put a value as both a key and a value.
*
* @param v The value and key
* @return True if the Trie had capacity to add the field.
*/
public boolean put(V v);
public V remove(String s);
/**
* Get an exact match from a String key
*
* @param s The key
* @return the value for the string key
*/
public V get(String s);
/**
* Get an exact match from a String key
*
* @param s The key
* @param offset The offset within the string of the key
* @param len the length of the key
* @return the value for the string / offset / length
*/
public V get(String s, int offset, int len);
/**
* Get an exact match from a segment of a ByteBuufer as key
*
* @param b The buffer
* @return The value or null if not found
*/
public V get(ByteBuffer b);
/**
* Get an exact match from a segment of a ByteBuufer as key
*
* @param b The buffer
* @param offset The offset within the buffer of the key
* @param len the length of the key
* @return The value or null if not found
*/
public V get(ByteBuffer b, int offset, int len);
/**
* Get the best match from key in a String.
*
* @param s The string
* @return The value or null if not found
*/
public V getBest(String s);
/**
* Get the best match from key in a String.
*
* @param s The string
* @param offset The offset within the string of the key
* @param len the length of the key
* @return The value or null if not found
*/
public V getBest(String s, int offset, int len);
/**
* Get the best match from key in a byte array.
* The key is assumed to by ISO_8859_1 characters.
*
* @param b The buffer
* @param offset The offset within the array of the key
* @param len the length of the key
* @return The value or null if not found
*/
public V getBest(byte[] b, int offset, int len);
/**
* Get the best match from key in a byte buffer.
* The key is assumed to by ISO_8859_1 characters.
*
* @param b The buffer
* @param offset The offset within the buffer of the key
* @param len the length of the key
* @return The value or null if not found
*/
public V getBest(ByteBuffer b, int offset, int len);
public Set<String> keySet();
public boolean isFull();
public boolean isCaseInsensitive();
public void clear();
static <T> Trie<T> empty(final boolean caseInsensitive)
{
return new Trie<T>()
{
@Override
public boolean put(String s, Object o)
{
return false;
}
@Override
public boolean put(Object o)
{
return false;
}
@Override
public T remove(String s)
{
return null;
}
@Override
public T get(String s)
{
return null;
}
@Override
public T get(String s, int offset, int len)
{
return null;
}
@Override
public T get(ByteBuffer b)
{
return null;
}
@Override
public T get(ByteBuffer b, int offset, int len)
{
return null;
}
@Override
public T getBest(String s)
{
return null;
}
@Override
public T getBest(String s, int offset, int len)
{
return null;
}
@Override
public T getBest(byte[] b, int offset, int len)
{
return null;
}
@Override
public T getBest(ByteBuffer b, int offset, int len)
{
return null;
}
@Override
public Set<String> keySet()
{
return Collections.emptySet();
}
@Override
public boolean isFull()
{
return true;
}
@Override
public boolean isCaseInsensitive()
{
return caseInsensitive;
}
@Override
public void clear()
{
}
};
}
}

View File

@ -0,0 +1,65 @@
//
// ========================================================================
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under
// the terms of the Eclipse Public License 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0
//
// This Source Code may also be made available under the following
// Secondary Licenses when the conditions for such availability set
// forth in the Eclipse Public License, v. 2.0 are satisfied:
// the Apache License v2.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.util;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
public class IndexTest
{
@Test
public void belowMaxCapacityTest()
{
int size = 10_450;
Index.Builder<Integer> builder = new Index.Builder<>();
builder.caseSensitive(true);
for (int i = 0; i < size; i++)
{
builder.with("/test/group" + i, i);
}
Index<Integer> index = builder.build();
for (int i = 0; i < size; i++)
{
Integer integer = index.get("/test/group" + i);
if (integer == null)
fail("missing entry for '/test/group" + i + "'");
else if (integer != i)
fail("incorrect value for '/test/group" + i + "' (" + integer + ")");
}
}
@Test
public void overMaxCapacityTest()
{
int size = 11_000;
Index.Builder<Integer> builder = new Index.Builder<>();
builder.caseSensitive(true);
for (int i = 0; i < size; i++)
{
builder.with("/test/group" + i, i);
}
assertThrows(IllegalArgumentException.class, builder::build);
}
}

View File

@ -21,30 +21,32 @@ package org.eclipse.jetty.util;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import static org.eclipse.jetty.util.AbstractTrie.requiredCapacity;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.in;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class TrieTest
{
public static Stream<Arguments> implementations()
{
List<Trie> impls = new ArrayList<>();
List<AbstractTrie<Integer>> impls = new ArrayList<>();
impls.add(new ArrayTrie<Integer>(128));
impls.add(new TreeTrie<Integer>());
impls.add(new ArrayTernaryTrie<Integer>(128));
impls.add(new ArrayTernaryTrie<Integer>(true, 128));
impls.add(new ArrayTernaryTrie.Growing<Integer>(true, 128, 128));
for (Trie<Integer> trie : impls)
for (AbstractTrie<Integer> trie : impls)
{
trie.put("hello", 1);
trie.put("He", 2);
@ -62,26 +64,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testOverflow(Trie<Integer> trie) throws Exception
{
int i = 0;
while (true)
{
if (++i > 10000)
break; // must not be fixed size
if (!trie.put("prefix" + i, i))
{
assertTrue(trie.isFull());
break;
}
}
assertTrue(!trie.isFull() || !trie.put("overflow", 0));
}
@ParameterizedTest
@MethodSource("implementations")
public void testKeySet(Trie<Integer> trie) throws Exception
public void testKeySet(AbstractTrie<Integer> trie) throws Exception
{
String[] values = new String[]{
"hello",
@ -103,7 +86,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testGetString(Trie<Integer> trie) throws Exception
public void testGetString(AbstractTrie<Integer> trie) throws Exception
{
assertEquals(1, trie.get("hello").intValue());
assertEquals(2, trie.get("He").intValue());
@ -130,7 +113,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testGetBuffer(Trie<Integer> trie) throws Exception
public void testGetBuffer(AbstractTrie<Integer> trie) throws Exception
{
assertEquals(1, trie.get(BufferUtil.toBuffer("xhellox"), 1, 5).intValue());
assertEquals(2, trie.get(BufferUtil.toBuffer("xhellox"), 1, 2).intValue());
@ -155,7 +138,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testGetDirectBuffer(Trie<Integer> trie) throws Exception
public void testGetDirectBuffer(AbstractTrie<Integer> trie) throws Exception
{
assertEquals(1, trie.get(BufferUtil.toDirectBuffer("xhellox"), 1, 5).intValue());
assertEquals(2, trie.get(BufferUtil.toDirectBuffer("xhellox"), 1, 2).intValue());
@ -180,7 +163,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testGetBestArray(Trie<Integer> trie) throws Exception
public void testGetBestArray(AbstractTrie<Integer> trie) throws Exception
{
assertEquals(1, trie.getBest(StringUtil.getUtf8Bytes("xhelloxxxx"), 1, 8).intValue());
assertEquals(2, trie.getBest(StringUtil.getUtf8Bytes("xhelxoxxxx"), 1, 8).intValue());
@ -198,7 +181,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testGetBestBuffer(Trie<Integer> trie) throws Exception
public void testGetBestBuffer(AbstractTrie<Integer> trie) throws Exception
{
assertEquals(1, trie.getBest(BufferUtil.toBuffer("xhelloxxxx"), 1, 8).intValue());
assertEquals(2, trie.getBest(BufferUtil.toBuffer("xhelxoxxxx"), 1, 8).intValue());
@ -219,7 +202,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testGetBestDirectBuffer(Trie<Integer> trie) throws Exception
public void testGetBestDirectBuffer(AbstractTrie<Integer> trie) throws Exception
{
assertEquals(1, trie.getBest(BufferUtil.toDirectBuffer("xhelloxxxx"), 1, 8).intValue());
assertEquals(2, trie.getBest(BufferUtil.toDirectBuffer("xhelxoxxxx"), 1, 8).intValue());
@ -240,7 +223,7 @@ public class TrieTest
@ParameterizedTest
@MethodSource("implementations")
public void testFull(Trie<Integer> trie) throws Exception
public void testFull(AbstractTrie<Integer> trie) throws Exception
{
if (!(trie instanceof ArrayTrie<?> || trie instanceof ArrayTernaryTrie<?>))
return;
@ -250,4 +233,33 @@ public class TrieTest
testGetBestArray(trie);
testGetBestBuffer(trie);
}
@Test
public void testRequiredCapacity()
{
assertThat(requiredCapacity(Set.of("ABC", "abc"), true), is(6));
assertThat(requiredCapacity(Set.of("ABC", "abc"), false), is(3));
assertThat(requiredCapacity(Set.of(""), false), is(0));
assertThat(requiredCapacity(Set.of("ABC", ""), false), is(3));
assertThat(requiredCapacity(Set.of("ABC"), false), is(3));
assertThat(requiredCapacity(Set.of("ABC", "XYZ"), false), is(6));
assertThat(requiredCapacity(Set.of("A00", "A11"), false), is(5));
assertThat(requiredCapacity(Set.of("A00", "A01", "A10", "A11"), false), is(7));
assertThat(requiredCapacity(Set.of("A", "AB"), false), is(2));
assertThat(requiredCapacity(Set.of("A", "ABC"), false), is(3));
assertThat(requiredCapacity(Set.of("A", "ABCD"), false), is(4));
assertThat(requiredCapacity(Set.of("AB", "ABC"), false), is(3));
assertThat(requiredCapacity(Set.of("ABC", "ABCD"), false), is(4));
assertThat(requiredCapacity(Set.of("ABC", "ABCDEF"), false), is(6));
assertThat(requiredCapacity(Set.of("AB", "A"), false), is(2));
assertThat(requiredCapacity(Set.of("ABC", "ABCDEF"), false), is(6));
assertThat(requiredCapacity(Set.of("ABCDEF", "ABC"), false), is(6));
assertThat(requiredCapacity(Set.of("ABC", "ABCDEF", "ABX"), false), is(7));
assertThat(requiredCapacity(Set.of("ABCDEF", "ABC", "ABX"), false), is(7));
assertThat(requiredCapacity(Set.of("ADEF", "AQPR4", "AQZ"), false), is(9));
assertThat(requiredCapacity(Set.of("111", "ADEF", "AQPR4", "AQZ", "999"), false), is(15));
assertThat(requiredCapacity(Set.of("utf-16", "utf-8"), false), is(7));
assertThat(requiredCapacity(Set.of("utf-16", "utf-8", "utf16", "utf8"), false), is(10));
assertThat(requiredCapacity(Set.of("utf-8", "utf8", "utf-16", "utf16", "iso-8859-1", "iso_8859_1"), false), is(27));
}
}

View File

@ -38,8 +38,8 @@ import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Supplier;
import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.IncludeExcludeSet;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.URIUtil;
@ -180,7 +180,10 @@ public class ClassMatcher extends AbstractSet<String>
public static class ByPackage extends AbstractSet<Entry> implements Predicate<String>
{
private final ArrayTernaryTrie.Growing<Entry> _entries = new ArrayTernaryTrie.Growing<>(false, 512, 512);
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
.caseSensitive(true)
.mutable()
.build();
@Override
public boolean test(String name)
@ -383,7 +386,10 @@ public class ClassMatcher extends AbstractSet<String>
@SuppressWarnings("serial")
public static class ByModule extends HashSet<Entry> implements Predicate<URI>
{
private final ArrayTernaryTrie.Growing<Entry> _entries = new ArrayTernaryTrie.Growing<>(false, 512, 512);
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
.caseSensitive(true)
.mutable()
.build();
@Override
public boolean test(URI uri)

View File

@ -29,23 +29,20 @@ import java.util.Set;
import java.util.stream.Collectors;
import org.eclipse.jetty.http.QuotedCSV;
import org.eclipse.jetty.util.ArrayTrie;
import org.eclipse.jetty.util.Index;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.Trie;
/**
* Represents an Extension Configuration, as seen during the connection Handshake process.
*/
public class ExtensionConfig
{
private static final Trie<ExtensionConfig> CACHE = new ArrayTrie<>(512);
static
{
CACHE.put("identity", new ExtensionConfig("identity"));
CACHE.put("permessage-deflate", new ExtensionConfig("permessage-deflate"));
CACHE.put("permessage-deflate; client_max_window_bits", new ExtensionConfig("permessage-deflate; client_max_window_bits"));
}
private static final Index<ExtensionConfig> CACHE = new Index.Builder<ExtensionConfig>()
.caseSensitive(false)
.with("identity", new ExtensionConfig("identity"))
.with("permessage-deflate", new ExtensionConfig("permessage-deflate"))
.with("permessage-deflate; client_max_window_bits", new ExtensionConfig("permessage-deflate; client_max_window_bits"))
.build();
/**
* Parse a single parameterized name.