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.ProxyConfiguration;
|
||||||
import org.eclipse.jetty.client.api.Request;
|
import org.eclipse.jetty.client.api.Request;
|
||||||
import org.eclipse.jetty.client.api.Response;
|
import org.eclipse.jetty.client.api.Response;
|
||||||
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
|
@ -350,7 +351,7 @@ public class HttpClient extends ContainerLifeCycle
|
||||||
newRequest.method(oldRequest.getMethod())
|
newRequest.method(oldRequest.getMethod())
|
||||||
.version(oldRequest.getVersion())
|
.version(oldRequest.getVersion())
|
||||||
.content(oldRequest.getContent());
|
.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
|
// We have a new URI, so skip the host header if present
|
||||||
if (HttpHeader.HOST == header.getHeader())
|
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.Enumeration;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
import java.util.TimeZone;
|
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.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
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.
|
* HTTP Fields. A collection of HTTP header and or Trailer fields.
|
||||||
|
@ -55,7 +56,7 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
* single thread.
|
* single thread.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class HttpFields implements Iterable<HttpFields.Field>
|
public class HttpFields implements Iterable<HttpField>
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(HttpFields.class);
|
private static final Logger LOG = Log.getLogger(HttpFields.class);
|
||||||
public static final String __COOKIE_DELIM="\"\\\n\r\t\f\b%+ ;=";
|
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 String __01Jan1970=formatDate(0);
|
||||||
public final static ByteBuffer __01Jan1970_BUFFER=BufferUtil.toBuffer(__01Jan1970);
|
public final static ByteBuffer __01Jan1970_BUFFER=BufferUtil.toBuffer(__01Jan1970);
|
||||||
public final static String __01Jan1970_COOKIE = formatCookieDate(0).trim();
|
public final static String __01Jan1970_COOKIE = formatCookieDate(0).trim();
|
||||||
private final static byte[] __colon_space = new byte[] {':',' '};
|
private final ArrayList<HttpField> _fields = new ArrayList<>(20);
|
||||||
private final ArrayList<Field> _fields = new ArrayList<>(20);
|
|
||||||
private final StringMap<Field> _names = new StringMap<>(true);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -291,11 +290,11 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
*/
|
*/
|
||||||
public Collection<String> getFieldNamesCollection()
|
public Collection<String> getFieldNamesCollection()
|
||||||
{
|
{
|
||||||
final List<String> list = new ArrayList<>(_fields.size());
|
final Set<String> list = new HashSet<>(_fields.size());
|
||||||
for (Field f : _fields)
|
for (HttpField f : _fields)
|
||||||
{
|
{
|
||||||
if (f!=null)
|
if (f!=null)
|
||||||
list.add(f._name);
|
list.add(f.getName());
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
@ -306,21 +305,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
*/
|
*/
|
||||||
public Enumeration<String> getFieldNames()
|
public Enumeration<String> getFieldNames()
|
||||||
{
|
{
|
||||||
final Enumeration<?> buffers = Collections.enumeration(_names.keySet());
|
return Collections.enumeration(getFieldNamesCollection());
|
||||||
return new Enumeration<String>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public String nextElement()
|
|
||||||
{
|
|
||||||
return buffers.nextElement().toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasMoreElements()
|
|
||||||
{
|
|
||||||
return buffers.hasMoreElements();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int size()
|
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
|
* @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);
|
return _fields.get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Field> iterator()
|
public Iterator<HttpField> iterator()
|
||||||
{
|
{
|
||||||
return _fields.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)
|
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)
|
public String getStringField(HttpHeader header)
|
||||||
|
@ -381,7 +406,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
*/
|
*/
|
||||||
public String getStringField(String name)
|
public String getStringField(String name)
|
||||||
{
|
{
|
||||||
Field field = getField(name);
|
HttpField field = getField(name);
|
||||||
return field==null?null:field.getValue();
|
return field==null?null:field.getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,17 +419,10 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
*/
|
*/
|
||||||
public Collection<String> getValuesCollection(String name)
|
public Collection<String> getValuesCollection(String name)
|
||||||
{
|
{
|
||||||
Field field = getField(name);
|
|
||||||
if (field==null)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
final List<String> list = new ArrayList<>();
|
final List<String> list = new ArrayList<>();
|
||||||
|
for (HttpField f : _fields)
|
||||||
while(field!=null)
|
if (f.getName().equalsIgnoreCase(name))
|
||||||
{
|
list.add(f.getValue());
|
||||||
list.add(field.getValue());
|
|
||||||
field=field._next;
|
|
||||||
}
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -414,34 +432,56 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
* @return Enumeration of the values
|
* @return Enumeration of the values
|
||||||
* @param name the case-insensitive field name
|
* @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);
|
for (int i=0;i<_fields.size();i++)
|
||||||
if (field == null)
|
|
||||||
{
|
{
|
||||||
List<String> empty=Collections.emptyList();
|
final HttpField f = _fields.get(i);
|
||||||
return Collections.enumeration(empty);
|
|
||||||
|
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>()
|
List<String> empty=Collections.emptyList();
|
||||||
{
|
return Collections.enumeration(empty);
|
||||||
Field f = field;
|
|
||||||
|
|
||||||
@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)
|
if (e == null)
|
||||||
return null;
|
return null;
|
||||||
return new Enumeration<String>()
|
return new Enumeration<String>()
|
||||||
{
|
{
|
||||||
QuotedStringTokenizer tok = null;
|
QuotedStringTokenizer tok = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -484,7 +524,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
if (next != null) next = next.trim();
|
if (next != null) next = next.trim();
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,9 +541,8 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// new value;
|
// new value;
|
||||||
Field field = new Field(name, value);
|
HttpField field = new HttpField(name, value);
|
||||||
_fields.add(field);
|
_fields.add(field);
|
||||||
_names.put(name, field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void put(HttpHeader header, HttpHeaderValue value)
|
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)
|
public void put(HttpHeader header, String value)
|
||||||
{
|
{
|
||||||
remove(header.toString());
|
remove(header);
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// new value;
|
// new value;
|
||||||
Field field = new Field(header, value);
|
HttpField field = new HttpField(header, value);
|
||||||
_fields.add(field);
|
_fields.add(field);
|
||||||
_names.put(header.toString(), field);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -557,23 +595,8 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
if (value == null)
|
if (value == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Field field = _names.get(name);
|
HttpField field = new HttpField(name, value);
|
||||||
Field last = null;
|
|
||||||
while (field != null)
|
|
||||||
{
|
|
||||||
last = field;
|
|
||||||
field = field._next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the field
|
|
||||||
field = new Field(name, value);
|
|
||||||
_fields.add(field);
|
_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
|
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 header the header
|
||||||
* @param value the value of the field.
|
* @param value the value of the field.
|
||||||
* @exception IllegalArgumentException If the name is a single valued field and already has a
|
* @exception IllegalArgumentException
|
||||||
* value.
|
|
||||||
*/
|
*/
|
||||||
public void add(HttpHeader header, String value) throws IllegalArgumentException
|
public void add(HttpHeader header, String value) throws IllegalArgumentException
|
||||||
{
|
{
|
||||||
if (value == null) throw new IllegalArgumentException("null value");
|
if (value == null) throw new IllegalArgumentException("null value");
|
||||||
|
|
||||||
Field field = _names.get(header.toString());
|
HttpField field = new HttpField(header, value);
|
||||||
Field last = null;
|
|
||||||
while (field != null)
|
|
||||||
{
|
|
||||||
last = field;
|
|
||||||
field = field._next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the field
|
|
||||||
field = new Field(header, value);
|
|
||||||
_fields.add(field);
|
_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)
|
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)
|
public void remove(String name)
|
||||||
{
|
{
|
||||||
Field field = _names.remove(name);
|
Iterator<HttpField> i=_fields.iterator();
|
||||||
while (field != null)
|
while (i.hasNext())
|
||||||
{
|
{
|
||||||
_fields.remove(field);
|
HttpField f=i.next();
|
||||||
field = field._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
|
public long getLongField(String name) throws NumberFormatException
|
||||||
{
|
{
|
||||||
Field field = getField(name);
|
HttpField field = getField(name);
|
||||||
return field==null?-1L:field.getLongValue();
|
return field==null?-1L:field.getLongValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -659,11 +673,11 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
*/
|
*/
|
||||||
public long getDateField(String name)
|
public long getDateField(String name)
|
||||||
{
|
{
|
||||||
Field field = getField(name);
|
HttpField field = getField(name);
|
||||||
if (field == null)
|
if (field == null)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
String val = valueParameters(field._value, null);
|
String val = valueParameters(field.getValue(), null);
|
||||||
if (val == null)
|
if (val == null)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -840,29 +854,27 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
name_value_params = buf.toString();
|
name_value_params = buf.toString();
|
||||||
|
|
||||||
// remove existing set-cookie of same name
|
// remove existing set-cookie of same name
|
||||||
Field field = getField(HttpHeader.SET_COOKIE);
|
|
||||||
Field last=null;
|
|
||||||
while (field!=null)
|
|
||||||
{
|
|
||||||
String val = (field._value == null ? null : field._value.toString());
|
|
||||||
if (val!=null && val.startsWith(start))
|
|
||||||
{
|
|
||||||
//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))))
|
|
||||||
{
|
|
||||||
_fields.remove(field);
|
|
||||||
if (last==null)
|
|
||||||
_names.put(HttpHeader.SET_COOKIE.toString(),field._next);
|
|
||||||
else
|
|
||||||
last._next=field._next;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last=field;
|
|
||||||
field=field._next;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
Iterator<HttpField> i=_fields.iterator();
|
||||||
|
while (i.hasNext())
|
||||||
|
{
|
||||||
|
HttpField field=i.next();
|
||||||
|
if (field.getHeader()==HttpHeader.SET_COOKIE)
|
||||||
|
{
|
||||||
|
String val = (field.getValue() == null ? null : field.getValue().toString());
|
||||||
|
if (val!=null && val.startsWith(start))
|
||||||
|
{
|
||||||
|
//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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
add(HttpHeader.SET_COOKIE.toString(), name_value_params);
|
add(HttpHeader.SET_COOKIE.toString(), name_value_params);
|
||||||
|
|
||||||
// Expire responses with set-cookie headers so they do not get cached.
|
// Expire responses with set-cookie headers so they do not get cached.
|
||||||
|
@ -871,7 +883,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
|
|
||||||
public void putTo(ByteBuffer bufferInFillMode) throws IOException
|
public void putTo(ByteBuffer bufferInFillMode) throws IOException
|
||||||
{
|
{
|
||||||
for (Field field : _fields)
|
for (HttpField field : _fields)
|
||||||
{
|
{
|
||||||
if (field != null)
|
if (field != null)
|
||||||
field.putTo(bufferInFillMode);
|
field.putTo(bufferInFillMode);
|
||||||
|
@ -886,7 +898,7 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
StringBuilder buffer = new StringBuilder();
|
StringBuilder buffer = new StringBuilder();
|
||||||
for (Field field : _fields)
|
for (HttpField field : _fields)
|
||||||
{
|
{
|
||||||
if (field != null)
|
if (field != null)
|
||||||
{
|
{
|
||||||
|
@ -914,7 +926,6 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
public void clear()
|
public void clear()
|
||||||
{
|
{
|
||||||
_fields.clear();
|
_fields.clear();
|
||||||
_names.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1088,151 +1099,5 @@ public class HttpFields implements Iterable<HttpFields.Field>
|
||||||
return vl;
|
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
|
// default field values
|
||||||
boolean has_server = false;
|
boolean has_server = false;
|
||||||
HttpFields.Field transfer_encoding=null;
|
HttpField transfer_encoding=null;
|
||||||
boolean keep_alive=false;
|
boolean keep_alive=false;
|
||||||
boolean close=false;
|
boolean close=false;
|
||||||
boolean content_type=false;
|
boolean content_type=false;
|
||||||
|
@ -551,11 +551,11 @@ public class HttpGenerator
|
||||||
// Generate fields
|
// Generate fields
|
||||||
if (_info.getHttpFields() != null)
|
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:
|
case CONTENT_LENGTH:
|
||||||
// handle specially below
|
// handle specially below
|
||||||
|
@ -666,11 +666,11 @@ public class HttpGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (name==null)
|
if (h==null)
|
||||||
field.putTo(header);
|
field.putTo(header);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
header.put(name.getBytesColonSpace());
|
header.put(h.getBytesColonSpace());
|
||||||
field.putValueTo(header);
|
field.putValueTo(header);
|
||||||
header.put(CRLF);
|
header.put(CRLF);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,11 +19,9 @@
|
||||||
package org.eclipse.jetty.http;
|
package org.eclipse.jetty.http;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
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.StringUtil;
|
||||||
|
import org.eclipse.jetty.util.Trie;
|
||||||
|
|
||||||
|
|
||||||
public enum HttpHeader
|
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
|
static
|
||||||
{
|
{
|
||||||
for (HttpHeader header : HttpHeader.values())
|
for (HttpHeader header : HttpHeader.values())
|
||||||
|
@ -122,71 +120,6 @@ public enum HttpHeader
|
||||||
CACHE.put(header.toString(),header);
|
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 String _string;
|
||||||
private final byte[] _bytes;
|
private final byte[] _bytes;
|
||||||
private final byte[] _bytesColonSpace;
|
private final byte[] _bytesColonSpace;
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.nio.ByteBuffer;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
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::");
|
UNKNOWN("::UNKNOWN::");
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public final static StringMap<HttpHeaderValue> CACHE= new StringMap<HttpHeaderValue>(true);
|
public final static Trie<HttpHeaderValue> CACHE= new Trie<HttpHeaderValue>();
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
for (HttpHeaderValue value : HttpHeaderValue.values())
|
for (HttpHeaderValue value : HttpHeaderValue.values())
|
||||||
|
|
|
@ -20,8 +20,8 @@ package org.eclipse.jetty.http;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.StringMap;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.util.Trie;
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
|
@ -109,11 +109,11 @@ public enum HttpMethod
|
||||||
{
|
{
|
||||||
if (buffer.hasArray())
|
if (buffer.hasArray())
|
||||||
return lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position(),buffer.arrayOffset()+buffer.limit());
|
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
|
static
|
||||||
{
|
{
|
||||||
for (HttpMethod method : HttpMethod.values())
|
for (HttpMethod method : HttpMethod.values())
|
||||||
|
|
|
@ -508,6 +508,86 @@ public class HttpParser
|
||||||
return return_from_parse;
|
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
|
* 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:
|
case HttpTokens.TAB:
|
||||||
{
|
{
|
||||||
// header value without name - continuation?
|
// header value without name - continuation?
|
||||||
_length=-1;
|
|
||||||
_string.setLength(0);
|
_string.setLength(0);
|
||||||
|
if (_valueString!=null)
|
||||||
|
{
|
||||||
|
_string.append(_valueString);
|
||||||
|
_string.append(' ');
|
||||||
|
}
|
||||||
|
_length=_string.length();
|
||||||
|
_valueString=null;
|
||||||
setState(State.HEADER_VALUE);
|
setState(State.HEADER_VALUE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -557,82 +643,8 @@ public class HttpParser
|
||||||
if (_headerString!=null || _valueString!=null)
|
if (_headerString!=null || _valueString!=null)
|
||||||
{
|
{
|
||||||
// Handle known headers
|
// Handle known headers
|
||||||
if (_header!=null)
|
if (_header!=null && handleKnownHeaders(buffer))
|
||||||
{
|
return true;
|
||||||
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_from_parse|=_handler.parsedHeader(_header, _headerString, _valueString);
|
return_from_parse|=_handler.parsedHeader(_header, _headerString, _valueString);
|
||||||
}
|
}
|
||||||
|
@ -704,14 +716,36 @@ public class HttpParser
|
||||||
{
|
{
|
||||||
if (buffer.remaining()>6 && buffer.hasArray())
|
if (buffer.remaining()>6 && buffer.hasArray())
|
||||||
{
|
{
|
||||||
// Try a look ahead for the known headers.
|
// Try a look ahead for the known header name and value.
|
||||||
_header=HttpHeader.lookAheadGet(buffer.array(),buffer.arrayOffset()+buffer.position()-1,buffer.arrayOffset()+buffer.limit());
|
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)
|
if (_header!=null)
|
||||||
{
|
{
|
||||||
_headerString=_header.asString();
|
_headerString=_header.asString();
|
||||||
buffer.position(buffer.position()+_headerString.length());
|
_string.setLength(0);
|
||||||
setState(buffer.get(buffer.position()-1)==':'?State.HEADER_VALUE:State.HEADER_NAME);
|
setState(State.HEADER_IN_NAME);
|
||||||
|
buffer.position(buffer.position()+_headerString.length()-1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -733,8 +767,11 @@ public class HttpParser
|
||||||
case HttpTokens.CARRIAGE_RETURN:
|
case HttpTokens.CARRIAGE_RETURN:
|
||||||
case HttpTokens.LINE_FEED:
|
case HttpTokens.LINE_FEED:
|
||||||
consumeCRLF(ch,buffer);
|
consumeCRLF(ch,buffer);
|
||||||
_headerString=takeLengthString();
|
if (_headerString==null)
|
||||||
_header=HttpHeader.CACHE.get(_headerString);
|
{
|
||||||
|
_headerString=takeLengthString();
|
||||||
|
_header=HttpHeader.CACHE.get(_headerString);
|
||||||
|
}
|
||||||
setState(State.HEADER);
|
setState(State.HEADER);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -753,15 +790,6 @@ public class HttpParser
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
if (_header!=null)
|
|
||||||
{
|
|
||||||
_string.setLength(0);
|
|
||||||
_string.append(_header.asString());
|
|
||||||
_string.append(' ');
|
|
||||||
_length=_string.length();
|
|
||||||
_header=null;
|
|
||||||
_headerString=null;
|
|
||||||
}
|
|
||||||
_string.append((char)ch);
|
_string.append((char)ch);
|
||||||
_length=_string.length();
|
_length=_string.length();
|
||||||
setState(State.HEADER_IN_NAME);
|
setState(State.HEADER_IN_NAME);
|
||||||
|
@ -793,10 +821,26 @@ public class HttpParser
|
||||||
break;
|
break;
|
||||||
case HttpTokens.SPACE:
|
case HttpTokens.SPACE:
|
||||||
case HttpTokens.TAB:
|
case HttpTokens.TAB:
|
||||||
|
if (_header!=null)
|
||||||
|
{
|
||||||
|
_string.setLength(0);
|
||||||
|
_string.append(_header.asString());
|
||||||
|
_length=_string.length();
|
||||||
|
_header=null;
|
||||||
|
_headerString=null;
|
||||||
|
}
|
||||||
setState(State.HEADER_NAME);
|
setState(State.HEADER_NAME);
|
||||||
_string.append((char)ch);
|
_string.append((char)ch);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (_header!=null)
|
||||||
|
{
|
||||||
|
_string.setLength(0);
|
||||||
|
_string.append(_header.asString());
|
||||||
|
_length=_string.length();
|
||||||
|
_header=null;
|
||||||
|
_headerString=null;
|
||||||
|
}
|
||||||
_string.append((char)ch);
|
_string.append((char)ch);
|
||||||
_length++;
|
_length++;
|
||||||
}
|
}
|
||||||
|
@ -849,13 +893,7 @@ public class HttpParser
|
||||||
consumeCRLF(ch,buffer);
|
consumeCRLF(ch,buffer);
|
||||||
if (_length > 0)
|
if (_length > 0)
|
||||||
{
|
{
|
||||||
if (_valueString!=null)
|
if (HttpHeaderValue.hasKnownValues(_header))
|
||||||
{
|
|
||||||
// multi line value!
|
|
||||||
_value=null;
|
|
||||||
_valueString+=" "+takeString();
|
|
||||||
}
|
|
||||||
else if (HttpHeaderValue.hasKnownValues(_header))
|
|
||||||
{
|
{
|
||||||
_valueString=takeString();
|
_valueString=takeString();
|
||||||
_value=HttpHeaderValue.CACHE.get(_valueString);
|
_value=HttpHeaderValue.CACHE.get(_valueString);
|
||||||
|
@ -871,10 +909,24 @@ public class HttpParser
|
||||||
break;
|
break;
|
||||||
case HttpTokens.SPACE:
|
case HttpTokens.SPACE:
|
||||||
case HttpTokens.TAB:
|
case HttpTokens.TAB:
|
||||||
|
if (_valueString!=null)
|
||||||
|
{
|
||||||
|
_string.setLength(0);
|
||||||
|
_string.append(_valueString);
|
||||||
|
_length=_valueString.length();
|
||||||
|
_valueString=null;
|
||||||
|
}
|
||||||
_string.append((char)ch);
|
_string.append((char)ch);
|
||||||
setState(State.HEADER_VALUE);
|
setState(State.HEADER_VALUE);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
if (_valueString!=null)
|
||||||
|
{
|
||||||
|
_string.setLength(0);
|
||||||
|
_string.append(_valueString);
|
||||||
|
_length=_valueString.length();
|
||||||
|
_valueString=null;
|
||||||
|
}
|
||||||
_string.append((char)ch);
|
_string.append((char)ch);
|
||||||
_length++;
|
_length++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ package org.eclipse.jetty.http;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
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");
|
WSS("wss");
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public final static StringMap<HttpScheme> CACHE= new StringMap<HttpScheme>(true);
|
public final static Trie<HttpScheme> CACHE= new Trie<HttpScheme>();
|
||||||
static
|
static
|
||||||
{
|
{
|
||||||
for (HttpScheme version : HttpScheme.values())
|
for (HttpScheme version : HttpScheme.values())
|
||||||
|
|
|
@ -20,8 +20,8 @@ package org.eclipse.jetty.http;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.StringMap;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
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);
|
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
|
static
|
||||||
{
|
{
|
||||||
for (HttpVersion version : HttpVersion.values())
|
for (HttpVersion version : HttpVersion.values())
|
||||||
|
|
|
@ -28,8 +28,8 @@ import java.util.MissingResourceException;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.StringMap;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
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.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
@ -109,8 +109,8 @@ public class MimeTypes
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
private static final Logger LOG = Log.getLogger(MimeTypes.class);
|
private static final Logger LOG = Log.getLogger(MimeTypes.class);
|
||||||
public final static StringMap<MimeTypes.Type> CACHE= new StringMap<MimeTypes.Type>(true);
|
public final static Trie<MimeTypes.Type> CACHE= new Trie<MimeTypes.Type>();
|
||||||
private final static StringMap<ByteBuffer> TYPES= new StringMap<ByteBuffer>(true);
|
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> __dftMimeMap = new HashMap<String,String>();
|
||||||
private final static Map<String,String> __encodings = 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++)
|
for (int i=0;i<7;i++)
|
||||||
{
|
{
|
||||||
assertFalse(""+i,header.getField(""+i).contains("xyz"));
|
assertFalse(""+i,header.contains(""+i,"xyz"));
|
||||||
assertEquals(""+i,i>=4,header.getField(""+i).contains("def"));
|
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 static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
import org.eclipse.jetty.http.HttpParser.State;
|
import org.eclipse.jetty.http.HttpParser.State;
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
@ -153,12 +154,15 @@ public class HttpParserTest
|
||||||
"Host: localhost\015\012" +
|
"Host: localhost\015\012" +
|
||||||
"Header1: value1\015\012" +
|
"Header1: value1\015\012" +
|
||||||
"Header 2 : value 2a \015\012" +
|
"Header 2 : value 2a \015\012" +
|
||||||
" value 2b \015\012" +
|
" value 2b \015\012" +
|
||||||
"Header3: \015\012" +
|
"Header3: \015\012" +
|
||||||
"Header4 \015\012" +
|
"Header4 \015\012" +
|
||||||
" value4\015\012" +
|
" value4\015\012" +
|
||||||
"Server5 : notServer\015\012" +
|
"Server5 : notServer\015\012" +
|
||||||
"Host Header: notHost\015\012" +
|
"Host Header: notHost\015\012" +
|
||||||
|
"Connection: close\015\012" +
|
||||||
|
"Accept-Encoding: gzip, deflated\015\012" +
|
||||||
|
"Accept: unknown\015\012" +
|
||||||
"\015\012");
|
"\015\012");
|
||||||
Handler handler = new Handler();
|
Handler handler = new Handler();
|
||||||
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
|
||||||
|
@ -181,7 +185,13 @@ public class HttpParserTest
|
||||||
assertEquals("notServer", _val[5]);
|
assertEquals("notServer", _val[5]);
|
||||||
assertEquals("Host Header", _hdr[6]);
|
assertEquals("Host Header", _hdr[6]);
|
||||||
assertEquals("notHost", _val[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
|
@Test
|
||||||
|
@ -736,8 +746,8 @@ public class HttpParserTest
|
||||||
{
|
{
|
||||||
request=true;
|
request=true;
|
||||||
_h= -1;
|
_h= -1;
|
||||||
_hdr= new String[9];
|
_hdr= new String[10];
|
||||||
_val= new String[9];
|
_val= new String[10];
|
||||||
_methodOrVersion= method;
|
_methodOrVersion= method;
|
||||||
_uriOrStatus= uri;
|
_uriOrStatus= uri;
|
||||||
_versionOrReason= version==null?null:version.asString();
|
_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.api.Result;
|
||||||
import org.eclipse.jetty.client.util.InputStreamContentProvider;
|
import org.eclipse.jetty.client.util.InputStreamContentProvider;
|
||||||
import org.eclipse.jetty.client.util.TimedResponseListener;
|
import org.eclipse.jetty.client.util.TimedResponseListener;
|
||||||
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpMethod;
|
import org.eclipse.jetty.http.HttpMethod;
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
|
@ -464,7 +465,7 @@ public class ProxyServlet extends HttpServlet
|
||||||
|
|
||||||
protected void onResponseHeaders(HttpServletRequest request, HttpServletResponse response, Response proxyResponse)
|
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 headerName = field.getName();
|
||||||
String lowerHeaderName = headerName.toLowerCase(Locale.ENGLISH);
|
String lowerHeaderName = headerName.toLowerCase(Locale.ENGLISH);
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -479,7 +480,7 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
||||||
Map<String, RoleInfo> mappings = _constraintMap.get(mapping.getPathSpec());
|
Map<String, RoleInfo> mappings = _constraintMap.get(mapping.getPathSpec());
|
||||||
if (mappings == null)
|
if (mappings == null)
|
||||||
{
|
{
|
||||||
mappings = new StringMap<>();
|
mappings = new HashMap<String,RoleInfo>();
|
||||||
_constraintMap.put(mapping.getPathSpec(),mappings);
|
_constraintMap.put(mapping.getPathSpec(),mappings);
|
||||||
}
|
}
|
||||||
RoleInfo allMethodsRoleInfo = mappings.get(ALL_METHODS);
|
RoleInfo allMethodsRoleInfo = mappings.get(ALL_METHODS);
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpField;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpGenerator;
|
import org.eclipse.jetty.http.HttpGenerator;
|
||||||
import org.eclipse.jetty.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
|
@ -128,7 +129,7 @@ public class HttpTransportOverSPDY implements HttpTransport
|
||||||
{
|
{
|
||||||
for (int i = 0; i < fields.size(); ++i)
|
for (int i = 0; i < fields.size(); ++i)
|
||||||
{
|
{
|
||||||
HttpFields.Field field = fields.getField(i);
|
HttpField field = fields.getField(i);
|
||||||
String name = field.getName();
|
String name = field.getName();
|
||||||
String value = field.getValue();
|
String value = field.getValue();
|
||||||
headers.put(name, value);
|
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())
|
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))
|
for (String value : request.getHeaders().get(headerName))
|
||||||
{
|
{
|
||||||
httpChannel.parsedHeader(header,headerName,value);
|
httpChannel.parsedHeader(header,headerName,value);
|
||||||
|
|
Loading…
Reference in New Issue