applied jetty-7p 7f68abf..b2e4270, 7f68abf..a900c5e, 9a93c9e..9f94539. decomposed async and blocking handling. Simplified HttpFields and Buffer handling from the HttpParser.

This commit is contained in:
Greg Wilkins 2011-07-07 12:16:58 +10:00
parent a7eabf0757
commit b890ff8fb2
31 changed files with 747 additions and 891 deletions

View File

@ -97,8 +97,8 @@ public class LikeJettyXml
HandlerCollection handlers = new HandlerCollection();
ContextHandlerCollection contexts = new ContextHandlerCollection();
RequestLogHandler requestLogHandler = new RequestLogHandler();
handlers.setHandlers(new Handler[]
{ contexts, new DefaultHandler(), requestLogHandler });
handlers.setHandlers(new Handler[] { contexts, new DefaultHandler(), requestLogHandler });
StatisticsHandler stats = new StatisticsHandler();
stats.setHandler(handlers);
@ -136,6 +136,7 @@ public class LikeJettyXml
server.setStopAtShutdown(true);
server.setSendServerVersion(true);
server.start();
server.join();

View File

@ -25,6 +25,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
@ -35,7 +36,7 @@ import org.eclipse.jetty.server.Server;
* duplication of HttpConnection
*
*/
public class Ajp13Connection extends HttpConnection
public class Ajp13Connection extends BlockingHttpConnection
{
public Ajp13Connection(Connector connector, EndPoint endPoint, Server server)
{

View File

@ -133,7 +133,7 @@ public class Ajp13Parser implements Parser
public void parse() throws IOException
{
if (_state == STATE_END)
reset(false);
reset();
if (_state != STATE_START)
throw new IllegalStateException("!START");
@ -206,7 +206,7 @@ public class Ajp13Parser implements Parser
{
// This is normal in AJP since the socket closes on timeout only
Log.debug(e);
reset(true);
reset();
throw (e instanceof EofException) ? e : new EofException(e);
}
}
@ -219,7 +219,7 @@ public class Ajp13Parser implements Parser
_handler.messageComplete(_contentPosition);
return filled;
}
reset(true);
reset();
throw new EofException();
}
@ -317,7 +317,7 @@ public class Ajp13Parser implements Parser
_buffer= null;
reset(true);
reset();
return -1;
case Ajp13Packet.SHUTDOWN_ORDINAL:
@ -606,7 +606,7 @@ public class Ajp13Parser implements Parser
}
/* ------------------------------------------------------------------------------- */
public void reset(boolean returnBuffers)
public void reset()
{
_state = STATE_START;
_contentLength = HttpTokens.UNKNOWN_CONTENT;
@ -614,51 +614,59 @@ public class Ajp13Parser implements Parser
_length = 0;
_packetLength = 0;
if (_body != null)
if (_body!=null && _body.hasContent())
{
if (_body.hasContent())
// There is content in the body after the end of the request.
// This is probably a pipelined header of the next request, so we need to
// copy it to the header buffer.
if (_header==null)
{
_header=_buffers.getHeader();
_tok0.update(_header);
_tok0.update(0,0);
_tok1.update(_header);
_tok1.update(0,0);
}
else
{
_header.setMarkIndex(-1);
_header.compact();
// TODO if pipelined requests received after big
// input - maybe this is not good?.
_body.skip(_header.put(_body));
}
if (_body.length() == 0)
{
if (_buffers != null && returnBuffers)
_buffers.returnBuffer(_body);
_body = null;
}
else
{
_body.setMarkIndex(-1);
_body.compact();
}
int take=_header.space();
if (take>_body.length())
take=_body.length();
_body.peek(_body.getIndex(),take);
_body.skip(_header.put(_body.peek(_body.getIndex(),take)));
}
if (_header != null)
{
if (_header!=null)
_header.setMarkIndex(-1);
if (!_header.hasContent() && _buffers != null && returnBuffers)
{
_buffers.returnBuffer(_header);
_header = null;
_buffer = null;
}
else
{
_header.compact();
_tok0.update(_header);
_tok0.update(0, 0);
_tok1.update(_header);
_tok1.update(0, 0);
}
if (_body!=null)
_body.setMarkIndex(-1);
_buffer=_header;
}
/* ------------------------------------------------------------------------------- */
public void returnBuffers()
{
if (_body!=null && !_body.hasContent() && _body.markIndex()==-1)
{
if (_buffer==_body)
_buffer=_header;
if (_buffers!=null)
_buffers.returnBuffer(_body);
_body=null;
}
_buffer = _header;
if (_header!=null && !_header.hasContent() && _header.markIndex()==-1)
{
if (_buffer==_header)
_buffer=null;
_buffers.returnBuffer(_header);
_header=null;
}
}
/* ------------------------------------------------------------------------------- */

View File

@ -535,7 +535,9 @@ public class HttpConnection extends AbstractConnection implements Dumpable
{
_requestComplete = false;
_connectionHeader = null;
_parser.reset(returnBuffers);
_parser.reset();
if (returnBuffers)
_parser.returnBuffers();
_generator.reset(returnBuffers);
_http11 = true;
}

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.client;
import java.io.FileInputStream;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.junit.Test;
public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTest
{
@ -36,4 +37,11 @@ public class ExternalKeyStoreAsyncSslHttpExchangeTest extends SslHttpExchangeTes
_httpClient.start();
}
@Override
@Test
public void testBigPostWithContentExchange() throws Exception
{
super.testBigPostWithContentExchange();
}
}

View File

@ -14,6 +14,7 @@
package org.eclipse.jetty.http;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
@ -28,6 +29,8 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.BufferCache;
@ -55,7 +58,7 @@ public class HttpFields
{
/* ------------------------------------------------------------ */
public static final TimeZone __GMT = TimeZone.getTimeZone("GMT");
public final static BufferDateCache __dateCache = new BufferDateCache("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
public static final BufferDateCache __dateCache = new BufferDateCache("EEE, dd MMM yyyy HH:mm:ss 'GMT'", Locale.US);
/* -------------------------------------------------------------- */
static
@ -159,8 +162,6 @@ public class HttpFields
StringUtil.append2digits(buf, seconds);
buf.append(" GMT");
}
}
/* ------------------------------------------------------------ */
@ -201,8 +202,6 @@ public class HttpFields
formatCookieDate(buf, date);
return buf.toString();
}
/* ------------------------------------------------------------ */
private final static String __dateReceiveFmt[] =
@ -219,7 +218,8 @@ public class HttpFields
"EEE, MMM dd HH:mm:ss yyyy zzz", "EEE, MMM dd HH:mm:ss yyyy", "EEE, dd-MMM-yy HH:mm:ss zzz",
"EEE dd-MMM-yy HH:mm:ss zzz", "EEE dd-MMM-yy HH:mm:ss",
};
/* ------------------------------------------------------------ */
private static class DateParser
{
final SimpleDateFormat _dateReceive[]= new SimpleDateFormat[__dateReceiveFmt.length];
@ -289,9 +289,8 @@ public class HttpFields
/* -------------------------------------------------------------- */
private final ArrayList<Field> _fields = new ArrayList<Field>(20);
private final HashMap<Buffer,Field> _bufferMap = new HashMap<Buffer,Field>(32);
private final HashMap<Buffer,Field> _names = new HashMap<Buffer,Field>(32);
private final int _maxCookieVersion;
private int _revision;
/* ------------------------------------------------------------ */
/**
@ -311,6 +310,31 @@ public class HttpFields
_maxCookieVersion=maxCookieVersion;
}
// TODO externalize this cache so it can be configurable
private static ConcurrentMap<String, Buffer> __cache = new ConcurrentHashMap<String, Buffer>();
/* -------------------------------------------------------------- */
private Buffer convertValue(String value)
{
Buffer buffer = __cache.get(value);
if (buffer!=null)
return buffer;
try
{
if (__cache.size()>1000)
__cache.clear();
buffer = new ByteArrayBuffer(value,StringUtil.__ISO_8859_1);
__cache.putIfAbsent(value,buffer);
return buffer;
}
catch (UnsupportedEncodingException e)
{
throw new RuntimeException(e);
}
}
/* -------------------------------------------------------------- */
/**
* Get enumeration of header _names. Returns an enumeration of strings representing the header
@ -318,40 +342,21 @@ public class HttpFields
*/
public Enumeration<String> getFieldNames()
{
final int revision=_revision;
final Enumeration<?> buffers = Collections.enumeration(_names.keySet());
return new Enumeration<String>()
{
int i = 0;
Field field = null;
public String nextElement()
{
return buffers.nextElement().toString();
}
public boolean hasMoreElements()
{
if (field != null) return true;
while (i < _fields.size())
{
Field f = _fields.get(i++);
if (f != null && f._prev == null && f._revision == revision)
{
field = f;
return true;
}
}
return false;
return buffers.hasMoreElements();
}
public String nextElement() throws NoSuchElementException
{
if (field != null || hasMoreElements())
{
String n = BufferUtil.to8859_1_String(field._name);
field = null;
return n;
}
throw new NoSuchElementException();
}
};
};
}
/* ------------------------------------------------------------ */
public int size()
{
@ -366,36 +371,31 @@ public class HttpFields
*/
public Field getField(int i)
{
final Field field = _fields.get(i);
if (field._revision!=_revision)
return null;
return field;
return _fields.get(i);
}
/* ------------------------------------------------------------ */
private Field getField(String name)
{
return _bufferMap.get(HttpHeaders.CACHE.lookup(name));
return _names.get(HttpHeaders.CACHE.lookup(name));
}
/* ------------------------------------------------------------ */
private Field getField(Buffer name)
{
return _bufferMap.get(name);
return _names.get(HttpHeaders.CACHE.lookup(name));
}
/* ------------------------------------------------------------ */
public boolean containsKey(Buffer name)
{
Field f = getField(name);
return (f != null && f._revision == _revision);
return _names.containsKey(HttpHeaders.CACHE.lookup(name));
}
/* ------------------------------------------------------------ */
public boolean containsKey(String name)
{
Field f = getField(name);
return (f != null && f._revision == _revision);
return _names.containsKey(HttpHeaders.CACHE.lookup(name));
}
/* -------------------------------------------------------------- */
@ -406,11 +406,8 @@ public class HttpFields
*/
public String getStringField(String name)
{
// TODO - really reuse strings from previous requests!
Field field = getField(name);
if (field != null && field._revision == _revision)
return field.getValue();
return null;
return field==null?null:field.getValue();
}
/* -------------------------------------------------------------- */
@ -421,11 +418,8 @@ public class HttpFields
*/
public String getStringField(Buffer name)
{
// TODO - really reuse strings from previous requests!
Field field = getField(name);
if (field != null && field._revision == _revision)
return BufferUtil.to8859_1_String(field._value);
return null;
return field==null?null:field.getValue();
}
/* -------------------------------------------------------------- */
@ -437,24 +431,24 @@ public class HttpFields
public Buffer get(Buffer name)
{
Field field = getField(name);
if (field != null && field._revision == _revision)
return field._value;
return null;
return field==null?null:field._value;
}
/* -------------------------------------------------------------- */
/**
* Get multi headers
*
* @return Enumeration of the values, or null if no such header.
* @return Enumeration of the values
* @param name the case-insensitive field name
*/
public Enumeration<String> getValues(String name)
{
final Field field = getField(name);
if (field == null)
return null;
final int revision=_revision;
{
List<String> empty=Collections.emptyList();
return Collections.enumeration(empty);
}
return new Enumeration<String>()
{
@ -462,8 +456,6 @@ public class HttpFields
public boolean hasMoreElements()
{
while (f != null && f._revision != revision)
f = f._next;
return f != null;
}
@ -471,9 +463,7 @@ public class HttpFields
{
if (f == null) throw new NoSuchElementException();
Field n = f;
do
f = f._next;
while (f != null && f._revision != revision);
f = f._next;
return n.getValue();
}
};
@ -483,15 +473,17 @@ public class HttpFields
/**
* Get multi headers
*
* @return Enumeration of the value Strings, or null if no such header.
* @return Enumeration of the value Strings
* @param name the case-insensitive field name
*/
public Enumeration<String> getValues(Buffer name)
{
final Field field = getField(name);
if (field == null)
return null;
final int revision=_revision;
{
List<String> empty=Collections.emptyList();
return Collections.enumeration(empty);
}
return new Enumeration<String>()
{
@ -499,8 +491,6 @@ public class HttpFields
public boolean hasMoreElements()
{
while (f != null && f._revision != revision)
f = f._next;
return f != null;
}
@ -509,8 +499,6 @@ public class HttpFields
if (f == null) throw new NoSuchElementException();
Field n = f;
f = f._next;
while (f != null && f._revision != revision)
f = f._next;
return n.getValue();
}
};
@ -558,6 +546,7 @@ public class HttpFields
};
}
/* -------------------------------------------------------------- */
/**
* Set a field.
@ -567,11 +556,14 @@ public class HttpFields
*/
public void put(String name, String value)
{
Buffer n = HttpHeaders.CACHE.lookup(name);
Buffer v = null;
if (value != null)
v = HttpHeaderValues.CACHE.lookup(value);
put(n, v, -1);
if (value==null)
remove(name);
else
{
Buffer n = HttpHeaders.CACHE.lookup(name);
Buffer v = convertValue(value);
put(n, v);
}
}
/* -------------------------------------------------------------- */
@ -583,8 +575,9 @@ public class HttpFields
*/
public void put(Buffer name, String value)
{
Buffer v = HttpHeaderValues.CACHE.lookup(value);
put(name, v, -1);
Buffer n = HttpHeaders.CACHE.lookup(name);
Buffer v = convertValue(value);
put(n, v);
}
/* -------------------------------------------------------------- */
@ -596,47 +589,19 @@ public class HttpFields
*/
public void put(Buffer name, Buffer value)
{
put(name, value, -1);
}
/* -------------------------------------------------------------- */
/**
* Set a field.
*
* @param name the name of the field
* @param value the value of the field. If null the field is cleared.
* @param numValue the numeric value of the field (must match value) or -1
*/
public void put(Buffer name, Buffer value, long numValue)
{
remove(name);
if (value == null)
{
remove(name);
return;
}
if (!(name instanceof BufferCache.CachedBuffer)) name = HttpHeaders.CACHE.lookup(name);
Field field = _bufferMap.get(name);
// Look for value to replace.
if (field != null)
{
field.reset(value, numValue, _revision);
field = field._next;
while (field != null)
{
field.clear();
field = field._next;
}
}
else
{
// new value;
field = new Field(name, value, numValue, _revision);
_fields.add(field);
_bufferMap.put(field.getNameBuffer(), field);
}
if (!(name instanceof BufferCache.CachedBuffer))
name = HttpHeaders.CACHE.lookup(name);
if (!(value instanceof CachedBuffer))
value= HttpHeaderValues.CACHE.lookup(value).asImmutableBuffer();
// new value;
Field field = new Field(name, value);
_fields.add(field);
_names.put(name, field);
}
/* -------------------------------------------------------------- */
@ -685,9 +650,11 @@ public class HttpFields
*/
public void add(String name, String value) throws IllegalArgumentException
{
if (value==null)
return;
Buffer n = HttpHeaders.CACHE.lookup(name);
Buffer v = HttpHeaderValues.CACHE.lookup(value);
add(n, v, -1);
Buffer v = convertValue(value);
add(n, v);
}
/* -------------------------------------------------------------- */
@ -701,55 +668,34 @@ public class HttpFields
* value.
*/
public void add(Buffer name, Buffer value) throws IllegalArgumentException
{
add(name, value, -1);
}
/* -------------------------------------------------------------- */
/**
* Add to or set a field. If the field is allowed to have multiple values, add will add multiple
* headers of the same name.
*
* @param name the name of the field
* @param value the value of the field.
* @exception IllegalArgumentException If the name is a single valued field and already has a
* value.
*/
private void add(Buffer name, Buffer value, long numValue) throws IllegalArgumentException
{
{
if (value == null) throw new IllegalArgumentException("null value");
if (!(name instanceof BufferCache.CachedBuffer)) name = HttpHeaders.CACHE.lookup(name);
if (!(name instanceof CachedBuffer))
name = HttpHeaders.CACHE.lookup(name);
name=name.asImmutableBuffer();
Field field = _bufferMap.get(name);
if (!(value instanceof CachedBuffer) && HttpHeaderValues.hasKnownValues(HttpHeaders.CACHE.getOrdinal(name)))
value= HttpHeaderValues.CACHE.lookup(value);
value=value.asImmutableBuffer();
Field field = _names.get(name);
Field last = null;
if (field != null)
while (field != null)
{
while (field != null && field._revision == _revision)
{
last = field;
field = field._next;
}
last = field;
field = field._next;
}
if (field != null)
field.reset(value, numValue, _revision);
// create the field
field = new Field(name, value);
_fields.add(field);
// look for chain to add too
if (last != null)
last._next = field;
else
{
// create the field
field = new Field(name, value, numValue, _revision);
// look for chain to add too
if (last != null)
{
field._prev = last;
last._next = field;
}
else
_bufferMap.put(field.getNameBuffer(), field);
_fields.add(field);
}
_names.put(name, field);
}
/* ------------------------------------------------------------ */
@ -771,15 +717,13 @@ public class HttpFields
*/
public void remove(Buffer name)
{
Field field = _bufferMap.get(name);
if (field != null)
if (!(name instanceof BufferCache.CachedBuffer))
name = HttpHeaders.CACHE.lookup(name);
Field field = _names.remove(name);
while (field != null)
{
while (field != null)
{
field.clear();
field = field._next;
}
_fields.remove(field);
field = field._next;
}
}
@ -794,9 +738,7 @@ public class HttpFields
public long getLongField(String name) throws NumberFormatException
{
Field field = getField(name);
if (field != null && field._revision == _revision) return field.getLongValue();
return -1L;
return field==null?-1L:field.getLongValue();
}
/* -------------------------------------------------------------- */
@ -810,8 +752,7 @@ public class HttpFields
public long getLongField(Buffer name) throws NumberFormatException
{
Field field = getField(name);
if (field != null && field._revision == _revision) return field.getLongValue();
return -1L;
return field==null?-1L:field.getLongValue();
}
/* -------------------------------------------------------------- */
@ -824,12 +765,9 @@ public class HttpFields
public long getDateField(String name)
{
Field field = getField(name);
if (field == null || field._revision != _revision)
if (field == null)
return -1;
if (field._numValue != -1)
return field._numValue;
String val = valueParameters(BufferUtil.to8859_1_String(field._value), null);
if (val == null)
return -1;
@ -837,7 +775,6 @@ public class HttpFields
final long date = __dateParser.get().parse(val);
if (date==-1)
throw new IllegalArgumentException("Cannot convert date: " + val);
field._numValue=date;
return date;
}
@ -851,7 +788,7 @@ public class HttpFields
public void putLongField(Buffer name, long value)
{
Buffer v = BufferUtil.toBuffer(value);
put(name, v, value);
put(name, v);
}
/* -------------------------------------------------------------- */
@ -865,7 +802,7 @@ public class HttpFields
{
Buffer n = HttpHeaders.CACHE.lookup(name);
Buffer v = BufferUtil.toBuffer(value);
put(n, v, value);
put(n, v);
}
/* -------------------------------------------------------------- */
@ -879,7 +816,7 @@ public class HttpFields
{
Buffer n = HttpHeaders.CACHE.lookup(name);
Buffer v = BufferUtil.toBuffer(value);
add(n, v, value);
add(n, v);
}
/* -------------------------------------------------------------- */
@ -892,7 +829,7 @@ public class HttpFields
public void addLongField(Buffer name, long value)
{
Buffer v = BufferUtil.toBuffer(value);
add(name, v, value);
add(name, v);
}
/* -------------------------------------------------------------- */
@ -906,7 +843,7 @@ public class HttpFields
{
String d=formatDate(date);
Buffer v = new ByteArrayBuffer(d);
put(name, v, date);
put(name, v);
}
/* -------------------------------------------------------------- */
@ -934,7 +871,7 @@ public class HttpFields
String d=formatDate(date);
Buffer n = HttpHeaders.CACHE.lookup(name);
Buffer v = new ByteArrayBuffer(d);
add(n, v, date);
add(n, v);
}
/* ------------------------------------------------------------ */
@ -984,7 +921,8 @@ public class HttpFields
String delim=_maxCookieVersion==0?"":"\"\\\n\r\t\f\b%+ ;=";
// Check arguments
if (name == null || name.length() == 0) throw new IllegalArgumentException("Bad cookie name");
if (name == null || name.length() == 0)
throw new IllegalArgumentException("Bad cookie name");
// Format value and params
StringBuilder buf = new StringBuilder(128);
@ -1053,38 +991,38 @@ public class HttpFields
name_value_params = buf.toString();
// look for existing set cookie of same name
Field field = getField(HttpHeaders.SET_COOKIE_BUFFER);
if (field != null)
// remove existing set-cookie of same name
Field field = getField(HttpHeaders.SET_COOKIE);
Field last=null;
while (field!=null)
{
final int revision=_revision;
while (field!=null)
if (field._value!=null && field._value.toString().startsWith(start))
{
if (field._revision==revision && field._value!=null && field._value.toString().startsWith(start))
{
field.reset(new ByteArrayBuffer(name_value_params),-1,revision);
name_value_params=null;
break;
}
field=field._next;
_fields.remove(field);
if (last==null)
_names.put(HttpHeaders.SET_COOKIE_BUFFER,field._next);
else
last._next=field._next;
break;
}
last=field;
field=field._next;
}
if (name_value_params!=null)
add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params));
add(HttpHeaders.SET_COOKIE_BUFFER, new ByteArrayBuffer(name_value_params));
// Expire responses with set-cookie headers so they do not get cached.
put(HttpHeaders.EXPIRES_BUFFER, __01Jan1970_BUFFER);
}
/* -------------------------------------------------------------- */
public void put(Buffer buffer) throws IOException
public void putTo(Buffer buffer) throws IOException
{
for (int i = 0; i < _fields.size(); i++)
{
Field field = _fields.get(i);
if (field != null && field._revision == _revision) field.put(buffer);
if (field != null)
field.putTo(buffer);
}
BufferUtil.putCRLF(buffer);
}
@ -1098,7 +1036,7 @@ public class HttpFields
for (int i = 0; i < _fields.size(); i++)
{
Field field = (Field) _fields.get(i);
if (field != null && field._revision == _revision)
if (field != null)
{
String tmp = field.getName();
if (tmp != null) buffer.append(tmp);
@ -1124,36 +1062,8 @@ public class HttpFields
*/
public void clear()
{
_revision++;
if (_revision > 1000000)
{
_revision = 0;
for (int i = _fields.size(); i-- > 0;)
{
Field field = _fields.get(i);
if (field != null) field.clear();
}
}
}
/* ------------------------------------------------------------ */
/**
* Destroy the header. Help the garbage collector by null everything that we can.
*/
public void destroy()
{
if (_fields != null)
{
for (int i = _fields.size(); i-- > 0;)
{
Field field = _fields.get(i);
if (field != null) {
_bufferMap.remove(field.getNameBuffer());
field.destroy();
}
}
_fields.clear();
}
_fields.clear();
_names.clear();
}
/* ------------------------------------------------------------ */
@ -1335,92 +1245,18 @@ public class HttpFields
{
private Buffer _name;
private Buffer _value;
private String _stringValue;
private long _numValue;
private Field _next;
private Field _prev;
private int _revision;
/* ------------------------------------------------------------ */
private Field(Buffer name, Buffer value, long numValue, int revision)
private Field(Buffer name, Buffer value)
{
_name = name.asImmutableBuffer();
_value = value.isImmutable() ? value : new View(value);
_name = name;
_value = value;
_next = null;
_prev = null;
_revision = revision;
_numValue = numValue;
_stringValue=null;
}
/* ------------------------------------------------------------ */
private void clear()
{
_revision = -1;
}
/* ------------------------------------------------------------ */
private void destroy()
{
_name = null;
_value = null;
_next = null;
_prev = null;
_stringValue=null;
}
/* ------------------------------------------------------------ */
/**
* Reassign a value to this field. Checks if the string value is the same as that in the char
* array, if so then just reuse existing value.
*/
private void reset(Buffer value, long numValue, int revision)
{
_revision = revision;
if (_value == null)
{
_value = value.isImmutable() ? value : new View(value);
_numValue = numValue;
_stringValue=null;
}
else if (value.isImmutable())
{
_value = value;
_numValue = numValue;
_stringValue=null;
}
else
{
if (_value instanceof View)
((View) _value).update(value);
else
_value = new View(value);
_numValue = numValue;
// check to see if string value is still valid.
if (_stringValue!=null)
{
if (_stringValue.length()!=value.length())
_stringValue=null;
else
{
for (int i=value.length();i-->0;)
{
if (value.peek(value.getIndex()+i)!=_stringValue.charAt(i))
{
_stringValue=null;
break;
}
}
}
}
}
}
/* ------------------------------------------------------------ */
public void put(Buffer buffer) throws IOException
public void putTo(Buffer buffer) throws IOException
{
int o=(_name instanceof CachedBuffer)?((CachedBuffer)_name).getOrdinal():-1;
if (o>=0)
@ -1448,7 +1284,7 @@ public class HttpFields
buffer.put((byte) ' ');
o=(_value instanceof CachedBuffer)?((CachedBuffer)_value).getOrdinal():-1;
if (o>=0 || _numValue>=0)
if (o>=0)
buffer.put(_value);
else
{
@ -1492,13 +1328,7 @@ public class HttpFields
/* ------------------------------------------------------------ */
public String getValue()
{
if (_stringValue==null)
{
_stringValue=(_value instanceof CachedBuffer)
?_value.toString()
:BufferUtil.to8859_1_String(_value);
}
return _stringValue;
return BufferUtil.to8859_1_String(_value);
}
/* ------------------------------------------------------------ */
@ -1522,14 +1352,13 @@ public class HttpFields
/* ------------------------------------------------------------ */
public long getLongValue()
{
if (_numValue == -1) _numValue = BufferUtil.toLong(_value);
return _numValue;
return BufferUtil.toLong(_value);
}
/* ------------------------------------------------------------ */
public String toString()
{
return ("[" + (_prev == null ? "" : "<-") + getName() + "="+_revision+"=" + _value + (_next == null ? "" : "->") + "]");
return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]");
}
}

View File

@ -523,7 +523,7 @@ public class HttpGenerator extends AbstractGenerator
content_length = null;
// write the field to the header buffer
field.put(_header);
field.putTo(_header);
break;
case HttpHeaders.CONTENT_TYPE_ORDINAL:
@ -531,7 +531,7 @@ public class HttpGenerator extends AbstractGenerator
// write the field to the header buffer
content_type=true;
field.put(_header);
field.putTo(_header);
break;
case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
@ -542,7 +542,7 @@ public class HttpGenerator extends AbstractGenerator
case HttpHeaders.CONNECTION_ORDINAL:
if (isRequest())
field.put(_header);
field.putTo(_header);
int connection_value = field.getValueOrdinal();
switch (connection_value)
@ -601,7 +601,7 @@ public class HttpGenerator extends AbstractGenerator
// special case for websocket connection ordering
if (isResponse())
{
field.put(_header);
field.putTo(_header);
continue;
}
}
@ -641,13 +641,13 @@ public class HttpGenerator extends AbstractGenerator
if (getSendServerVersion())
{
has_server=true;
field.put(_header);
field.putTo(_header);
}
break;
default:
// write the field to the header buffer
field.put(_header);
field.putTo(_header);
}
}
}
@ -721,7 +721,7 @@ public class HttpGenerator extends AbstractGenerator
{
String c = transfer_encoding.getValue();
if (c.endsWith(HttpHeaderValues.CHUNKED))
transfer_encoding.put(_header);
transfer_encoding.putTo(_header);
else
throw new IllegalArgumentException("BAD TE");
}

View File

@ -73,38 +73,16 @@ public class HttpHeaderValues extends BufferCache
NO_CACHE_BUFFER=CACHE.add(NO_CACHE,NO_CACHE_ORDINAL),
UPGRADE_BUFFER=CACHE.add(UPGRADE,UPGRADE_ORDINAL);
static
{
int index=100;
CACHE.add("gzip",index++);
CACHE.add("gzip,deflate",index++);
CACHE.add("deflate",index++);
InputStream ua = HttpHeaderValues.class.getResourceAsStream("/org/eclipse/jetty/http/useragents");
try
public static boolean hasKnownValues(int httpHeaderOrdinal)
{
switch(httpHeaderOrdinal)
{
if (ua!=null)
{
try
{
LineNumberReader in = new LineNumberReader(new InputStreamReader(ua));
String line = in.readLine();
while (line!=null)
{
CACHE.add(line,index++);
line = in.readLine();
}
}
finally
{
ua.close();
}
}
}
catch(Exception e)
{
Log.warn(e.toString());
Log.debug(e);
case HttpHeaders.CONNECTION_ORDINAL:
case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
case HttpHeaders.CONTENT_ENCODING_ORDINAL:
return true;
}
return false;
}
}

View File

@ -18,8 +18,6 @@ import org.eclipse.jetty.io.BufferCache;
/* ------------------------------------------------------------------------------- */
/**
*
*
*/
public class HttpHeaders extends BufferCache
{
@ -78,7 +76,10 @@ public class HttpHeaders extends BufferCache
REFERER= "Referer",
TE= "TE",
USER_AGENT= "User-Agent",
X_FORWARDED_FOR= "X-Forwarded-For";
X_FORWARDED_FOR= "X-Forwarded-For",
X_FORWARDED_PROTO= "X-Forwarded-Proto",
X_FORWARDED_SERVER= "X-Forwarded-Server",
X_FORWARDED_HOST= "X-Forwarded-Host";
/* ------------------------------------------------------------ */
/** Response Fields.
@ -160,7 +161,10 @@ public class HttpHeaders extends BufferCache
MIME_VERSION_ORDINAL= 55,
IDENTITY_ORDINAL= 56,
CACHE_CONTROL_ORDINAL=57,
PROXY_CONNECTION_ORDINAL=58;
PROXY_CONNECTION_ORDINAL=58,
X_FORWARDED_PROTO_ORDINAL=59,
X_FORWARDED_SERVER_ORDINAL=60,
X_FORWARDED_HOST_ORDINAL=61;
public final static HttpHeaders CACHE= new HttpHeaders();
@ -208,6 +212,9 @@ public class HttpHeaders extends BufferCache
TE_BUFFER=CACHE.add(TE,TE_ORDINAL),
USER_AGENT_BUFFER=CACHE.add(USER_AGENT,USER_AGENT_ORDINAL),
X_FORWARDED_FOR_BUFFER=CACHE.add(X_FORWARDED_FOR,X_FORWARDED_FOR_ORDINAL),
X_FORWARDED_PROTO_BUFFER=CACHE.add(X_FORWARDED_PROTO,X_FORWARDED_PROTO_ORDINAL),
X_FORWARDED_SERVER_BUFFER=CACHE.add(X_FORWARDED_SERVER,X_FORWARDED_SERVER_ORDINAL),
X_FORWARDED_HOST_BUFFER=CACHE.add(X_FORWARDED_HOST,X_FORWARDED_HOST_ORDINAL),
ACCEPT_RANGES_BUFFER=CACHE.add(ACCEPT_RANGES,ACCEPT_RANGES_ORDINAL),
AGE_BUFFER=CACHE.add(AGE,AGE_ORDINAL),
ETAG_BUFFER=CACHE.add(ETAG,ETAG_ORDINAL),
@ -224,4 +231,6 @@ public class HttpHeaders extends BufferCache
MIME_VERSION_BUFFER=CACHE.add(MIME_VERSION,MIME_VERSION_ORDINAL),
IDENTITY_BUFFER=CACHE.add(IDENTITY,IDENTITY_ORDINAL),
PROXY_CONNECTION_BUFFER=CACHE.add(PROXY_CONNECTION,PROXY_CONNECTION_ORDINAL);
}

View File

@ -58,7 +58,6 @@ public class HttpParser implements Parser
private Buffer _header; // Buffer for header data (and small _content)
private Buffer _body; // Buffer for large content
private Buffer _buffer; // The current buffer in use (either _header or _content)
private final View _contentView=new View(); // View of the content in the buffer for {@link Input}
private CachedBuffer _cached;
private View.CaseInsensitive _tok0; // Saved token: header name, request method or response version
private View.CaseInsensitive _tok1; // Saved token: header value, request URI or response code
@ -67,6 +66,7 @@ public class HttpParser implements Parser
private boolean _forceContentBuffer;
/* ------------------------------------------------------------------------------- */
protected final View _contentView=new View(); // View of the content in the buffer for {@link Input}
protected int _state=STATE_START;
protected byte _eol;
protected int _length;
@ -191,7 +191,7 @@ public class HttpParser implements Parser
public void parse() throws IOException
{
if (_state==STATE_END)
reset(false);
reset();
if (_state!=STATE_START)
throw new IllegalStateException("!START");
@ -263,41 +263,8 @@ public class HttpParser implements Parser
// Fill buffer if we can
if (length == 0)
{
int filled=-1;
if (_body!=null && _buffer!=_body)
{
_buffer=_body;
filled=_buffer.length();
}
if (_buffer.markIndex() == 0 && _buffer.putIndex() == _buffer.capacity())
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL");
long filled=fill();
IOException ioex=null;
if (_endp != null && filled<=0)
{
// Compress buffer if handling _content buffer
// TODO check this is not moving data too much
if (_buffer == _body)
_buffer.compact();
if (_buffer.space() == 0)
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
try
{
filled=_endp.fill(_buffer);
if (filled>0)
progress++;
}
catch(IOException e)
{
Log.debug(e);
ioex=e;
filled=-1;
}
}
if (filled < 0)
{
if (_headResponse && _state>STATE_END)
@ -429,8 +396,7 @@ public class HttpParser implements Parser
else if (ch < HttpTokens.SPACE && ch>=0)
{
// HTTP/0.9
_handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer
.sliceFromMark(), null);
_handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _buffer.sliceFromMark(), null);
_state=STATE_END;
_handler.headerComplete();
_handler.messageComplete(_contentPosition);
@ -473,7 +439,7 @@ public class HttpParser implements Parser
if (_responseStatus>0)
_handler.startResponse(HttpVersions.CACHE.lookup(_tok0), _responseStatus,_buffer.sliceFromMark());
else
_handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1,HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
_handler.startRequest(HttpMethods.CACHE.lookup(_tok0), _tok1, HttpVersions.CACHE.lookup(_buffer.sliceFromMark()));
_eol=ch;
_state=STATE_HEADER;
_tok0.setPutIndex(_tok0.getIndex());
@ -553,13 +519,12 @@ public class HttpParser implements Parser
_tok1.setPutIndex(_tok1.getIndex());
_multiLineValue=null;
}
_buffer.setMarkIndex(-1);
// now handle ch
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
{
// End of header
// work out the _content demarcation
if (_contentLength == HttpTokens.UNKNOWN_CONTENT)
{
@ -583,16 +548,11 @@ public class HttpParser implements Parser
{
case HttpTokens.EOF_CONTENT:
_state=STATE_EOF_CONTENT;
if(_body==null && _buffers!=null)
_body=_buffers.getBuffer();
_handler.headerComplete(); // May recurse here !
break;
case HttpTokens.CHUNKED_CONTENT:
_state=STATE_CHUNKED_CONTENT;
if (_body==null && _buffers!=null)
_body=_buffers.getBuffer();
_handler.headerComplete(); // May recurse here !
break;
@ -604,9 +564,6 @@ public class HttpParser implements Parser
default:
_state=STATE_CONTENT;
if(_forceContentBuffer ||
(_buffers!=null && _body==null && _buffer==_header && _contentLength>=(_header.capacity()-_header.getIndex())))
_body=_buffers.getBuffer();
_handler.headerComplete(); // May recurse here !
break;
}
@ -930,43 +887,54 @@ public class HttpParser implements Parser
*/
public long fill() throws IOException
{
// Do we have a buffer?
if (_buffer==null)
{
_buffer=_header=getHeaderBuffer();
_tok0=new View.CaseInsensitive(_buffer);
_tok1=new View.CaseInsensitive(_buffer);
}
if (_body!=null && _buffer!=_body)
_buffer=_body;
if (_buffer == _body)
//noinspection ConstantConditions
_buffer.compact();
int space=_buffer.space();
// Fill buffer if we can
if (space == 0)
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
else
// Is there unconsumed content in body buffer
if (_state>STATE_END && _buffer==_header && _body!=null && _body.hasContent() && _header!=null && !_header.hasContent())
{
int filled=-1;
if (_endp != null )
_buffer=_body;
return _buffer.length();
}
// Do we need a body buffer?
if (_buffer==_header && _state>STATE_END && (_forceContentBuffer || _header.space()==0) && (_body!=null||_buffers!=null))
{
if (_body==null)
_body=_buffers.getBuffer();
_buffer=_body;
}
// Do we have somewhere to fill from?
if (_endp != null )
{
// Shall we compact the body?
if (_buffer==_body || _state>STATE_END)
{
try
{
filled=_endp.fill(_buffer);
}
catch(IOException e)
{
Log.debug(e);
reset(true);
throw (e instanceof EofException) ? e:new EofException(e);
}
_buffer.compact();
}
return filled;
// Are we full?
if (_buffer.space() == 0)
throw new HttpException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413, "FULL "+(_buffer==_body?"body":"head"));
try
{
return _endp.fill(_buffer);
}
catch(IOException e)
{
Log.debug(e);
throw (e instanceof EofException) ? e:new EofException(e);
}
}
return -1;
}
/* ------------------------------------------------------------------------------- */
@ -1003,69 +971,74 @@ public class HttpParser implements Parser
}
/* ------------------------------------------------------------------------------- */
public void reset(boolean returnBuffers)
public void reset()
{
// reset state
_contentView.setGetIndex(_contentView.putIndex());
_state=STATE_START;
_contentLength=HttpTokens.UNKNOWN_CONTENT;
_contentPosition=0;
_length=0;
_responseStatus=0;
// Consume LF if CRLF
if (_eol == HttpTokens.CARRIAGE_RETURN && _buffer!=null && _buffer.hasContent() && _buffer.peek() == HttpTokens.LINE_FEED)
_eol=_buffer.get();
if (_body!=null)
{
if (_body.hasContent())
if (_body!=null && _body.hasContent())
{
// There is content in the body after the end of the request.
// This is probably a pipelined header of the next request, so we need to
// copy it to the header buffer.
if (_header==null)
{
// There is content in the body after the end of the request.
// This is probably a pipelined header of the next request, so we need to
// copy it to the header buffer.
_header.setMarkIndex(-1);
_header.compact();
int take=_header.space();
if (take>_body.length())
take=_body.length();
_body.peek(_body.getIndex(),take);
_body.skip(_header.put(_body.peek(_body.getIndex(),take)));
}
if (_body.length()==0)
{
if (_buffers!=null && returnBuffers)
_buffers.returnBuffer(_body);
_body=null;
_header=_buffers.getHeader();
}
else
{
_body.setMarkIndex(-1);
_body.compact();
_header.setMarkIndex(-1);
_header.compact();
}
int take=_header.space();
if (take>_body.length())
take=_body.length();
_body.peek(_body.getIndex(),take);
_body.skip(_header.put(_body.peek(_body.getIndex(),take)));
}
if (_header!=null)
{
_header.setMarkIndex(-1);
if (!_header.hasContent() && _buffers!=null && returnBuffers)
{
_buffers.returnBuffer(_header);
_header=null;
}
else
{
_header.compact();
_tok0.update(_header);
_tok0.update(0,0);
_tok1.update(_header);
_tok1.update(0,0);
}
_header.compact();
}
if (_body!=null)
_body.setMarkIndex(-1);
_buffer=_header;
}
/* ------------------------------------------------------------------------------- */
public void returnBuffers()
{
if (_body!=null && !_body.hasContent() && _body.markIndex()==-1)
{
if (_buffer==_body)
_buffer=_header;
if (_buffers!=null)
_buffers.returnBuffer(_body);
_body=null;
}
if (_header!=null && !_header.hasContent() && _header.markIndex()==-1)
{
if (_buffer==_header)
_buffer=null;
_buffers.returnBuffer(_header);
_header=null;
}
}
/* ------------------------------------------------------------------------------- */
public void setState(int state)
{
@ -1111,8 +1084,6 @@ public class HttpParser implements Parser
_forceContentBuffer=force;
}
/* ------------------------------------------------------------ */
public Buffer blockForContent(long maxIdleTime) throws IOException
{
@ -1121,50 +1092,33 @@ public class HttpParser implements Parser
if (getState() <= HttpParser.STATE_END)
return null;
// Handle simple end points.
if (_endp==null)
parseNext();
// Handle blocking end points
else if (_endp.isBlocking())
{
try
{
parseNext();
// parse until some progress is made (or IOException thrown for timeout)
while(_contentView.length() == 0 && !isState(HttpParser.STATE_END) && _endp.isOpen())
{
// Try to get more _parser._content
parseNext();
}
}
catch(IOException e)
{
_endp.close();
throw e;
}
}
else // Handle non-blocking end point
try
{
parseNext();
// parse until some progress is made (or IOException thrown for timeout)
while(_contentView.length() == 0 && !isState(HttpParser.STATE_END) && _endp.isOpen())
while(_contentView.length() == 0 && !isState(HttpParser.STATE_END) && _endp!=null && _endp.isOpen())
{
if (_endp.isBufferingInput() && parseNext()>0)
continue;
if (!_endp.blockReadable(maxIdleTime))
if (!_endp.isBlocking())
{
_endp.close();
throw new EofException("timeout");
if (_endp.isBufferingInput() && parseNext()>0)
continue;
if (!_endp.blockReadable(maxIdleTime))
{
_endp.close();
throw new EofException("timeout");
}
}
// Try to get more _parser._content
parseNext();
}
}
catch(IOException e)
{
_endp.close();
throw e;
}
return _contentView.length()>0?_contentView:null;
}

View File

@ -20,7 +20,8 @@ import java.io.IOException;
*/
public interface Parser
{
void reset(boolean returnBuffers);
void returnBuffers();
void reset();
boolean isComplete();

View File

@ -1,57 +0,0 @@
Mozilla/5.0 (Windows; U; Windows NT 5.1; hu; rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Mozilla/5.0 (Windows; U; Windows NT 5.1; pl; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; GTB5; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)
Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5
Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Mozilla/5.0 (Windows; U; Windows NT 5.1; de; rv:1.9.0.6) Gecko/2009011913 Firefox/3.0.6
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506)
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727)
Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5
Mozilla/5.0 (Windows; U; Windows NT 6.0; en-GB; rv:1.9.0.5) Gecko/2008120122 Firefox/3.0.5
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.20) Gecko/20081217 Firefox/2.0.0.20
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; InfoPath.2)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 1.1.4322)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; WOW64; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0)
msnbot/1.1 (+http://search.msn.com/msnbot.htm)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; FunWebProducts; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; .NET CLR 1.1.4322)
Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 1.1.4322)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0; .NET CLR 2.0.50727)
FeedBurner/1.0 (http://www.FeedBurner.com)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 1.1.4322)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; InfoPath.1)
Mozilla/5.0 (Twiceler-0.9 http://www.cuil.com/twiceler/robot.html)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; InfoPath.2)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; InfoPath.1)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.0.3705; .NET CLR 1.1.4322; Media Center PC 4.0)
Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1)
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 1.1.4322)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.2)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30)
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.1)
Jakarta Commons-HttpClient/2.0.2
Java/1.6.0

View File

@ -63,7 +63,21 @@ public class HttpFieldsTest
assertEquals(e.nextElement(), "value0");
assertEquals(false, e.hasMoreElements());
}
@Test
public void testGet() throws Exception
{
HttpFields header = new HttpFields();
header.put("name0", "value0");
header.put(new ByteArrayBuffer("name1"), new ByteArrayBuffer("value1"));
assertEquals("value0",header.getStringField("name0"));
assertEquals("value0",header.getStringField("Name0"));
assertEquals("value1",header.getStringField("name1"));
assertEquals("value1",header.getStringField("Name1"));
}
@Test
public void testCRLF() throws Exception
{
@ -74,7 +88,7 @@ public class HttpFieldsTest
header.put("name:2", "value:\r\n2");
ByteArrayBuffer buffer = new ByteArrayBuffer(1024);
header.put(buffer);
header.putTo(buffer);
assertTrue(buffer.toString().contains("name0: value0"));
assertTrue(buffer.toString().contains("name1: value1"));
assertTrue(buffer.toString().contains("name2: value:2"));
@ -122,10 +136,10 @@ public class HttpFieldsTest
assertNull(header.getStringField("name3"));
int matches=0;
Enumeration e = header.getFieldNames();
Enumeration<String> e = header.getFieldNames();
while (e.hasMoreElements())
{
Object o=e.nextElement();
String o=e.nextElement();
if ("name0".equals(o))
matches++;
if ("name1".equals(o))
@ -269,21 +283,6 @@ public class HttpFieldsTest
assertEquals(false, e.hasMoreElements());
}
@Test
public void testDestroy() throws Exception
{
HttpFields header = new HttpFields();
header.put(new ByteArrayBuffer("name0"), new View(new ByteArrayBuffer("value0")));
assertTrue(header.getFieldNames().hasMoreElements());
assertNotNull(header.getStringField("name0"));
assertNull(header.getStringField("name1"));
header.destroy();
assertNull(header.getStringField("name0"));
}
@Test
public void testCase() throws Exception
{
@ -344,7 +343,6 @@ public class HttpFieldsTest
assertTrue(s.contains("message-id"));
assertEquals("value",fields.getStringField("Message-ID").toLowerCase());
assertEquals("value",fields.getStringField("message-id").toLowerCase());
}
@Test
@ -352,7 +350,6 @@ public class HttpFieldsTest
{
assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("unknown value")).getOrdinal()<0);
assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("close")).getOrdinal()>=0);
assertTrue(((CachedBuffer)HttpHeaderValues.CACHE.lookup("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)")).getOrdinal()>=0);
}
@Test

