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:
parent
df5622ecfc
commit
aa8bd5d820
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue