jetty-9 HttpParser tests passing

This commit is contained in:
Greg Wilkins 2012-02-09 23:27:49 +11:00
parent 9c1d3ff0b3
commit 2659d87868
7 changed files with 432 additions and 479 deletions

View File

@ -927,7 +927,7 @@ public class HttpFields
private static final StringMap<Float> __qualities = new StringMap<>();
static
{
__qualities.put(null, __one);
__qualities.put("*", __one);
__qualities.put("1.0", __one);
__qualities.put("1", __one);
__qualities.put("0.9", new Float("0.9"));
@ -956,14 +956,16 @@ public class HttpFields
if (value.charAt(qe++) == 'q')
{
qe++;
Map.Entry<String,Float> entry = __qualities.getEntry(value, qe, value.length() - qe);
if (entry != null)
return (Float) entry.getValue();
Float q = __qualities.get(value, qe, value.length() - qe);
if (q != null)
return q;
}
Map<String,String> params = new HashMap<String,String>(4);
valueParameters(value, params);
String qs = (String) params.get("q");
if (qs==null)
qs="*";
Float q = (Float) __qualities.get(qs);
if (q == null)
{

View File

@ -27,28 +27,31 @@ public class HttpParser implements Parser
private static final Logger LOG = Log.getLogger(HttpParser.class);
// States
public static final int STATE_START=-14;
public static final int STATE_METHOD=-13;
public static final int STATE_RESPONSE_VERSION=-12;
public static final int STATE_SPACE1=-11;
public static final int STATE_STATUS=-10;
public static final int STATE_URI=-9;
public static final int STATE_SPACE2=-8;
public static final int STATE_REQUEST_VERSION=-7;
public static final int STATE_REASON=-6;
public static final int STATE_HEADER=-5;
public static final int STATE_HEADER_NAME=-4;
public static final int STATE_HEADER_IN_NAME=-3;
public static final int STATE_HEADER_VALUE=-2;
public static final int STATE_HEADER_IN_VALUE=-1;
public static final int STATE_END=0;
public static final int STATE_EOF_CONTENT=1;
public static final int STATE_CONTENT=2;
public static final int STATE_CHUNKED_CONTENT=3;
public static final int STATE_CHUNK_SIZE=4;
public static final int STATE_CHUNK_PARAMS=5;
public static final int STATE_CHUNK=6;
public static final int STATE_SEEKING_EOF=7;
public enum State
{
START,
METHOD,
RESPONSE_VERSION,
SPACE1,
STATUS,
URI,
SPACE2,
REQUEST_VERSION,
REASON,
HEADER,
HEADER_NAME,
HEADER_IN_NAME,
HEADER_VALUE,
HEADER_IN_VALUE,
END,
EOF_CONTENT,
CONTENT,
CHUNKED_CONTENT,
CHUNK_SIZE,
CHUNK_PARAMS,
CHUNK,
SEEKING_EOF
};
private final EventHandler _handler;
private final RequestHandler _requestHandler;
@ -59,7 +62,7 @@ public class HttpParser implements Parser
private boolean _persistent;
/* ------------------------------------------------------------------------------- */
private int _state=STATE_START;
private State _state=State.START;
private String _field0;
private String _field1;
private byte _eol;
@ -113,7 +116,7 @@ public class HttpParser implements Parser
}
/* ------------------------------------------------------------------------------- */
public int getState()
public State getState()
{
return _state;
}
@ -121,13 +124,13 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------------------------- */
public boolean inContentState()
{
return _state > 0;
return _state.ordinal() > State.END.ordinal();
}
/* ------------------------------------------------------------------------------- */
public boolean inHeaderState()
{
return _state < 0;
return _state.ordinal() < State.END.ordinal();
}
/* ------------------------------------------------------------------------------- */
@ -139,17 +142,17 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------ */
public boolean isIdle()
{
return isState(STATE_START);
return isState(State.START);
}
/* ------------------------------------------------------------ */
public boolean isComplete()
{
return isState(STATE_END);
return isState(State.END);
}
/* ------------------------------------------------------------------------------- */
public boolean isState(int state)
public boolean isState(State state)
{
return _state == state;
}
@ -164,49 +167,34 @@ public class HttpParser implements Parser
public void setPersistent(boolean persistent)
{
_persistent = persistent;
if (!_persistent &&(_state==STATE_END || _state==STATE_START))
_state=STATE_SEEKING_EOF;
if (!_persistent &&(_state==State.END || _state==State.START))
_state=State.SEEKING_EOF;
}
/* ------------------------------------------------------------------------------- */
/**
* Parse until {@link #STATE_END END} state.
* Parse until {@link #END END} state.
* If the parser is already in the END state, then it is {@link #reset reset} and re-parsed.
* @throws IllegalStateException If the buffers have already been partially parsed.
*/
public void parse(ByteBuffer buffer) throws IOException
public void parseAll(ByteBuffer buffer) throws IOException
{
if (_state==STATE_END)
if (_state==State.END)
reset();
if (_state!=STATE_START)
if (_state!=State.START)
throw new IllegalStateException("!START");
// continue parsing
while (_state != STATE_END && buffer.hasRemaining())
if (!parseNext(buffer))
return;
}
/* ------------------------------------------------------------------------------- */
/**
* Parse until END state.
* This method will parse any remaining content in the current buffer. It does not care about the
* {@link #getState current state} of the parser.
* @see #parse
* @see #parseNext
*/
public boolean parseAvailable(ByteBuffer buffer) throws IOException
{
boolean progress=parseNext(buffer);
// continue parsing
while (!isComplete() && buffer.hasRemaining())
while (_state != State.END && buffer.hasRemaining())
{
progress |= parseNext(buffer);
int remaining=buffer.remaining();
parseNext(buffer);
if (remaining==buffer.remaining())
break;
}
return progress;
}
/* ------------------------------------------------------------------------------- */
/**
* Parse until next Event.
@ -214,35 +202,28 @@ public class HttpParser implements Parser
*/
public boolean parseNext(ByteBuffer buffer) throws IOException
{
int start=-1;
State startState=null;
try
{
int progress=0;
if (_state == STATE_END)
if (_state == State.END)
return false;
if (_state == STATE_CONTENT && _contentPosition == _contentLength)
if (_state == State.CONTENT && _contentPosition == _contentLength)
{
_state=STATE_END;
_handler.messageComplete(_contentPosition);
return true;
_state=State.END;
if(_handler.messageComplete(_contentPosition))
return true;
}
// Handle header states
byte ch;
int last=_state;
int start=-1;
int length=-1;
boolean at_next=false;
while (_state<STATE_END && buffer.hasRemaining())
{
if (last!=_state)
{
progress++;
last=_state;
}
while (_state.ordinal()<State.END.ordinal() && buffer.hasRemaining() && !at_next)
{
ch=buffer.get();
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
@ -254,22 +235,23 @@ public class HttpParser implements Parser
switch (_state)
{
case STATE_START:
case START:
_contentLength=HttpTokens.UNKNOWN_CONTENT;
_header=null;
if (ch > HttpTokens.SPACE || ch<0)
{
start=buffer.position()-1;
_state=_requestHandler!=null?STATE_METHOD:STATE_RESPONSE_VERSION;
startState=_state;
_state=_requestHandler!=null?State.METHOD:State.RESPONSE_VERSION;
}
break;
case STATE_METHOD:
case METHOD:
if (ch == HttpTokens.SPACE)
{
HttpMethods method=HttpMethods.CACHE.get(buffer,start,buffer.position()-start-1);
_field0=method==null?BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET):method.toString();
_state=STATE_SPACE1;
_state=State.SPACE1;
}
else if (ch < HttpTokens.SPACE && ch>=0)
{
@ -277,15 +259,14 @@ public class HttpParser implements Parser
}
break;
case STATE_RESPONSE_VERSION:
case RESPONSE_VERSION:
if (ch == HttpTokens.SPACE)
{
int l=buffer.position()-start;
HttpVersions v=HttpVersions.CACHE.get(buffer,start,l);
_field0=v==null?BufferUtil.toString(buffer,start,l,StringUtil.__ISO_8859_1_CHARSET):v.toString();
HttpVersions v=HttpVersions.CACHE.get(buffer,start,buffer.position()-start-1);
_field0=v==null?BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET):v.toString();
start=-1;
_persistent=HttpVersions.HTTP_1_1==v;
_state=STATE_SPACE1;
_state=State.SPACE1;
}
else if (ch < HttpTokens.SPACE && ch>=0)
{
@ -293,18 +274,19 @@ public class HttpParser implements Parser
}
break;
case STATE_SPACE1:
case SPACE1:
if (ch > HttpTokens.SPACE || ch<0)
{
if (_responseHandler!=null)
{
_state=STATE_STATUS;
_state=State.STATUS;
_responseStatus=ch-'0';
}
else
{
_state=STATE_URI;
start=buffer.position()-1;
startState=_state;
_state=State.URI;
}
}
else if (ch < HttpTokens.SPACE)
@ -313,10 +295,10 @@ public class HttpParser implements Parser
}
break;
case STATE_STATUS:
case STATUS:
if (ch == HttpTokens.SPACE)
{
_state=STATE_SPACE2;
_state=State.SPACE2;
}
else if (ch>='0' && ch<='9')
{
@ -324,10 +306,10 @@ public class HttpParser implements Parser
}
else if (ch < HttpTokens.SPACE && ch>=0)
{
_responseHandler.startResponse(_field0, _responseStatus, null);
at_next|=_responseHandler.startResponse(_field0, _responseStatus, null);
_eol=ch;
_state=STATE_HEADER;
_state=State.HEADER;
_field0=_field1=null;
}
else
@ -336,84 +318,85 @@ public class HttpParser implements Parser
}
break;
case STATE_URI:
case URI:
if (ch == HttpTokens.SPACE)
{
_field1=BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__UTF8_CHARSET);
start=-1;
_state=STATE_SPACE2;
_state=State.SPACE2;
}
else if (ch < HttpTokens.SPACE && ch>=0)
{
// HTTP/0.9
_field1=BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__UTF8_CHARSET);
start=-1;
_requestHandler.startRequest(_field0,_field1,null);
at_next|=_requestHandler.startRequest(_field0,_field1,null);
_persistent=false;
_state=STATE_SEEKING_EOF;
_handler.headerComplete();
_handler.messageComplete(_contentPosition);
_state=State.SEEKING_EOF;
at_next|=_handler.headerComplete();
at_next|=_handler.messageComplete(_contentPosition);
}
break;
case STATE_SPACE2:
case SPACE2:
if (ch > HttpTokens.SPACE || ch<0)
{
_state=_requestHandler!=null?STATE_REQUEST_VERSION:STATE_REASON;
start=buffer.position()-1;
startState=_state;
_state=_requestHandler!=null?State.REQUEST_VERSION:State.REASON;
}
else if (ch < HttpTokens.SPACE)
{
if (_responseHandler!=null)
{
_responseHandler.startResponse(_field0, _responseStatus, null);
at_next|=_responseHandler.startResponse(_field0, _responseStatus, null);
_eol=ch;
_state=STATE_HEADER;
_state=State.HEADER;
_field0=_field1=null;
}
else
{
// HTTP/0.9
_requestHandler.startRequest(_field0, _field1, null);
at_next|=_requestHandler.startRequest(_field0, _field1, null);
_persistent=false;
_state=STATE_SEEKING_EOF;
_handler.headerComplete();
_handler.messageComplete(_contentPosition);
_state=State.SEEKING_EOF;
at_next|=_handler.headerComplete();
at_next|=_handler.messageComplete(_contentPosition);
}
}
break;
case STATE_REQUEST_VERSION:
case REQUEST_VERSION:
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
{
HttpVersions v=HttpVersions.CACHE.get(buffer,start,buffer.position()-start-1);
String version=v==null?BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET):v.toString();
start=-1;
_requestHandler.startRequest(_field0, _field1, version);
at_next|=_requestHandler.startRequest(_field0, _field1, version);
_eol=ch;
_persistent=HttpVersions.HTTP_1_1==v;
_state=STATE_HEADER;
_state=State.HEADER;
_field0=_field1=null;
continue;
}
break;
case STATE_REASON:
case REASON:
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
{
String reason=BufferUtil.toString(buffer,start,buffer.position()-start,StringUtil.__ISO_8859_1_CHARSET);
String reason=BufferUtil.toString(buffer,start,buffer.position()-start-1,StringUtil.__ISO_8859_1_CHARSET);
start=-1;
_responseHandler.startResponse(_field0, _responseStatus, reason);
at_next|=_responseHandler.startResponse(_field0, _responseStatus, reason);
_eol=ch;
_state=STATE_HEADER;
_state=State.HEADER;
_field0=_field1=null;
continue;
}
break;
case STATE_HEADER:
case HEADER:
switch(ch)
{
case HttpTokens.COLON:
@ -422,7 +405,7 @@ public class HttpParser implements Parser
{
// header value without name - continuation?
length=-1;
_state=STATE_HEADER_VALUE;
_state=State.HEADER_VALUE;
break;
}
@ -497,7 +480,7 @@ public class HttpParser implements Parser
}
}
_handler.parsedHeader(_field0, _field1);
at_next|=_handler.parsedHeader(_field0, _field1);
}
_field0=_field1=null;
_header=null;
@ -528,24 +511,24 @@ public class HttpParser implements Parser
switch (_contentLength > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) _contentLength)
{
case HttpTokens.EOF_CONTENT:
_state=STATE_EOF_CONTENT;
_handler.headerComplete(); // May recurse here !
_state=State.EOF_CONTENT;
at_next|=_handler.headerComplete(); // May recurse here !
break;
case HttpTokens.CHUNKED_CONTENT:
_state=STATE_CHUNKED_CONTENT;
_handler.headerComplete(); // May recurse here !
_state=State.CHUNKED_CONTENT;
at_next|=_handler.headerComplete(); // May recurse here !
break;
case HttpTokens.NO_CONTENT:
_handler.headerComplete();
_state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
at_next|=_handler.headerComplete();
_state=_persistent||(_responseStatus>=100&&_responseStatus<200)?State.END:State.SEEKING_EOF;
at_next|=_handler.messageComplete(_contentPosition);
break;
default:
_state=STATE_CONTENT;
_handler.headerComplete(); // May recurse here !
_state=State.CONTENT;
at_next|=_handler.headerComplete(); // May recurse here !
break;
}
}
@ -553,15 +536,16 @@ public class HttpParser implements Parser
{
// New header
start=buffer.position()-1;
startState=_state;
length=1;
_state=STATE_HEADER_NAME;
_state=State.HEADER_NAME;
}
}
}
break;
case STATE_HEADER_NAME:
case HEADER_NAME:
switch(ch)
{
case HttpTokens.CARRIAGE_RETURN:
@ -570,14 +554,14 @@ public class HttpParser implements Parser
_header=HttpHeaders.CACHE.get(buffer,start,length);
_field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString();
start=length=-1;
_state=STATE_HEADER;
_state=State.HEADER;
break;
case HttpTokens.COLON:
_header=HttpHeaders.CACHE.get(buffer,start,length);
_field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString();
start=length=-1;
_state=STATE_HEADER_VALUE;
_state=State.HEADER_VALUE;
break;
case HttpTokens.SPACE:
case HttpTokens.TAB:
@ -585,13 +569,13 @@ public class HttpParser implements Parser
default:
{
length=buffer.position()-start;
_state=STATE_HEADER_IN_NAME;
_state=State.HEADER_IN_NAME;
}
}
break;
case STATE_HEADER_IN_NAME:
case HEADER_IN_NAME:
switch(ch)
{
case HttpTokens.CARRIAGE_RETURN:
@ -600,25 +584,25 @@ public class HttpParser implements Parser
_header=HttpHeaders.CACHE.get(buffer,start,length);
_field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString();
start=length=-1;
_state=STATE_HEADER;
_state=State.HEADER;
break;
case HttpTokens.COLON:
_header=HttpHeaders.CACHE.get(buffer,start,length);
_field0=_header==null?BufferUtil.toString(buffer,start,length,StringUtil.__ISO_8859_1_CHARSET):_header.toString();
start=length=-1;
_state=STATE_HEADER_VALUE;
_state=State.HEADER_VALUE;
break;
case HttpTokens.SPACE:
case HttpTokens.TAB:
_state=STATE_HEADER_NAME;
_state=State.HEADER_NAME;
break;
default:
length++;
}
break;
case STATE_HEADER_VALUE:
case HEADER_VALUE:
switch(ch)
{
case HttpTokens.CARRIAGE_RETURN:
@ -643,7 +627,7 @@ public class HttpParser implements Parser
}
start=length=-1;
}
_state=STATE_HEADER;
_state=State.HEADER;
break;
case HttpTokens.SPACE:
case HttpTokens.TAB:
@ -651,14 +635,17 @@ public class HttpParser implements Parser
default:
{
if (start==-1)
{
start=buffer.position()-1;
startState=_state;
}
length=buffer.position()-start;
_state=STATE_HEADER_IN_VALUE;
_state=State.HEADER_IN_VALUE;
}
}
break;
case STATE_HEADER_IN_VALUE:
case HEADER_IN_VALUE:
switch(ch)
{
case HttpTokens.CARRIAGE_RETURN:
@ -683,11 +670,11 @@ public class HttpParser implements Parser
}
start=length=-1;
}
_state=STATE_HEADER;
_state=State.HEADER;
break;
case HttpTokens.SPACE:
case HttpTokens.TAB:
_state=STATE_HEADER_VALUE;
_state=State.HEADER_VALUE;
break;
default:
length++;
@ -701,24 +688,17 @@ public class HttpParser implements Parser
// Handle HEAD response
if (_responseStatus>0 && _headResponse)
{
_state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentLength);
_state=_persistent||(_responseStatus>=100&&_responseStatus<200)?State.END:State.SEEKING_EOF;
at_next|=_handler.messageComplete(_contentLength);
}
// ==========================
// Handle _content
last=_state;
ByteBuffer chunk;
while (_state > STATE_END && buffer.hasRemaining())
while (_state.ordinal() > State.END.ordinal() && buffer.hasRemaining())
{
if (last!=_state)
{
progress++;
last=_state;
}
if (_eol == HttpTokens.CARRIAGE_RETURN && buffer.get(buffer.position()) == HttpTokens.LINE_FEED)
{
_eol=buffer.get();
@ -728,20 +708,20 @@ public class HttpParser implements Parser
switch (_state)
{
case STATE_EOF_CONTENT:
case EOF_CONTENT:
chunk=buffer.asReadOnlyBuffer();
_contentPosition += chunk.remaining();
buffer.position(buffer.position()+chunk.remaining());
_handler.content(chunk); // May recurse here
at_next|=_handler.content(chunk); // May recurse here
break;
case STATE_CONTENT:
case CONTENT:
{
long remaining=_contentLength - _contentPosition;
if (remaining == 0)
{
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
_state=_persistent?State.END:State.SEEKING_EOF;
at_next|=_handler.messageComplete(_contentPosition);
}
else
{
@ -757,18 +737,18 @@ public class HttpParser implements Parser
_contentPosition += chunk.remaining();
buffer.position(buffer.position()+chunk.remaining());
_handler.content(chunk); // May recurse here
at_next|=_handler.content(chunk); // May recurse here
if(_contentPosition == _contentLength)
{
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
_state=_persistent?State.END:State.SEEKING_EOF;
at_next|=_handler.messageComplete(_contentPosition);
}
}
break;
}
case STATE_CHUNKED_CONTENT:
case CHUNKED_CONTENT:
{
ch=buffer.get(buffer.position());
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
@ -779,12 +759,12 @@ public class HttpParser implements Parser
{
_chunkLength=0;
_chunkPosition=0;
_state=STATE_CHUNK_SIZE;
_state=State.CHUNK_SIZE;
}
break;
}
case STATE_CHUNK_SIZE:
case CHUNK_SIZE:
{
ch=buffer.get();
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
@ -795,14 +775,14 @@ public class HttpParser implements Parser
{
if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
_eol=buffer.get();
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
_state=_persistent?State.END:State.SEEKING_EOF;
at_next|=_handler.messageComplete(_contentPosition);
}
else
_state=STATE_CHUNK;
_state=State.CHUNK;
}
else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
_state=STATE_CHUNK_PARAMS;
_state=State.CHUNK_PARAMS;
else if (ch >= '0' && ch <= '9')
_chunkLength=_chunkLength * 16 + (ch - '0');
else if (ch >= 'a' && ch <= 'f')
@ -814,7 +794,7 @@ public class HttpParser implements Parser
break;
}
case STATE_CHUNK_PARAMS:
case CHUNK_PARAMS:
{
ch=buffer.get();
if (ch == HttpTokens.CARRIAGE_RETURN || ch == HttpTokens.LINE_FEED)
@ -824,21 +804,21 @@ public class HttpParser implements Parser
{
if (_eol==HttpTokens.CARRIAGE_RETURN && buffer.hasRemaining() && buffer.get(buffer.position())==HttpTokens.LINE_FEED)
_eol=buffer.get();
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
_state=_persistent?State.END:State.SEEKING_EOF;
at_next|=_handler.messageComplete(_contentPosition);
}
else
_state=STATE_CHUNK;
_state=State.CHUNK;
}
break;
}
case STATE_CHUNK:
case CHUNK:
{
int remaining=_chunkLength - _chunkPosition;
if (remaining == 0)
{
_state=STATE_CHUNKED_CONTENT;
_state=State.CHUNKED_CONTENT;
}
else
{
@ -851,13 +831,12 @@ public class HttpParser implements Parser
_contentPosition += remaining;
_chunkPosition += remaining;
buffer.position(buffer.position()+remaining);
_handler.content(chunk); // May recurse here
_handler.content(chunk);
at_next|=_handler.content(chunk); // May recurse here
}
break;
}
case STATE_SEEKING_EOF:
case SEEKING_EOF:
{
buffer.clear().limit(0);
break;
@ -866,14 +845,23 @@ public class HttpParser implements Parser
}
return progress>0;
return at_next;
}
catch(HttpException e)
{
_persistent=false;
_state=STATE_SEEKING_EOF;
_state=State.SEEKING_EOF;
throw e;
}
finally
{
if (start>=0)
{
buffer.position(start);
_state=startState;
}
}
}
@ -885,18 +873,18 @@ public class HttpParser implements Parser
// was this unexpected?
switch(_state)
{
case STATE_END:
case STATE_SEEKING_EOF:
_state=STATE_END;
case END:
case SEEKING_EOF:
_state=State.END;
break;
case STATE_EOF_CONTENT:
_state=STATE_END;
case EOF_CONTENT:
_state=State.END;
_handler.messageComplete(_contentPosition);
break;
default:
_state=STATE_END;
_state=State.END;
if (!_headResponse)
_handler.earlyEOF();
_handler.messageComplete(_contentPosition);
@ -914,7 +902,7 @@ public class HttpParser implements Parser
public void reset()
{
// reset state
_state=_persistent?STATE_START:_state==STATE_END?STATE_END:STATE_SEEKING_EOF;
_state=_persistent?State.START:_state==State.END?State.END:State.SEEKING_EOF;
_contentLength=HttpTokens.UNKNOWN_CONTENT;
_contentPosition=0;
_responseStatus=0;
@ -925,7 +913,7 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------------------------- */
public void setState(int state)
public void setState(State state)
{
this._state=state;
_contentLength=HttpTokens.UNKNOWN_CONTENT;
@ -946,20 +934,24 @@ public class HttpParser implements Parser
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* Event Handler interface
* These methods return true if they want parsing to return to
* the caller.
*/
public interface EventHandler
{
public void content(ByteBuffer ref) throws IOException;
public boolean content(ByteBuffer ref) throws IOException;
public void headerComplete() throws IOException;
public boolean headerComplete() throws IOException;
public void messageComplete(long contentLength) throws IOException;
public boolean messageComplete(long contentLength) throws IOException;
/**
* This is the method called by parser when a HTTP Header name and value is found
*/
public void parsedHeader(String name, String value) throws IOException;
public boolean parsedHeader(String name, String value) throws IOException;
public void earlyEOF();
public boolean earlyEOF();
}
public interface RequestHandler extends EventHandler
@ -967,7 +959,7 @@ public class HttpParser implements Parser
/**
* This is the method called by parser when the HTTP request line is parsed
*/
public abstract void startRequest(String method, String uri, String version)
public abstract boolean startRequest(String method, String uri, String version)
throws IOException;
}
@ -976,7 +968,7 @@ public class HttpParser implements Parser
/**
* This is the method called by parser when the HTTP request line is parsed
*/
public abstract void startResponse(String version, int status, String reason)
public abstract boolean startResponse(String version, int status, String reason)
throws IOException;
}

View File

@ -25,11 +25,14 @@ public interface Parser
boolean isComplete();
/* ------------------------------------------------------------ */
/**
* @return True if progress made
* @param buffer
* @return True if parsed to the next unit
* @throws IOException
*/
boolean parseAvailable(ByteBuffer buffer) throws IOException;
boolean parseNext(ByteBuffer buffer) throws IOException;
boolean onEOF()throws IOException;

View File

@ -56,7 +56,7 @@ import org.eclipse.jetty.util.URIUtil;
*
*
*/
public class PathMap extends HashMap implements Externalizable
public class PathMap<O> extends HashMap<String,O>
{
/* ------------------------------------------------------------ */
private static String __pathSpecSeparators = ":,";
@ -74,13 +74,13 @@ public class PathMap extends HashMap implements Externalizable
}
/* --------------------------------------------------------------- */
final StringMap _prefixMap=new StringMap();
final StringMap _suffixMap=new StringMap();
final StringMap _exactMap=new StringMap();
final StringMap<MappedEntry<O>> _prefixMap=new StringMap<>();
final StringMap<MappedEntry<O>> _suffixMap=new StringMap<>();
final StringMap<MappedEntry<O>> _exactMap=new StringMap<>();
List _defaultSingletonList=null;
Entry _prefixDefault=null;
Entry _default=null;
MappedEntry<O> _prefixDefault=null;
MappedEntry<O> _default=null;
final Set _entrySet;
boolean _nodefault=false;
@ -121,22 +121,6 @@ public class PathMap extends HashMap implements Externalizable
_entrySet=entrySet();
}
/* ------------------------------------------------------------ */
public void writeExternal(java.io.ObjectOutput out)
throws java.io.IOException
{
HashMap map = new HashMap(this);
out.writeObject(map);
}
/* ------------------------------------------------------------ */
public void readExternal(java.io.ObjectInput in)
throws java.io.IOException, ClassNotFoundException
{
HashMap map = (HashMap)in.readObject();
this.putAll(map);
}
/* --------------------------------------------------------------- */
/** Add a single path match to the PathMap.
* @param pathSpec The path specification, or comma separated list of
@ -144,19 +128,19 @@ public class PathMap extends HashMap implements Externalizable
* @param object The object the path maps to
*/
@Override
public Object put(Object pathSpec, Object object)
public O put(String pathSpec, O object)
{
String str = pathSpec.toString();
if ("".equals(str.trim()))
{
Entry entry = new Entry("",object);
MappedEntry entry = new MappedEntry("",object);
entry.setMapped("");
_exactMap.put("", entry);
return super.put("", object);
}
StringTokenizer tok = new StringTokenizer(str,__pathSpecSeparators);
Object old =null;
O old =null;
while (tok.hasMoreTokens())
{
@ -168,7 +152,7 @@ public class PathMap extends HashMap implements Externalizable
old = super.put(spec,object);
// Make entry that was just created.
Entry entry = new Entry(spec,object);
MappedEntry entry = new MappedEntry(spec,object);
if (entry.getKey().equals(spec))
{
@ -225,9 +209,9 @@ public class PathMap extends HashMap implements Externalizable
* @param path the path.
* @return Map.Entry of the best matched or null.
*/
public Entry getMatch(String path)
public MappedEntry<O> getMatch(String path)
{
Map.Entry entry=null;
MappedEntry<O> entry=null;
if (path==null)
return null;
@ -237,23 +221,23 @@ public class PathMap extends HashMap implements Externalizable
//special case
if (l == 1 && path.charAt(0)=='/')
{
entry = (Map.Entry)_exactMap.get("");
entry = _exactMap.get("");
if (entry != null)
return (Entry)entry;
return (MappedEntry)entry;
}
// try exact match
entry=_exactMap.getEntry(path,0,l);
entry=_exactMap.get(path,0,l);
if (entry!=null)
return (Entry) entry.getValue();
return entry;
// prefix search
int i=l;
while((i=path.lastIndexOf('/',i-1))>=0)
{
entry=_prefixMap.getEntry(path,0,i);
entry=_prefixMap.get(path,0,i);
if (entry!=null)
return (Entry) entry.getValue();
return entry;
}
// Prefix Default
@ -264,9 +248,9 @@ public class PathMap extends HashMap implements Externalizable
i=0;
while ((i=path.indexOf('.',i+1))>0)
{
entry=_suffixMap.getEntry(path,i+1,l-i-1);
entry=_suffixMap.get(path,i+1,l-i-1);
if (entry!=null)
return (Entry) entry.getValue();
return entry;
}
// Default
@ -281,7 +265,7 @@ public class PathMap extends HashMap implements Externalizable
*/
public Object getLazyMatches(String path)
{
Map.Entry entry;
MappedEntry entry;
Object entries=null;
if (path==null)
@ -290,17 +274,17 @@ public class PathMap extends HashMap implements Externalizable
int l=path.length();
// try exact match
entry=_exactMap.getEntry(path,0,l);
entry=_exactMap.get(path,0,l);
if (entry!=null)
entries=LazyList.add(entries,entry.getValue());
entries=LazyList.add(entries,entry);
// prefix search
int i=l-1;
while((i=path.lastIndexOf('/',i-1))>=0)
{
entry=_prefixMap.getEntry(path,0,i);
entry=_prefixMap.get(path,0,i);
if (entry!=null)
entries=LazyList.add(entries,entry.getValue());
entries=LazyList.add(entries,entry);
}
// Prefix Default
@ -311,9 +295,9 @@ public class PathMap extends HashMap implements Externalizable
i=0;
while ((i=path.indexOf('.',i+1))>0)
{
entry=_suffixMap.getEntry(path,i+1,l-i-1);
entry=_suffixMap.get(path,i+1,l-i-1);
if (entry!=null)
entries=LazyList.add(entries,entry.getValue());
entries=LazyList.add(entries,entry);
}
// Default
@ -348,13 +332,13 @@ public class PathMap extends HashMap implements Externalizable
*/
public boolean containsMatch(String path)
{
Entry match = getMatch(path);
MappedEntry match = getMatch(path);
return match!=null && !match.equals(_default);
}
/* --------------------------------------------------------------- */
@Override
public Object remove(Object pathSpec)
public O remove(Object pathSpec)
{
if (pathSpec!=null)
{
@ -532,30 +516,29 @@ public class PathMap extends HashMap implements Externalizable
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
public static class Entry implements Map.Entry
public static class MappedEntry<O> implements Map.Entry<String,O>
{
private final Object key;
private final Object value;
private final String key;
private final O value;
private String mapped;
private transient String string;
Entry(Object key, Object value)
MappedEntry(String key, O value)
{
this.key=key;
this.value=value;
}
public Object getKey()
public String getKey()
{
return key;
}
public Object getValue()
public O getValue()
{
return value;
}
public Object setValue(Object o)
public O setValue(O o)
{
throw new UnsupportedOperationException();
}
@ -563,9 +546,7 @@ public class PathMap extends HashMap implements Externalizable
@Override
public String toString()
{
if (string==null)
string=key+"="+value;
return string;
return key+"="+value;
}
public String getMapped()

View File

@ -37,7 +37,7 @@ public class HttpParserTest
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertEquals("POST", f0);
assertEquals("/foo", f1);
assertEquals("HTTP/1.0", f2);
@ -52,7 +52,7 @@ public class HttpParserTest
f2= null;
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertEquals("GET", f0);
assertEquals("/999", f1);
assertEquals(null, f2);
@ -67,7 +67,7 @@ public class HttpParserTest
f2= null;
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertEquals("POST", f0);
assertEquals("/222", f1);
assertEquals(null, f2);
@ -81,7 +81,7 @@ public class HttpParserTest
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertEquals("POST", f0);
assertEquals("/fo\u0690", f1);
assertEquals("HTTP/1.0", f2);
@ -95,7 +95,7 @@ public class HttpParserTest
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertEquals("POST", f0);
assertEquals("/foo?param=\u0690", f1);
assertEquals("HTTP/1.0", f2);
@ -108,7 +108,7 @@ public class HttpParserTest
ByteBuffer buffer= BufferUtil.toBuffer("CONNECT 192.168.1.2:80 HTTP/1.1\015\012" + "\015\012");
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertTrue(handler.request);
assertEquals("CONNECT", f0);
assertEquals("192.168.1.2:80", f1);
@ -120,19 +120,19 @@ public class HttpParserTest
public void testHeaderParse() throws Exception
{
ByteBuffer buffer= BufferUtil.toBuffer(
"GET / HTTP/1.0\015\012"
+ "Host: localhost\015\012"
+ "Header1: value1\015\012"
+ "Header2 : value 2a \015\012"
+ " value 2b \015\012"
+ "Header3: \015\012"
+ "Header4 \015\012"
+ " value4\015\012"
+ "Server5: notServer\015\012"
+ "\015\012");
"GET / HTTP/1.0\015\012" +
"Host: localhost\015\012" +
"Header1: value1\015\012" +
"Header2 : value 2a \015\012" +
" value 2b \015\012" +
"Header3: \015\012" +
"Header4 \015\012" +
" value4\015\012" +
"Server5: notServer\015\012" +
"\015\012");
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertEquals("GET", f0);
assertEquals("/", f1);
@ -151,14 +151,58 @@ public class HttpParserTest
assertEquals("notServer", val[5]);
assertEquals(5, h);
}
@Test
public void testHttpHeaders() throws Exception
public void testSplitHeaderParse() throws Exception
{
ByteBuffer buffer= BufferUtil.toBuffer("Transfer-Encoding");
assertEquals(HttpHeaders.TRANSFER_ENCODING,HttpHeaders.CACHE.get(buffer));
ByteBuffer buffer= BufferUtil.toBuffer(
"XXXXGET / HTTP/1.0\015\012" +
"Host: localhost\015\012" +
"Header1: value1\015\012" +
"Header2 : value 2a \015\012" +
" value 2b \015\012" +
"Header3: \015\012" +
"Header4 \015\012" +
" value4\015\012" +
"Server5: notServer\015\012" +
"\015\012ZZZZ");
buffer.position(2);
buffer.limit(buffer.capacity()-2);
buffer=buffer.slice();
for (int i=0;i<buffer.capacity()-4;i++)
{
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
buffer.position(2);
buffer.limit(2+i);
if (!parser.parseNext(buffer))
{
buffer.limit(buffer.capacity()-2);
parser.parseNext(buffer);
}
assertEquals("GET", f0);
assertEquals("/", f1);
assertEquals("HTTP/1.0", f2);
assertEquals("Host", hdr[0]);
assertEquals("localhost", val[0]);
assertEquals("Header1", hdr[1]);
assertEquals("value1", val[1]);
assertEquals("Header2", hdr[2]);
assertEquals("value 2a value 2b", val[2]);
assertEquals("Header3", hdr[3]);
assertEquals(null, val[3]);
assertEquals("Header4", hdr[4]);
assertEquals("value4", val[4]);
assertEquals("Server5", hdr[5]);
assertEquals("notServer", val[5]);
assertEquals(5, h);
}
}
@Test
public void testChunkParse() throws Exception
@ -175,7 +219,7 @@ public class HttpParserTest
+ "0\015\012");
Handler handler = new Handler();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parse(buffer);
parser.parseAll(buffer);
assertEquals("GET", f0);
assertEquals("/chunk", f1);
@ -189,9 +233,8 @@ public class HttpParserTest
@Test
public void testMultiParse() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
"GET /mp HTTP/1.0\015\012"
ByteBuffer buffer= BufferUtil.toBuffer(
"GET /mp HTTP/1.0\015\012"
+ "Connection: Keep-Alive\015\012"
+ "Header1: value1\015\012"
+ "Transfer-Encoding: chunked\015\012"
@ -213,13 +256,10 @@ public class HttpParserTest
+ "\015\012"
+ "0123456789\015\012");
ByteBuffer buffer= BufferUtil.allocate(4096);
ByteBuffer content=BufferUtil.allocate(8192);
SimpleBuffers buffers=new SimpleBuffers(buffer,content);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
HttpParser parser= new HttpParser((HttpParser.RequestHandler)handler);
parser.parseNext(buffer);
assertEquals("GET", f0);
assertEquals("/mp", f1);
assertEquals("HTTP/1.0", f2);
@ -227,8 +267,9 @@ public class HttpParserTest
assertEquals("Header1", hdr[1]);
assertEquals("value1", val[1]);
assertEquals("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content);
parser.parse();
parser.reset();
parser.parseNext(buffer);
assertEquals("POST", f0);
assertEquals("/foo", f1);
assertEquals("HTTP/1.0", f2);
@ -237,7 +278,9 @@ public class HttpParserTest
assertEquals("value2", val[1]);
assertEquals(null, _content);
parser.parse();
parser.reset();
parser.parseNext(buffer);
parser.onEOF();
assertEquals("PUT", f0);
assertEquals("/doodle", f1);
assertEquals("HTTP/1.0", f2);
@ -247,117 +290,19 @@ public class HttpParserTest
assertEquals("0123456789", _content);
}
@Test
public void testStreamParse() throws Exception
{
StringEndPoint io=new StringEndPoint();
String http="GET / HTTP/1.1\015\012"
+ "Host: test\015\012"
+ "Header1: value1\015\012"
+ "Transfer-Encoding: chunked\015\012"
+ "\015\012"
+ "a;\015\012"
+ "0123456789\015\012"
+ "1a\015\012"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ\015\012"
+ "0\015\012"
+ "POST /foo HTTP/1.1\015\012"
+ "Host: test\015\012"
+ "Header2: value2\015\012"
+ "Content-Length: 0\015\012"
+ "\015\012"
+ "PUT /doodle HTTP/1.1\015\012"
+ "Host: test\015\012"
+ "Connection: close\015\012"
+ "Header3: value3\015\012"
+ "Content-Length: 10\015\012"
+ "\015\012"
+ "0123456789\015\012";
int[] tests=
{
1024,
http.length() + 3,
http.length() + 2,
http.length() + 1,
http.length() + 0,
http.length() - 1,
http.length() - 2,
http.length() / 2,
http.length() / 3,
128,
32
};
for (int t= 0; t < tests.length; t++)
{
String tst="t"+t+"="+tests[t];
try
{
f0=f1=f2=null;
h=0;
ByteBuffer buffer= BufferUtil.allocate(tests[t]);
ByteBuffer content=BufferUtil.allocate(8192);
SimpleBuffers buffers=new SimpleBuffers(buffer,content);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
io.setInput(http);
// System.err.println(tst);
parser.parse();
assertEquals(tst,"GET", f0);
assertEquals(tst,"/", f1);
assertEquals(tst,"HTTP/1.1", f2);
assertEquals(tst,2, h);
assertEquals(tst,"Header1", hdr[1]);
assertEquals(tst,"value1", val[1]);
assertEquals(tst,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ", _content);
parser.parse();
assertEquals(tst,"POST", f0);
assertEquals(tst,"/foo", f1);
assertEquals(tst,"HTTP/1.1", f2);
assertEquals(tst,2, h);
assertEquals(tst,"Header2", hdr[1]);
assertEquals(tst,"value2", val[1]);
assertEquals(tst,null, _content);
parser.parse();
assertEquals(tst,"PUT", f0);
assertEquals(tst,"/doodle", f1);
assertEquals(tst,"HTTP/1.1", f2);
assertEquals(tst,3, h);
assertEquals(tst,"Header3", hdr[2]);
assertEquals(tst,"value3", val[2]);
assertEquals(tst,"0123456789", _content);
}
catch(Exception e)
{
if (t+1 < tests.length)
throw e;
assertTrue(e.toString().indexOf("FULL")>=0);
}
}
}
@Test
public void testResponseParse0() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
ByteBuffer buffer= BufferUtil.toBuffer(
"HTTP/1.1 200 Correct\015\012"
+ "Content-Length: 10\015\012"
+ "Content-Type: text/plain\015\012"
+ "\015\012"
+ "0123456789\015\012");
ByteBuffer buffer= BufferUtil.allocate(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
parser.parseNext(buffer);
assertEquals("HTTP/1.1", f0);
assertEquals("200", f1);
assertEquals("Correct", f2);
@ -369,17 +314,14 @@ public class HttpParserTest
@Test
public void testResponseParse1() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
ByteBuffer buffer= BufferUtil.toBuffer(
"HTTP/1.1 304 Not-Modified\015\012"
+ "Connection: close\015\012"
+ "\015\012");
ByteBuffer buffer= BufferUtil.allocate(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
parser.parseNext(buffer);
assertEquals("HTTP/1.1", f0);
assertEquals("304", f1);
assertEquals("Not-Modified", f2);
@ -390,8 +332,7 @@ public class HttpParserTest
@Test
public void testResponseParse2() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
ByteBuffer buffer= BufferUtil.toBuffer(
"HTTP/1.1 204 No-Content\015\012"
+ "Header: value\015\012"
+ "\015\012"
@ -400,19 +341,21 @@ public class HttpParserTest
+ "Content-Type: text/plain\015\012"
+ "\015\012"
+ "0123456789\015\012");
ByteBuffer buffer= BufferUtil.allocate(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
parser.parseNext(buffer);
assertEquals("HTTP/1.1", f0);
assertEquals("204", f1);
assertEquals("No-Content", f2);
assertTrue(headerCompleted);
assertTrue(messageCompleted);
parser.parse();
parser.setPersistent(true);
parser.reset();
parser.parseNext(buffer);
parser.onEOF();
assertEquals("HTTP/1.1", f0);
assertEquals("200", f1);
assertEquals("Correct", f2);
@ -425,19 +368,16 @@ public class HttpParserTest
@Test
public void testResponseParse3() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
ByteBuffer buffer= BufferUtil.toBuffer(
"HTTP/1.1 200\015\012"
+ "Content-Length: 10\015\012"
+ "Content-Type: text/plain\015\012"
+ "\015\012"
+ "0123456789\015\012");
ByteBuffer buffer= BufferUtil.allocate(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
parser.parseNext(buffer);
assertEquals("HTTP/1.1", f0);
assertEquals("200", f1);
assertEquals(null, f2);
@ -449,19 +389,16 @@ public class HttpParserTest
@Test
public void testResponseParse4() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
ByteBuffer buffer= BufferUtil.toBuffer(
"HTTP/1.1 200 \015\012"
+ "Content-Length: 10\015\012"
+ "Content-Type: text/plain\015\012"
+ "\015\012"
+ "0123456789\015\012");
ByteBuffer buffer= BufferUtil.allocate(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
parser.parseNext(buffer);
assertEquals("HTTP/1.1", f0);
assertEquals("200", f1);
assertEquals(null, f2);
@ -473,17 +410,14 @@ public class HttpParserTest
@Test
public void testResponse304WithContentLength() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
ByteBuffer buffer= BufferUtil.toBuffer(
"HTTP/1.1 304 found\015\012"
+ "Content-Length: 10\015\012"
+ "\015\012");
ByteBuffer buffer= BufferUtil.allocate(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
parser.parseNext(buffer);
assertEquals("HTTP/1.1", f0);
assertEquals("304", f1);
assertEquals("found", f2);
@ -495,8 +429,7 @@ public class HttpParserTest
@Test
public void testSeekEOF() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
ByteBuffer buffer= BufferUtil.toBuffer(
"HTTP/1.1 200 OK\015\012"
+ "Content-Length: 0\015\012"
+ "Connection: close\015\012"
@ -504,14 +437,11 @@ public class HttpParserTest
+ "\015\012" // extra CRLF ignored
+ "HTTP/1.1 400 OK\015\012"); // extra data causes close
ByteBuffer buffer= BufferUtil.allocate(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
HttpParser parser= new HttpParser((HttpParser.ResponseHandler)handler);
parser.parse();
parser.parseNext(buffer);
assertEquals("HTTP/1.1", f0);
assertEquals("200", f1);
assertEquals("OK", f2);
@ -538,15 +468,19 @@ public class HttpParserTest
private HttpFields fields;
private boolean request;
public void content(ByteBuffer ref)
public boolean content(ByteBuffer ref)
{
if (_content==null)
_content="";
_content= _content + BufferUtil.toString(ref,StringUtil.__UTF8_CHARSET);
String c = BufferUtil.toString(ref,StringUtil.__UTF8_CHARSET);
//System.err.println("content '"+c+"'");
_content= _content + c;
return false;
}
public void startRequest(String tok0, String tok1, String tok2)
public boolean startRequest(String tok0, String tok1, String tok2)
{
//System.err.println("request "+tok0+" "+tok1+" "+tok2);
request=true;
h= -1;
hdr= new String[9];
@ -558,16 +492,20 @@ public class HttpParserTest
fields=new HttpFields();
messageCompleted = false;
headerCompleted = false;
return false;
}
public void parsedHeader(String name, String value)
public boolean parsedHeader(String name, String value)
{
//System.err.println("header "+name+": "+value);
hdr[++h]= name;
val[h]= value;
return false;
}
public void headerComplete()
public boolean headerComplete()
{
//System.err.println("headerComplete");
_content= null;
String s0=fields.toString();
String s1=fields.toString();
@ -579,14 +517,17 @@ public class HttpParserTest
}
headerCompleted = true;
return false;
}
public void messageComplete(long contentLength)
public boolean messageComplete(long contentLength)
{
//System.err.println("messageComplete");
messageCompleted = true;
return true;
}
public void startResponse(String version, int status, String reason)
public boolean startResponse(String version, int status, String reason)
{
request=false;
f0 = version.toString();
@ -599,11 +540,13 @@ public class HttpParserTest
messageCompleted = false;
headerCompleted = false;
return false;
}
@Override
public void earlyEOF()
public boolean earlyEOF()
{
return true;
}
}
}

View File

@ -16,6 +16,8 @@ package org.eclipse.jetty.util;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import javax.swing.text.Position;
/* ------------------------------------------------------------------------------- */
/**
@ -179,11 +181,11 @@ public class BufferUtil
byte[] array = buffer.hasArray()?buffer.array():null;
if (array == null)
{
ByteBuffer slice=buffer.slice();
slice.position(position);
slice.limit(position+length);
ByteBuffer ro=buffer.asReadOnlyBuffer();
ro.position(position);
ro.limit(position+length);
byte[] to = new byte[length];
slice.get(to);
ro.get(to);
return new String(to,0,to.length,charset);
}
return new String(array,buffer.arrayOffset()+position,length,charset);
@ -461,6 +463,73 @@ public class BufferUtil
return ByteBuffer.wrap(s.getBytes(charset));
}
public static String toDetailString(ByteBuffer buffer)
{
StringBuilder buf = new StringBuilder();
buf.append("[p=");
buf.append(buffer.position());
buf.append(",l=");
buf.append(buffer.limit());
buf.append(",c=");
buf.append(buffer.capacity());
buf.append("]={");
for (int i=0;i<buffer.position();i++)
{
char c=(char)buffer.get(i);
if (c>=' ')
buf.append(c);
else if (c=='\r'||c=='\n')
buf.append('|');
else
buf.append('?');
if (i==16&&buffer.position()>32)
{
buf.append("...");
i=buffer.position()-16;
}
}
buf.append("}{");
for (int i=buffer.position();i<buffer.limit();i++)
{
char c=(char)buffer.get(i);
if (c>=' ')
buf.append(c);
else if (c=='\r'||c=='\n')
buf.append('|');
else
buf.append('?');
if (i==buffer.position()+16&&buffer.limit()>buffer.position()+32)
{
buf.append("...");
i=buffer.limit()-16;
}
}
buf.append("}{");
int limit=buffer.limit();
buffer.limit(buffer.capacity());
for (int i=limit;i<buffer.capacity();i++)
{
char c=(char)buffer.get(i);
if (c>=' ')
buf.append(c);
else if (c=='\r'||c=='\n')
buf.append('|');
else
buf.append('?');
if (i==limit+16&&buffer.capacity()>limit+32)
{
buf.append("...");
i=buffer.capacity()-16;
}
}
buffer.limit(limit);
buf.append("}");
return buf.toString();
}
private final static int[] decDivisors =
{ 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1 };

View File

@ -111,44 +111,6 @@ public class StringMap<O> extends AbstractMap<String,O>
return _caseInsensitive;
}
/* ------------------------------------------------------------ */
public static void main(String[] arg)
{
StringMap<String> map = new StringMap<>();
System.err.println("null="+map.get("nothing"));
map.put("foo","1");
System.err.println("null="+map.get("nothing"));
System.err.println("null="+map.get("foobar"));
System.err.println("1="+map.get("foo"));
System.err.println("null="+map.get("fo"));
map.put("foobar","2");
System.err.println("null="+map.get("nothing"));
System.err.println("2="+map.get("foobar"));
System.err.println("1="+map.get("foo"));
System.err.println("null="+map.get("fo"));
System.err.println("null="+map.get("foob"));
map.put("foob","3");
System.err.println("null="+map.get("nothing"));
System.err.println("2="+map.get("foobar"));
System.err.println("3="+map.get("foob"));
System.err.println("1="+map.get("foo"));
map.put("fool","4");
map.put("fop","5");
map.put("fred","6");
System.err.println("2="+map.get(BufferUtil.toBuffer("foobar")));
System.err.println("3="+map.get(BufferUtil.toBuffer("foob")));
System.err.println("1="+map.get(BufferUtil.toBuffer("foo")));
}
/* ------------------------------------------------------------ */
@Override
public O put(String key, O value)
@ -178,10 +140,11 @@ public class StringMap<O> extends AbstractMap<String,O>
/* ------------------------------------------------------------ */
public O get(ByteBuffer buffer, int position, int length)
{
ByteBuffer slice=buffer.slice();
slice.position(position);
slice.limit(position+length);
return _map.get(slice);
ByteBuffer ro=buffer.asReadOnlyBuffer();
ro.limit(ro.capacity());
ro.position(position);
ro.limit(position+length);
return _map.get(ro);
}