View File

@ -77,7 +77,7 @@ public abstract class AbstractBuffer implements Buffer
public ByteArrayBuffer duplicate(int access)
{
Buffer b=this.buffer();
if (b instanceof Buffer.CaseInsensitve)
if (this instanceof Buffer.CaseInsensitve || b instanceof Buffer.CaseInsensitve)
return new ByteArrayBuffer.CaseInsensitive(asArray(), 0, length(),access);
else
return new ByteArrayBuffer(asArray(), 0, length(), access);

View File

@ -66,12 +66,15 @@ public class BufferCache
public Buffer lookup(Buffer buffer)
{
if (buffer instanceof CachedBuffer)
return buffer;
Buffer b= get(buffer);
if (b == null)
{
if (buffer instanceof Buffer.CaseInsensitve)
return buffer;
return new View.CaseInsensitive(buffer);
return new ByteArrayBuffer.CaseInsensitive(buffer.asArray(),0,buffer.length(),Buffer.IMMUTABLE);
}
return b;

View File

@ -26,11 +26,11 @@ import org.eclipse.jetty.util.StringUtil;
*/
public class ByteArrayBuffer extends AbstractBuffer
{
protected byte[] _bytes;
final protected byte[] _bytes;
protected ByteArrayBuffer(int access, boolean isVolatile)
protected ByteArrayBuffer(int size, int access, boolean isVolatile)
{
super(access, isVolatile);
this(new byte[size],0,0,access, isVolatile);
}
public ByteArrayBuffer(byte[] bytes)
@ -63,7 +63,7 @@ public class ByteArrayBuffer extends AbstractBuffer
public ByteArrayBuffer(int size)
{
this(new byte[size], 0, size, READWRITE);
this(new byte[size], 0, 0, READWRITE);
setPutIndex(0);
}
@ -332,38 +332,7 @@ public class ByteArrayBuffer extends AbstractBuffer
return length;
}
/* ------------------------------------------------------------ */
/** Wrap a byte array.
* @param b
* @param off
* @param len
*/
public void wrap(byte[] b, int off, int len)
{
if (b==null)
throw new IllegalArgumentException();
if (isReadOnly()) throw new IllegalStateException(__READONLY);
if (isImmutable()) throw new IllegalStateException(__IMMUTABLE);
_bytes=b;
clear();
setGetIndex(off);
setPutIndex(off+len);
}
/* ------------------------------------------------------------ */
/** Wrap a byte array
* @param b
*/
public void wrap(byte[] b)
{
if (isReadOnly()) throw new IllegalStateException(__READONLY);
if (isImmutable()) throw new IllegalStateException(__IMMUTABLE);
_bytes=b;
setGetIndex(0);
setPutIndex(b.length);
}
/* ------------------------------------------------------------ */
@Override
public void writeTo(OutputStream out)
@ -420,7 +389,7 @@ public class ByteArrayBuffer extends AbstractBuffer
{
super(s);
}
public CaseInsensitive(byte[] b, int o, int l, int rw)
{
super(b,o,l,rw);

View File

@ -18,22 +18,21 @@ import org.eclipse.jetty.io.ByteArrayBuffer;
public class IndirectNIOBuffer extends ByteArrayBuffer implements NIOBuffer
{
protected ByteBuffer _buf;
protected final ByteBuffer _buf;
/* ------------------------------------------------------------ */
public IndirectNIOBuffer(int size)
{
super(READWRITE,NON_VOLATILE);
_buf = ByteBuffer.allocate(size);
super(size,READWRITE,NON_VOLATILE);
_buf = ByteBuffer.wrap(_bytes);
_buf.position(0);
_buf.limit(_buf.capacity());
_bytes=_buf.array();
}
/* ------------------------------------------------------------ */
public IndirectNIOBuffer(ByteBuffer buffer,boolean immutable)
{
super(immutable?IMMUTABLE:READWRITE,NON_VOLATILE);
super(buffer.array(),0,0, immutable?IMMUTABLE:READWRITE,NON_VOLATILE);
if (buffer.isDirect())
throw new IllegalArgumentException();
_buf = buffer;
@ -41,7 +40,6 @@ public class IndirectNIOBuffer extends ByteArrayBuffer implements NIOBuffer
_put=buffer.limit();
buffer.position(0);
buffer.limit(buffer.capacity());
_bytes=_buf.array();
}
/* ------------------------------------------------------------ */

View File

@ -26,6 +26,7 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/**
@ -33,6 +34,8 @@ import org.eclipse.jetty.util.log.Log;
*/
public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPoint, ConnectedEndPoint
{
public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio");
private final SelectorManager.SelectSet _selectSet;
private final SelectorManager _manager;
private final Runnable _handler = new Runnable()
@ -196,7 +199,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
if(!dispatched)
{
_dispatched = false;
Log.warn("Dispatched Failed! "+this+" to "+_manager);
__log.warn("Dispatched Failed! "+this+" to "+_manager);
updateKey();
}
}
@ -330,7 +333,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (InterruptedException e)
{
Log.warn(e);
__log.warn(e);
}
finally
{
@ -375,7 +378,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (InterruptedException e)
{
Log.warn(e);
__log.warn(e);
}
finally
{
@ -388,7 +391,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
catch(Throwable e)
{
// TODO remove this if it finds nothing
Log.warn(e);
__log.warn(e);
if (e instanceof RuntimeException)
throw (RuntimeException)e;
if (e instanceof Error)
@ -435,7 +438,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
catch(Exception e)
{
_key=null;
Log.ignore(e);
__log.ignore(e);
}
}
@ -473,7 +476,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (Exception e)
{
Log.ignore(e);
__log.ignore(e);
if (_key!=null && _key.isValid())
{
_key.cancel();
@ -535,7 +538,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
final Connection next = _connection.handle();
if (next!=_connection)
{
Log.debug("{} replaced {}",next,_connection);
__log.debug("{} replaced {}",next,_connection);
_connection=next;
continue;
}
@ -544,26 +547,26 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (ClosedChannelException e)
{
Log.ignore(e);
__log.ignore(e);
}
catch (EofException e)
{
Log.debug("EOF", e);
__log.debug("EOF", e);
try{close();}
catch(IOException e2){Log.ignore(e2);}
catch(IOException e2){__log.ignore(e2);}
}
catch (IOException e)
{
Log.warn(e.toString());
Log.debug(e);
__log.warn(e.toString());
__log.debug(e);
try{close();}
catch(IOException e2){Log.ignore(e2);}
catch(IOException e2){__log.ignore(e2);}
}
catch (Throwable e)
{
Log.warn("handle failed", e);
__log.warn("handle failed", e);
try{close();}
catch(IOException e2){Log.ignore(e2);}
catch(IOException e2){__log.ignore(e2);}
}
dispatched=!undispatch();
}
@ -575,7 +578,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
dispatched=!undispatch();
while (dispatched)
{
Log.warn("SCEP.run() finally DISPATCHED");
__log.warn("SCEP.run() finally DISPATCHED");
dispatched=!undispatch();
}
}
@ -595,7 +598,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
}
catch (IOException e)
{
Log.ignore(e);
__log.ignore(e);
}
finally
{

View File

@ -30,7 +30,6 @@ import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.management.RuntimeErrorException;
import org.eclipse.jetty.io.ConnectedEndPoint;
import org.eclipse.jetty.io.Connection;
@ -40,6 +39,7 @@ import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Timeout;
import org.eclipse.jetty.util.thread.Timeout.Task;
@ -54,6 +54,8 @@ import org.eclipse.jetty.util.thread.Timeout.Task;
*/
public abstract class SelectorManager extends AbstractLifeCycle implements Dumpable
{
public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio");
// TODO Tune these by approx system speed.
private static final int __JVMBUG_THRESHHOLD=Integer.getInteger("org.eclipse.jetty.io.nio.JVMBUG_THRESHHOLD",0).intValue();
private static final int __MONITOR_PERIOD=Integer.getInteger("org.eclipse.jetty.io.nio.MONITOR_PERIOD",1000).intValue();
@ -295,8 +297,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
/* ------------------------------------------------------------------------------- */
protected void connectionFailed(SocketChannel channel,Throwable ex,Object attachment)
{
Log.warn(ex+","+channel+","+attachment);
Log.debug(ex);
__log.warn(ex+","+channel+","+attachment);
__log.debug(ex);
}
/* ------------------------------------------------------------ */
@ -447,7 +449,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch (CancelledKeyException e)
{
Log.ignore(e);
__log.ignore(e);
}
catch (Throwable e)
{
@ -455,9 +457,9 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
throw (ThreadDeath)e;
if (isRunning())
Log.warn(e);
__log.warn(e);
else
Log.debug(e);
__log.debug(e);
try
{
@ -465,7 +467,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch(IOException e2)
{
Log.debug(e2);
__log.debug(e2);
}
}
}
@ -489,7 +491,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch(InterruptedException e)
{
Log.ignore(e);
__log.ignore(e);
}
now=System.currentTimeMillis();
}
@ -583,14 +585,14 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch (CancelledKeyException e)
{
Log.ignore(e);
__log.ignore(e);
}
catch (Exception e)
{
if (isRunning())
Log.warn(e);
__log.warn(e);
else
Log.ignore(e);
__log.ignore(e);
try
{
@ -599,7 +601,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch(IOException e2)
{
Log.debug(e2);
__log.debug(e2);
}
if (key != null && !(key.channel() instanceof ServerSocketChannel) && key.isValid())
@ -644,13 +646,13 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
catch (ClosedSelectorException e)
{
if (isRunning())
Log.warn(e);
__log.warn(e);
else
Log.ignore(e);
__log.ignore(e);
}
catch (CancelledKeyException e)
{
Log.ignore(e);
__log.ignore(e);
}
finally
{
@ -685,16 +687,16 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
if (now>_log)
{
if (_paused>0)
Log.debug(this+" Busy selector - injecting delay "+_paused+" times");
__log.debug(this+" Busy selector - injecting delay "+_paused+" times");
if (_jvmFix2>0)
Log.debug(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times");
__log.debug(this+" JVM BUG(s) - injecting delay"+_jvmFix2+" times");
if (_jvmFix1>0)
Log.debug(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times");
__log.debug(this+" JVM BUG(s) - recreating selector "+_jvmFix1+" times, cancelled keys "+_jvmFix0+" times");
else if(Log.isDebugEnabled() && _jvmFix0>0)
Log.debug(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times");
else if(__log.isDebugEnabled() && _jvmFix0>0)
__log.debug(this+" JVM BUG(s) - cancelled keys "+_jvmFix0+" times");
_paused=0;
_jvmFix2=0;
_jvmFix1=0;
@ -718,7 +720,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch(InterruptedException e)
{
Log.ignore(e);
__log.ignore(e);
}
}
else if (_jvmBug==__JVMBUG_THRESHHOLD)
@ -752,7 +754,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
if (++_busyKeyCount>__BUSY_KEY && !(busy.channel() instanceof ServerSocketChannel))
{
final SelectChannelEndPoint endpoint = (SelectChannelEndPoint)busy.attachment();
Log.warn("Busy Key "+busy.channel()+" "+endpoint);
__log.warn("Busy Key "+busy.channel()+" "+endpoint);
busy.cancel();
if (endpoint!=null)
{
@ -766,7 +768,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch (IOException e)
{
Log.ignore(e);
__log.ignore(e);
}
}
});
@ -905,7 +907,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch(Exception e)
{
Log.ignore(e);
__log.ignore(e);
}
// close endpoints and selector
@ -925,7 +927,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch(IOException e)
{
Log.ignore(e);
__log.ignore(e);
}
}
}
@ -939,7 +941,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch (IOException e)
{
Log.ignore(e);
__log.ignore(e);
}
_selector=null;
}
@ -990,7 +992,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
}
catch(InterruptedException e)
{
Log.ignore(e);
__log.ignore(e);
}
AggregateLifeCycle.dump(out,indent,dump);
}

View File

@ -41,8 +41,8 @@ import org.eclipse.jetty.util.log.Logger;
*/
public class SslSelectChannelEndPoint extends SelectChannelEndPoint
{
static Logger __log = Log.getLogger("org.eclipse.jetty.http.ssl");
public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio").getLogger("ssl");
private static final ByteBuffer[] __NO_BUFFERS={};
private final Buffers _buffers;
@ -325,7 +325,7 @@ public class SslSelectChannelEndPoint extends SelectChannelEndPoint
*/
@Override
public int fill(Buffer buffer) throws IOException
{
{
// This end point only works on NIO buffer type (director
// or indirect), so extract the NIO buffer that is wrapped
// by the passed jetty Buffer.

View File

@ -25,7 +25,11 @@ public class NestedParser implements Parser
{
}
public void reset(boolean returnBuffers)
public void reset()
{
}
public void returnBuffers()
{
}

View File

@ -69,10 +69,10 @@ public abstract class AbstractConnector extends HttpBuffers implements Connector
private boolean _forwarded;
private String _hostHeader;
private String _forwardedHostHeader = "X-Forwarded-Host";
private String _forwardedServerHeader = "X-Forwarded-Server";
private String _forwardedForHeader = "X-Forwarded-For";
private String _forwardedProtoHeader = "X-Forwarded-Proto";
private String _forwardedHostHeader = HttpHeaders.X_FORWARDED_HOST;
private String _forwardedServerHeader = HttpHeaders.X_FORWARDED_SERVER;
private String _forwardedForHeader = HttpHeaders.X_FORWARDED_FOR;
private String _forwardedProtoHeader = HttpHeaders.X_FORWARDED_PROTO;
private String _forwardedCipherSuiteHeader;
private String _forwardedSslSessionIdHeader;
private boolean _reuseAddress = true;

View File

@ -0,0 +1,123 @@
package org.eclipse.jetty.server;
import java.io.IOException;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.log.Log;
public class AsyncHttpConnection extends HttpConnection
{
public AsyncHttpConnection(Connector connector, EndPoint endpoint, Server server)
{
super(connector,endpoint,server);
}
public Connection handle() throws IOException
{
Connection connection = this;
// Loop while more in buffer
try
{
setCurrentConnection(this);
boolean progress=true;
boolean more_in_buffer =false;
while (_endp.isOpen() && (more_in_buffer || progress))
{
progress=false;
try
{
Log.debug("async request",_request);
// Handle resumed request
if (_request._async.isAsync() && !_request._async.isComplete())
handleRequest();
// else Parse more input
else if (!_parser.isComplete() && _parser.parseAvailable()>0)
progress=true;
// Generate more output
if (_generator.isCommitted() && !_generator.isComplete() && _generator.flushBuffer()>0)
progress=true;
// Flush output from buffering endpoint
if (_endp.isBufferingOutput())
_endp.flush();
}
catch (HttpException e)
{
if (Log.isDebugEnabled())
{
Log.debug("uri="+_uri);
Log.debug("fields="+_requestFields);
Log.debug(e);
}
_generator.sendError(e.getStatus(), e.getReason(), null, true);
_parser.reset();
_endp.close();
}
finally
{
// Do we need to complete a half close?
if (_endp.isInputShutdown() && (_parser.isIdle() || _parser.isComplete()))
{
Log.debug("complete half close {}",this);
more_in_buffer=false;
_endp.close();
reset(true);
}
// else Is this request/response round complete?
else if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
{
// look for a switched connection instance?
if (_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
{
Connection switched=(Connection)_request.getAttribute("org.eclipse.jetty.io.Connection");
if (switched!=null)
{
_parser.reset();
_generator.reset(true);
return switched;
}
}
// Reset the parser/generator
// keep the buffers as we will cycle
progress=true;
reset(false);
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
}
// else Are we suspended?
else if (_request.isAsyncStarted())
{
Log.debug("suspended {}",this);
more_in_buffer=false;
progress=false;
}
else
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
}
}
}
finally
{
setCurrentConnection(null);
_parser.returnBuffers();
// Are we write blocked
if (_generator.isCommitted() && !_generator.isComplete())
((AsyncEndPoint)_endp).scheduleWrite();
}
return connection;
}
}

View File

@ -0,0 +1,161 @@
package org.eclipse.jetty.server;
import java.io.IOException;
import org.eclipse.jetty.http.Generator;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.Parser;
import org.eclipse.jetty.io.AsyncEndPoint;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.util.log.Log;
public class BlockingHttpConnection extends HttpConnection
{
private volatile boolean _handling;
public BlockingHttpConnection(Connector connector, EndPoint endpoint, Server server)
{
super(connector,endpoint,server);
}
public BlockingHttpConnection(Connector connector, EndPoint endpoint, Server server, Parser parser, Generator generator, Request request)
{
super(connector,endpoint,server,parser,generator,request);
}
public Connection handle() throws IOException
{
// TODO - simplify this - as much of it is taken from the async case and does not apply to blocking.
Connection connection = this;
// Loop while more in buffer
boolean more_in_buffer =true; // assume true until proven otherwise
boolean progress=true;
try
{
assert getCurrentConnection()==null;
assert _handling==false;
_handling=true;
setCurrentConnection(this);
while (more_in_buffer && _endp.isOpen())
{
try
{
// If we are not ended then parse available
if (!_parser.isComplete())
{
int parsed=_parser.parseAvailable();
if (parsed>0)
progress=true;
}
// Do we have more generating to do?
// Loop here because some writes may take multiple steps and
// we need to flush them all before potentially blocking in the
// next loop.
while (_generator.isCommitted() && !_generator.isComplete())
{
long written=_generator.flushBuffer();
if (written<=0)
break;
progress=true;
if (_endp.isBufferingOutput())
_endp.flush();
}
// Flush buffers
if (_endp.isBufferingOutput())
{
_endp.flush();
if (!_endp.isBufferingOutput())
progress=true;
}
if (!progress)
return this;
progress=false;
}
catch (HttpException e)
{
if (Log.isDebugEnabled())
{
Log.debug("uri="+_uri);
Log.debug("fields="+_requestFields);
Log.debug(e);
}
_generator.sendError(e.getStatus(), e.getReason(), null, true);
_parser.reset();
_endp.close();
}
finally
{
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
// Is this request/response round complete?
if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
{
// look for a switched connection instance?
Connection switched=(_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
?(Connection)_request.getAttribute("org.eclipse.jetty.io.Connection"):null;
// have we switched?
if (switched!=null)
{
_parser.reset();
_generator.reset(true);
connection=switched;
}
else
{
// No switch, so cleanup and reset
if (!_generator.isPersistent() || _endp.isInputShutdown())
{
_parser.reset();
more_in_buffer=false;
_endp.close();
}
if (more_in_buffer)
{
reset(false);
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
}
else
reset(true);
progress=true;
}
}
else if (_parser.isIdle() && _endp.isInputShutdown())
{
more_in_buffer=false;
_endp.close();
}
if (_request.isAsyncStarted())
{
throw new IllegalStateException();
}
else if (_generator.isCommitted() && !_generator.isComplete() && _endp instanceof AsyncEndPoint)
((AsyncEndPoint)_endp).scheduleWrite();
}
}
}
finally
{
_parser.returnBuffers();
setCurrentConnection(null);
_handling=false;
}
return connection;
}
}

View File

@ -94,7 +94,6 @@ public class HttpConnection extends AbstractConnection implements Connection
private static final ThreadLocal<HttpConnection> __currentConnection = new ThreadLocal<HttpConnection>();
private int _requests;
private volatile boolean _handling;
protected final Connector _connector;
protected final Server _server;
@ -363,158 +362,6 @@ public class HttpConnection extends AbstractConnection implements Connection
return _generator.isCommitted();
}
/* ------------------------------------------------------------ */
public Connection handle() throws IOException
{
Connection connection = this;
// Loop while more in buffer
boolean more_in_buffer =true; // assume true until proven otherwise
boolean progress=true;
try
{
assert getCurrentConnection()==null;
assert _handling==false;
_handling=true;
setCurrentConnection(this);
while (more_in_buffer && _endp.isOpen())
{
try
{
if (_request._async.isAsync())
{
// TODO - handle the case of input being read for a
// suspended request.
Log.debug("async request",_request);
if (!_request._async.isComplete())
handleRequest();
else if (!_parser.isComplete())
{
int parsed=_parser.parseAvailable();
if (parsed>0)
progress=true;
}
if (_generator.isCommitted() && !_generator.isComplete())
progress|=_generator.flushBuffer()>0;
if (_endp.isBufferingOutput())
_endp.flush();
}
else
{
// If we are not ended then parse available
if (!_parser.isComplete())
{
int parsed=_parser.parseAvailable();
if (parsed>0)
progress=true;
}
// Do we have more generating to do?
// Loop here because some writes may take multiple steps and
// we need to flush them all before potentially blocking in the
// next loop.
while (_generator.isCommitted() && !_generator.isComplete())
{
long written=_generator.flushBuffer();
if (written<=0)
break;
progress=true;
if (_endp.isBufferingOutput())
_endp.flush();
}
// Flush buffers
if (_endp.isBufferingOutput())
{
_endp.flush();
if (!_endp.isBufferingOutput())
progress=true;
}
if (!progress)
return this;
}
progress=false;
}
catch (HttpException e)
{
if (Log.isDebugEnabled())
{
Log.debug("uri="+_uri);
Log.debug("fields="+_requestFields);
Log.debug(e);
}
_generator.sendError(e.getStatus(), e.getReason(), null, true);
_parser.reset(true);
_endp.close();
}
finally
{
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
// Is this request/response round complete?
if (_parser.isComplete() && _generator.isComplete() && !_endp.isBufferingOutput())
{
// look for a switched connection instance?
Connection switched=(_response.getStatus()==HttpStatus.SWITCHING_PROTOCOLS_101)
?(Connection)_request.getAttribute("org.eclipse.jetty.io.Connection"):null;
// have we switched?
if (switched!=null)
{
_parser.reset(true);
_generator.reset(true);
connection=switched;
}
else
{
// No switch, so cleanup and reset
if (!_generator.isPersistent() || _endp.isInputShutdown())
{
_parser.reset(true);
more_in_buffer=false;
_endp.close();
}
if (more_in_buffer)
{
reset(false);
more_in_buffer = _parser.isMoreInBuffer() || _endp.isBufferingInput();
}
else
reset(true);
progress=true;
}
}
else if (_parser.isIdle() && _endp.isInputShutdown())
{
more_in_buffer=false;
_endp.close();
}
if (_request.isAsyncStarted())
{
Log.debug("return with suspended request");
more_in_buffer=false;
}
else if (_generator.isCommitted() && !_generator.isComplete() && _endp instanceof AsyncEndPoint)
((AsyncEndPoint)_endp).scheduleWrite();
}
}
}
finally
{
setCurrentConnection(null);
_handling=false;
}
return connection;
}
/* ------------------------------------------------------------ */
public void scheduleTimeout(Timeout.Task task, long timeoutMs)
{
@ -530,7 +377,9 @@ public class HttpConnection extends AbstractConnection implements Connection
/* ------------------------------------------------------------ */
public void reset(boolean returnBuffers)
{
_parser.reset(returnBuffers); // TODO maybe only release when low on resources
_parser.reset();
if (returnBuffers)
_parser.returnBuffers();
_requestFields.clear();
_request.recycle();
@ -678,6 +527,12 @@ public class HttpConnection extends AbstractConnection implements Connection
}
}
/* ------------------------------------------------------------ */
public Connection handle() throws IOException
{
return this;
}
/* ------------------------------------------------------------ */
public void commitResponse(boolean last) throws IOException
{
@ -1204,7 +1059,7 @@ public class HttpConnection extends AbstractConnection implements Connection
Buffer lm = httpContent.getLastModified();
long lml=httpContent.getResource().lastModified();
if (lm != null)
_responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm,lml);
_responseFields.put(HttpHeaders.LAST_MODIFIED_BUFFER, lm);
else if (httpContent.getResource()!=null)
{
if (lml!=-1)

View File

@ -113,7 +113,7 @@ public class LocalConnector extends AbstractConnector
};
endPoint.setGrowOutput(true);
HttpConnection connection = new HttpConnection(LocalConnector.this, endPoint, getServer());
HttpConnection connection = new BlockingHttpConnection(LocalConnector.this, endPoint, getServer());
endPoint.setConnection(connection);
connectionOpened(connection);

View File

@ -29,6 +29,7 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.bio.SocketEndPoint;
import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.log.Log;
@ -117,7 +118,7 @@ public class SocketConnector extends AbstractConnector
*/
protected Connection newConnection(EndPoint endpoint)
{
return new HttpConnection(this, endpoint, getServer());
return new BlockingHttpConnection(this, endpoint, getServer());
}
/* ------------------------------------------------------------------------------- */

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.ChannelEndPoint;
import org.eclipse.jetty.server.BlockingHttpConnection;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.ConcurrentHashSet;
@ -172,7 +173,7 @@ public class BlockingChannelConnector extends AbstractNIOConnector
throws IOException
{
super(channel,BlockingChannelConnector.this._maxIdleTime);
_connection = new HttpConnection(BlockingChannelConnector.this,this,getServer());
_connection = new BlockingHttpConnection(BlockingChannelConnector.this,this,getServer());
}
/* ------------------------------------------------------------ */

View File

@ -28,6 +28,7 @@ import org.eclipse.jetty.io.EndPoint;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.io.nio.SelectorManager;
import org.eclipse.jetty.io.nio.SelectorManager.SelectSet;
import org.eclipse.jetty.server.AsyncHttpConnection;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
@ -335,7 +336,7 @@ public class SelectChannelConnector extends AbstractNIOConnector
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private class SelectChannelHttpConnection extends HttpConnection
private class SelectChannelHttpConnection extends AsyncHttpConnection
{
private final SelectChannelEndPoint _endpoint;

View File

@ -16,11 +16,13 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpParser;
import org.eclipse.jetty.http.ssl.SslContextFactory;
import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.nio.SelectChannelEndPoint;
import org.eclipse.jetty.io.nio.SelectorManager;
import org.eclipse.jetty.io.nio.SslSelectChannelEndPoint;
import org.eclipse.jetty.server.AsyncHttpConnection;
import org.eclipse.jetty.server.HttpConnection;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
@ -65,7 +67,7 @@ public class SslTruncationAttackTest
@Override
protected Connection newConnection(SocketChannel channel, SelectChannelEndPoint endpoint)
{
return new HttpConnection(this, endpoint, server)
AsyncHttpConnection connection=new AsyncHttpConnection(this, endpoint, server)
{
@Override
public Connection handle() throws IOException
@ -74,6 +76,8 @@ public class SslTruncationAttackTest
return super.handle();
}
};
((HttpParser)connection.getParser()).setForceContentBuffer(true);
return connection;
}
};
server.addConnector(connector);
@ -151,7 +155,7 @@ public class SslTruncationAttackTest
// Sleep for a while to detect eventual spin looping
TimeUnit.SECONDS.sleep(1);
Assert.assertEquals("handle() invocations", 1, handleCount.get());
Assert.assertTrue("handle() invocations", handleCount.get()<=1);
Assert.assertTrue("endpoint not closed", endPointClosed.get());
}

View File

@ -957,7 +957,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
HttpFields fields = r.getHttpFields();
if (content.getLastModified()!=null)
fields.put(HttpHeaders.LAST_MODIFIED_BUFFER,content.getLastModified(),content.getResource().lastModified());
fields.put(HttpHeaders.LAST_MODIFIED_BUFFER,content.getLastModified());
else if (content.getResource()!=null)
{
long lml=content.getResource().lastModified();