diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
index f59548589d7..67c95111e16 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java
@@ -39,12 +39,14 @@ import java.util.Set;
import java.util.StringTokenizer;
import java.util.TimeZone;
+import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.DateCache;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringMap;
import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -1007,7 +1009,7 @@ public class HttpFields implements Iterable
private static final Float __one = new Float("1.0");
private static final Float __zero = new Float("0.0");
- private static final StringMap __qualities = new StringMap<>();
+ private static final Trie __qualities = new ArrayTernaryTrie<>();
static
{
__qualities.put("*", __one);
diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
index d8e25434d36..0385c8ed663 100644
--- a/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
+++ b/jetty-http/src/main/java/org/eclipse/jetty/http/PathMap.java
@@ -22,11 +22,11 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.StringTokenizer;
+import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.LazyList;
-import org.eclipse.jetty.util.StringMap;
+import org.eclipse.jetty.util.Trie;
import org.eclipse.jetty.util.URIUtil;
/* ------------------------------------------------------------ */
@@ -78,14 +78,13 @@ public class PathMap extends HashMap
}
/* --------------------------------------------------------------- */
- final StringMap> _prefixMap=new StringMap<>();
- final StringMap> _suffixMap=new StringMap<>();
- final StringMap> _exactMap=new StringMap<>();
+ Trie> _prefixMap=new ArrayTernaryTrie<>(false);
+ Trie> _suffixMap=new ArrayTernaryTrie<>(false);
+ final Map> _exactMap=new HashMap<>();
- List _defaultSingletonList=null;
+ List> _defaultSingletonList=null;
MappedEntry _prefixDefault=null;
MappedEntry _default=null;
- final Set _entrySet;
boolean _nodefault=false;
/* --------------------------------------------------------------- */
@@ -111,7 +110,6 @@ public class PathMap extends HashMap
{
super(capacity);
_nodefault=noDefault;
- _entrySet=entrySet();
}
/* --------------------------------------------------------------- */
@@ -120,7 +118,6 @@ public class PathMap extends HashMap
public PathMap(Map m)
{
putAll(m);
- _entrySet=entrySet();
}
/* --------------------------------------------------------------- */
@@ -163,12 +160,15 @@ public class PathMap extends HashMap
{
String mapped=spec.substring(0,spec.length()-2);
entry.setMapped(mapped);
- _prefixMap.put(mapped,entry);
- _exactMap.put(mapped,entry);
- _exactMap.put(spec.substring(0,spec.length()-1),entry);
+ while (!_prefixMap.put(mapped,entry))
+ _prefixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_prefixMap,1.5);
}
else if (spec.startsWith("*."))
- _suffixMap.put(spec.substring(2),entry);
+ {
+ String suffix=spec.substring(2);
+ while(!_suffixMap.put(suffix,entry))
+ _suffixMap=new ArrayTernaryTrie<>((ArrayTernaryTrie>)_suffixMap,1.5);
+ }
else if (spec.equals(URIUtil.SLASH))
{
if (_nodefault)
@@ -176,8 +176,7 @@ public class PathMap extends HashMap
else
{
_default=entry;
- _defaultSingletonList=
- Collections.singletonList(_default);
+ _defaultSingletonList=Collections.singletonList(_default);
}
}
else
@@ -228,17 +227,22 @@ public class PathMap extends HashMap
}
// try exact match
- entry=_exactMap.get(path,0,l);
+ entry=_exactMap.get(path);
if (entry!=null)
return entry;
// prefix search
int i=l;
- while((i=path.lastIndexOf('/',i-1))>=0)
+ final Trie> prefix_map=_prefixMap;
+ while(i>=0)
{
- entry=_prefixMap.get(path,0,i);
- if (entry!=null)
+ entry=prefix_map.getBest(path,0,i);
+ if (entry==null)
+ break;
+ String key = entry.getKey();
+ if (key.length()-2>=path.length() || path.charAt(key.length()-2)=='/')
return entry;
+ i=key.length()-3;
}
// Prefix Default
@@ -247,9 +251,10 @@ public class PathMap extends HashMap
// Extension search
i=0;
+ final Trie> suffix_map=_suffixMap;
while ((i=path.indexOf('.',i+1))>0)
{
- entry=_suffixMap.get(path,i+1,l-i-1);
+ entry=suffix_map.get(path,i+1,l-i-1);
if (entry!=null)
return entry;
}
@@ -266,26 +271,31 @@ public class PathMap extends HashMap
*/
public Object getLazyMatches(String path)
{
- MappedEntry entry;
+ MappedEntry entry;
Object entries=null;
if (path==null)
return LazyList.getList(entries);
- int l=path.length();
-
// try exact match
- entry=_exactMap.get(path,0,l);
+ entry=_exactMap.get(path);
if (entry!=null)
entries=LazyList.add(entries,entry);
// prefix search
- int i=l-1;
- while((i=path.lastIndexOf('/',i-1))>=0)
+ int l=path.length();
+ int i=l;
+ final Trie> prefix_map=_prefixMap;
+ while(i>=0)
{
- entry=_prefixMap.get(path,0,i);
- if (entry!=null)
+ entry=prefix_map.getBest(path,0,i);
+ if (entry==null)
+ break;
+ String key = entry.getKey();
+ if (key.length()-2>=path.length() || path.charAt(key.length()-2)=='/')
entries=LazyList.add(entries,entry);
+
+ i=key.length()-3;
}
// Prefix Default
@@ -294,9 +304,10 @@ public class PathMap extends HashMap
// Extension search
i=0;
+ final Trie> suffix_map=_suffixMap;
while ((i=path.indexOf('.',i+1))>0)
{
- entry=_suffixMap.get(path,i+1,l-i-1);
+ entry=suffix_map.get(path,i+1,l-i-1);
if (entry!=null)
entries=LazyList.add(entries,entry);
}
@@ -320,7 +331,7 @@ public class PathMap extends HashMap
* @param path Path to match
* @return List of Map.Entry instances key=pathSpec
*/
- public List getMatches(String path)
+ public List> getMatches(String path)
{
return LazyList.getList(getLazyMatches(path));
}
@@ -333,7 +344,7 @@ public class PathMap extends HashMap
*/
public boolean containsMatch(String path)
{
- MappedEntry match = getMatch(path);
+ MappedEntry> match = getMatch(path);
return match!=null && !match.equals(_default);
}
@@ -347,11 +358,7 @@ public class PathMap extends HashMap
if (spec.equals("/*"))
_prefixDefault=null;
else if (spec.endsWith("/*"))
- {
_prefixMap.remove(spec.substring(0,spec.length()-2));
- _exactMap.remove(spec.substring(0,spec.length()-1));
- _exactMap.remove(spec.substring(0,spec.length()-2));
- }
else if (spec.startsWith("*."))
_suffixMap.remove(spec.substring(2));
else if (spec.equals(URIUtil.SLASH))
@@ -370,8 +377,8 @@ public class PathMap extends HashMap
public void clear()
{
_exactMap.clear();
- _prefixMap.clear();
- _suffixMap.clear();
+ _prefixMap=new ArrayTernaryTrie<>(false);
+ _suffixMap=new ArrayTernaryTrie<>(false);
_default=null;
_defaultSingletonList=null;
super.clear();
@@ -382,18 +389,18 @@ public class PathMap extends HashMap
* @return true if match.
*/
public static boolean match(String pathSpec, String path)
- throws IllegalArgumentException
- {
+ throws IllegalArgumentException
+ {
return match(pathSpec, path, false);
- }
+ }
/* --------------------------------------------------------------- */
/**
* @return true if match.
*/
public static boolean match(String pathSpec, String path, boolean noDefault)
- throws IllegalArgumentException
- {
+ throws IllegalArgumentException
+ {
char c = pathSpec.charAt(0);
if (c=='/')
{
@@ -407,7 +414,7 @@ public class PathMap extends HashMap
return path.regionMatches(path.length()-pathSpec.length()+1,
pathSpec,1,pathSpec.length()-1);
return false;
- }
+ }
/* --------------------------------------------------------------- */
private static boolean isPathWildcardMatch(String pathSpec, String path)
diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
index cda9f11e63b..36e9b2e1581 100644
--- a/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
+++ b/jetty-http/src/test/java/org/eclipse/jetty/http/PathMapTest.java
@@ -44,6 +44,7 @@ public class PathMapTest
p.put("/", "8");
p.put("/XXX:/YYY", "9");
p.put("", "10");
+ p.put("/\u20ACuro/*", "11");
String[][] tests = {
{ "/abs/path", "1"},
@@ -62,7 +63,9 @@ public class PathMapTest
{ "/suffix/path.tar.gz", "6"},
{ "/suffix/path.gz", "7"},
{ "/animal/path.gz", "5"},
- { "/Other/path", "8"},};
+ { "/Other/path", "8"},
+ { "/\u20ACuro/path", "11"},
+ };
for (String[] test : tests)
{
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 caa37762497..d4298be1d9a 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
@@ -25,7 +25,9 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
+import org.eclipse.jetty.util.ArrayTernaryTrie;
import org.eclipse.jetty.util.StringMap;
+import org.eclipse.jetty.util.Trie;
/**
* MSIE (Microsoft Internet Explorer) SSL Rule.
@@ -38,7 +40,7 @@ public class MsieSslRule extends Rule
{
private static final int IEv5 = '5';
private static final int IEv6 = '6';
- private static StringMap __IE6_BadOS = new StringMap();
+ private static Trie __IE6_BadOS = new ArrayTernaryTrie<>();
{
__IE6_BadOS.put("NT 5.01", Boolean.TRUE);
__IE6_BadOS.put("NT 5.0",Boolean.TRUE);
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
index 4867016204d..9e290ab2ec3 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
@@ -234,27 +234,19 @@ public class PartialRFC2616Test
}
@Test
- public void test3_9()
+ public void test3_9() throws Exception
{
- try
- {
- HttpFields fields=new HttpFields();
+ HttpFields fields=new HttpFields();
- fields.put("Q","bbb;q=0.5,aaa,ccc;q=0.002,d;q=0,e;q=0.0001,ddd;q=0.001,aa2,abb;q=0.7");
- Enumeration qualities=fields.getValues("Q",", \t");
- List list=HttpFields.qualityList(qualities);
- assertEquals("Quality parameters","aaa",HttpFields.valueParameters(list.get(0),null));
- assertEquals("Quality parameters","aa2",HttpFields.valueParameters(list.get(1),null));
- assertEquals("Quality parameters","abb",HttpFields.valueParameters(list.get(2),null));
- assertEquals("Quality parameters","bbb",HttpFields.valueParameters(list.get(3),null));
- assertEquals("Quality parameters","ccc",HttpFields.valueParameters(list.get(4),null));
- assertEquals("Quality parameters","ddd",HttpFields.valueParameters(list.get(5),null));
- }
- catch (Exception e)
- {
- e.printStackTrace();
- assertTrue(false);
- }
+ fields.put("Q","bbb;q=0.5,aaa,ccc;q=0.002,d;q=0,e;q=0.0001,ddd;q=0.001,aa2,abb;q=0.7");
+ Enumeration qualities=fields.getValues("Q",", \t");
+ List list=HttpFields.qualityList(qualities);
+ assertEquals("Quality parameters","aaa",HttpFields.valueParameters(list.get(0),null));
+ assertEquals("Quality parameters","aa2",HttpFields.valueParameters(list.get(1),null));
+ assertEquals("Quality parameters","abb",HttpFields.valueParameters(list.get(2),null));
+ assertEquals("Quality parameters","bbb",HttpFields.valueParameters(list.get(3),null));
+ assertEquals("Quality parameters","ccc",HttpFields.valueParameters(list.get(4),null));
+ assertEquals("Quality parameters","ddd",HttpFields.valueParameters(list.get(5),null));
}
@Test
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
new file mode 100644
index 00000000000..dd2f53c933d
--- /dev/null
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
@@ -0,0 +1,103 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.util;
+
+import java.nio.ByteBuffer;
+
+
+/* ------------------------------------------------------------ */
+/** Abstract Trie implementation.
+ * Provides some common implementations, which may not be the most
+ * efficient. For byte operations, the assumption is made that the charset
+ * is ISO-8859-1
+ * @param
+ */
+public abstract class AbstractTrie implements Trie
+{
+ final boolean _caseInsensitive;
+
+ protected AbstractTrie(boolean insensitive)
+ {
+ _caseInsensitive=insensitive;
+ }
+
+ @Override
+ public boolean put(V v)
+ {
+ return put(v.toString(),v);
+ }
+
+ @Override
+ public V remove(String s)
+ {
+ V o=get(s);
+ put(s,null);
+ return o;
+ }
+
+ @Override
+ public V get(String s)
+ {
+ return get(s,0,s.length());
+ }
+
+
+ @Override
+ public V get(ByteBuffer b, int offset, int len)
+ {
+ b=b.duplicate();
+ b.position(b.position()+offset);
+ b.limit(b.position()+len);
+ return get(BufferUtil.toString(b,StringUtil.__ISO_8859_1_CHARSET));
+ }
+
+ @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,StringUtil.__ISO_8859_1_CHARSET));
+ }
+
+ @Override
+ public V getBest(ByteBuffer b, int offset, int len)
+ {
+ b=b.duplicate();
+ b.position(b.position()+offset);
+ b.limit(b.position()+len);
+ return getBest(BufferUtil.toString(b,StringUtil.__ISO_8859_1_CHARSET));
+ }
+
+ @Override
+ public boolean isCaseInsensitive()
+ {
+ return _caseInsensitive;
+ }
+
+}
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 73413232a0d..7c92ac5477e 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
@@ -18,7 +18,6 @@
package org.eclipse.jetty.util;
-import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
@@ -28,7 +27,7 @@ import java.util.Set;
* This Trie is of a fixed size and cannot grow (which can be a good thing with regards to DOS when used as a cache).
* @param
*/
-public class ArrayTernaryTrie implements Trie
+public class ArrayTernaryTrie extends AbstractTrie
{
private static int LO=1;
private static int EQ=2;
@@ -70,13 +69,37 @@ public class ArrayTernaryTrie implements Trie
this(128);
}
+ public ArrayTernaryTrie(boolean insensitive)
+ {
+ this(insensitive,128);
+ }
+
public ArrayTernaryTrie(int capacityInNodes)
{
+ this(true,capacityInNodes);
+ }
+
+ public ArrayTernaryTrie(boolean insensitive, int capacityInNodes)
+ {
+ super(insensitive);
_value=new Object[capacityInNodes];
_tree=new char[capacityInNodes*ROW_SIZE];
_key=new String[capacityInNodes];
}
-
+
+ /* ------------------------------------------------------------ */
+ /** Copy Trie and change capacity by a factor
+ * @param trie
+ * @param factor
+ */
+ public ArrayTernaryTrie(ArrayTernaryTrie trie, double factor)
+ {
+ this(trie.isCaseInsensitive(),(int)(trie._value.length*factor));
+ _rows=trie._rows;
+ System.arraycopy(trie._value,0,_value,0,trie._value.length);
+ System.arraycopy(trie._tree,0,_tree,0,trie._tree.length);
+ System.arraycopy(trie._key,0,_key,0,trie._key.length);
+ }
/* ------------------------------------------------------------ */
@Override
@@ -90,8 +113,8 @@ public class ArrayTernaryTrie implements Trie
for(k=0; k < limit; k++)
{
char c=s.charAt(k);
- if (c<128)
- c=StringUtil.lowercases[c&0x7f];
+ if(isCaseInsensitive() && c<128)
+ c=StringUtil.lowercases[c];
while (true)
{
@@ -132,67 +155,20 @@ public class ArrayTernaryTrie implements Trie
return true;
}
-
/* ------------------------------------------------------------ */
@Override
- public boolean put(V v)
- {
- return put(v.toString(),v);
- }
-
- /* ------------------------------------------------------------ */
- @Override
- public V remove(String s)
- {
- V o=get(s);
- put(s,null);
- return o;
- }
-
- /* ------------------------------------------------------------ */
- @Override
- public V get(String s)
+ public V get(String s,int offset, int length)
{
int t = _tree[EQ];
- int len = s.length();
- int node=0;
- for(int i=0; t!=0 && i < len ; i++)
+ int len = length;
+ int i=0;
+ while(i implements Trie
if (diff==0)
{
- node=t;
+ if (i==len)
+ return (V)_value[t];
t=_tree[row+EQ];
+ if (t==0)
+ return null;
break;
}
- if (diff<0)
- t=_tree[row+LO];
- else
- t=_tree[row+HI];
+ t=_tree[row+((diff<0)?LO:HI)];
+ if (t==0)
+ return null;
}
}
- return (V)_value[node];
+ return null;
}
+
/* ------------------------------------------------------------ */
@Override
- public V getBest(byte[] b,int offset,int len)
+ public V getBest(String s)
{
- return getBest(_tree[EQ],b,offset,len);
- }
-
- /* ------------------------------------------------------------ */
- @Override
- public V getBest(ByteBuffer b,int offset,int len)
- {
- if (b.hasArray())
- return getBest(_tree[EQ],b.array(),b.arrayOffset()+b.position()+offset,len);
- return getBest(_tree[EQ],b,offset,len);
+ return getBest(_tree[EQ],s,0,s.length());
}
- private V getBest(int t,byte[] b,int offset,int len)
+ /* ------------------------------------------------------------ */
+ @Override
+ public V getBest(String s, int offset, int length)
+ {
+ return getBest(_tree[EQ],s,offset,length);
+ }
+
+ /* ------------------------------------------------------------ */
+ private V getBest(int t,String s,int offset,int len)
{
int node=0;
for(int i=0; t!=0 && i implements Trie
// if this node is a match, recurse to remember
if (_key[node]!=null)
{
- V best=getBest(t,b,offset+i+1,len-i-1);
+ V best=getBest(t,s,offset+i+1,len-i-1);
if (best!=null)
return best;
return (V)_value[node];
@@ -261,57 +241,12 @@ public class ArrayTernaryTrie implements Trie
break;
}
- if (diff<0)
- t=_tree[row+LO];
- else
- t=_tree[row+HI];
+ t=_tree[row+((diff<0)?LO:HI)];
}
}
return null;
}
- private V getBest(int t,ByteBuffer b,int offset,int len)
- {
- int pos=b.position()+offset;
- int node=0;
- for(int i=0; t!=0 && iThis implementation is always case insensitive and is optimal for
+ * a small number of fixed strings with few special characters.
+ *
* @param
*/
-public class ArrayTrie implements Trie
+public class ArrayTrie extends AbstractTrie
{
/**
* The Size of a Trie row is how many characters can be looked
@@ -99,6 +101,7 @@ public class ArrayTrie implements Trie
public ArrayTrie(int capacityInNodes)
{
+ super(true);
_value=new Object[capacityInNodes];
_rowIndex=new char[capacityInNodes*32];
_key=new String[capacityInNodes];
@@ -154,32 +157,14 @@ public class ArrayTrie implements Trie
return true;
}
-
/* ------------------------------------------------------------ */
@Override
- public boolean put(V v)
- {
- return put(v.toString(),v);
- }
-
- /* ------------------------------------------------------------ */
- @Override
- public V remove(String s)
- {
- V o=get(s);
- put(s,null);
- return o;
- }
-
- /* ------------------------------------------------------------ */
- @Override
- public V get(String s)
+ public V get(String s, int offset, int len)
{
int t = 0;
- int len = s.length();
for(int i=0; i < len; i++)
{
- char c=s.charAt(i);
+ char c=s.charAt(offset+i);
int index=__lookup[c&0x7f];
if (index>=0)
{
@@ -245,7 +230,53 @@ public class ArrayTrie implements Trie
return getBest(0,b.array(),b.arrayOffset()+b.position()+offset,len);
return getBest(0,b,offset,len);
}
+
+ /* ------------------------------------------------------------ */
+ @Override
+ public V getBest(String s, int offset, int len)
+ {
+ return getBest(0,s,offset,len);
+ }
+ /* ------------------------------------------------------------ */
+ private V getBest(int t, String s, int offset, int len)
+ {
+ int pos=offset;
+ for(int i=0; i < len; i++)
+ {
+ char c=s.charAt(pos++);
+ int index=__lookup[c&0x7f];
+ if (index>=0)
+ {
+ int idx=t*ROW_SIZE+index;
+ t=_rowIndex[idx];
+ if (t==0)
+ return null;
+ }
+ else
+ {
+ char[] big = _bigIndex==null?null:_bigIndex[t];
+ if (big==null)
+ return null;
+ t=big[c];
+ if (t==0)
+ return null;
+ }
+
+ // Is the next Trie is a match
+ if (_key[t]!=null)
+ {
+ // Recurse so we can remember this possibility
+ V best=getBest(t,s,offset+i+1,len-i-1);
+ if (best!=null)
+ return best;
+ return (V)_value[t];
+ }
+ }
+ return (V)_value[t];
+ }
+
+ /* ------------------------------------------------------------ */
private V getBest(int t,byte[] b,int offset,int len)
{
for(int i=0; i < len; i++)
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java
index a62df9fa468..b8846de5b91 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringMap.java
@@ -37,6 +37,7 @@ import java.util.TreeMap;
* objects from being created just to look up in the map.
*
* This map is NOT synchronized.
+ * @deprecated Use {@link Trie}
*/
public class StringMap extends AbstractMap
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
index 59426d48ea3..29db2113ad1 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/StringUtil.java
@@ -39,7 +39,7 @@ public class StringUtil
private static final Logger LOG = Log.getLogger(StringUtil.class);
- private final static StringMap CHARSETS= new StringMap(true);
+ private final static Trie CHARSETS= new ArrayTrie<>(256);
public static final String ALL_INTERFACES="0.0.0.0";
public static final String CRLF="\015\012";
@@ -87,28 +87,9 @@ public class StringUtil
String n=CHARSETS.get(s,offset,length);
return (n==null)?s.substring(offset,offset+length):n;
}
+
/* ------------------------------------------------------------ */
- /** Convert alternate charset names (eg utf8) to normalized
- * name (eg UTF-8).
- */
- public static String normalizeCharset(ByteBuffer b,int position,int length)
- {
- ByteBuffer ro=b.asReadOnlyBuffer();
- ro.limit(ro.capacity());
- ro.position(position);
- ro.limit(position+length);
- String n=CHARSETS.get(ro);
- if (n!=null)
- return n;
- ByteBuffer slice = b.slice();
- slice.position(position);
- slice.limit(position+length);
- return BufferUtil.toString(slice,__UTF8_CHARSET);
- }
-
-
-
public static char[] lowercases = {
'\000','\001','\002','\003','\004','\005','\006','\007',
'\010','\011','\012','\013','\014','\015','\016','\017',
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
index 417bbce30b2..484a642040f 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/TreeTrie.java
@@ -25,7 +25,14 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
-public class TreeTrie implements Trie
+/* ------------------------------------------------------------ */
+/** A Trie String lookup data structure using a tree
+ * This implementation is always case insensitive and is optimal for
+ * a variable number of fixed strings with few special characters.
+ *
+ * @param
+ */
+public class TreeTrie extends AbstractTrie
{
private static final int[] __lookup =
{ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
@@ -47,22 +54,18 @@ public class TreeTrie implements Trie
public TreeTrie()
{
+ super(true);
_nextIndex = new TreeTrie[INDEX];
_c=0;
}
private TreeTrie(char c)
{
+ super(true);
_nextIndex = new TreeTrie[INDEX];
this._c=c;
}
- @Override
- public boolean put(V v)
- {
- return put(v.toString(),v);
- }
-
@Override
public boolean put(String s, V v)
{
@@ -105,21 +108,12 @@ public class TreeTrie implements Trie
}
@Override
- public V remove(String s)
- {
- V o=get(s);
- put(s,null);
- return o;
- }
-
- @Override
- public V get(String s)
+ public V get(String s,int offset, int len)
{
TreeTrie t = this;
- int len = s.length();
for(int i=0; i < len; i++)
{
- char c=s.charAt(i);
+ char c=s.charAt(offset+i);
int index=c>=0&&c<0x7f?__lookup[c]:-1;
if (index>=0)
{
@@ -219,6 +213,14 @@ public class TreeTrie implements Trie
return t._value;
}
+ @Override
+ public V getBest(String s, int offset, int len)
+ {
+ // TODO inefficient
+ byte[] b=s.substring(offset,offset+len).getBytes(StringUtil.__ISO_8859_1_CHARSET);
+ return getBest(b,0,b.length);
+ }
+
@Override
public V getBest(ByteBuffer b,int offset,int len)
{
@@ -343,5 +345,6 @@ public class TreeTrie implements Trie
{
return false;
}
-
+
+
}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java
index 3bf17ac20e9..1b095215307 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/Trie.java
@@ -52,7 +52,23 @@ public interface Trie
* @return
*/
public V get(String s);
-
+
+ /* ------------------------------------------------------------ */
+ /** Get and 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
+ */
+ public V get(String s,int offset,int len);
+
+ /* ------------------------------------------------------------ */
+ /** Get and exact match from a segment of a ByteBuufer as key
+ * @param b The buffer
+ * @return The value or null if not found
+ */
+ public V get(ByteBuffer b);
+
/* ------------------------------------------------------------ */
/** Get and exact match from a segment of a ByteBuufer as key
* @param b The buffer
@@ -61,6 +77,22 @@ public interface Trie
* @return The value or null if not found
*/
public V get(ByteBuffer b,int offset,int len);
+
+ /* ------------------------------------------------------------ */
+ /** Get the best match from key in a String.
+ * @param s The string
+ * @return The value or null if not found
+ */
+ public V getBest(String s);
+
+ /* ------------------------------------------------------------ */
+ /** Get the best match from key in a String.
+ * @param s The string
+ * @param offset The offset within the string of the key
+ * @param len the length of the key
+ * @return The value or null if not found
+ */
+ public V getBest(String s,int offset,int len);
/* ------------------------------------------------------------ */
/** Get the best match from key in a byte array.
@@ -81,10 +113,14 @@ public interface Trie
* @return The value or null if not found
*/
public V getBest(ByteBuffer b,int offset,int len);
-
+
/* ------------------------------------------------------------ */
public Set keySet();
-
+
+ /* ------------------------------------------------------------ */
public boolean isFull();
-
+
+ /* ------------------------------------------------------------ */
+ public boolean isCaseInsensitive();
+
}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TrieTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TrieTest.java
index 1febc2f26d5..8fe5f6ea486 100644
--- a/jetty-util/src/test/java/org/eclipse/jetty/util/TrieTest.java
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TrieTest.java
@@ -82,7 +82,8 @@ public class TrieTest
Assert.assertEquals(5,trie.get("wobble").intValue());
Assert.assertEquals(6,trie.get("Foo-bar").intValue());
Assert.assertEquals(7,trie.get("FOO+bar").intValue());
-
+
+ Assert.assertEquals(null,trie.get("helloworld"));
Assert.assertEquals(null,trie.get("Help"));
Assert.assertEquals(null,trie.get("Blah"));
}
@@ -105,7 +106,8 @@ public class TrieTest
Assert.assertEquals(5,trie.get(BufferUtil.toBuffer("xwobble"),1,6).intValue());
Assert.assertEquals(6,trie.get(BufferUtil.toBuffer("xFOO-barx"),1,7).intValue());
Assert.assertEquals(7,trie.get(BufferUtil.toBuffer("xFOO+barx"),1,7).intValue());
-
+
+ Assert.assertEquals(null,trie.get(BufferUtil.toBuffer("xHelloworldx"),1,10));
Assert.assertEquals(null,trie.get(BufferUtil.toBuffer("xHelpx"),1,4));
Assert.assertEquals(null,trie.get(BufferUtil.toBuffer("xBlahx"),1,4));
}
@@ -128,7 +130,8 @@ public class TrieTest
Assert.assertEquals(5,trie.get(BufferUtil.toDirectBuffer("xwobble"),1,6).intValue());
Assert.assertEquals(6,trie.get(BufferUtil.toDirectBuffer("xFOO-barx"),1,7).intValue());
Assert.assertEquals(7,trie.get(BufferUtil.toDirectBuffer("xFOO+barx"),1,7).intValue());
-
+
+ Assert.assertEquals(null,trie.get(BufferUtil.toDirectBuffer("xHelloworldx"),1,10));
Assert.assertEquals(null,trie.get(BufferUtil.toDirectBuffer("xHelpx"),1,4));
Assert.assertEquals(null,trie.get(BufferUtil.toDirectBuffer("xBlahx"),1,4));
}