From aa8bd5d8201615b9faacd7675ef97e8adf32167d Mon Sep 17 00:00:00 2001
From: Ludovic Orban
Date: Mon, 23 Nov 2020 14:56:54 +0100
Subject: [PATCH] replace Trie interface and impls usage with new *Index
interfaces and Builders
Signed-off-by: Ludovic Orban
---
.../org/eclipse/jetty/http/HttpGenerator.java | 17 +-
.../org/eclipse/jetty/http/HttpHeader.java | 22 +-
.../eclipse/jetty/http/HttpHeaderValue.java | 20 +-
.../org/eclipse/jetty/http/HttpMethod.java | 33 +-
.../org/eclipse/jetty/http/HttpParser.java | 148 +++--
.../org/eclipse/jetty/http/HttpScheme.java | 16 +-
.../org/eclipse/jetty/http/HttpVersion.java | 16 +-
.../org/eclipse/jetty/http/MimeTypes.java | 35 +-
.../jetty/http/pathmap/PathMappings.java | 45 +-
.../org/eclipse/jetty/http2/HTTP2Cipher.java | 591 +++++++++---------
.../jetty/http2/hpack/HpackContext.java | 13 +-
.../jetty/rewrite/handler/MsieRule.java | 25 +-
.../jetty/rewrite/handler/MsieSslRule.java | 24 +-
.../server/ForwardedRequestCustomizer.java | 61 +-
.../jetty/server/HttpChannelOverHttp.java | 51 +-
.../jetty/server/HttpConfiguration.java | 14 +-
.../handler/ContextHandlerCollection.java | 79 ++-
.../eclipse/jetty/util/ajax/AsyncJSON.java | 10 +-
.../org/eclipse/jetty/util/AbstractTrie.java | 104 ++-
.../eclipse/jetty/util/ArrayTernaryTrie.java | 129 ++--
.../org/eclipse/jetty/util/ArrayTrie.java | 48 +-
.../org/eclipse/jetty/util/EmptyTrie.java | 99 +++
.../java/org/eclipse/jetty/util/Index.java | 364 +++++++++++
.../org/eclipse/jetty/util/StringUtil.java | 20 +-
.../java/org/eclipse/jetty/util/TreeTrie.java | 24 +-
.../java/org/eclipse/jetty/util/Trie.java | 230 -------
.../org/eclipse/jetty/util/IndexTest.java | 65 ++
.../java/org/eclipse/jetty/util/TrieTest.java | 76 ++-
.../eclipse/jetty/webapp/ClassMatcher.java | 12 +-
.../jetty/websocket/core/ExtensionConfig.java | 17 +-
30 files changed, 1363 insertions(+), 1045 deletions(-)
create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/EmptyTrie.java
create mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/Index.java
delete mode 100644 jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java
create mode 100644 jetty-util/src/test/java/org/eclipse/jetty/util/IndexTest.java
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java
index b9c9b04576e1..16e122bb0b09 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java
@@ -26,10 +26,9 @@
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 enum Result
private final int _send;
private static final int SEND_SERVER = 0x01;
private static final int SEND_XPOWEREDBY = 0x02;
- private static final Trie 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 ASSUMED_CONTENT_METHODS = new Index.Builder()
+ .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 @@ else if (contentLength != field.getLongValue())
// 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;
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
index ee5282638d46..c1414d287822 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeader.java
@@ -20,9 +20,8 @@
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 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 CACHE = new Index.Builder()
+ .caseSensitive(false)
+ .withAll(HttpHeader.values(), HttpHeader::toString)
+ .build();
private final String _string;
private final String _lowerCase;
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java
index e4d84eb72a4e..ae475883a6e8 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpHeaderValue.java
@@ -21,9 +21,8 @@
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 CACHE = new ArrayTrie();
-
- static
- {
- for (HttpHeaderValue value : HttpHeaderValue.values())
- {
- if (value != UNKNOWN)
- CACHE.put(value.toString(), value);
- }
- }
+ public static final Index CACHE = new Index.Builder()
+ .caseSensitive(false)
+ .withAll(HttpHeaderValue.values(), HttpHeaderValue::toString)
+ .build();
private final String _string;
private final ByteBuffer _buffer;
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
index 9e4dd2ee89f8..a329ddd41d14 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java
@@ -20,10 +20,8 @@
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 String toString()
return _method;
}
- public static final Trie INSENSITIVE_CACHE = new ArrayTrie<>(252);
- public static final Trie CACHE = new ArrayTernaryTrie<>(false, 300);
- public static final Trie LOOK_AHEAD = new ArrayTernaryTrie<>(false, 330);
+ public static final Index INSENSITIVE_CACHE = new Index.Builder()
+ .caseSensitive(false)
+ .withAll(HttpMethod.values(), HttpMethod::asString)
+ .build();
+ public static final Index CACHE = new Index.Builder()
+ .caseSensitive(true)
+ .withAll(HttpMethod.values(), HttpMethod::asString)
+ .build();
+ public static final Index LOOK_AHEAD = new Index.Builder()
+ .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.
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
index 75b6694483f9..2adfdcd0f87e 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java
@@ -21,15 +21,15 @@
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 @@
*
*
* 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
*
*/
- public static final Trie CACHE = new ArrayTrie<>(2048);
- private static final Trie NO_CACHE = Trie.empty(true);
+ public static final Index CACHE = new Index.Builder()
+ .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 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 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 NO_CACHE = new Index.Builder()
+ .caseSensitive(false)
+ .mutable()
+ .maxCapacity(0)
+ .build();
// States
public enum FieldState
@@ -181,65 +247,12 @@ public enum State
private boolean _headResponse;
private boolean _cr;
private ByteBuffer _contentChunk;
- private Trie _fieldCache;
+ private Index.Mutable _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 @@ else if (_endOfContent == EndOfContent.CHUNKED_CONTENT)
if (_fieldCache == null)
{
_fieldCache = (getHeaderCacheSize() > 0 && (_version != null && _version == HttpVersion.HTTP_1_1))
- ? new ArrayTernaryTrie<>(getHeaderCacheSize())
+ ? new Index.Builder()
+ .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 @@ protected void setState(FieldState state)
_fieldState = state;
}
- public Trie getFieldCache()
+ public Index getFieldCache()
{
return _fieldCache;
}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java
index 01f85c1491a0..da8369988de9 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpScheme.java
@@ -20,9 +20,8 @@
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 CACHE = new ArrayTrie();
-
- static
- {
- for (HttpScheme version : HttpScheme.values())
- {
- CACHE.put(version.asString(), version);
- }
- }
+ public static final Index CACHE = new Index.Builder()
+ .caseSensitive(false)
+ .withAll(HttpScheme.values(), HttpScheme::asString)
+ .build();
private final String _string;
private final ByteBuffer _buffer;
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java
index a259f201f22d..ccd0eec564b3 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpVersion.java
@@ -20,9 +20,8 @@
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 CACHE = new ArrayTrie();
-
- static
- {
- for (HttpVersion version : HttpVersion.values())
- {
- CACHE.put(version.toString(), version);
- }
- }
+ public static final Index CACHE = new Index.Builder()
+ .caseSensitive(false)
+ .withAll(HttpVersion.values(), HttpVersion::toString)
+ .build();
/**
* Optimised lookup to find an Http Version and whitespace in a byte array.
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java
index 2eb61902cd19..2e34c947edb4 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java
@@ -32,10 +32,9 @@
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 TYPES = new ArrayTrie(512);
private static final Map __dftMimeMap = new HashMap();
private static final Map __inferredEncodings = new HashMap();
private static final Map __assumedEncodings = new HashMap();
@@ -168,23 +166,30 @@ public Type getBaseType()
}
}
- public static final Trie CACHE = new ArrayTrie<>(512);
+ public static final Index CACHE = new Index.Builder()
+ .caseSensitive(false)
+ .withAll(() ->
+ {
+ Map 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());
}
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java
index f70b5529c708..300477b6bb58 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/pathmap/PathMappings.java
@@ -28,8 +28,7 @@
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 implements Iterable>, Dumpable
private static final Logger LOG = LoggerFactory.getLogger(PathMappings.class);
private final Set> _mappings = new TreeSet<>(Comparator.comparing(MappedResource::getPathSpec));
- private Trie> _exactMap = new ArrayTernaryTrie<>(false);
- private Trie> _prefixMap = new ArrayTernaryTrie<>(false);
- private Trie> _suffixMap = new ArrayTernaryTrie<>(false);
+ private final Index.Mutable> _exactMap = new Index.Builder>()
+ .caseSensitive(true)
+ .mutable()
+ .build();
+ private final Index.Mutable> _prefixMap = new Index.Builder>()
+ .caseSensitive(true)
+ .mutable()
+ .build();
+ private final Index.Mutable> _suffixMap = new Index.Builder>()
+ .caseSensitive(true)
+ .mutable()
+ .build();
@Override
public String dump()
@@ -136,10 +144,9 @@ public MappedResource getMatch(String path)
case EXACT:
{
int i = path.length();
- final Trie> exact_map = _exactMap;
while (i >= 0)
{
- MappedResource candidate = exact_map.getBest(path, 0, i);
+ MappedResource candidate = _exactMap.getBest(path, 0, i);
if (candidate == null)
break;
if (candidate.getPathSpec().matches(path))
@@ -152,10 +159,9 @@ public MappedResource getMatch(String path)
case PREFIX_GLOB:
{
int i = path.length();
- final Trie> prefix_map = _prefixMap;
while (i >= 0)
{
- MappedResource candidate = prefix_map.getBest(path, 0, i);
+ MappedResource candidate = _prefixMap.getBest(path, 0, i);
if (candidate == null)
break;
if (candidate.getPathSpec().matches(path))
@@ -168,10 +174,9 @@ public MappedResource getMatch(String path)
case SUFFIX_GLOB:
{
int i = 0;
- final Trie> suffix_map = _suffixMap;
while ((i = path.indexOf('.', i + 1)) > 0)
{
- MappedResource candidate = suffix_map.get(path, i + 1, path.length() - i - 1);
+ MappedResource candidate = _suffixMap.get(path, i + 1, path.length() - i - 1);
if (candidate != null && candidate.getPathSpec().matches(path))
return candidate;
}
@@ -230,24 +235,18 @@ public boolean put(PathSpec pathSpec, E resource)
{
case EXACT:
String exact = pathSpec.getPrefix();
- while (exact != null && !_exactMap.put(exact, entry))
- {
- _exactMap = new ArrayTernaryTrie<>((ArrayTernaryTrie>)_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>)_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>)_prefixMap, 1.5);
- }
+ if (suffix != null)
+ _suffixMap.put(suffix, entry);
break;
default:
}
diff --git a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java
index d287934fee22..571ea4b62c12 100644
--- a/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java
+++ b/jetty-http2/http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Cipher.java
@@ -20,319 +20,310 @@
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 COMPARATOR = new CipherComparator();
- private static final Trie __blackProtocols = new ArrayTrie<>(6 * 5);
- private static final Trie __blackCiphers = new ArrayTrie<>(275 * 40);
+ private static final Index __blackProtocols = new Index.Builder()
+ .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 __blackCiphers = new Index.Builder()
+ .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;
}
/**
diff --git a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java
index 70be6754f25b..338e2821bbec 100644
--- a/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java
+++ b/jetty-http2/http2-hpack/src/main/java/org/eclipse/jetty/http2/hpack/HpackContext.java
@@ -29,9 +29,8 @@
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 __staticFieldMap = new HashMap<>();
- private static final Trie __staticNameMap = new ArrayTernaryTrie<>(true, 512);
- private static final StaticEntry[] __staticTableByHeader = new StaticEntry[HttpHeader.UNKNOWN.ordinal()];
+ private static final Index __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 staticNameMapBuilder = new Index.Builder().caseSensitive(false);
Set 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())
{
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieRule.java
index 3b0e0ce02a98..5fdee3a84130 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieRule.java
@@ -28,8 +28,7 @@
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 __IE6_BadOS = new ArrayTernaryTrie<>();
+ private static final Index __IE6_BadOS = new Index.Builder()
+ .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;
diff --git a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieSslRule.java b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieSslRule.java
index fda3c1d3238d..ca725183bb1d 100644
--- a/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieSslRule.java
+++ b/jetty-rewrite/src/main/java/org/eclipse/jetty/rewrite/handler/MsieSslRule.java
@@ -24,8 +24,7 @@
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 __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 __IE6_BadOS = new Index.Builder()
+ .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()
{
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
index 91d3e2668934..b608d601ce40 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ForwardedRequestCustomizer.java
@@ -33,10 +33,9 @@
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 _handles;
+ private final Index.Mutable _handles = new Index.Builder()
+ .caseSensitive(false)
+ .mutable()
+ .build();
public ForwardedRequestCustomizer()
{
@@ -596,52 +598,33 @@ public void setHostHeader(String hostHeader)
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
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
index 694aca4abb39..88b7c917ccac 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java
@@ -508,38 +508,27 @@ public void parsedHeader(HttpField field)
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;
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
index 5916ce182a19..991d7c57de36 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java
@@ -27,9 +27,8 @@
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 _customizers = new CopyOnWriteArrayList<>();
- private final Trie _formEncodedMethods = new TreeTrie<>();
+ private final Index.Mutable _formEncodedMethods = new Index.Builder()
+ .caseSensitive(false)
+ .mutable()
+ .build();
private int _outputBufferSize = 32 * 1024;
private int _outputAggregationSize = _outputBufferSize / 4;
private int _requestHeaderSize = 8 * 1024;
@@ -424,7 +426,7 @@ public void setResponseHeaderSize(int responseHeaderSize)
/**
* @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 Set getFormEncodedMethods()
*/
public void addFormEncodedMethod(String method)
{
- _formEncodedMethods.put(method, Boolean.TRUE);
+ _formEncodedMethods.put(method,Boolean.TRUE);
}
/**
@@ -504,7 +506,7 @@ public void addFormEncodedMethod(String method)
*/
public boolean isFormEncodedMethod(String method)
{
- return Boolean.TRUE.equals(_formEncodedMethods.get(method));
+ return _formEncodedMethods.get(method) != null;
}
/**
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
index 7045b1aadbb9..123d7be34242 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandlerCollection.java
@@ -20,8 +20,10 @@
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.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 @@ protected Handlers newHandlers(Handler[] handlers)
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 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 void handle(String target, Request baseRequest, HttpServletRequest reques
// handle many contexts
if (target.startsWith("/"))
{
- Trie> pathBranches = mapping._pathBranches;
+ Index> pathBranches = mapping._pathBranches;
if (pathBranches == null)
return;
@@ -377,13 +343,38 @@ public String toString()
private static class Mapping extends Handlers
{
- private final Map _contextBranches = new HashMap<>();
- private final Trie> _pathBranches;
+ private final Map _contextBranches;
+ private final Index> _pathBranches;
- private Mapping(Handler[] handlers, int capacity)
+ private Mapping(Handler[] handlers, Map path2Branches)
{
super(handlers);
- _pathBranches = new ArrayTernaryTrie<>(false, capacity);
+ _pathBranches = new Index.Builder>()
+ .caseSensitive(true)
+ .withAll(() ->
+ {
+ Map> result = new LinkedHashMap<>();
+ for (Map.Entry entry : path2Branches.entrySet())
+ {
+ result.put(entry.getKey().substring(1), entry);
+ }
+ return result;
+ })
+ .build();
+
+ // add new context branches to map
+ Map 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);
}
}
}
diff --git a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/AsyncJSON.java b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/AsyncJSON.java
index a16d28bb0414..180b4cc8c6ab 100644
--- a/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/AsyncJSON.java
+++ b/jetty-util-ajax/src/main/java/org/eclipse/jetty/util/ajax/AsyncJSON.java
@@ -26,10 +26,9 @@
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 cache;
+ private Index.Mutable cache;
private Map convertors;
private boolean detailedParseException;
@@ -106,7 +105,10 @@ public void setDetailedParseException(boolean detailedParseException)
public boolean cache(String value)
{
if (cache == null)
- cache = new ArrayTernaryTrie.Growing<>(false, 64, 64);
+ cache = new Index.Builder()
+ .caseSensitive(true)
+ .mutable()
+ .build();
CachedString cached = new CachedString(value);
if (cached.isCacheable())
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
index 15e45a614f22..07110018ef83 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
@@ -20,6 +20,11 @@
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 @@
*
* @param the type of object that the Trie holds
*/
-public abstract class AbstractTrie implements Trie
+abstract class AbstractTrie implements Index.Mutable
{
final boolean _caseInsensitive;
@@ -38,13 +43,16 @@ protected AbstractTrie(boolean insensitive)
_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 V remove(String s)
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:
+ *
+ * - utf_16
+ * - utf_8
+ * - utf16
+ * - utf8
+ *
+ * The tree has 10 nodes as follows:
+ *
+ * 1 - 6
+ * /
+ * _ - 8
+ * /
+ * u - t - f - 1 - 6
+ * \
+ * 8
+ *
+ * @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 keys, boolean caseSensitive)
{
- return _caseInsensitive;
+ List 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 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;
}
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
index 4f2d0ae0d345..41838c013aaf 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
@@ -23,6 +23,7 @@
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -57,11 +58,11 @@
*
* @param the Entry type
*/
-public class ArrayTernaryTrie extends AbstractTrie
+class ArrayTernaryTrie extends AbstractTrie
{
- 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 extends AbstractTrie
*/
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 extends AbstractTrie
*/
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 ArrayTernaryTrie(int capacity)
* 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 trie, double factor)
+ @SuppressWarnings("unchecked")
+ ArrayTernaryTrie(boolean insensitive, Map 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 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 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 Set> entrySet()
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 void dump()
}
}
- public static class Growing implements Trie
+ static class Growing extends AbstractTrie
{
private final int _growby;
private ArrayTernaryTrie _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 V remove(String s)
}
@Override
- public boolean isCaseInsensitive()
- {
- return _trie.isCaseInsensitive();
- }
-
- @Override
- public boolean equals(Object obj)
+ public boolean equals(Object o)
{
- 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 Set keySet()
return _trie.keySet();
}
- @Override
- public boolean isFull()
- {
- return false;
- }
-
public void dump()
{
_trie.dump();
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
index 177dddde898c..b21502921952 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTrie.java
@@ -22,6 +22,7 @@
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
/**
@@ -47,7 +48,7 @@
*
* @param the entry type
*/
-public class ArrayTrie extends AbstractTrie
+class ArrayTrie extends AbstractTrie
{
/**
* The Size of a Trie row is how many characters can be looked
@@ -112,11 +113,6 @@ public class ArrayTrie extends AbstractTrie
*/
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,12 +122,30 @@ public ArrayTrie()
* 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 * ROW_SIZE];
+ _key = new String[capacity];
+ }
+
+ @SuppressWarnings("unchecked")
+ ArrayTrie(Map 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 * 32];
+ _rowIndex = new char[capacity * ROW_SIZE];
_key = new String[capacity];
+ for (Map.Entry entry : initialValues.entrySet())
+ {
+ if (!put(entry.getKey(), entry.getValue()))
+ throw new AssertionError("Invalid capacity calculated (" + capacity + ") at '" + entry + "' for " + initialValues);
+ }
}
@Override
@@ -446,6 +460,18 @@ public Set keySet()
return keys;
}
+ @Override
+ public int size()
+ {
+ return keySet().size();
+ }
+
+ @Override
+ public boolean isEmpty()
+ {
+ return keySet().isEmpty();
+ }
+
private void keySet(Set set, int t)
{
if (t < _value.length && _value[t] != null)
@@ -468,10 +494,4 @@ private void keySet(Set set, int t)
}
}
}
-
- @Override
- public boolean isFull()
- {
- return _rows + 1 >= _key.length;
- }
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/EmptyTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/EmptyTrie.java
new file mode 100644
index 000000000000..f90480409de4
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/EmptyTrie.java
@@ -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 the entry type
+ */
+class EmptyTrie extends AbstractTrie
+{
+ @SuppressWarnings("rawtypes")
+ private static final EmptyTrie SENSITIVE = new EmptyTrie<>(false);
+ @SuppressWarnings("rawtypes")
+ private static final EmptyTrie INSENSITIVE = new EmptyTrie<>(true);
+
+ @SuppressWarnings("unchecked")
+ public static EmptyTrie 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 keySet()
+ {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public int size()
+ {
+ return 0;
+ }
+
+ @Override
+ public void clear()
+ {
+ }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Index.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Index.java
new file mode 100644
index 000000000000..b37345ace4ca
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Index.java
@@ -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 the entry type
+ */
+public interface Index
+{
+ /**
+ * 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 keySet();
+
+ /**
+ * A mutable String lookup data structure.
+ * Implementations are not thread-safe.
+ * @param the entry type
+ */
+ interface Mutable extends Index
+ {
+ /**
+ * 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 the entry type
+ */
+ class Builder extends Index.Builder
+ {
+ private int maxCapacity = -1;
+
+ Builder(boolean caseSensitive, Map 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 maxCapacity(int capacity)
+ {
+ this.maxCapacity = capacity;
+ return this;
+ }
+
+ /**
+ * Build a {@link Mutable} instance.
+ * @return a {@link Mutable} instance.
+ */
+ public Mutable 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 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 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 the entry type
+ */
+ class Builder
+ {
+ Map contents;
+ boolean caseSensitive;
+
+ /**
+ * Create a new index builder instance.
+ */
+ public Builder()
+ {
+ this(false, null);
+ }
+
+ Builder(boolean caseSensitive, Map contents)
+ {
+ this.caseSensitive = caseSensitive;
+ this.contents = contents;
+ }
+
+ private Map 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 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 withAll(V[] values, Function 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 withAll(Supplier