mirror of
https://github.com/jetty/jetty.project.git
synced 2025-02-28 19:09:10 +00:00
jetty-9 HttpParser tests passing
This commit is contained in:
parent
9c1d3ff0b3
commit
2659d87868
@ -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)
|
||||
{
|
||||
|
@ -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,48 +167,33 @@ 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;
|
||||
while (_state != State.END && buffer.hasRemaining())
|
||||
{
|
||||
int remaining=buffer.remaining();
|
||||
parseNext(buffer);
|
||||
if (remaining==buffer.remaining())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
* 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())
|
||||
{
|
||||
progress |= parseNext(buffer);
|
||||
}
|
||||
return progress;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------------- */
|
||||
/**
|
||||
@ -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);
|
||||
_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())
|
||||
while (_state.ordinal()<State.END.ordinal() && buffer.hasRemaining() && !at_next)
|
||||
{
|
||||
if (last!=_state)
|
||||
{
|
||||
progress++;
|
||||
last=_state;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
@ -153,13 +153,57 @@ public class HttpParserTest
|
||||
}
|
||||
|
||||
@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,8 +233,7 @@ public class HttpParserTest
|
||||
@Test
|
||||
public void testMultiParse() throws Exception
|
||||
{
|
||||
StringEndPoint io=new StringEndPoint();
|
||||
io.setInput(
|
||||
ByteBuffer buffer= BufferUtil.toBuffer(
|
||||
"GET /mp HTTP/1.0\015\012"
|
||||
+ "Connection: Keep-Alive\015\012"
|
||||
+ "Header1: value1\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);
|
||||
@ -228,7 +268,8 @@ public class HttpParserTest
|
||||
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"
|
||||
@ -505,13 +438,10 @@ public class HttpParserTest
|
||||
+ "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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 };
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user