jetty-9 Added Trie for cached string lookup. HttpFields does not use StringMap
This commit is contained in:
parent
dc2850c898
commit
a20d984d30
|
@ -46,6 +46,7 @@ import org.eclipse.jetty.client.api.Destination;
|
|||
import org.eclipse.jetty.client.api.ProxyConfiguration;
|
||||
import org.eclipse.jetty.client.api.Request;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
|
@ -350,7 +351,7 @@ public class HttpClient extends ContainerLifeCycle
|
|||
newRequest.method(oldRequest.getMethod())
|
||||
.version(oldRequest.getVersion())
|
||||
.content(oldRequest.getContent());
|
||||
for (HttpFields.Field header : oldRequest.getHeaders())
|
||||
for (HttpField header : oldRequest.getHeaders())
|
||||
{
|
||||
// We have a new URI, so skip the host header if present
|
||||
if (HttpHeader.HOST == header.getHeader())
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** A HTTP Field
|
||||
*/
|
||||
public class HttpField
|
||||
{
|
||||
public final static Trie<HttpField> CACHE = new Trie<>();
|
||||
|
||||
static
|
||||
{
|
||||
CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE));
|
||||
CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.KEEP_ALIVE));
|
||||
CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate"));
|
||||
CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;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.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.CONTENT_LENGTH,"0"));
|
||||
CACHE.put(new HttpField(HttpHeader.CONTENT_TYPE,"text/plain; charset=utf-8"));
|
||||
CACHE.put(new HttpField(HttpHeader.CONTENT_TYPE,"application/x-www-form-urlencoded; charset=UTF-8"));
|
||||
CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"gzip"));
|
||||
CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"deflate"));
|
||||
CACHE.put(new HttpField(HttpHeader.EXPIRES,"Fri, 01 Jan 1990 00:00:00 GMT"));
|
||||
|
||||
|
||||
// Add headers with null values so HttpParser can avoid looking up name again for unknown values
|
||||
CACHE.put(new HttpField(HttpHeader.CONNECTION,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.ACCEPT,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.PRAGMA,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.CONTENT_TYPE,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,(String)null));
|
||||
CACHE.put(new HttpField(HttpHeader.EXPIRES,(String)null));
|
||||
|
||||
// TODO add common user agents
|
||||
}
|
||||
|
||||
private final static byte[] __colon_space = new byte[] {':',' '};
|
||||
|
||||
private final HttpHeader _header;
|
||||
private final String _name;
|
||||
private final String _value;
|
||||
|
||||
public HttpField(HttpHeader header, String name, String value)
|
||||
{
|
||||
_header = header;
|
||||
_name = name;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public HttpField(HttpHeader header, String value)
|
||||
{
|
||||
_header = header;
|
||||
_name = _header.asString();
|
||||
_value = value;
|
||||
}
|
||||
|
||||
|
||||
public HttpField(HttpHeader header, HttpHeaderValue value)
|
||||
{
|
||||
_header = header;
|
||||
_name = _header.asString();
|
||||
_value = value.asString();
|
||||
}
|
||||
|
||||
public HttpField(String name, String value)
|
||||
{
|
||||
_header = HttpHeader.CACHE.get(name);
|
||||
_name = name;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public HttpHeader getHeader()
|
||||
{
|
||||
return _header;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public boolean contains(String value)
|
||||
{
|
||||
if (_value==null)
|
||||
return false;
|
||||
|
||||
if (value.equalsIgnoreCase(_value))
|
||||
return true;
|
||||
|
||||
String[] split = _value.split("\\s*,\\s*");
|
||||
for (String s : split)
|
||||
{
|
||||
if (value.equalsIgnoreCase(s))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public int getIntValue()
|
||||
{
|
||||
return StringUtil.toInt(_value);
|
||||
}
|
||||
|
||||
public long getLongValue()
|
||||
{
|
||||
return StringUtil.toLong(_value);
|
||||
}
|
||||
|
||||
private byte[] toSanitisedName(String s)
|
||||
{
|
||||
byte[] bytes = s.getBytes(StringUtil.__ISO_8859_1_CHARSET);
|
||||
for (int i=bytes.length;i-->0;)
|
||||
{
|
||||
switch(bytes[i])
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
case ':' :
|
||||
bytes[i]=(byte)'?';
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private byte[] toSanitisedValue(String s)
|
||||
{
|
||||
byte[] bytes = s.getBytes(StringUtil.__ISO_8859_1_CHARSET);
|
||||
for (int i=bytes.length;i-->0;)
|
||||
{
|
||||
switch(bytes[i])
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
bytes[i]=(byte)'?';
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void putTo(ByteBuffer bufferInFillMode)
|
||||
{
|
||||
HttpHeader header = HttpHeader.CACHE.get(_name);
|
||||
if (header!=null)
|
||||
{
|
||||
bufferInFillMode.put(header.getBytesColonSpace());
|
||||
|
||||
if (HttpHeaderValue.hasKnownValues(header))
|
||||
{
|
||||
HttpHeaderValue value=HttpHeaderValue.CACHE.get(_value);
|
||||
if (value!=null)
|
||||
bufferInFillMode.put(value.toBuffer());
|
||||
else
|
||||
bufferInFillMode.put(toSanitisedValue(_value));
|
||||
}
|
||||
else
|
||||
bufferInFillMode.put(toSanitisedValue(_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferInFillMode.put(toSanitisedName(_name));
|
||||
bufferInFillMode.put(__colon_space);
|
||||
bufferInFillMode.put(toSanitisedValue(_value));
|
||||
}
|
||||
|
||||
BufferUtil.putCRLF(bufferInFillMode);
|
||||
}
|
||||
|
||||
public void putValueTo(ByteBuffer buffer)
|
||||
{
|
||||
buffer.put(toSanitisedValue(_value));
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String v=getValue();
|
||||
return getName() + ": " + (v==null?"":v.toString());
|
||||
}
|
||||
}
|
|
@ -29,11 +29,13 @@ import java.util.Date;
|
|||
import java.util.Enumeration;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.TimeZone;
|
||||
|
||||
|
@ -46,7 +48,6 @@ import org.eclipse.jetty.util.StringUtil;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
// TODO Make this class inherit from oej.util.Fields
|
||||
|
||||
/**
|
||||
* HTTP Fields. A collection of HTTP header and or Trailer fields.
|
||||
|
@ -55,7 +56,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* single thread.
|
||||
*
|
||||
*/
|
||||
public class HttpFields implements Iterable<HttpFields.Field>
|
||||
public class HttpFields implements Iterable<HttpField>
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HttpFields.class);
|
||||
public static final String __COOKIE_DELIM="\"\\\n\r\t\f\b%+ ;=";
|
||||
|
@ -274,9 +275,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
public final static String __01Jan1970=formatDate(0);
|
||||
public final static ByteBuffer __01Jan1970_BUFFER=BufferUtil.toBuffer(__01Jan1970);
|
||||
public final static String __01Jan1970_COOKIE = formatCookieDate(0).trim();
|
||||
private final static byte[] __colon_space = new byte[] {':',' '};
|
||||
private final ArrayList<Field> _fields = new ArrayList<>(20);
|
||||
private final StringMap<Field> _names = new StringMap<>(true);
|
||||
private final ArrayList<HttpField> _fields = new ArrayList<>(20);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -291,11 +290,11 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public Collection<String> getFieldNamesCollection()
|
||||
{
|
||||
final List<String> list = new ArrayList<>(_fields.size());
|
||||
for (Field f : _fields)
|
||||
final Set<String> list = new HashSet<>(_fields.size());
|
||||
for (HttpField f : _fields)
|
||||
{
|
||||
if (f!=null)
|
||||
list.add(f._name);
|
||||
list.add(f.getName());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
@ -306,21 +305,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public Enumeration<String> getFieldNames()
|
||||
{
|
||||
final Enumeration<?> buffers = Collections.enumeration(_names.keySet());
|
||||
return new Enumeration<String>()
|
||||
{
|
||||
@Override
|
||||
public String nextElement()
|
||||
{
|
||||
return buffers.nextElement().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return buffers.hasMoreElements();
|
||||
}
|
||||
};
|
||||
return Collections.enumeration(getFieldNamesCollection());
|
||||
}
|
||||
|
||||
public int size()
|
||||
|
@ -333,30 +318,70 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
* @return A Field value or null if the Field value has not been set
|
||||
*
|
||||
*/
|
||||
public Field getField(int i)
|
||||
public HttpField getField(int i)
|
||||
{
|
||||
return _fields.get(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Field> iterator()
|
||||
public Iterator<HttpField> iterator()
|
||||
{
|
||||
return _fields.iterator();
|
||||
}
|
||||
|
||||
public Field getField(HttpHeader header)
|
||||
public HttpField getField(HttpHeader header)
|
||||
{
|
||||
return _names.get(header.toString());
|
||||
for (int i=0;i<_fields.size();i++)
|
||||
{
|
||||
HttpField f=_fields.get(i);
|
||||
if (f.getHeader()==header)
|
||||
return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Field getField(String name)
|
||||
public HttpField getField(String name)
|
||||
{
|
||||
return _names.get(name);
|
||||
for (int i=0;i<_fields.size();i++)
|
||||
{
|
||||
HttpField f=_fields.get(i);
|
||||
if (f.getName().equalsIgnoreCase(name))
|
||||
return f;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean contains(HttpHeader header, String value)
|
||||
{
|
||||
for (int i=0;i<_fields.size();i++)
|
||||
{
|
||||
HttpField f=_fields.get(i);
|
||||
if (f.getHeader()==header && f.contains(value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean contains(String name, String value)
|
||||
{
|
||||
for (int i=0;i<_fields.size();i++)
|
||||
{
|
||||
HttpField f=_fields.get(i);
|
||||
if (f.getName().equalsIgnoreCase(name) && f.contains(value))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean containsKey(String name)
|
||||
{
|
||||
return _names.containsKey(name);
|
||||
for (int i=0;i<_fields.size();i++)
|
||||
{
|
||||
HttpField f=_fields.get(i);
|
||||
if (f.getName().equalsIgnoreCase(name))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getStringField(HttpHeader header)
|
||||
|
@ -381,7 +406,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public String getStringField(String name)
|
||||
{
|
||||
Field field = getField(name);
|
||||
HttpField field = getField(name);
|
||||
return field==null?null:field.getValue();
|
||||
}
|
||||
|
||||
|
@ -394,17 +419,10 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public Collection<String> getValuesCollection(String name)
|
||||
{
|
||||
Field field = getField(name);
|
||||
if (field==null)
|
||||
return null;
|
||||
|
||||
final List<String> list = new ArrayList<>();
|
||||
|
||||
while(field!=null)
|
||||
{
|
||||
list.add(field.getValue());
|
||||
field=field._next;
|
||||
}
|
||||
for (HttpField f : _fields)
|
||||
if (f.getName().equalsIgnoreCase(name))
|
||||
list.add(f.getValue());
|
||||
return list;
|
||||
}
|
||||
|
||||
|
@ -414,34 +432,56 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
* @return Enumeration of the values
|
||||
* @param name the case-insensitive field name
|
||||
*/
|
||||
public Enumeration<String> getValues(String name)
|
||||
public Enumeration<String> getValues(final String name)
|
||||
{
|
||||
final Field field = getField(name);
|
||||
if (field == null)
|
||||
for (int i=0;i<_fields.size();i++)
|
||||
{
|
||||
List<String> empty=Collections.emptyList();
|
||||
return Collections.enumeration(empty);
|
||||
final HttpField f = _fields.get(i);
|
||||
|
||||
if (f.getName().equalsIgnoreCase(name))
|
||||
{
|
||||
final int first=i;
|
||||
return new Enumeration<String>()
|
||||
{
|
||||
HttpField field=f;
|
||||
int i = first+1;
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
if (field==null)
|
||||
{
|
||||
while (i<_fields.size())
|
||||
{
|
||||
field=_fields.get(i++);
|
||||
if (field.getName().equalsIgnoreCase(name))
|
||||
return true;
|
||||
}
|
||||
field=null;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nextElement() throws NoSuchElementException
|
||||
{
|
||||
if (hasMoreElements())
|
||||
{
|
||||
String value=field.getValue();
|
||||
field=null;
|
||||
return value;
|
||||
}
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return new Enumeration<String>()
|
||||
{
|
||||
Field f = field;
|
||||
List<String> empty=Collections.emptyList();
|
||||
return Collections.enumeration(empty);
|
||||
|
||||
@Override
|
||||
public boolean hasMoreElements()
|
||||
{
|
||||
return f != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nextElement() throws NoSuchElementException
|
||||
{
|
||||
if (f == null) throw new NoSuchElementException();
|
||||
Field n = f;
|
||||
f = f._next;
|
||||
return n.getValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -459,7 +499,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
if (e == null)
|
||||
return null;
|
||||
return new Enumeration<String>()
|
||||
{
|
||||
{
|
||||
QuotedStringTokenizer tok = null;
|
||||
|
||||
@Override
|
||||
|
@ -484,7 +524,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
if (next != null) next = next.trim();
|
||||
return next;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
@ -501,9 +541,8 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
return;
|
||||
|
||||
// new value;
|
||||
Field field = new Field(name, value);
|
||||
HttpField field = new HttpField(name, value);
|
||||
_fields.add(field);
|
||||
_names.put(name, field);
|
||||
}
|
||||
|
||||
public void put(HttpHeader header, HttpHeaderValue value)
|
||||
|
@ -519,14 +558,13 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public void put(HttpHeader header, String value)
|
||||
{
|
||||
remove(header.toString());
|
||||
remove(header);
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
// new value;
|
||||
Field field = new Field(header, value);
|
||||
HttpField field = new HttpField(header, value);
|
||||
_fields.add(field);
|
||||
_names.put(header.toString(), field);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -557,23 +595,8 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
if (value == null)
|
||||
return;
|
||||
|
||||
Field field = _names.get(name);
|
||||
Field last = null;
|
||||
while (field != null)
|
||||
{
|
||||
last = field;
|
||||
field = field._next;
|
||||
}
|
||||
|
||||
// create the field
|
||||
field = new Field(name, value);
|
||||
HttpField field = new HttpField(name, value);
|
||||
_fields.add(field);
|
||||
|
||||
// look for chain to add too
|
||||
if (last != null)
|
||||
last._next = field;
|
||||
else
|
||||
_names.put(name, field);
|
||||
}
|
||||
|
||||
public void add(HttpHeader header, HttpHeaderValue value) throws IllegalArgumentException
|
||||
|
@ -587,30 +610,14 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*
|
||||
* @param header the header
|
||||
* @param value the value of the field.
|
||||
* @exception IllegalArgumentException If the name is a single valued field and already has a
|
||||
* value.
|
||||
* @exception IllegalArgumentException
|
||||
*/
|
||||
public void add(HttpHeader header, String value) throws IllegalArgumentException
|
||||
{
|
||||
if (value == null) throw new IllegalArgumentException("null value");
|
||||
|
||||
Field field = _names.get(header.toString());
|
||||
Field last = null;
|
||||
while (field != null)
|
||||
{
|
||||
last = field;
|
||||
field = field._next;
|
||||
}
|
||||
|
||||
// create the field
|
||||
field = new Field(header, value);
|
||||
HttpField field = new HttpField(header, value);
|
||||
_fields.add(field);
|
||||
|
||||
// look for chain to add too
|
||||
if (last != null)
|
||||
last._next = field;
|
||||
else
|
||||
_names.put(header.toString(), field);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -620,7 +627,13 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public void remove(HttpHeader name)
|
||||
{
|
||||
remove(name.toString());
|
||||
Iterator<HttpField> i=_fields.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
HttpField f=i.next();
|
||||
if (f.getHeader()==name)
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -630,11 +643,12 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public void remove(String name)
|
||||
{
|
||||
Field field = _names.remove(name);
|
||||
while (field != null)
|
||||
Iterator<HttpField> i=_fields.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
_fields.remove(field);
|
||||
field = field._next;
|
||||
HttpField f=i.next();
|
||||
if (f.getName().equalsIgnoreCase(name))
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -647,7 +661,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public long getLongField(String name) throws NumberFormatException
|
||||
{
|
||||
Field field = getField(name);
|
||||
HttpField field = getField(name);
|
||||
return field==null?-1L:field.getLongValue();
|
||||
}
|
||||
|
||||
|
@ -659,11 +673,11 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
*/
|
||||
public long getDateField(String name)
|
||||
{
|
||||
Field field = getField(name);
|
||||
HttpField field = getField(name);
|
||||
if (field == null)
|
||||
return -1;
|
||||
|
||||
String val = valueParameters(field._value, null);
|
||||
String val = valueParameters(field.getValue(), null);
|
||||
if (val == null)
|
||||
return -1;
|
||||
|
||||
|
@ -840,27 +854,25 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
name_value_params = buf.toString();
|
||||
|
||||
// remove existing set-cookie of same name
|
||||
Field field = getField(HttpHeader.SET_COOKIE);
|
||||
Field last=null;
|
||||
while (field!=null)
|
||||
|
||||
Iterator<HttpField> i=_fields.iterator();
|
||||
while (i.hasNext())
|
||||
{
|
||||
String val = (field._value == null ? null : field._value.toString());
|
||||
if (val!=null && val.startsWith(start))
|
||||
HttpField field=i.next();
|
||||
if (field.getHeader()==HttpHeader.SET_COOKIE)
|
||||
{
|
||||
//existing cookie has same name, does it also match domain and path?
|
||||
if (((!hasDomain && !val.contains("Domain")) || (hasDomain && val.contains("Domain="+domain))) &&
|
||||
((!hasPath && !val.contains("Path")) || (hasPath && val.contains("Path="+path))))
|
||||
String val = (field.getValue() == null ? null : field.getValue().toString());
|
||||
if (val!=null && val.startsWith(start))
|
||||
{
|
||||
_fields.remove(field);
|
||||
if (last==null)
|
||||
_names.put(HttpHeader.SET_COOKIE.toString(),field._next);
|
||||
else
|
||||
last._next=field._next;
|
||||
break;
|
||||
//existing cookie has same name, does it also match domain and path?
|
||||
if (((!hasDomain && !val.contains("Domain")) || (hasDomain && val.contains("Domain="+domain))) &&
|
||||
((!hasPath && !val.contains("Path")) || (hasPath && val.contains("Path="+path))))
|
||||
{
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
last=field;
|
||||
field=field._next;
|
||||
}
|
||||
|
||||
add(HttpHeader.SET_COOKIE.toString(), name_value_params);
|
||||
|
@ -871,7 +883,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
|
||||
public void putTo(ByteBuffer bufferInFillMode) throws IOException
|
||||
{
|
||||
for (Field field : _fields)
|
||||
for (HttpField field : _fields)
|
||||
{
|
||||
if (field != null)
|
||||
field.putTo(bufferInFillMode);
|
||||
|
@ -886,7 +898,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
try
|
||||
{
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (Field field : _fields)
|
||||
for (HttpField field : _fields)
|
||||
{
|
||||
if (field != null)
|
||||
{
|
||||
|
@ -914,7 +926,6 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
public void clear()
|
||||
{
|
||||
_fields.clear();
|
||||
_names.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1088,151 +1099,5 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
|||
return vl;
|
||||
}
|
||||
|
||||
public static final class Field
|
||||
{
|
||||
private final HttpHeader _header;
|
||||
private final String _name;
|
||||
private final String _value;
|
||||
private Field _next;
|
||||
|
||||
private Field(HttpHeader header, String value)
|
||||
{
|
||||
_header = header;
|
||||
_name = header.toString();
|
||||
_value = value;
|
||||
_next = null;
|
||||
}
|
||||
|
||||
private Field(String name, String value)
|
||||
{
|
||||
_header = HttpHeader.CACHE.get(name);
|
||||
_name = _header==null?name:_header.toString();
|
||||
_value = value;
|
||||
_next = null;
|
||||
}
|
||||
|
||||
private byte[] toSanitisedName(String s)
|
||||
{
|
||||
byte[] bytes = s.getBytes(StringUtil.__ISO_8859_1_CHARSET);
|
||||
for (int i=bytes.length;i-->0;)
|
||||
{
|
||||
switch(bytes[i])
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
case ':' :
|
||||
bytes[i]=(byte)'?';
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
private byte[] toSanitisedValue(String s)
|
||||
{
|
||||
byte[] bytes = s.getBytes(StringUtil.__ISO_8859_1_CHARSET);
|
||||
for (int i=bytes.length;i-->0;)
|
||||
{
|
||||
switch(bytes[i])
|
||||
{
|
||||
case '\r':
|
||||
case '\n':
|
||||
bytes[i]=(byte)'?';
|
||||
}
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
public void putTo(ByteBuffer bufferInFillMode)
|
||||
{
|
||||
HttpHeader header = HttpHeader.CACHE.get(_name);
|
||||
if (header!=null)
|
||||
{
|
||||
bufferInFillMode.put(header.getBytesColonSpace());
|
||||
|
||||
if (HttpHeaderValue.hasKnownValues(header))
|
||||
{
|
||||
HttpHeaderValue value=HttpHeaderValue.CACHE.get(_value);
|
||||
if (value!=null)
|
||||
bufferInFillMode.put(value.toBuffer());
|
||||
else
|
||||
bufferInFillMode.put(toSanitisedValue(_value));
|
||||
}
|
||||
else
|
||||
bufferInFillMode.put(toSanitisedValue(_value));
|
||||
}
|
||||
else
|
||||
{
|
||||
bufferInFillMode.put(toSanitisedName(_name));
|
||||
bufferInFillMode.put(__colon_space);
|
||||
bufferInFillMode.put(toSanitisedValue(_value));
|
||||
}
|
||||
|
||||
BufferUtil.putCRLF(bufferInFillMode);
|
||||
}
|
||||
|
||||
public void putValueTo(ByteBuffer buffer)
|
||||
{
|
||||
buffer.put(toSanitisedValue(_value));
|
||||
}
|
||||
|
||||
public HttpHeader getHeader()
|
||||
{
|
||||
return _header;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public String getValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public int getIntValue()
|
||||
{
|
||||
return StringUtil.toInt(_value);
|
||||
}
|
||||
|
||||
public long getLongValue()
|
||||
{
|
||||
return StringUtil.toLong(_value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]");
|
||||
}
|
||||
|
||||
public boolean contains(String value)
|
||||
{
|
||||
if (_value==null)
|
||||
return false;
|
||||
|
||||
if (value.equalsIgnoreCase(_value))
|
||||
return true;
|
||||
|
||||
String[] split = _value.split("\\s*,\\s*");
|
||||
for (String s : split)
|
||||
{
|
||||
if (value.equalsIgnoreCase(s))
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_next!=null)
|
||||
return _next.contains(value);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean contains(HttpHeader header, String value)
|
||||
{
|
||||
Field field = getField(header);
|
||||
if (field==null)
|
||||
return false;
|
||||
return field.contains(value);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -542,7 +542,7 @@ public class HttpGenerator
|
|||
|
||||
// default field values
|
||||
boolean has_server = false;
|
||||
HttpFields.Field transfer_encoding=null;
|
||||
HttpField transfer_encoding=null;
|
||||
boolean keep_alive=false;
|
||||
boolean close=false;
|
||||
boolean content_type=false;
|
||||
|
@ -551,11 +551,11 @@ public class HttpGenerator
|
|||
// Generate fields
|
||||
if (_info.getHttpFields() != null)
|
||||
{
|
||||
for (HttpFields.Field field : _info.getHttpFields())
|
||||
for (HttpField field : _info.getHttpFields())
|
||||
{
|
||||
HttpHeader name = field.getHeader();
|
||||
HttpHeader h = field.getHeader();
|
||||
|
||||
switch (name==null?HttpHeader.UNKNOWN:name)
|
||||
switch (h==null?HttpHeader.UNKNOWN:h)
|
||||
{
|
||||
case CONTENT_LENGTH:
|
||||
// handle specially below
|
||||
|
@ -666,11 +666,11 @@ public class HttpGenerator
|
|||
}
|
||||
|
||||
default:
|
||||
if (name==null)
|
||||
if (h==null)
|
||||
field.putTo(header);
|
||||
else
|
||||
{
|
||||
header.put(name.getBytesColonSpace());
|
||||
header.put(h.getBytesColonSpace());
|
||||
field.putValueTo(header);
|
||||
header.put(CRLF);
|
||||
}
|
||||
|
|
|
@ -19,11 +19,9 @@
|
|||
package org.eclipse.jetty.http;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jetty.util.StringMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
|
||||
public enum HttpHeader
|
||||
|
@ -114,7 +112,7 @@ public enum HttpHeader
|
|||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static StringMap<HttpHeader> CACHE= new StringMap<HttpHeader>(true);
|
||||
public final static Trie<HttpHeader> CACHE= new Trie<HttpHeader>();
|
||||
static
|
||||
{
|
||||
for (HttpHeader header : HttpHeader.values())
|
||||
|
@ -122,71 +120,6 @@ public enum HttpHeader
|
|||
CACHE.put(header.toString(),header);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private final static HttpHeader[] __hashed= new HttpHeader[4096];
|
||||
private final static int __maxHashed;
|
||||
static
|
||||
{
|
||||
// This hash function has been picked to have no collisions for
|
||||
// the known header values. This allows a very quick lookup.
|
||||
int max=0;
|
||||
Map<Integer,HttpHeader> hashes=new HashMap<>();
|
||||
for (HttpHeader header : HttpHeader.values())
|
||||
{
|
||||
String s=header.asString();
|
||||
max=Math.max(max,s.length());
|
||||
int h=0;
|
||||
for (char c:s.toCharArray())
|
||||
h = 31*h + ((c>='a')?(c-'a'+'A'):c);
|
||||
int hash=h%__hashed.length;
|
||||
if (hash<0)hash=-hash;
|
||||
if (hashes.containsKey(hash))
|
||||
{
|
||||
// This should not happen with known headers.
|
||||
System.err.println("Duplicate hash "+header+" "+hashes.get(hash));
|
||||
System.exit(1);
|
||||
}
|
||||
hashes.put(hash,header);
|
||||
__hashed[hash]=header;
|
||||
}
|
||||
__maxHashed=max;
|
||||
}
|
||||
|
||||
public static HttpHeader lookAheadGet(byte[] bytes, int position, int limit)
|
||||
{
|
||||
int h=0;
|
||||
byte b=0;
|
||||
limit=Math.min(position+__maxHashed,limit);
|
||||
for (int i=position;i<limit;i++)
|
||||
{
|
||||
b=bytes[i];
|
||||
if (b==':'||b==' ')
|
||||
break;
|
||||
h= 31*h+ ((b>='a')?(b-'a'+'A'):b);
|
||||
}
|
||||
if (b!=':'&&b!=' ')
|
||||
return null;
|
||||
|
||||
int hash=h%__hashed.length;
|
||||
if (hash<0)hash=-hash;
|
||||
HttpHeader header=__hashed[hash];
|
||||
|
||||
if (header!=null)
|
||||
{
|
||||
String s=header.asString();
|
||||
for (int i=s.length();i-->0;)
|
||||
{
|
||||
b=bytes[position+i];
|
||||
char c=s.charAt(i);
|
||||
if (c!=b && Character.toUpperCase(c)!=(b>='a'?(b-'a'+'A'):b))
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
|
||||
private final String _string;
|
||||
private final byte[] _bytes;
|
||||
private final byte[] _bytesColonSpace;
|
||||
|
|
|
@ -22,7 +22,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.EnumSet;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringMap;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -44,7 +44,7 @@ public enum HttpHeaderValue
|
|||
UNKNOWN("::UNKNOWN::");
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static StringMap<HttpHeaderValue> CACHE= new StringMap<HttpHeaderValue>(true);
|
||||
public final static Trie<HttpHeaderValue> CACHE= new Trie<HttpHeaderValue>();
|
||||
static
|
||||
{
|
||||
for (HttpHeaderValue value : HttpHeaderValue.values())
|
||||
|
|
|
@ -20,8 +20,8 @@ package org.eclipse.jetty.http;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.StringMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -109,11 +109,11 @@ public enum HttpMethod
|
|||
{
|
||||
if (buffer.hasArray())
|
||||
return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit());
|
||||
return null;
|
||||
return CACHE.getBest(buffer,0,buffer.remaining());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static StringMap<HttpMethod> CACHE= new StringMap<HttpMethod>(true);
|
||||
public final static Trie<HttpMethod> CACHE= new Trie<HttpMethod>();
|
||||
static
|
||||
{
|
||||
for (HttpMethod method : HttpMethod.values())
|
||||
|
|
|
@ -508,6 +508,86 @@ public class HttpParser
|
|||
return return_from_parse;
|
||||
}
|
||||
|
||||
private boolean handleKnownHeaders(ByteBuffer buffer)
|
||||
{
|
||||
switch (_header)
|
||||
{
|
||||
case CONTENT_LENGTH:
|
||||
if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
|
||||
{
|
||||
try
|
||||
{
|
||||
_contentLength=Long.parseLong(_valueString);
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
|
||||
return true;
|
||||
}
|
||||
if (_contentLength <= 0)
|
||||
_endOfContent=EndOfContent.NO_CONTENT;
|
||||
else
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
}
|
||||
break;
|
||||
|
||||
case TRANSFER_ENCODING:
|
||||
if (_value==HttpHeaderValue.CHUNKED)
|
||||
_endOfContent=EndOfContent.CHUNKED_CONTENT;
|
||||
else
|
||||
{
|
||||
if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString()))
|
||||
_endOfContent=EndOfContent.CHUNKED_CONTENT;
|
||||
else if (_valueString.indexOf(HttpHeaderValue.CHUNKED.toString()) >= 0)
|
||||
{
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad chunking");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HOST:
|
||||
_host=true;
|
||||
String host=_valueString;
|
||||
int port=0;
|
||||
if (host==null || host.length()==0)
|
||||
{
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Host header");
|
||||
return true;
|
||||
}
|
||||
|
||||
loop: for (int i = host.length(); i-- > 0;)
|
||||
{
|
||||
char c2 = (char)(0xff & host.charAt(i));
|
||||
switch (c2)
|
||||
{
|
||||
case ']':
|
||||
break loop;
|
||||
|
||||
case ':':
|
||||
try
|
||||
{
|
||||
port = StringUtil.toInt(host.substring(i+1));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Host header");
|
||||
return true;
|
||||
}
|
||||
host = host.substring(0,i);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (_requestHandler!=null)
|
||||
_requestHandler.parsedHostHeader(host,port);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/*
|
||||
* Parse the message headers and return true if the handler has signaled for a return
|
||||
|
@ -545,8 +625,14 @@ public class HttpParser
|
|||
case HttpTokens.TAB:
|
||||
{
|
||||
// header value without name - continuation?
|
||||
_length=-1;
|
||||
_string.setLength(0);
|
||||
if (_valueString!=null)
|
||||
{
|
||||
_string.append(_valueString);
|
||||
_string.append(' ');
|
||||
}
|
||||
_length=_string.length();
|
||||
_valueString=null;
|
||||
setState(State.HEADER_VALUE);
|
||||
break;
|
||||
}
|
||||
|
@ -557,82 +643,8 @@ public class HttpParser
|
|||
if (_headerString!=null || _valueString!=null)
|
||||
{
|
||||
// Handle known headers
|
||||
if (_header!=null)
|
||||
{
|
||||
switch (_header)
|
||||
{
|
||||
case CONTENT_LENGTH:
|
||||
if (_endOfContent != EndOfContent.CHUNKED_CONTENT)
|
||||
{
|
||||
try
|
||||
{
|
||||
_contentLength=Long.parseLong(_valueString);
|
||||
}
|
||||
catch(NumberFormatException e)
|
||||
{
|
||||
LOG.ignore(e);
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Content-Length");
|
||||
return true;
|
||||
}
|
||||
if (_contentLength <= 0)
|
||||
_endOfContent=EndOfContent.NO_CONTENT;
|
||||
else
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
}
|
||||
break;
|
||||
|
||||
case TRANSFER_ENCODING:
|
||||
if (_value==HttpHeaderValue.CHUNKED)
|
||||
_endOfContent=EndOfContent.CHUNKED_CONTENT;
|
||||
else
|
||||
{
|
||||
if (_valueString.endsWith(HttpHeaderValue.CHUNKED.toString()))
|
||||
_endOfContent=EndOfContent.CHUNKED_CONTENT;
|
||||
else if (_valueString.indexOf(HttpHeaderValue.CHUNKED.toString()) >= 0)
|
||||
{
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad chunking");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case HOST:
|
||||
_host=true;
|
||||
String host=_valueString;
|
||||
int port=0;
|
||||
if (host==null || host.length()==0)
|
||||
{
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Host header");
|
||||
return true;
|
||||
}
|
||||
|
||||
loop: for (int i = host.length(); i-- > 0;)
|
||||
{
|
||||
char c2 = (char)(0xff & host.charAt(i));
|
||||
switch (c2)
|
||||
{
|
||||
case ']':
|
||||
break loop;
|
||||
|
||||
case ':':
|
||||
try
|
||||
{
|
||||
port = StringUtil.toInt(host.substring(i+1));
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
badMessage(buffer,HttpStatus.BAD_REQUEST_400,"Bad Host header");
|
||||
return true;
|
||||
}
|
||||
host = host.substring(0,i);
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
if (_requestHandler!=null)
|
||||
_requestHandler.parsedHostHeader(host,port);
|
||||
}
|
||||
}
|
||||
if (_header!=null && handleKnownHeaders(buffer))
|
||||
return true;
|
||||
|
||||
return_from_parse|=_handler.parsedHeader(_header, _headerString, _valueString);
|
||||
}
|
||||
|
@ -704,14 +716,36 @@ public class HttpParser
|
|||
{
|
||||
if (buffer.remaining()>6 && buffer.hasArray())
|
||||
{
|
||||
// Try a look ahead for the known headers.
|
||||
_header=HttpHeader.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
|
||||
// Try a look ahead for the known header name and value.
|
||||
HttpField field=HttpField.CACHE.getBest(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.remaining()+1);
|
||||
if (field!=null)
|
||||
{
|
||||
_header=field.getHeader();
|
||||
_headerString=field.getName();
|
||||
_valueString=field.getValue();
|
||||
if (_valueString==null)
|
||||
{
|
||||
setState(State.HEADER_VALUE);
|
||||
buffer.position(buffer.position()+_headerString.length()+1);
|
||||
_string.setLength(0);
|
||||
_length=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
setState(State.HEADER_IN_VALUE);
|
||||
buffer.position(buffer.position()+_headerString.length()+_valueString.length()+1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Try a look ahead for the known header name.
|
||||
_header=HttpHeader.CACHE.getBest(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.remaining()+1);
|
||||
if (_header!=null)
|
||||
{
|
||||
_headerString=_header.asString();
|
||||
buffer.position(buffer.position()+_headerString.length());
|
||||
setState(buffer.get(buffer.position()-1)==':'?State.HEADER_VALUE:State.HEADER_NAME);
|
||||
_string.setLength(0);
|
||||
setState(State.HEADER_IN_NAME);
|
||||
buffer.position(buffer.position()+_headerString.length()-1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -733,8 +767,11 @@ public class HttpParser
|
|||
case HttpTokens.CARRIAGE_RETURN:
|
||||
case HttpTokens.LINE_FEED:
|
||||
consumeCRLF(ch,buffer);
|
||||
_headerString=takeLengthString();
|
||||
_header=HttpHeader.CACHE.get(_headerString);
|
||||
if (_headerString==null)
|
||||
{
|
||||
_headerString=takeLengthString();
|
||||
_header=HttpHeader.CACHE.get(_headerString);
|
||||
}
|
||||
setState(State.HEADER);
|
||||
|
||||
break;
|
||||
|
@ -753,15 +790,6 @@ public class HttpParser
|
|||
break;
|
||||
default:
|
||||
{
|
||||
if (_header!=null)
|
||||
{
|
||||
_string.setLength(0);
|
||||
_string.append(_header.asString());
|
||||
_string.append(' ');
|
||||
_length=_string.length();
|
||||
_header=null;
|
||||
_headerString=null;
|
||||
}
|
||||
_string.append((char)ch);
|
||||
_length=_string.length();
|
||||
setState(State.HEADER_IN_NAME);
|
||||
|
@ -793,10 +821,26 @@ public class HttpParser
|
|||
break;
|
||||
case HttpTokens.SPACE:
|
||||
case HttpTokens.TAB:
|
||||
if (_header!=null)
|
||||
{
|
||||
_string.setLength(0);
|
||||
_string.append(_header.asString());
|
||||
_length=_string.length();
|
||||
_header=null;
|
||||
_headerString=null;
|
||||
}
|
||||
setState(State.HEADER_NAME);
|
||||
_string.append((char)ch);
|
||||
break;
|
||||
default:
|
||||
if (_header!=null)
|
||||
{
|
||||
_string.setLength(0);
|
||||
_string.append(_header.asString());
|
||||
_length=_string.length();
|
||||
_header=null;
|
||||
_headerString=null;
|
||||
}
|
||||
_string.append((char)ch);
|
||||
_length++;
|
||||
}
|
||||
|
@ -849,13 +893,7 @@ public class HttpParser
|
|||
consumeCRLF(ch,buffer);
|
||||
if (_length > 0)
|
||||
{
|
||||
if (_valueString!=null)
|
||||
{
|
||||
// multi line value!
|
||||
_value=null;
|
||||
_valueString+=" "+takeString();
|
||||
}
|
||||
else if (HttpHeaderValue.hasKnownValues(_header))
|
||||
if (HttpHeaderValue.hasKnownValues(_header))
|
||||
{
|
||||
_valueString=takeString();
|
||||
_value=HttpHeaderValue.CACHE.get(_valueString);
|
||||
|
@ -871,10 +909,24 @@ public class HttpParser
|
|||
break;
|
||||
case HttpTokens.SPACE:
|
||||
case HttpTokens.TAB:
|
||||
if (_valueString!=null)
|
||||
{
|
||||
_string.setLength(0);
|
||||
_string.append(_valueString);
|
||||
_length=_valueString.length();
|
||||
_valueString=null;
|
||||
}
|
||||
_string.append((char)ch);
|
||||
setState(State.HEADER_VALUE);
|
||||
break;
|
||||
default:
|
||||
if (_valueString!=null)
|
||||
{
|
||||
_string.setLength(0);
|
||||
_string.append(_valueString);
|
||||
_length=_valueString.length();
|
||||
_valueString=null;
|
||||
}
|
||||
_string.append((char)ch);
|
||||
_length++;
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ package org.eclipse.jetty.http;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringMap;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
|
@ -34,7 +34,7 @@ public enum HttpScheme
|
|||
WSS("wss");
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static StringMap<HttpScheme> CACHE= new StringMap<HttpScheme>(true);
|
||||
public final static Trie<HttpScheme> CACHE= new Trie<HttpScheme>();
|
||||
static
|
||||
{
|
||||
for (HttpScheme version : HttpScheme.values())
|
||||
|
|
|
@ -20,8 +20,8 @@ package org.eclipse.jetty.http;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.StringMap;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Trie;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
|
@ -33,7 +33,7 @@ public enum HttpVersion
|
|||
HTTP_2_0("HTTP/2.0",20);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public final static StringMap<HttpVersion> CACHE= new StringMap<HttpVersion>(true);
|
||||
public final static Trie<HttpVersion> CACHE= new Trie<HttpVersion>();
|
||||
static
|
||||
{
|
||||
for (HttpVersion version : HttpVersion.values())
|
||||
|
|
|
@ -28,8 +28,8 @@ import java.util.MissingResourceException;
|
|||
import java.util.ResourceBundle;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
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;
|
||||
|
||||
|
@ -109,8 +109,8 @@ public class MimeTypes
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static final Logger LOG = Log.getLogger(MimeTypes.class);
|
||||
public final static StringMap<MimeTypes.Type> CACHE= new StringMap<MimeTypes.Type>(true);
|
||||
private final static StringMap<ByteBuffer> TYPES= new StringMap<ByteBuffer>(true);
|
||||
public final static Trie<MimeTypes.Type> CACHE= new Trie<MimeTypes.Type>();
|
||||
private final static Trie<ByteBuffer> TYPES= new Trie<ByteBuffer>();
|
||||
private final static Map<String,String> __dftMimeMap = new HashMap<String,String>();
|
||||
private final static Map<String,String> __encodings = new HashMap<String,String>();
|
||||
|
||||
|
|
|
@ -514,8 +514,8 @@ public class HttpFieldsTest
|
|||
|
||||
for (int i=0;i<7;i++)
|
||||
{
|
||||
assertFalse(""+i,header.getField(""+i).contains("xyz"));
|
||||
assertEquals(""+i,i>=4,header.getField(""+i).contains("def"));
|
||||
assertFalse(""+i,header.contains(""+i,"xyz"));
|
||||
assertEquals(""+i,i>=4,header.contains(""+i,"def"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.eclipse.jetty.http.HttpParser.State;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
@ -153,12 +154,15 @@ public class HttpParserTest
|
|||
"Host: localhost\015\012" +
|
||||
"Header1: value1\015\012" +
|
||||
"Header 2 : value 2a \015\012" +
|
||||
" value 2b \015\012" +
|
||||
" value 2b \015\012" +
|
||||
"Header3: \015\012" +
|
||||
"Header4 \015\012" +
|
||||
" value4\015\012" +
|
||||
"Server5 : notServer\015\012" +
|
||||
"Host Header: notHost\015\012" +
|
||||
"Connection: close\015\012" +
|
||||
"Accept-Encoding: gzip, deflated\015\012" +
|
||||
"Accept: unknown\015\012" +
|
||||
"\015\012");
|
||||
Handler handler = new Handler();
|
||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||
|
@ -181,7 +185,13 @@ public class HttpParserTest
|
|||
assertEquals("notServer", _val[5]);
|
||||
assertEquals("Host Header", _hdr[6]);
|
||||
assertEquals("notHost", _val[6]);
|
||||
assertEquals(6, _h);
|
||||
assertEquals("Connection", _hdr[7]);
|
||||
assertEquals("close", _val[7]);
|
||||
assertEquals("Accept-Encoding", _hdr[8]);
|
||||
assertEquals("gzip, deflated", _val[8]);
|
||||
assertEquals("Accept", _hdr[9]);
|
||||
assertEquals("unknown", _val[9]);
|
||||
assertEquals(9, _h);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -736,8 +746,8 @@ public class HttpParserTest
|
|||
{
|
||||
request=true;
|
||||
_h= -1;
|
||||
_hdr= new String[9];
|
||||
_val= new String[9];
|
||||
_hdr= new String[10];
|
||||
_val= new String[10];
|
||||
_methodOrVersion= method;
|
||||
_uriOrStatus= uri;
|
||||
_versionOrReason= version==null?null:version.asString();
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.eclipse.jetty.client.api.Response;
|
|||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.util.InputStreamContentProvider;
|
||||
import org.eclipse.jetty.client.util.TimedResponseListener;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
|
@ -464,7 +465,7 @@ public class ProxyServlet extends HttpServlet
|
|||
|
||||
protected void onResponseHeaders(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
|
||||
{
|
||||
for (HttpFields.Field field : proxyResponse.getHeaders())
|
||||
for (HttpField field : proxyResponse.getHeaders())
|
||||
{
|
||||
String headerName = field.getName();
|
||||
String lowerHeaderName = headerName.toLowerCase(Locale.ENGLISH);
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -479,7 +480,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
Map<String, RoleInfo> mappings = _constraintMap.get(mapping.getPathSpec());
|
||||
if (mappings == null)
|
||||
{
|
||||
mappings = new StringMap<>();
|
||||
mappings = new HashMap<String,RoleInfo>();
|
||||
_constraintMap.put(mapping.getPathSpec(),mappings);
|
||||
}
|
||||
RoleInfo allMethodsRoleInfo = mappings.get(ALL_METHODS);
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
@ -128,7 +129,7 @@ public class HttpTransportOverSPDY implements HttpTransport
|
|||
{
|
||||
for (int i = 0; i < fields.size(); ++i)
|
||||
{
|
||||
HttpFields.Field field = fields.getField(i);
|
||||
HttpField field = fields.getField(i);
|
||||
String name = field.getName();
|
||||
String value = field.getValue();
|
||||
headers.put(name, value);
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class Trie<V>
|
||||
{
|
||||
private static final int[] __lookup =
|
||||
{ // 0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
/*0*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
/*1*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 30,
|
||||
/*2*/31, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 26, -1, 27, -1, -1,
|
||||
/*3*/-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 28, 29, -1, -1, -1, -1,
|
||||
/*4*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*5*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
/*6*/-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
/*7*/15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
|
||||
};
|
||||
private static final int INDEX = 32;
|
||||
private final Trie<V>[] _nextIndex;
|
||||
private final List<Trie<V>> _nextOther=new ArrayList<>();
|
||||
private final char _c;
|
||||
private String _key;
|
||||
private V _value;
|
||||
|
||||
public Trie()
|
||||
{
|
||||
_nextIndex = new Trie[INDEX];
|
||||
_c=0;
|
||||
}
|
||||
|
||||
private Trie(char c)
|
||||
{
|
||||
_nextIndex = new Trie[INDEX];
|
||||
this._c=c;
|
||||
}
|
||||
|
||||
public V put(V v)
|
||||
{
|
||||
return put(v.toString(),v);
|
||||
}
|
||||
|
||||
public V put(String s, V v)
|
||||
{
|
||||
Trie<V> t = this;
|
||||
int k;
|
||||
int limit = s.length();
|
||||
for(k=0; k < limit; k++)
|
||||
{
|
||||
char c=s.charAt(k);
|
||||
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
t._nextIndex[index] = new Trie<V>(c);
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
Trie<V> n=null;
|
||||
for (int i=t._nextOther.size();i-->0;)
|
||||
{
|
||||
n=t._nextOther.get(i);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
{
|
||||
n=new Trie<V>(c);
|
||||
t._nextOther.add(n);
|
||||
}
|
||||
t=n;
|
||||
}
|
||||
}
|
||||
t._key=v==null?null:s;
|
||||
V old=t._value;
|
||||
t._value = v;
|
||||
return old;
|
||||
}
|
||||
|
||||
public V remove(String s)
|
||||
{
|
||||
V o=get(s);
|
||||
put(s,null);
|
||||
return o;
|
||||
}
|
||||
|
||||
public V get(String s)
|
||||
{
|
||||
Trie<V> t = this;
|
||||
int len = s.length();
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
char c=s.charAt(i);
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
Trie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
public V get(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
Trie<V> t = this;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(offset+i);
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
Trie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
public V getBest(byte[] b,int offset,int len)
|
||||
{
|
||||
Trie<V> t = this;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b[offset+i];
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
Trie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (t._key!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=t.getBest(b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return t._value;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
public V getBest(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
if (b.hasArray())
|
||||
return getBest(b.array(),b.arrayOffset()+b.position()+offset,len);
|
||||
return doGetBest(b,offset,len);
|
||||
}
|
||||
|
||||
private V doGetBest(ByteBuffer b,int offset,int len)
|
||||
{
|
||||
Trie<V> t = this;
|
||||
for(int i=0; i < len; i++)
|
||||
{
|
||||
byte c=b.get(offset+i);
|
||||
int index=c>=0&&c<0x7f?__lookup[c]:-1;
|
||||
if (index>=0)
|
||||
{
|
||||
if (t._nextIndex[index] == null)
|
||||
return null;
|
||||
t = t._nextIndex[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
Trie<V> n=null;
|
||||
for (int j=t._nextOther.size();j-->0;)
|
||||
{
|
||||
n=t._nextOther.get(j);
|
||||
if (n._c==c)
|
||||
break;
|
||||
n=null;
|
||||
}
|
||||
if (n==null)
|
||||
return null;
|
||||
t=n;
|
||||
}
|
||||
|
||||
// Is the next Trie is a match
|
||||
if (t._key!=null)
|
||||
{
|
||||
// Recurse so we can remember this possibility
|
||||
V best=t.getBest(b,offset+i+1,len-i-1);
|
||||
if (best!=null)
|
||||
return best;
|
||||
return t._value;
|
||||
}
|
||||
}
|
||||
return t._value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder buf = new StringBuilder();
|
||||
toString(buf,this);
|
||||
|
||||
if (buf.length()==0)
|
||||
return "{}";
|
||||
|
||||
buf.setCharAt(0,'{');
|
||||
buf.append('}');
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
||||
private static <V> void toString(Appendable out, Trie<V> t)
|
||||
{
|
||||
if (t != null)
|
||||
{
|
||||
if (t._value!=null)
|
||||
{
|
||||
try
|
||||
{
|
||||
out.append(',');
|
||||
out.append(t._key);
|
||||
out.append('=');
|
||||
out.append(t._value.toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < INDEX; i++)
|
||||
{
|
||||
if (t._nextIndex[i] != null)
|
||||
toString(out,t._nextIndex[i]);
|
||||
}
|
||||
for (int i=t._nextOther.size();i-->0;)
|
||||
toString(out,t._nextOther.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> keySet()
|
||||
{
|
||||
Set<String> keys = new HashSet<>();
|
||||
keySet(keys,this);
|
||||
return keys;
|
||||
}
|
||||
|
||||
private static <V> void keySet(Set<String> set, Trie<V> t)
|
||||
{
|
||||
if (t != null)
|
||||
{
|
||||
if (t._key!=null)
|
||||
set.add(t._key);
|
||||
|
||||
for(int i=0; i < INDEX; i++)
|
||||
{
|
||||
if (t._nextIndex[i] != null)
|
||||
keySet(set,t._nextIndex[i]);
|
||||
}
|
||||
for (int i=t._nextOther.size();i-->0;)
|
||||
keySet(set,t._nextOther.get(i));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TrieTest
|
||||
{
|
||||
Trie<Integer> trie = new Trie<>();
|
||||
|
||||
@Before
|
||||
public void before()
|
||||
{
|
||||
trie.put("hello",1);
|
||||
trie.put("He",2);
|
||||
trie.put("HELL",3);
|
||||
trie.put("wibble",4);
|
||||
trie.put("Wobble",5);
|
||||
trie.put("foo-bar",6);
|
||||
trie.put("foo+bar",7);
|
||||
trie.put("HELL4",8);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetString() throws Exception
|
||||
{
|
||||
Assert.assertEquals(1,trie.get("hello").intValue());
|
||||
Assert.assertEquals(2,trie.get("He").intValue());
|
||||
Assert.assertEquals(3,trie.get("HELL").intValue());
|
||||
Assert.assertEquals(4,trie.get("wibble").intValue());
|
||||
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(1,trie.get("Hello").intValue());
|
||||
Assert.assertEquals(2,trie.get("HE").intValue());
|
||||
Assert.assertEquals(3,trie.get("heLL").intValue());
|
||||
Assert.assertEquals(4,trie.get("Wibble").intValue());
|
||||
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("Help"));
|
||||
Assert.assertEquals(null,trie.get("Blah"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBuffer() throws Exception
|
||||
{
|
||||
Assert.assertEquals(1,trie.get(BufferUtil.toBuffer("xhellox"),1,5).intValue());
|
||||
Assert.assertEquals(2,trie.get(BufferUtil.toBuffer("xhellox"),1,2).intValue());
|
||||
Assert.assertEquals(3,trie.get(BufferUtil.toBuffer("xhellox"),1,4).intValue());
|
||||
Assert.assertEquals(4,trie.get(BufferUtil.toBuffer("wibble"),0,6).intValue());
|
||||
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(1,trie.get(BufferUtil.toBuffer("xhellox"),1,5).intValue());
|
||||
Assert.assertEquals(2,trie.get(BufferUtil.toBuffer("xHELLox"),1,2).intValue());
|
||||
Assert.assertEquals(3,trie.get(BufferUtil.toBuffer("xhellox"),1,4).intValue());
|
||||
Assert.assertEquals(4,trie.get(BufferUtil.toBuffer("Wibble"),0,6).intValue());
|
||||
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("xHelpx"),1,4));
|
||||
Assert.assertEquals(null,trie.get(BufferUtil.toBuffer("xBlahx"),1,4));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testGetBest() throws Exception
|
||||
{
|
||||
Assert.assertEquals(1,trie.getBest(BufferUtil.toBuffer("xhelloxxxx"),1,10).intValue());
|
||||
Assert.assertEquals(2,trie.getBest(BufferUtil.toBuffer("xhelxoxxxx"),1,10).intValue());
|
||||
Assert.assertEquals(3,trie.getBest(BufferUtil.toBuffer("xhellxxxxx"),1,10).intValue());
|
||||
Assert.assertEquals(6,trie.getBest(BufferUtil.toBuffer("xfoo-barxx"),1,10).intValue());
|
||||
Assert.assertEquals(8,trie.getBest(BufferUtil.toBuffer("xhell4xxxx"),1,10).intValue());
|
||||
|
||||
Assert.assertEquals(1,trie.getBest(BufferUtil.toBuffer("xHELLOxxxx"),1,10).intValue());
|
||||
Assert.assertEquals(2,trie.getBest(BufferUtil.toBuffer("xHELxoxxxx"),1,10).intValue());
|
||||
Assert.assertEquals(3,trie.getBest(BufferUtil.toBuffer("xHELLxxxxx"),1,10).intValue());
|
||||
Assert.assertEquals(6,trie.getBest(BufferUtil.toBuffer("xfoo-BARxx"),1,10).intValue());
|
||||
Assert.assertEquals(8,trie.getBest(BufferUtil.toBuffer("xHELL4xxxx"),1,10).intValue());
|
||||
|
||||
ByteBuffer buffer = (ByteBuffer)BufferUtil.toBuffer("xhelloxxxxxxx").position(2);
|
||||
Assert.assertEquals(1,trie.getBest(buffer,-1,10).intValue());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -92,7 +92,7 @@ public class MuxAddHandler implements MuxAddServer
|
|||
|
||||
for (String headerName : request.getHeaders().keySet())
|
||||
{
|
||||
HttpHeader header = HttpHeader.lookAheadGet(headerName.getBytes(),0,headerName.length());
|
||||
HttpHeader header = HttpHeader.CACHE.getBest(headerName.getBytes(),0,headerName.length());
|
||||
for (String value : request.getHeaders().get(headerName))
|
||||
{
|
||||
httpChannel.parsedHeader(header,headerName,value);
|
||||
|
|
Loading…
Reference in New Issue