jetty-9 work in progress on moving aggregation out of HttpChannel
This commit is contained in:
parent
9080882900
commit
325bfc290d
|
@ -42,18 +42,15 @@ public class HttpGenerator
|
|||
new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0,HttpStatus.INTERNAL_SERVER_ERROR_500,null,false);
|
||||
|
||||
// states
|
||||
public enum Action { FLUSH, COMPLETE, PREPARE }
|
||||
public enum State { START, COMMITTING, COMMITTING_COMPLETING, COMMITTED, COMPLETING, COMPLETING_1XX, END }
|
||||
public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,NEED_BUFFER,FLUSH,FLUSH_CONTENT,OK,SHUTDOWN_OUT}
|
||||
public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END }
|
||||
public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,FLUSH,CONTINUE,SHUTDOWN_OUT,DONE}
|
||||
|
||||
// other statics
|
||||
public static final int CHUNK_SIZE = 12;
|
||||
|
||||
|
||||
private State _state = State.START;
|
||||
private EndOfContent _content = EndOfContent.UNKNOWN_CONTENT;
|
||||
private EndOfContent _endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
||||
|
||||
private int _largeContent=4096;
|
||||
private long _contentPrepared = 0;
|
||||
private boolean _noContent = false;
|
||||
private Boolean _persistent = null;
|
||||
|
@ -79,7 +76,7 @@ public class HttpGenerator
|
|||
public void reset()
|
||||
{
|
||||
_state = State.START;
|
||||
_content = EndOfContent.UNKNOWN_CONTENT;
|
||||
_endOfContent = EndOfContent.UNKNOWN_CONTENT;
|
||||
_noContent=false;
|
||||
_persistent = null;
|
||||
_contentPrepared = 0;
|
||||
|
@ -118,7 +115,7 @@ public class HttpGenerator
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isComplete()
|
||||
public boolean isEnd()
|
||||
{
|
||||
return _state == State.END;
|
||||
}
|
||||
|
@ -132,19 +129,7 @@ public class HttpGenerator
|
|||
/* ------------------------------------------------------------ */
|
||||
public boolean isChunking()
|
||||
{
|
||||
return _content==EndOfContent.CHUNKED_CONTENT;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getLargeContent()
|
||||
{
|
||||
return _largeContent;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setLargeContent(int largeContent)
|
||||
{
|
||||
_largeContent = largeContent;
|
||||
return _endOfContent==EndOfContent.CHUNKED_CONTENT;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -179,298 +164,292 @@ public class HttpGenerator
|
|||
{
|
||||
_persistent=false;
|
||||
_state=State.END;
|
||||
_content=null;
|
||||
_endOfContent=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Result generate(Info info, ByteBuffer header, ByteBuffer chunk, ByteBuffer buffer, ByteBuffer content, Action action)
|
||||
public Result generateRequest(RequestInfo info, ByteBuffer headerOrChunk, ByteBuffer content, boolean last)
|
||||
{
|
||||
Result result = Result.OK;
|
||||
if (_state==State.END)
|
||||
return result;
|
||||
if (action==null)
|
||||
action=Action.PREPARE;
|
||||
|
||||
// Do we have content to handle
|
||||
if (BufferUtil.hasContent(content))
|
||||
switch(_state)
|
||||
{
|
||||
// Do we have too much content?
|
||||
if (_content==EndOfContent.CONTENT_LENGTH && info!=null && info.getContentLength()>=0 && content.remaining()>(info.getContentLength()-_contentPrepared))
|
||||
case START:
|
||||
{
|
||||
LOG.warn("Content truncated. Info.getContentLength()=="+info.getContentLength()+" prepared="+_contentPrepared+" content="+content.remaining(),new Throwable());
|
||||
content.limit(content.position()+(int)(info.getContentLength()-_contentPrepared));
|
||||
}
|
||||
if (info==null)
|
||||
return Result.NEED_INFO;
|
||||
|
||||
// Can we do a direct flush
|
||||
if (BufferUtil.isEmpty(buffer) && content.remaining()>_largeContent)
|
||||
{
|
||||
if (isCommitted())
|
||||
// Do we need a request header
|
||||
if (headerOrChunk==null || headerOrChunk.capacity()<=CHUNK_SIZE)
|
||||
return Result.NEED_HEADER;
|
||||
|
||||
// If we have not been told our persistence, set the default
|
||||
if (_persistent==null)
|
||||
_persistent=(info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
|
||||
|
||||
// prepare the header
|
||||
ByteBuffer header = headerOrChunk;
|
||||
int pos=BufferUtil.flipToFill(header);
|
||||
try
|
||||
{
|
||||
if (isChunking())
|
||||
{
|
||||
if (chunk==null)
|
||||
return Result.NEED_CHUNK;
|
||||
BufferUtil.clearToFill(chunk);
|
||||
prepareChunk(chunk,content.remaining());
|
||||
BufferUtil.flipToFlush(chunk,0);
|
||||
}
|
||||
_contentPrepared+=content.remaining();
|
||||
return Result.FLUSH_CONTENT;
|
||||
}
|
||||
// generate ResponseLine
|
||||
generateRequestLine(info,header);
|
||||
|
||||
_state=action==Action.COMPLETE?State.COMMITTING_COMPLETING:State.COMMITTING;
|
||||
result=Result.FLUSH_CONTENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// we copy content to buffer
|
||||
// if we don't have one, we need one
|
||||
if (buffer==null)
|
||||
return Result.NEED_BUFFER;
|
||||
|
||||
// Copy the content
|
||||
_contentPrepared+=BufferUtil.append(content,buffer);
|
||||
|
||||
// are we full?
|
||||
if (BufferUtil.isFull(buffer))
|
||||
{
|
||||
if (isCommitted())
|
||||
{
|
||||
if (isChunking())
|
||||
{
|
||||
if (chunk==null)
|
||||
return Result.NEED_CHUNK;
|
||||
BufferUtil.clearToFill(chunk);
|
||||
prepareChunk(chunk,buffer.remaining());
|
||||
BufferUtil.flipToFlush(chunk,0);
|
||||
}
|
||||
return Result.FLUSH;
|
||||
}
|
||||
_state=action==Action.COMPLETE?State.COMMITTING_COMPLETING:State.COMMITTING;
|
||||
result=Result.FLUSH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the actions
|
||||
if (result==Result.OK)
|
||||
{
|
||||
switch(action)
|
||||
{
|
||||
case COMPLETE:
|
||||
if (!isCommitted())
|
||||
_state=State.COMMITTING_COMPLETING;
|
||||
else if (_state==State.COMMITTED)
|
||||
_state=State.COMPLETING;
|
||||
result=BufferUtil.hasContent(buffer)?Result.FLUSH:Result.OK;
|
||||
break;
|
||||
case FLUSH:
|
||||
if (!isCommitted())
|
||||
_state=State.COMMITTING;
|
||||
result=BufferUtil.hasContent(buffer)?Result.FLUSH:Result.OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// flip header if we have one
|
||||
final int pos=header==null?-1:BufferUtil.flipToFill(header);
|
||||
try
|
||||
{
|
||||
// handle by state
|
||||
switch (_state)
|
||||
{
|
||||
case START:
|
||||
return Result.OK;
|
||||
|
||||
case COMMITTING:
|
||||
case COMMITTING_COMPLETING:
|
||||
{
|
||||
if (info==null)
|
||||
return Result.NEED_INFO;
|
||||
|
||||
if (info instanceof RequestInfo)
|
||||
{
|
||||
if (header==null || header.capacity()<=CHUNK_SIZE)
|
||||
return Result.NEED_HEADER;
|
||||
|
||||
if(info.getHttpVersion()==HttpVersion.HTTP_0_9)
|
||||
{
|
||||
_noContent=true;
|
||||
generateRequestLine((RequestInfo)info,header);
|
||||
_state = State.END;
|
||||
return Result.OK;
|
||||
}
|
||||
_persistent=true;
|
||||
generateRequestLine((RequestInfo)info,header);
|
||||
}
|
||||
if (info.getHttpVersion()==HttpVersion.HTTP_0_9)
|
||||
_noContent=true;
|
||||
else
|
||||
generateHeaders(info,header,content,last);
|
||||
|
||||
// handle the content.
|
||||
int len = BufferUtil.length(content);
|
||||
if (len>0)
|
||||
{
|
||||
// Responses
|
||||
|
||||
// Do we need a response header?
|
||||
if (info.getHttpVersion() == HttpVersion.HTTP_0_9)
|
||||
{
|
||||
_persistent = false;
|
||||
_content=EndOfContent.EOF_CONTENT;
|
||||
_state = State.COMMITTED;
|
||||
if (result==Result.FLUSH_CONTENT)
|
||||
_contentPrepared+=content.remaining();
|
||||
return result;
|
||||
}
|
||||
|
||||
// yes we need a response header
|
||||
if (header==null || header.capacity()<=CHUNK_SIZE)
|
||||
return Result.NEED_HEADER;
|
||||
|
||||
// Are we persistent by default?
|
||||
if (_persistent==null)
|
||||
_persistent=(info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
|
||||
|
||||
generateResponseLine(((ResponseInfo)info),header);
|
||||
|
||||
// Handle 1xx
|
||||
int status=((ResponseInfo)info).getStatus();
|
||||
if (status>=100 && status<200 )
|
||||
{
|
||||
_noContent=true;
|
||||
|
||||
if (status!=HttpStatus.SWITCHING_PROTOCOLS_101 )
|
||||
{
|
||||
header.put(HttpTokens.CRLF);
|
||||
_state=State.COMPLETING_1XX;
|
||||
return Result.FLUSH;
|
||||
}
|
||||
}
|
||||
else if (status==HttpStatus.NO_CONTENT_204 || status==HttpStatus.NOT_MODIFIED_304)
|
||||
{
|
||||
_noContent=true;
|
||||
}
|
||||
_contentPrepared+=len;
|
||||
if (isChunking())
|
||||
prepareChunk(header,len);
|
||||
}
|
||||
|
||||
boolean completing=action==Action.COMPLETE||_state==State.COMMITTING_COMPLETING;
|
||||
generateHeaders(info,header,content,completing);
|
||||
_state = completing?State.COMPLETING:State.COMMITTED;
|
||||
|
||||
// handle result
|
||||
switch(result)
|
||||
{
|
||||
case FLUSH:
|
||||
if (isChunking())
|
||||
prepareChunk(header,buffer.remaining());
|
||||
break;
|
||||
case FLUSH_CONTENT:
|
||||
if (isChunking())
|
||||
prepareChunk(header,content.remaining());
|
||||
_contentPrepared+=content.remaining();
|
||||
break;
|
||||
case OK:
|
||||
if (BufferUtil.hasContent(buffer))
|
||||
{
|
||||
if (isChunking())
|
||||
prepareChunk(header,buffer.remaining());
|
||||
}
|
||||
result=Result.FLUSH;
|
||||
}
|
||||
|
||||
return result;
|
||||
_state = last?State.COMPLETING:State.COMMITTED;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
if (e instanceof BufferOverflowException)
|
||||
LOG.warn("Response header too large");
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
BufferUtil.flipToFlush(header,pos);
|
||||
}
|
||||
|
||||
|
||||
case COMMITTED:
|
||||
return Result.OK;
|
||||
|
||||
|
||||
case COMPLETING:
|
||||
// handle content with commit
|
||||
|
||||
return Result.FLUSH;
|
||||
}
|
||||
|
||||
case COMMITTED:
|
||||
{
|
||||
int len = BufferUtil.length(content);
|
||||
|
||||
if (len>0)
|
||||
{
|
||||
// Do we need a chunk buffer?
|
||||
if (isChunking())
|
||||
{
|
||||
if (chunk==null)
|
||||
// Do we need a chunk buffer?
|
||||
if (headerOrChunk==null || headerOrChunk.capacity()>CHUNK_SIZE)
|
||||
return Result.NEED_CHUNK;
|
||||
ByteBuffer chunk = headerOrChunk;
|
||||
BufferUtil.clearToFill(chunk);
|
||||
|
||||
switch(result)
|
||||
{
|
||||
case FLUSH:
|
||||
prepareChunk(chunk,buffer.remaining());
|
||||
break;
|
||||
case FLUSH_CONTENT:
|
||||
prepareChunk(chunk,content.remaining());
|
||||
break;
|
||||
case OK:
|
||||
if (BufferUtil.hasContent(buffer))
|
||||
{
|
||||
result=Result.FLUSH;
|
||||
prepareChunk(chunk,buffer.remaining());
|
||||
}
|
||||
else
|
||||
{
|
||||
result=Result.FLUSH;
|
||||
_state=State.END;
|
||||
prepareChunk(chunk,0);
|
||||
}
|
||||
}
|
||||
prepareChunk(chunk,len);
|
||||
BufferUtil.flipToFlush(chunk,0);
|
||||
}
|
||||
else if (result==Result.OK)
|
||||
{
|
||||
if (BufferUtil.hasContent(buffer))
|
||||
result=Result.FLUSH;
|
||||
else
|
||||
{
|
||||
if (!Boolean.TRUE.equals(_persistent))
|
||||
result=Result.SHUTDOWN_OUT;
|
||||
_state=State.END;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
case COMPLETING_1XX:
|
||||
reset();
|
||||
return Result.OK;
|
||||
|
||||
case END:
|
||||
return Boolean.TRUE.equals(_persistent) ? Result.OK : Result.SHUTDOWN_OUT;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
if (header!=null && info instanceof ResponseInfo)
|
||||
{
|
||||
if (e instanceof BufferOverflowException)
|
||||
{
|
||||
LOG.warn("Response header too large");
|
||||
LOG.debug(e);
|
||||
_contentPrepared+=len;
|
||||
}
|
||||
else
|
||||
LOG.warn(e);
|
||||
_state=State.COMPLETING;
|
||||
// We were probably trying to generate a header, so let's make it a 500 instead
|
||||
header.clear();
|
||||
_persistent=false;
|
||||
generateResponseLine(RESPONSE_500_INFO,header);
|
||||
generateHeaders(RESPONSE_500_INFO,header,null,true);
|
||||
if (buffer!=null)
|
||||
BufferUtil.clear(buffer);
|
||||
if (chunk!=null)
|
||||
BufferUtil.clear(chunk);
|
||||
if (content!=null)
|
||||
BufferUtil.clear(content);
|
||||
return Result.FLUSH;
|
||||
|
||||
if (last)
|
||||
{
|
||||
_state=State.COMPLETING;
|
||||
return len>0?Result.FLUSH:Result.CONTINUE;
|
||||
}
|
||||
|
||||
return len>0?Result.FLUSH:Result.DONE;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (pos>=0)
|
||||
BufferUtil.flipToFlush(header,pos);
|
||||
|
||||
case COMPLETING:
|
||||
{
|
||||
if (BufferUtil.hasContent(content))
|
||||
throw new IllegalStateException(); // Can't pass new content in COMPLETING state
|
||||
|
||||
if (isChunking())
|
||||
{
|
||||
// Do we need a chunk buffer?
|
||||
if (headerOrChunk==null || headerOrChunk.capacity()>CHUNK_SIZE)
|
||||
return Result.NEED_CHUNK;
|
||||
ByteBuffer chunk=headerOrChunk;
|
||||
BufferUtil.clearToFill(chunk);
|
||||
prepareChunk(chunk,0);
|
||||
BufferUtil.flipToFlush(chunk,0);
|
||||
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
|
||||
return Result.FLUSH;
|
||||
}
|
||||
|
||||
_state=State.END;
|
||||
return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT;
|
||||
}
|
||||
|
||||
case END:
|
||||
if (BufferUtil.hasContent(content))
|
||||
throw new IllegalStateException(); // Can't pass new content in END state
|
||||
return Result.DONE;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Result generateResponse(ResponseInfo info, ByteBuffer headerOrChunk, ByteBuffer content, boolean last)
|
||||
{
|
||||
switch(_state)
|
||||
{
|
||||
case START:
|
||||
{
|
||||
|
||||
if (info==null)
|
||||
return Result.NEED_INFO;
|
||||
|
||||
// Handle 0.9
|
||||
if (info.getHttpVersion() == HttpVersion.HTTP_0_9)
|
||||
{
|
||||
_persistent = false;
|
||||
_endOfContent=EndOfContent.EOF_CONTENT;
|
||||
if (BufferUtil.hasContent(content))
|
||||
_contentPrepared+=content.remaining();
|
||||
_state = last?State.COMPLETING:State.COMMITTED;
|
||||
return Result.FLUSH;
|
||||
}
|
||||
|
||||
// Do we need a response header
|
||||
if (headerOrChunk==null || headerOrChunk.capacity()<=CHUNK_SIZE)
|
||||
return Result.NEED_HEADER;
|
||||
|
||||
// If we have not been told our persistence, set the default
|
||||
if (_persistent==null)
|
||||
_persistent=(info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
|
||||
|
||||
// prepare the header
|
||||
ByteBuffer header = headerOrChunk;
|
||||
int pos=BufferUtil.flipToFill(header);
|
||||
try
|
||||
{
|
||||
// generate ResponseLine
|
||||
generateResponseLine(info,header);
|
||||
|
||||
// Handle 1xx and no content responses
|
||||
int status=info.getStatus();
|
||||
if (status>=100 && status<200 )
|
||||
{
|
||||
_noContent=true;
|
||||
|
||||
if (status!=HttpStatus.SWITCHING_PROTOCOLS_101 )
|
||||
{
|
||||
header.put(HttpTokens.CRLF);
|
||||
_state=State.COMPLETING_1XX;
|
||||
return Result.FLUSH;
|
||||
}
|
||||
}
|
||||
else if (status==HttpStatus.NO_CONTENT_204 || status==HttpStatus.NOT_MODIFIED_304)
|
||||
{
|
||||
_noContent=true;
|
||||
}
|
||||
|
||||
generateHeaders(info,header,content,last);
|
||||
|
||||
// handle the content.
|
||||
int len = BufferUtil.length(content);
|
||||
if (len>0)
|
||||
{
|
||||
_contentPrepared+=len;
|
||||
if (isChunking() && !info.isHead())
|
||||
prepareChunk(header,len);
|
||||
}
|
||||
_state = last?State.COMPLETING:State.COMMITTED;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
if (e instanceof BufferOverflowException)
|
||||
{
|
||||
LOG.warn("Response header too large");
|
||||
LOG.debug(e);
|
||||
}
|
||||
else
|
||||
LOG.warn(e);
|
||||
|
||||
// We were probably trying to generate a header, so let's make it a 500 instead
|
||||
_persistent=false;
|
||||
BufferUtil.clearToFill(header);
|
||||
generateResponseLine(RESPONSE_500_INFO,header);
|
||||
generateHeaders(RESPONSE_500_INFO,header,null,true);
|
||||
_state=State.COMPLETING;
|
||||
}
|
||||
finally
|
||||
{
|
||||
BufferUtil.flipToFlush(header,pos);
|
||||
}
|
||||
|
||||
return Result.FLUSH;
|
||||
}
|
||||
|
||||
case COMMITTED:
|
||||
{
|
||||
int len = BufferUtil.length(content);
|
||||
|
||||
// handle the content.
|
||||
if (len>0)
|
||||
{
|
||||
// Do we need a chunk buffer?
|
||||
if (isChunking() && (headerOrChunk==null || headerOrChunk.capacity()>CHUNK_SIZE))
|
||||
return Result.NEED_CHUNK;
|
||||
|
||||
ByteBuffer chunk = headerOrChunk;
|
||||
|
||||
_contentPrepared+=len;
|
||||
if (isChunking())
|
||||
{
|
||||
BufferUtil.clearToFill(chunk);
|
||||
prepareChunk(chunk,len);
|
||||
BufferUtil.flipToFlush(chunk,0);
|
||||
}
|
||||
}
|
||||
|
||||
if (last)
|
||||
{
|
||||
_state=State.COMPLETING;
|
||||
return len>0?Result.FLUSH:Result.CONTINUE;
|
||||
}
|
||||
return len>0?Result.FLUSH:Result.DONE;
|
||||
|
||||
}
|
||||
|
||||
case COMPLETING_1XX:
|
||||
{
|
||||
reset();
|
||||
return Result.DONE;
|
||||
}
|
||||
|
||||
case COMPLETING:
|
||||
{
|
||||
if (BufferUtil.hasContent(content))
|
||||
throw new IllegalStateException(); // Can't pass new content in COMPLETING state
|
||||
|
||||
if (isChunking())
|
||||
{
|
||||
// Do we need a chunk buffer?
|
||||
if (headerOrChunk==null || headerOrChunk.capacity()>CHUNK_SIZE)
|
||||
return Result.NEED_CHUNK;
|
||||
ByteBuffer chunk=headerOrChunk;
|
||||
|
||||
// Write the last chunk
|
||||
BufferUtil.clearToFill(chunk);
|
||||
prepareChunk(chunk,0);
|
||||
BufferUtil.flipToFlush(chunk,0);
|
||||
_endOfContent=EndOfContent.UNKNOWN_CONTENT;
|
||||
return Result.FLUSH;
|
||||
}
|
||||
|
||||
_state=State.END;
|
||||
|
||||
return Boolean.TRUE.equals(_persistent)?Result.DONE:Result.SHUTDOWN_OUT;
|
||||
}
|
||||
|
||||
case END:
|
||||
if (BufferUtil.hasContent(content))
|
||||
throw new IllegalStateException(); // Can't pass new content in END state
|
||||
return Result.DONE;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void prepareChunk(ByteBuffer chunk, int remaining)
|
||||
{
|
||||
|
@ -585,13 +564,13 @@ public class HttpGenerator
|
|||
case CONTENT_LENGTH:
|
||||
// handle specially below
|
||||
if (_info.getContentLength()>=0)
|
||||
_content=EndOfContent.CONTENT_LENGTH;
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
break;
|
||||
|
||||
case CONTENT_TYPE:
|
||||
{
|
||||
if (field.getValue().startsWith(MimeTypes.Type.MULTIPART_BYTERANGES.toString()))
|
||||
_content=EndOfContent.SELF_DEFINING_CONTENT;
|
||||
_endOfContent=EndOfContent.SELF_DEFINING_CONTENT;
|
||||
|
||||
// write the field to the header
|
||||
content_type=true;
|
||||
|
@ -647,8 +626,8 @@ public class HttpGenerator
|
|||
if (_response!=null)
|
||||
{
|
||||
_persistent=false;
|
||||
if (_content == EndOfContent.UNKNOWN_CONTENT)
|
||||
_content=EndOfContent.EOF_CONTENT;
|
||||
if (_endOfContent == EndOfContent.UNKNOWN_CONTENT)
|
||||
_endOfContent=EndOfContent.EOF_CONTENT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -715,7 +694,7 @@ public class HttpGenerator
|
|||
// 5. multipart/byteranges
|
||||
// 6. close
|
||||
int status=_response!=null?_response.getStatus():-1;
|
||||
switch (_content)
|
||||
switch (_endOfContent)
|
||||
{
|
||||
case UNKNOWN_CONTENT:
|
||||
// It may be that we have no _content, or perhaps _content just has not been
|
||||
|
@ -723,11 +702,11 @@ public class HttpGenerator
|
|||
|
||||
// Response known not to have a body
|
||||
if (_contentPrepared == 0 && _response!=null && (status < 200 || status == 204 || status == 304))
|
||||
_content=EndOfContent.NO_CONTENT;
|
||||
_endOfContent=EndOfContent.NO_CONTENT;
|
||||
else if (_info.getContentLength()>0)
|
||||
{
|
||||
// we have been given a content length
|
||||
_content=EndOfContent.CONTENT_LENGTH;
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
long content_length = _info.getContentLength();
|
||||
if ((_response!=null || content_length>0 || content_type ) && !_noContent)
|
||||
{
|
||||
|
@ -740,7 +719,7 @@ public class HttpGenerator
|
|||
else if (last)
|
||||
{
|
||||
// we have seen all the _content there is, so we can be content-length limited.
|
||||
_content=EndOfContent.CONTENT_LENGTH;
|
||||
_endOfContent=EndOfContent.CONTENT_LENGTH;
|
||||
long content_length = _contentPrepared+BufferUtil.length(content);
|
||||
|
||||
// Do we need to tell the headers about it
|
||||
|
@ -754,10 +733,10 @@ public class HttpGenerator
|
|||
else
|
||||
{
|
||||
// No idea, so we must assume that a body is coming
|
||||
_content = (!isPersistent() || _info.getHttpVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal() ) ? EndOfContent.EOF_CONTENT : EndOfContent.CHUNKED_CONTENT;
|
||||
if (_response!=null && _content==EndOfContent.EOF_CONTENT)
|
||||
_endOfContent = (!isPersistent() || _info.getHttpVersion().ordinal() < HttpVersion.HTTP_1_1.ordinal() ) ? EndOfContent.EOF_CONTENT : EndOfContent.CHUNKED_CONTENT;
|
||||
if (_response!=null && _endOfContent==EndOfContent.EOF_CONTENT)
|
||||
{
|
||||
_content=EndOfContent.NO_CONTENT;
|
||||
_endOfContent=EndOfContent.NO_CONTENT;
|
||||
_noContent=true;
|
||||
}
|
||||
}
|
||||
|
@ -808,7 +787,7 @@ public class HttpGenerator
|
|||
}
|
||||
|
||||
// Handle connection if need be
|
||||
if (_content==EndOfContent.EOF_CONTENT)
|
||||
if (_endOfContent==EndOfContent.EOF_CONTENT)
|
||||
{
|
||||
keep_alive=false;
|
||||
_persistent=false;
|
||||
|
|
|
@ -23,6 +23,8 @@ import java.io.IOException;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator.RequestInfo;
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
|
@ -172,20 +174,25 @@ public class HttpTester
|
|||
System.err.println(info);
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
ByteBuffer header=BufferUtil.allocate(8192);
|
||||
ByteBuffer buffer=BufferUtil.allocate(8192);
|
||||
ByteBuffer chunk=BufferUtil.allocate(16);
|
||||
ByteBuffer header=null;
|
||||
ByteBuffer content=_content==null?null:ByteBuffer.wrap(_content.toByteArray());
|
||||
|
||||
|
||||
loop: while(true)
|
||||
loop: while(!generator.isEnd())
|
||||
{
|
||||
HttpGenerator.Result result = generator.generate(info,header,chunk,buffer,content,HttpGenerator.Action.COMPLETE);
|
||||
HttpGenerator.Result result = info instanceof RequestInfo
|
||||
?generator.generateRequest((RequestInfo)info,header,content,true)
|
||||
:generator.generateResponse((ResponseInfo)info,header,content,true);
|
||||
switch(result)
|
||||
{
|
||||
case NEED_BUFFER:
|
||||
case NEED_HEADER:
|
||||
header=BufferUtil.allocate(8192);
|
||||
continue;
|
||||
|
||||
case NEED_CHUNK:
|
||||
header=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
continue;
|
||||
|
||||
case NEED_INFO:
|
||||
throw new IllegalStateException();
|
||||
|
||||
|
@ -195,36 +202,13 @@ public class HttpTester
|
|||
out.write(BufferUtil.toArray(header));
|
||||
BufferUtil.clear(header);
|
||||
}
|
||||
if (BufferUtil.hasContent(chunk))
|
||||
{
|
||||
out.write(BufferUtil.toArray(chunk));
|
||||
BufferUtil.clear(chunk);
|
||||
}
|
||||
if (BufferUtil.hasContent(buffer))
|
||||
{
|
||||
out.write(BufferUtil.toArray(buffer));
|
||||
BufferUtil.clear(buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case FLUSH_CONTENT:
|
||||
if (BufferUtil.hasContent(header))
|
||||
{
|
||||
out.write(BufferUtil.toArray(header));
|
||||
BufferUtil.clear(header);
|
||||
}
|
||||
if (BufferUtil.hasContent(chunk))
|
||||
{
|
||||
out.write(BufferUtil.toArray(chunk));
|
||||
BufferUtil.clear(chunk);
|
||||
}
|
||||
if (BufferUtil.hasContent(content))
|
||||
{
|
||||
out.write(BufferUtil.toArray(content));
|
||||
BufferUtil.clear(content);
|
||||
}
|
||||
break;
|
||||
case OK:
|
||||
|
||||
case SHUTDOWN_OUT:
|
||||
break loop;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import static org.junit.matchers.JUnitMatchers.containsString;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator.Action;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -55,86 +54,77 @@ public class HttpGeneratorClientTest
|
|||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
result=gen.generate(null,null,null,null,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
|
||||
result=gen.generateRequest(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
Info info = new Info("GET","/index.html");
|
||||
info.getHttpFields().add("Host","something");
|
||||
info.getHttpFields().add("User-Agent","test");
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
result=gen.generate(info,header,null,null,null,null);
|
||||
result=gen.generateRequest(info,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generateRequest(info,header,null,true);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
assertTrue(!gen.isChunking());
|
||||
String head = BufferUtil.toString(header);
|
||||
String out = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
|
||||
result=gen.generate(info,null,null,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
result=gen.generateResponse(null,null,null,false);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
assertEquals(0,gen.getContentPrepared());
|
||||
assertThat(head,containsString("GET /index.html HTTP/1.1"));
|
||||
assertThat(head,not(containsString("Content-Length")));
|
||||
assertThat(out,containsString("GET /index.html HTTP/1.1"));
|
||||
assertThat(out,not(containsString("Content-Length")));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithSmallContent() throws Exception
|
||||
public void testRequestWithContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
String out;
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer buffer=BufferUtil.allocate(8096);
|
||||
ByteBuffer content=BufferUtil.toBuffer("Hello World");
|
||||
ByteBuffer content1=BufferUtil.toBuffer(". The quick brown fox jumped over the lazy dog.");
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World. The quick brown fox jumped over the lazy dog.");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World",BufferUtil.toString(buffer));
|
||||
assertTrue(BufferUtil.isEmpty(content));
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",BufferUtil.toString(buffer));
|
||||
assertTrue(BufferUtil.isEmpty(content1));
|
||||
|
||||
result=gen.generate(null,null,null,buffer,null,Action.COMPLETE);
|
||||
result=gen.generateRequest(null,null,content0,true);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
Info info = new Info("POST","/index.html");
|
||||
info.getHttpFields().add("Host","something");
|
||||
info.getHttpFields().add("User-Agent","test");
|
||||
result=gen.generate(info,header,null,buffer,null,null);
|
||||
|
||||
result=gen.generateRequest(info,null,content0,true);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generateRequest(info,header,content0,true);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
assertTrue(!gen.isChunking());
|
||||
out = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body += BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
out+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
result=gen.generateResponse(null,null,null,false);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertThat(head,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(head,containsString("Host: something"));
|
||||
assertThat(head,containsString("Content-Length: 58"));
|
||||
assertTrue(head.endsWith("\r\n\r\n"));
|
||||
|
||||
assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",body);
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
|
||||
assertThat(out,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(out,containsString("Host: something"));
|
||||
assertThat(out,containsString("Content-Length: 58"));
|
||||
assertThat(out,containsString("Hello World. The quick brown fox jumped over the lazy dog."));
|
||||
|
||||
assertEquals(58,gen.getContentPrepared());
|
||||
}
|
||||
|
@ -142,328 +132,132 @@ public class HttpGeneratorClientTest
|
|||
@Test
|
||||
public void testRequestWithChunkedContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
String out;
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer buffer=BufferUtil.allocate(16);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World. ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog.");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content0,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World! ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content0.remaining());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content1,null);
|
||||
result=gen.generateRequest(null,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
Info info = new Info("POST","/index.html");
|
||||
info.getHttpFields().add("Host","something");
|
||||
info.getHttpFields().add("User-Agent","test");
|
||||
result=gen.generate(info,header,null,buffer,content1,null);
|
||||
|
||||
result=gen.generateRequest(info,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generateRequest(info,header,content0,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
assertTrue(gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
out = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
out+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
result=gen.generateRequest(null,header,content1,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_CHUNK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
result=gen.generate(info,null,chunk,buffer,content1,null);
|
||||
result=gen.generateRequest(null,chunk,content1,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("\r\n10\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(" quick brown fox",BufferUtil.toString(buffer));
|
||||
assertEquals(27,content1.remaining());
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(buffer);
|
||||
assertTrue(gen.isChunking());
|
||||
out+=BufferUtil.toString(chunk);
|
||||
BufferUtil.clear(chunk);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("\r\n10\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(" jumped over the",BufferUtil.toString(buffer));
|
||||
assertEquals(11,content1.remaining());
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(chunk);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("",BufferUtil.toString(chunk));
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content1.remaining());
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,null,Action.COMPLETE);
|
||||
out+=BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generateResponse(null,chunk,null,true);
|
||||
assertEquals(HttpGenerator.Result.CONTINUE,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
assertTrue(gen.isChunking());
|
||||
|
||||
result=gen.generateResponse(null,chunk,null,true);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
assertEquals("\r\nB\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(buffer);
|
||||
out+=BufferUtil.toString(chunk);
|
||||
BufferUtil.clear(chunk);
|
||||
BufferUtil.clear(buffer);
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
result=gen.generateResponse(null,chunk,null,true);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(0,buffer.remaining());
|
||||
BufferUtil.toString(chunk);
|
||||
BufferUtil.clear(chunk);
|
||||
|
||||
assertThat(out,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(out,containsString("Host: something"));
|
||||
assertThat(out,containsString("Transfer-Encoding: chunked"));
|
||||
assertThat(out,containsString("\r\nD\r\nHello World. \r\n"));
|
||||
assertThat(out,containsString("\r\n2D\r\nThe quick brown fox jumped over the lazy dog.\r\n"));
|
||||
assertThat(out,containsString("\r\n0\r\n\r\n"));
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertEquals(59,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(head,containsString("Host: something"));
|
||||
assertThat(head,not(containsString("Content-Length")));
|
||||
assertThat(head,containsString("Transfer-Encoding: chunked"));
|
||||
assertTrue(head.endsWith("\r\n\r\n10\r\n"));
|
||||
assertThat(body,containsString("dog"));
|
||||
assertEquals(58,gen.getContentPrepared());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithLargeChunkedContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello Cruel World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
gen.setLargeContent(8);
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
|
||||
Info info = new Info("POST","/index.html");
|
||||
info.getHttpFields().add("Host","something");
|
||||
info.getHttpFields().add("User-Agent","test");
|
||||
result=gen.generate(info,header,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertTrue(gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generate(info,header,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
result=gen.generate(info,null,null,null,content1,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_CHUNK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
result=gen.generate(info,null,chunk,null,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("\r\n2E\r\n",BufferUtil.toString(chunk));
|
||||
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generate(info,null,chunk,null,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk));
|
||||
BufferUtil.toString(chunk);
|
||||
|
||||
result=gen.generate(info,null,chunk,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertEquals(65,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(head,containsString("Host: something"));
|
||||
assertThat(head,not(containsString("Content-Length")));
|
||||
assertThat(head,containsString("Transfer-Encoding: chunked"));
|
||||
assertTrue(head.endsWith("\r\n\r\n13\r\n"));
|
||||
assertThat(body,containsString("dog"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRequestWithKnownContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
String out;
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer buffer=BufferUtil.allocate(16);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World. ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog.");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
|
||||
result=gen.generateRequest(null,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content0,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
Info info = new Info("POST","/index.html",58);
|
||||
info.getHttpFields().add("Host","something");
|
||||
info.getHttpFields().add("User-Agent","test");
|
||||
|
||||
result=gen.generateRequest(info,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World! ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content0.remaining());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
|
||||
Info info = new Info("POST","/index.html",59);
|
||||
info.getHttpFields().add("Host","something");
|
||||
info.getHttpFields().add("User-Agent","test");
|
||||
info.getHttpFields().add("Content-Length","59");
|
||||
result=gen.generate(info,header,null,buffer,content1,null);
|
||||
result=gen.generateRequest(info,header,content0,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals(" quick brown fox",BufferUtil.toString(buffer));
|
||||
assertEquals(27,content1.remaining());
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals(" jumped over the",BufferUtil.toString(buffer));
|
||||
assertEquals(11,content1.remaining());
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content1.remaining());
|
||||
|
||||
result=gen.generate(info,null,null,buffer,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
assertEquals(0,buffer.remaining());
|
||||
|
||||
assertEquals(59,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(head,containsString("Host: something"));
|
||||
assertThat(head,containsString("Content-Length: 59"));
|
||||
assertThat(head,not(containsString("chunked")));
|
||||
assertTrue(head.endsWith("\r\n\r\n"));
|
||||
assertThat(body,containsString("dog"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestWithKnownLargeContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
gen.setLargeContent(8);
|
||||
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
|
||||
Info info = new Info("POST","/index.html",59);
|
||||
info.getHttpFields().add("Host","something");
|
||||
info.getHttpFields().add("User-Agent","test");
|
||||
info.getHttpFields().add("Content-Length","59");
|
||||
result=gen.generate(info,header,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
out = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(content0);
|
||||
out+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generate(info,header,null,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
result=gen.generateRequest(null,null,content1,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
result=gen.generate(info,null,null,null,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
body+=BufferUtil.toString(content1);
|
||||
assertTrue(!gen.isChunking());
|
||||
out+=BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generate(info,null,null,null,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.CONTINUE,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
out+=BufferUtil.toString(chunk);
|
||||
BufferUtil.clear(chunk);
|
||||
|
||||
assertThat(out,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(out,containsString("Host: something"));
|
||||
assertThat(out,containsString("Content-Length: 58"));
|
||||
assertThat(out,containsString("\r\n\r\nHello World. The quick brown fox jumped over the lazy dog."));
|
||||
|
||||
assertEquals(59,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("POST /index.html HTTP/1.1"));
|
||||
assertThat(head,containsString("Host: something"));
|
||||
assertThat(head,containsString("Content-Length: 59"));
|
||||
assertThat(head,not(containsString("chunked")));
|
||||
assertTrue(head.endsWith("\r\n\r\n"));
|
||||
assertThat(body,containsString("dog"));
|
||||
assertEquals(58,gen.getContentPrepared());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator.Action;
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.hamcrest.Matchers;
|
||||
|
@ -160,11 +159,10 @@ public class HttpGeneratorServerTest
|
|||
// System.err.printf("content %d %s%n",c,BufferUtil.toDetailString(content));
|
||||
}
|
||||
ByteBuffer header=null;
|
||||
ByteBuffer chunk=null;
|
||||
ByteBuffer buffer=null;
|
||||
HttpGenerator.Info info=null;
|
||||
HttpGenerator.ResponseInfo info=null;
|
||||
|
||||
while(!gen.isComplete())
|
||||
loop:
|
||||
while(true)
|
||||
{
|
||||
// if we have unwritten content
|
||||
if (source!=null && content!=null && content.remaining()==0 && c<nchunks)
|
||||
|
@ -174,7 +172,7 @@ public class HttpGeneratorServerTest
|
|||
}
|
||||
|
||||
// Generate
|
||||
Action action=BufferUtil.hasContent(content)?null:Action.COMPLETE;
|
||||
boolean last=!BufferUtil.hasContent(content);
|
||||
|
||||
/*
|
||||
System.err.printf("generate(%s,%s,%s,%s,%s)@%s%n",
|
||||
|
@ -184,7 +182,7 @@ public class HttpGeneratorServerTest
|
|||
BufferUtil.toSummaryString(content),
|
||||
action,gen.getState());
|
||||
*/
|
||||
HttpGenerator.Result result=gen.generate(info,header,chunk,buffer,content,action);
|
||||
HttpGenerator.Result result=gen.generateResponse(info,header,content,last);
|
||||
/*System.err.printf("%s (%s,%s,%s,%s,%s)@%s%n",
|
||||
result,
|
||||
BufferUtil.toSummaryString(header),
|
||||
|
@ -197,20 +195,15 @@ public class HttpGeneratorServerTest
|
|||
{
|
||||
case NEED_INFO:
|
||||
info=new HttpGenerator.ResponseInfo(HttpVersion.fromVersion(version),_fields,_contentLength,_code,reason,_head);
|
||||
break;
|
||||
continue;
|
||||
|
||||
case NEED_HEADER:
|
||||
header=BufferUtil.allocate(2048);
|
||||
break;
|
||||
|
||||
case NEED_BUFFER:
|
||||
buffer=BufferUtil.allocate(8192);
|
||||
break;
|
||||
continue;
|
||||
|
||||
case NEED_CHUNK:
|
||||
header=null;
|
||||
chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
break;
|
||||
header=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
continue;
|
||||
|
||||
case FLUSH:
|
||||
if (BufferUtil.hasContent(header))
|
||||
|
@ -218,29 +211,6 @@ public class HttpGeneratorServerTest
|
|||
response+=BufferUtil.toString(header);
|
||||
header.position(header.limit());
|
||||
}
|
||||
else if (BufferUtil.hasContent(chunk))
|
||||
{
|
||||
response+=BufferUtil.toString(chunk);
|
||||
chunk.position(chunk.limit());
|
||||
}
|
||||
if (BufferUtil.hasContent(buffer))
|
||||
{
|
||||
response+=BufferUtil.toString(buffer);
|
||||
buffer.position(buffer.limit());
|
||||
}
|
||||
break;
|
||||
|
||||
case FLUSH_CONTENT:
|
||||
if (BufferUtil.hasContent(header))
|
||||
{
|
||||
response+=BufferUtil.toString(header);
|
||||
header.position(header.limit());
|
||||
}
|
||||
else if (BufferUtil.hasContent(chunk))
|
||||
{
|
||||
response+=BufferUtil.toString(chunk);
|
||||
chunk.position(chunk.limit());
|
||||
}
|
||||
if (BufferUtil.hasContent(content))
|
||||
{
|
||||
response+=BufferUtil.toString(content);
|
||||
|
@ -248,9 +218,14 @@ public class HttpGeneratorServerTest
|
|||
}
|
||||
break;
|
||||
|
||||
case OK:
|
||||
case CONTINUE:
|
||||
continue;
|
||||
|
||||
case SHUTDOWN_OUT:
|
||||
// TODO
|
||||
break;
|
||||
|
||||
case DONE:
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
|
@ -376,20 +351,24 @@ public class HttpGeneratorServerTest
|
|||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
result=gen.generate(null,null,null,null,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),-1,200,null,false);
|
||||
info.getHttpFields().add("Last-Modified",HttpFields.__01Jan1970);
|
||||
|
||||
result=gen.generate(info,header,null,null,null,null);
|
||||
result=gen.generateResponse(info,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
|
||||
result=gen.generateResponse(info,header,null,true);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
|
||||
result=gen.generate(info,null,null,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
result=gen.generateResponse(null,null,null,false);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertEquals(0,gen.getContentPrepared());
|
||||
|
@ -406,22 +385,23 @@ public class HttpGeneratorServerTest
|
|||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
result=gen.generate(null,null,null,null,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),-1,101,null,false);
|
||||
info.getHttpFields().add("Upgrade","WebSocket");
|
||||
info.getHttpFields().add("Connection","Upgrade");
|
||||
info.getHttpFields().add("Sec-WebSocket-Accept","123456789==");
|
||||
|
||||
result=gen.generate(info,header,null,null,null,null);
|
||||
result=gen.generateResponse(info,header,null,true);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
|
||||
result=gen.generate(info,null,null,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
result=gen.generateResponse(info,null,null,false);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertEquals(0,gen.getContentPrepared());
|
||||
|
@ -434,441 +414,185 @@ public class HttpGeneratorServerTest
|
|||
@Test
|
||||
public void testResponseWithChunkedContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer buffer=BufferUtil.allocate(16);
|
||||
ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content0,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World! ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content0.remaining());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content1,null);
|
||||
result=gen.generateResponse(null,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),-1,200,null,false);
|
||||
info.getHttpFields().add("Last-Modified",HttpFields.__01Jan1970);
|
||||
result=gen.generate(info,header,null,buffer,content1,null);
|
||||
result=gen.generateResponse(info,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generateResponse(info,header,content0,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
assertTrue(gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
|
||||
String out = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
out+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generateResponse(null,header,content1,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_CHUNK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
result=gen.generate(info,null,chunk,buffer,content1,null);
|
||||
result=gen.generateResponse(null,chunk,content1,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("\r\n10\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(" quick brown fox",BufferUtil.toString(buffer));
|
||||
assertEquals(27,content1.remaining());
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(buffer);
|
||||
out+=BufferUtil.toString(chunk);
|
||||
BufferUtil.clear(chunk);
|
||||
BufferUtil.clear(buffer);
|
||||
out+=BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("\r\n10\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(" jumped over the",BufferUtil.toString(buffer));
|
||||
assertEquals(11,content1.remaining());
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(chunk);
|
||||
BufferUtil.clear(buffer);
|
||||
result=gen.generateResponse(null,chunk,null,true);
|
||||
assertEquals(HttpGenerator.Result.CONTINUE,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("",BufferUtil.toString(chunk));
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content1.remaining());
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,null,Action.COMPLETE);
|
||||
result=gen.generateResponse(null,chunk,null,true);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
assertEquals("\r\nB\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(chunk);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk));
|
||||
assertEquals(0,buffer.remaining());
|
||||
body+=BufferUtil.toString(chunk);
|
||||
out+=BufferUtil.toString(chunk);
|
||||
BufferUtil.clear(chunk);
|
||||
|
||||
result=gen.generate(info,null,chunk,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
result=gen.generateResponse(null,chunk,null,true);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertEquals(59,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(head,not(containsString("Content-Length")));
|
||||
assertThat(head,containsString("Transfer-Encoding: chunked"));
|
||||
assertTrue(head.endsWith("\r\n\r\n10\r\n"));
|
||||
|
||||
assertThat(out,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(out,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(out,not(containsString("Content-Length")));
|
||||
assertThat(out,containsString("Transfer-Encoding: chunked"));
|
||||
assertThat(out,containsString("\r\n\r\nD\r\n"));
|
||||
assertThat(out,containsString("\r\nHello World! \r\n"));
|
||||
assertThat(out,containsString("\r\n2E\r\n"));
|
||||
assertThat(out,containsString("\r\nThe quick brown fox jumped over the lazy dog. \r\n"));
|
||||
assertThat(out,containsString("\r\n0\r\n"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testResponseWithKnownContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer buffer=BufferUtil.allocate(16);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content0,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World! ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content0.remaining());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),59,200,null,false);
|
||||
info.getHttpFields().add("Last-Modified",HttpFields.__01Jan1970);
|
||||
info.getHttpFields().add("Content-Length","59");
|
||||
result=gen.generate(info,header,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("Hello World! The",BufferUtil.toString(buffer));
|
||||
assertEquals(43,content1.remaining());
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals(" quick brown fox",BufferUtil.toString(buffer));
|
||||
assertEquals(27,content1.remaining());
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals(" jumped over the",BufferUtil.toString(buffer));
|
||||
assertEquals(11,content1.remaining());
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
assertEquals(0,content1.remaining());
|
||||
|
||||
result=gen.generate(info,null,null,buffer,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
assertEquals(" lazy dog. ",BufferUtil.toString(buffer));
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
assertEquals(0,buffer.remaining());
|
||||
|
||||
assertEquals(59,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(head,containsString("Content-Length: 59"));
|
||||
assertThat(head,not(containsString("chunked")));
|
||||
assertTrue(head.endsWith("\r\n\r\n"));
|
||||
}
|
||||
@Test
|
||||
public void testResponseWithKnownLargeContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
gen.setLargeContent(8);
|
||||
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
result=gen.generateResponse(null,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),59,200,null,false);
|
||||
info.getHttpFields().add("Last-Modified",HttpFields.__01Jan1970);
|
||||
info.getHttpFields().add("Content-Length","59");
|
||||
|
||||
result=gen.generate(info,header,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertTrue(!gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generate(info,header,null,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
result=gen.generate(info,null,null,null,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
body+=BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generate(info,null,null,null,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertEquals(59,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(head,containsString("Content-Length: 59"));
|
||||
assertThat(head,not(containsString("chunked")));
|
||||
assertTrue(head.endsWith("\r\n\r\n"));
|
||||
}
|
||||
@Test
|
||||
public void testResponseWithLargeChunkedContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello Cruel World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
gen.setLargeContent(8);
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING,gen.getState());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),-1,200,null,false);
|
||||
info.getHttpFields().add("Last-Modified",HttpFields.__01Jan1970);
|
||||
result=gen.generate(info,header,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertTrue(gen.isChunking());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generate(info,header,null,null,content0,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
result=gen.generate(info,null,null,null,content1,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_CHUNK,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
ByteBuffer chunk=BufferUtil.allocate(HttpGenerator.CHUNK_SIZE);
|
||||
result=gen.generate(info,null,chunk,null,content1,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH_CONTENT,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
assertEquals("\r\n2E\r\n",BufferUtil.toString(chunk));
|
||||
|
||||
body+=BufferUtil.toString(chunk)+BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generate(info,null,chunk,null,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
assertEquals("\r\n0\r\n\r\n",BufferUtil.toString(chunk));
|
||||
body+=BufferUtil.toString(chunk);
|
||||
|
||||
result=gen.generate(info,null,chunk,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertEquals(65,gen.getContentPrepared());
|
||||
|
||||
// System.err.println(head+body);
|
||||
|
||||
assertThat(head,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(head,not(containsString("Content-Length")));
|
||||
assertThat(head,containsString("Transfer-Encoding: chunked"));
|
||||
assertTrue(head.endsWith("\r\n\r\n13\r\n"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResponseWithSmallContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer buffer=BufferUtil.allocate(8096);
|
||||
ByteBuffer content=BufferUtil.toBuffer("Hello World");
|
||||
ByteBuffer content1=BufferUtil.toBuffer(". The quick brown fox jumped over the lazy dog.");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(null,null,null,null,content,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World",BufferUtil.toString(buffer));
|
||||
assertTrue(BufferUtil.isEmpty(content));
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",BufferUtil.toString(buffer));
|
||||
assertTrue(BufferUtil.isEmpty(content1));
|
||||
|
||||
result=gen.generate(null,null,null,buffer,null,Action.COMPLETE);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),-1,200,null,false);
|
||||
info.getHttpFields().add("Last-Modified",HttpFields.__01Jan1970);
|
||||
result=gen.generate(info,header,null,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertThat(head,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(head,containsString("Content-Length: 58"));
|
||||
assertTrue(head.endsWith("\r\n\r\n"));
|
||||
|
||||
assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",body);
|
||||
|
||||
assertEquals(58,gen.getContentPrepared());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test100ThenResponseWithSmallContent() throws Exception
|
||||
{
|
||||
String body="";
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer buffer=BufferUtil.allocate(8096);
|
||||
ByteBuffer content=BufferUtil.toBuffer("Hello World");
|
||||
ByteBuffer content1=BufferUtil.toBuffer(". The quick brown fox jumped over the lazy dog.");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generate(HttpGenerator.CONTINUE_100_INFO,null,null,null,null,Action.COMPLETE);
|
||||
result=gen.generateResponse(info,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generateResponse(info,header,content0,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
result=gen.generate(HttpGenerator.CONTINUE_100_INFO,header,null,null,null,Action.COMPLETE);
|
||||
String out = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
out+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generateResponse(null,null,content1,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
out+=BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.CONTINUE,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertThat(out,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(out,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(out,not(containsString("chunked")));
|
||||
assertThat(out,containsString("Content-Length: 59"));
|
||||
assertThat(out,containsString("\r\n\r\nHello World! The quick brown fox jumped over the lazy dog. "));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test100ThenResponseWithContent() throws Exception
|
||||
{
|
||||
|
||||
ByteBuffer header=BufferUtil.allocate(4096);
|
||||
ByteBuffer content0=BufferUtil.toBuffer("Hello World! ");
|
||||
ByteBuffer content1=BufferUtil.toBuffer("The quick brown fox jumped over the lazy dog. ");
|
||||
HttpGenerator gen = new HttpGenerator();
|
||||
|
||||
HttpGenerator.Result
|
||||
|
||||
result=gen.generateResponse(HttpGenerator.CONTINUE_100_INFO,null,null,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generateResponse(HttpGenerator.CONTINUE_100_INFO,header,null,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING_1XX,gen.getState());
|
||||
assertThat(BufferUtil.toString(header),Matchers.startsWith("HTTP/1.1 100 Continue"));
|
||||
BufferUtil.clear(header);
|
||||
|
||||
result=gen.generate(null,null,null,null,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
String out = BufferUtil.toString(header);
|
||||
|
||||
result=gen.generate(null,null,null,null,content,null);
|
||||
assertEquals(HttpGenerator.Result.NEED_BUFFER,result);
|
||||
result=gen.generateResponse(null,null,null,false);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World",BufferUtil.toString(buffer));
|
||||
assertTrue(BufferUtil.isEmpty(content));
|
||||
assertThat(out,containsString("HTTP/1.1 100 Continue"));
|
||||
|
||||
|
||||
result=gen.generate(null,null,null,buffer,content1,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",BufferUtil.toString(buffer));
|
||||
assertTrue(BufferUtil.isEmpty(content1));
|
||||
|
||||
result=gen.generate(null,null,null,buffer,null,Action.COMPLETE);
|
||||
result=gen.generateResponse(null,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_INFO,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTING_COMPLETING,gen.getState());
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),-1,200,null,false);
|
||||
ResponseInfo info = new ResponseInfo(HttpVersion.HTTP_1_1,new HttpFields(),59,200,null,false);
|
||||
info.getHttpFields().add("Last-Modified",HttpFields.__01Jan1970);
|
||||
result=gen.generate(info,header,null,buffer,null,null);
|
||||
result=gen.generateResponse(info,null,content0,false);
|
||||
assertEquals(HttpGenerator.Result.NEED_HEADER,result);
|
||||
assertEquals(HttpGenerator.State.START,gen.getState());
|
||||
|
||||
result=gen.generateResponse(info,header,content0,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
|
||||
out = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
out+=BufferUtil.toString(content0);
|
||||
BufferUtil.clear(content0);
|
||||
|
||||
result=gen.generateResponse(null,null,content1,false);
|
||||
assertEquals(HttpGenerator.Result.FLUSH,result);
|
||||
assertEquals(HttpGenerator.State.COMMITTED,gen.getState());
|
||||
out+=BufferUtil.toString(content1);
|
||||
BufferUtil.clear(content1);
|
||||
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.CONTINUE,result);
|
||||
assertEquals(HttpGenerator.State.COMPLETING,gen.getState());
|
||||
|
||||
String head = BufferUtil.toString(header);
|
||||
BufferUtil.clear(header);
|
||||
body+=BufferUtil.toString(buffer);
|
||||
BufferUtil.clear(buffer);
|
||||
|
||||
result=gen.generate(info,null,null,buffer,null,null);
|
||||
assertEquals(HttpGenerator.Result.OK,result);
|
||||
result=gen.generateResponse(null,null,null,true);
|
||||
assertEquals(HttpGenerator.Result.DONE,result);
|
||||
assertEquals(HttpGenerator.State.END,gen.getState());
|
||||
|
||||
assertThat(head,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(head,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(head,containsString("Content-Length: 58"));
|
||||
assertTrue(head.endsWith("\r\n\r\n"));
|
||||
|
||||
assertEquals("Hello World. The quick brown fox jumped over the lazy dog.",body);
|
||||
|
||||
assertEquals(58,gen.getContentPrepared());
|
||||
|
||||
assertThat(out,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(out,containsString("Last-Modified: Thu, 01 Jan 1970 00:00:00 GMT"));
|
||||
assertThat(out,not(containsString("chunked")));
|
||||
assertThat(out,containsString("Content-Length: 59"));
|
||||
assertThat(out,containsString("\r\n\r\nHello World! The quick brown fox jumped over the lazy dog. "));
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -301,7 +301,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
shutdownInput();
|
||||
if (_ishut)
|
||||
return -1;
|
||||
int filled=BufferUtil.append(_in,buffer);
|
||||
int filled=BufferUtil.flipPutFlip(_in,buffer);
|
||||
if (filled>0)
|
||||
notIdle();
|
||||
return filled;
|
||||
|
@ -331,12 +331,12 @@ public class ByteArrayEndPoint extends AbstractEndPoint
|
|||
if (b.remaining()>BufferUtil.space(_out))
|
||||
{
|
||||
ByteBuffer n = BufferUtil.allocate(_out.capacity()+b.remaining()*2);
|
||||
BufferUtil.append(_out,n);
|
||||
BufferUtil.flipPutFlip(_out,n);
|
||||
_out=n;
|
||||
}
|
||||
}
|
||||
|
||||
flushed+=BufferUtil.append(b,_out);
|
||||
flushed+=BufferUtil.flipPutFlip(b,_out);
|
||||
|
||||
if (BufferUtil.hasContent(b))
|
||||
break;
|
||||
|
|
|
@ -407,7 +407,7 @@ public class SslConnection extends AbstractConnection
|
|||
{
|
||||
// Do we already have some decrypted data?
|
||||
if (BufferUtil.hasContent(_decryptedInput))
|
||||
return BufferUtil.append(_decryptedInput, buffer);
|
||||
return BufferUtil.flipPutFlip(_decryptedInput, buffer);
|
||||
|
||||
// We will need a network buffer
|
||||
if (_encryptedInput == null)
|
||||
|
@ -502,7 +502,7 @@ public class SslConnection extends AbstractConnection
|
|||
{
|
||||
if (app_in == buffer)
|
||||
return unwrapResult.bytesProduced();
|
||||
return BufferUtil.append(_decryptedInput, buffer);
|
||||
return BufferUtil.flipPutFlip(_decryptedInput, buffer);
|
||||
}
|
||||
|
||||
// Dang! we have to care about the handshake state
|
||||
|
|
|
@ -163,7 +163,7 @@ public class SelectChannelEndPointTest
|
|||
}
|
||||
|
||||
// Copy to the out buffer
|
||||
if (BufferUtil.hasContent(_in) && BufferUtil.append(_in, _out) > 0)
|
||||
if (BufferUtil.hasContent(_in) && BufferUtil.flipPutFlip(_in, _out) > 0)
|
||||
progress = true;
|
||||
|
||||
// Blocking writes
|
||||
|
|
|
@ -20,9 +20,11 @@ package org.eclipse.jetty.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import javax.servlet.DispatcherType;
|
||||
import javax.servlet.ServletException;
|
||||
|
@ -46,6 +48,7 @@ import org.eclipse.jetty.io.EndPoint;
|
|||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.UncheckedPrintWriter;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -197,7 +200,18 @@ public abstract class HttpChannel
|
|||
{
|
||||
if (_response.isCommitted())
|
||||
throw new IllegalStateException("Committed before 100 Continues");
|
||||
commitResponse(HttpGenerator.CONTINUE_100_INFO,null);
|
||||
try
|
||||
{
|
||||
write(HttpGenerator.CONTINUE_100_INFO,null).get();
|
||||
}
|
||||
catch (final InterruptedException e)
|
||||
{
|
||||
throw new InterruptedIOException(){{this.initCause(e);}};
|
||||
}
|
||||
catch (final ExecutionException e)
|
||||
{
|
||||
throw new IOException(){{this.initCause(e);}};
|
||||
}
|
||||
}
|
||||
_expect100Continue=false;
|
||||
}
|
||||
|
@ -359,12 +373,24 @@ public abstract class HttpChannel
|
|||
}
|
||||
|
||||
HttpGenerator.ResponseInfo info = _handler.commit();
|
||||
commitResponse(info,buffer);
|
||||
try
|
||||
{
|
||||
write(info,buffer).get();
|
||||
}
|
||||
catch (final InterruptedException e)
|
||||
{
|
||||
throw new InterruptedIOException(){{this.initCause(e);}};
|
||||
}
|
||||
catch (final ExecutionException e)
|
||||
{
|
||||
throw new IOException(){{this.initCause(e);}};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
LOG.debug("failed to sendError {} {}",status, reason, e);
|
||||
}
|
||||
finally
|
||||
|
@ -697,7 +723,7 @@ public abstract class HttpChannel
|
|||
// Process content.
|
||||
if (content instanceof ByteBuffer)
|
||||
{
|
||||
commitResponse(_handler.commit(),(ByteBuffer)content);
|
||||
HttpChannel.this.write(_handler.commit(),(ByteBuffer)content);
|
||||
}
|
||||
else if (content instanceof InputStream)
|
||||
{
|
||||
|
@ -712,20 +738,9 @@ public abstract class HttpChannel
|
|||
|
||||
public abstract HttpConfiguration getHttpConfiguration();
|
||||
|
||||
protected abstract int write(ByteBuffer content) throws IOException;
|
||||
protected abstract void write(ByteBuffer content,boolean last) throws IOException;
|
||||
|
||||
/* Called by the channel or application to commit a specific response info */
|
||||
protected abstract void commitResponse(ResponseInfo info, ByteBuffer content) throws IOException;
|
||||
|
||||
protected abstract int getContentBufferSize();
|
||||
|
||||
protected abstract void increaseContentBufferSize(int size);
|
||||
|
||||
protected abstract void resetBuffer();
|
||||
|
||||
protected abstract void flushResponse() throws IOException;
|
||||
|
||||
protected abstract void completeResponse() throws IOException;
|
||||
protected abstract FutureCallback<Void> write(ResponseInfo info, ByteBuffer content) throws IOException;
|
||||
|
||||
protected abstract void completed();
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ import java.util.concurrent.RejectedExecutionException;
|
|||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
||||
import org.eclipse.jetty.http.HttpGenerator;
|
||||
import org.eclipse.jetty.http.HttpGenerator.Action;
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.http.HttpParser;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
|
@ -47,9 +46,15 @@ public class HttpConnection extends AbstractConnection
|
|||
private static final Logger LOG = Log.getLogger(HttpConnection.class);
|
||||
|
||||
private static final ThreadLocal<HttpConnection> __currentConnection = new ThreadLocal<>();
|
||||
|
||||
private static final FutureCallback<Void> __completed = new FutureCallback<>();
|
||||
static
|
||||
{
|
||||
__completed.completed(null);
|
||||
}
|
||||
|
||||
public static final String UPGRADE_CONNECTION_ATTR = "org.eclispe.jetty.server.HttpConnection.UPGRADE";
|
||||
|
||||
|
||||
private final Server _server;
|
||||
private final HttpConfiguration _httpConfig;
|
||||
private final Connector _connector;
|
||||
|
@ -59,11 +64,10 @@ public class HttpConnection extends AbstractConnection
|
|||
private final ByteBufferPool _bufferPool;
|
||||
private final HttpHttpInput _httpInput;
|
||||
|
||||
|
||||
private ResponseInfo _info;
|
||||
ByteBuffer _requestBuffer=null;
|
||||
ByteBuffer _responseHeader=null;
|
||||
ByteBuffer _chunk=null;
|
||||
ByteBuffer _responseBuffer=null;
|
||||
private int _headerBytes;
|
||||
|
||||
|
||||
|
@ -146,16 +150,6 @@ public class HttpConnection extends AbstractConnection
|
|||
_channel.reset();
|
||||
_httpInput.recycle();
|
||||
releaseRequestBuffer();
|
||||
if (_responseHeader!=null && !_responseHeader.hasRemaining())
|
||||
{
|
||||
_bufferPool.release(_responseHeader);
|
||||
_responseHeader=null;
|
||||
}
|
||||
if (_responseBuffer!=null && !_responseBuffer.hasRemaining())
|
||||
{
|
||||
_bufferPool.release(_responseBuffer);
|
||||
_responseBuffer=null;
|
||||
}
|
||||
if (_chunk!=null)
|
||||
_bufferPool.release(_chunk);
|
||||
_chunk=null;
|
||||
|
@ -339,46 +333,6 @@ public class HttpConnection extends AbstractConnection
|
|||
super(server,HttpConnection.this,_httpInput);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int write(ByteBuffer content) throws IOException
|
||||
{
|
||||
return generate(content,Action.PREPARE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetBuffer()
|
||||
{
|
||||
if (_responseBuffer!=null)
|
||||
BufferUtil.clear(_responseBuffer);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void increaseContentBufferSize(int size)
|
||||
{
|
||||
if (_responseBuffer!=null && _responseBuffer.capacity()>=size)
|
||||
return;
|
||||
if (_responseBuffer==null && _httpConfig.getResponseBufferSize()>=size)
|
||||
return;
|
||||
|
||||
ByteBuffer r=_bufferPool.acquire(size,false);
|
||||
if (_responseBuffer!=null)
|
||||
{
|
||||
BufferUtil.append(_responseBuffer,r);
|
||||
_bufferPool.release(_responseBuffer);
|
||||
}
|
||||
_responseBuffer=r;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentBufferSize()
|
||||
{
|
||||
ByteBuffer buffer=_responseBuffer;
|
||||
if (buffer!=null)
|
||||
return buffer.capacity();
|
||||
|
||||
return _httpConfig.getResponseBufferSize();
|
||||
}
|
||||
|
||||
public Connector getConnector()
|
||||
{
|
||||
return _connector;
|
||||
|
@ -389,19 +343,6 @@ public class HttpConnection extends AbstractConnection
|
|||
return _httpConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void flushResponse() throws IOException
|
||||
{
|
||||
generate(null,Action.FLUSH);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeResponse() throws IOException
|
||||
{
|
||||
generate(null,Action.COMPLETE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected boolean commitError(int status, String reason, String content)
|
||||
{
|
||||
|
@ -411,9 +352,6 @@ public class HttpConnection extends AbstractConnection
|
|||
|
||||
// We could not send the error, so a shutdown of the connection will at least tell
|
||||
// the client something is wrong
|
||||
|
||||
if (BufferUtil.hasContent(_responseBuffer))
|
||||
BufferUtil.clear(_responseBuffer);
|
||||
getEndPoint().shutdownOutput();
|
||||
_generator.abort();
|
||||
return false;
|
||||
|
@ -488,8 +426,7 @@ public class HttpConnection extends AbstractConnection
|
|||
getEndPoint().shutdownOutput();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// make sure that an oshut connection is driven towards close
|
||||
// TODO this is a little ugly
|
||||
if (getEndPoint().isOpen() && getEndPoint().isOutputShutdown())
|
||||
|
@ -506,33 +443,33 @@ public class HttpConnection extends AbstractConnection
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private int generate(ByteBuffer content, Action action) throws IOException
|
||||
@Override
|
||||
public void write(ByteBuffer content, boolean last) throws IOException
|
||||
{
|
||||
// Only one response writer at a time.
|
||||
synchronized(this)
|
||||
{
|
||||
long prepared_before=0;
|
||||
long prepared_after;
|
||||
ByteBuffer header=null;
|
||||
try
|
||||
{
|
||||
if (_generator.isComplete())
|
||||
if (_generator.isEnd())
|
||||
{
|
||||
if (Action.COMPLETE==action)
|
||||
return 0;
|
||||
// TODO do we need this escape?
|
||||
if (last && BufferUtil.isEmpty(content))
|
||||
return;
|
||||
throw new EofException();
|
||||
}
|
||||
|
||||
prepared_before=_generator.getContentPrepared();
|
||||
loop: while (true)
|
||||
{
|
||||
HttpGenerator.Result result=_generator.generate(_info,_responseHeader,_chunk,_responseBuffer,content,action);
|
||||
HttpGenerator.Result result=_generator.generateResponse(_info,header,content,last);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} generate: {} ({},{},{})@{}",
|
||||
this,
|
||||
result,
|
||||
BufferUtil.toSummaryString(_responseHeader),
|
||||
BufferUtil.toSummaryString(_responseBuffer),
|
||||
BufferUtil.toSummaryString(header),
|
||||
BufferUtil.toSummaryString(content),
|
||||
last,
|
||||
_generator.getState());
|
||||
|
||||
switch(result)
|
||||
|
@ -540,53 +477,37 @@ public class HttpConnection extends AbstractConnection
|
|||
case NEED_INFO:
|
||||
if (_info==null)
|
||||
_info=_channel.getEventHandler().commit();
|
||||
LOG.debug("{} Gcommit {}",this,_info);
|
||||
if (_responseHeader==null)
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
continue;
|
||||
|
||||
case NEED_HEADER:
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
continue;
|
||||
|
||||
case NEED_BUFFER:
|
||||
_responseBuffer=_bufferPool.acquire(_httpConfig.getResponseBufferSize(),false);
|
||||
if (header!=null)
|
||||
_bufferPool.release(header);
|
||||
header=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
continue;
|
||||
|
||||
case NEED_CHUNK:
|
||||
_responseHeader=null;
|
||||
_chunk=_bufferPool.acquire(HttpGenerator.CHUNK_SIZE,false);
|
||||
if (header!=null)
|
||||
_bufferPool.release(header);
|
||||
header=_bufferPool.acquire(HttpGenerator.CHUNK_SIZE,false);
|
||||
continue;
|
||||
|
||||
case FLUSH:
|
||||
if (_info.isHead())
|
||||
{
|
||||
if (_chunk!=null)
|
||||
BufferUtil.clear(_chunk);
|
||||
if (_responseBuffer!=null)
|
||||
BufferUtil.clear(_responseBuffer);
|
||||
write(header,null).get();
|
||||
BufferUtil.clear(content);
|
||||
}
|
||||
write(_responseHeader,_chunk,_responseBuffer).get();
|
||||
else
|
||||
write(header,content).get();
|
||||
|
||||
continue;
|
||||
|
||||
case FLUSH_CONTENT:
|
||||
if (_info.isHead())
|
||||
{
|
||||
if (_chunk!=null)
|
||||
BufferUtil.clear(_chunk);
|
||||
if (_responseBuffer!=null)
|
||||
BufferUtil.clear(content);
|
||||
}
|
||||
write(_responseHeader,_chunk,content).get();
|
||||
break;
|
||||
|
||||
case SHUTDOWN_OUT:
|
||||
terminate();
|
||||
getEndPoint().shutdownOutput();
|
||||
continue;
|
||||
|
||||
case DONE:
|
||||
break loop;
|
||||
|
||||
case OK:
|
||||
if (!BufferUtil.hasContent(content))
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -603,124 +524,84 @@ public class HttpConnection extends AbstractConnection
|
|||
}
|
||||
finally
|
||||
{
|
||||
prepared_after=_generator.getContentPrepared();
|
||||
if (header!=null)
|
||||
_bufferPool.release(header);
|
||||
}
|
||||
return (int)(prepared_after-prepared_before);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commitResponse(ResponseInfo info, ByteBuffer content) throws IOException
|
||||
protected FutureCallback<Void> write(ResponseInfo info, ByteBuffer content) throws IOException
|
||||
{
|
||||
// Only one response writer at a time.
|
||||
synchronized (this)
|
||||
synchronized(this)
|
||||
{
|
||||
_info=info;
|
||||
|
||||
LOG.debug("{} commit {}",this,_info);
|
||||
|
||||
ByteBuffer header=null;
|
||||
try
|
||||
{
|
||||
if (_generator.isCommitted())
|
||||
throw new IllegalStateException("committed");
|
||||
if (BufferUtil.hasContent(_responseBuffer))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("discarding uncommitted response {}",BufferUtil.toDetailString(_responseBuffer));
|
||||
BufferUtil.clear(_responseBuffer);
|
||||
}
|
||||
if (_generator.isComplete())
|
||||
if (_generator.isEnd())
|
||||
throw new EofException();
|
||||
|
||||
FutureCallback<Void> fcb=null;
|
||||
|
||||
loop: while (true)
|
||||
{
|
||||
HttpGenerator.Result result=_generator.generate(_info,_responseHeader,null,_responseBuffer,content,Action.COMPLETE);
|
||||
HttpGenerator.Result result=_generator.generateResponse(info,header,content,true);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} commit: {} ({},{},{})@{}",
|
||||
LOG.debug("{} send: {} ({},{})@{}",
|
||||
this,
|
||||
result,
|
||||
BufferUtil.toDetailString(_responseHeader),
|
||||
BufferUtil.toSummaryString(_responseBuffer),
|
||||
BufferUtil.toSummaryString(header),
|
||||
BufferUtil.toSummaryString(content),
|
||||
_generator.getState());
|
||||
|
||||
switch(result)
|
||||
{
|
||||
case NEED_INFO:
|
||||
_info=_channel.getEventHandler().commit();
|
||||
if (_responseHeader==null)
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
break;
|
||||
throw new IllegalStateException();
|
||||
|
||||
case NEED_HEADER:
|
||||
_responseHeader=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
break;
|
||||
|
||||
case NEED_BUFFER:
|
||||
_responseBuffer=_bufferPool.acquire(_httpConfig.getResponseBufferSize(),false);
|
||||
break;
|
||||
if (header!=null)
|
||||
_bufferPool.release(header);
|
||||
header=_bufferPool.acquire(_httpConfig.getResponseHeaderSize(),false);
|
||||
continue;
|
||||
|
||||
case NEED_CHUNK:
|
||||
throw new IllegalStateException("!chunk when content length known");
|
||||
if (header!=null)
|
||||
_bufferPool.release(header);
|
||||
header=_bufferPool.acquire(HttpGenerator.CHUNK_SIZE,false);
|
||||
continue;
|
||||
|
||||
case FLUSH:
|
||||
if (_info.isHead())
|
||||
if(info.isHead())
|
||||
{
|
||||
if (_chunk!=null)
|
||||
BufferUtil.clear(_chunk);
|
||||
if (_responseBuffer!=null)
|
||||
BufferUtil.clear(_responseBuffer);
|
||||
BufferUtil.clear(content);
|
||||
fcb=write(header,null);
|
||||
}
|
||||
write(_responseHeader,_chunk,_responseBuffer).get();
|
||||
break;
|
||||
|
||||
case FLUSH_CONTENT:
|
||||
if (_info.isHead())
|
||||
{
|
||||
if (_chunk!=null)
|
||||
BufferUtil.clear(_chunk);
|
||||
if (_responseBuffer!=null)
|
||||
BufferUtil.clear(content);
|
||||
}
|
||||
// TODO need a proper call back to complete.
|
||||
write(_responseHeader,_chunk,content);
|
||||
break loop;
|
||||
else
|
||||
fcb=write(header,content);
|
||||
continue;
|
||||
|
||||
case SHUTDOWN_OUT:
|
||||
terminate();
|
||||
break loop;
|
||||
|
||||
case OK:
|
||||
if (_info!=null && _info.isInformational())
|
||||
_info=null;
|
||||
getEndPoint().shutdownOutput();
|
||||
continue;
|
||||
|
||||
case DONE:
|
||||
if (fcb==null)
|
||||
fcb=__completed;
|
||||
break loop;
|
||||
}
|
||||
}
|
||||
return fcb;
|
||||
}
|
||||
catch(InterruptedException e)
|
||||
finally
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch(ExecutionException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
FutureCallback.rethrow(e);
|
||||
if (header!=null)
|
||||
_bufferPool.release(header);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void terminate()
|
||||
{
|
||||
// This method is called when the generator determines that the connection should be closed
|
||||
// either for HTTP/1.0 or because of Connection headers.
|
||||
// We need to close gently, first shutting down the output, so that we can send the SSL close
|
||||
// message, and then closing without waiting to read -1, since the semantic of this method
|
||||
// is exactly that the connection should be closed: no further reads must be accepted.
|
||||
EndPoint endPoint = getEndPoint();
|
||||
endPoint.shutdownOutput();
|
||||
endPoint.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScheduledExecutorService getScheduler()
|
||||
{
|
||||
|
@ -733,41 +614,29 @@ public class HttpConnection extends AbstractConnection
|
|||
_connector.getExecutor().execute(task);
|
||||
}
|
||||
|
||||
private FutureCallback<Void> write(ByteBuffer b0,ByteBuffer b1,ByteBuffer b2)
|
||||
private FutureCallback<Void> write(ByteBuffer b0,ByteBuffer b1)
|
||||
{
|
||||
FutureCallback<Void> fcb=new FutureCallback<>();
|
||||
if (BufferUtil.hasContent(b0))
|
||||
{
|
||||
if (BufferUtil.hasContent(b1))
|
||||
{
|
||||
if (BufferUtil.hasContent(b2))
|
||||
getEndPoint().write(null,fcb,b0,b1,b2);
|
||||
else
|
||||
getEndPoint().write(null,fcb,b0,b1);
|
||||
getEndPoint().write(null,fcb,b0,b1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BufferUtil.hasContent(b2))
|
||||
getEndPoint().write(null,fcb,b0,b2);
|
||||
else
|
||||
getEndPoint().write(null,fcb,b0);
|
||||
getEndPoint().write(null,fcb,b0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BufferUtil.hasContent(b1))
|
||||
{
|
||||
if (BufferUtil.hasContent(b2))
|
||||
getEndPoint().write(null,fcb,b1,b2);
|
||||
else
|
||||
getEndPoint().write(null,fcb,b1);
|
||||
getEndPoint().write(null,fcb,b1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BufferUtil.hasContent(b2))
|
||||
getEndPoint().write(null,fcb,b2);
|
||||
else
|
||||
fcb.completed(null);
|
||||
fcb.completed(null);
|
||||
}
|
||||
}
|
||||
return fcb;
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.nio.ByteBuffer;
|
|||
import javax.servlet.ServletOutputStream;
|
||||
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.ByteArrayOutputStream2;
|
||||
|
||||
/** Output.
|
||||
|
@ -41,6 +42,7 @@ public class HttpOutput extends ServletOutputStream
|
|||
private final HttpChannel _channel;
|
||||
private boolean _closed;
|
||||
private long _written;
|
||||
private ByteBuffer _aggregate;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public HttpOutput(HttpChannel channel)
|
||||
|
@ -81,8 +83,18 @@ public class HttpOutput extends ServletOutputStream
|
|||
public void close() throws IOException
|
||||
{
|
||||
if (!_closed)
|
||||
_channel.completeResponse();
|
||||
{
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
_channel.write(_aggregate,!_channel.getResponse().isIncluding());
|
||||
else
|
||||
_channel.write(BufferUtil.EMPTY_BUFFER,!_channel.getResponse().isIncluding());
|
||||
}
|
||||
_closed=true;
|
||||
if (_aggregate!=null)
|
||||
{
|
||||
_channel.getConnector().getByteBufferPool().release(_aggregate);
|
||||
_aggregate=null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -95,13 +107,19 @@ public class HttpOutput extends ServletOutputStream
|
|||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
_channel.flushResponse();
|
||||
if (_closed)
|
||||
throw new EofException();
|
||||
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
_channel.write(_aggregate,false);
|
||||
else
|
||||
_channel.write(BufferUtil.EMPTY_BUFFER,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void checkAllWritten()
|
||||
public boolean checkAllWritten()
|
||||
{
|
||||
_channel.getResponse().checkAllContentWritten(_written);
|
||||
return _channel.getResponse().checkAllContentWritten(_written);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -110,23 +128,52 @@ public class HttpOutput extends ServletOutputStream
|
|||
{
|
||||
if (_closed)
|
||||
throw new EofException();
|
||||
|
||||
// Do we have an aggregate buffer already
|
||||
if (_aggregate==null)
|
||||
{
|
||||
// what size should the aggregate be?
|
||||
int size=_channel.getHttpConfiguration().getResponseBufferSize();
|
||||
|
||||
// if this write would fill more than half the aggregate, just write it directory
|
||||
if (len>size/2)
|
||||
{
|
||||
_channel.write(ByteBuffer.wrap(b,off,len),false);
|
||||
_written+=len;
|
||||
return;
|
||||
}
|
||||
|
||||
// allocate an aggregate buffer
|
||||
_aggregate=_channel.getConnector().getByteBufferPool().acquire(size,false);
|
||||
}
|
||||
|
||||
// Do we have space to aggregate?
|
||||
int space = BufferUtil.space(_aggregate);
|
||||
if (len>space)
|
||||
{
|
||||
// No space so write the aggregate out if it is not empty
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
{
|
||||
_channel.write(_aggregate,false);
|
||||
space=BufferUtil.space(_aggregate);
|
||||
}
|
||||
}
|
||||
|
||||
_written+=_channel.write(ByteBuffer.wrap(b,off,len));
|
||||
checkAllWritten();
|
||||
}
|
||||
// Do we now have space to aggregate?
|
||||
if (len>space)
|
||||
{
|
||||
// No space so write the content directly
|
||||
_channel.write(ByteBuffer.wrap(b,off,len),false);
|
||||
_written+=len;
|
||||
return;
|
||||
}
|
||||
|
||||
// aggregate the content
|
||||
BufferUtil.append(_aggregate,b,off,len);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/*
|
||||
* @see java.io.OutputStream#write(byte[])
|
||||
*/
|
||||
@Override
|
||||
public void write(byte[] b) throws IOException
|
||||
{
|
||||
if (_closed)
|
||||
throw new IOException("Closed");
|
||||
|
||||
_written+=_channel.write(ByteBuffer.wrap(b));
|
||||
checkAllWritten();
|
||||
// Check if all written or full
|
||||
if (!checkAllWritten() && BufferUtil.isFull(_aggregate))
|
||||
_channel.write(_aggregate,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -139,8 +186,15 @@ public class HttpOutput extends ServletOutputStream
|
|||
if (_closed)
|
||||
throw new IOException("Closed");
|
||||
|
||||
_written+=_channel.write(ByteBuffer.wrap(new byte[]{(byte)b}));
|
||||
checkAllWritten();
|
||||
if (_aggregate==null)
|
||||
_aggregate=_channel.getConnector().getByteBufferPool().acquire(_channel.getHttpConfiguration().getResponseBufferSize(),false);
|
||||
|
||||
BufferUtil.append(_aggregate,(byte)b);
|
||||
_written++;
|
||||
|
||||
// Check if all written or full
|
||||
if (!checkAllWritten() && BufferUtil.isFull(_aggregate))
|
||||
_channel.write(_aggregate,false);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -158,5 +212,35 @@ public class HttpOutput extends ServletOutputStream
|
|||
{
|
||||
throw new IllegalStateException("Not implemented");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getContentBufferSize()
|
||||
{
|
||||
if (_aggregate!=null)
|
||||
return _aggregate.capacity();
|
||||
return _channel.getHttpConfiguration().getResponseBufferSize();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void increaseContentBufferSize(int size)
|
||||
{
|
||||
if (_aggregate==null || size<=getContentBufferSize())
|
||||
return;
|
||||
|
||||
ByteBuffer r=_channel.getConnector().getByteBufferPool().acquire(size,false);
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
BufferUtil.flipPutFlip(_aggregate,r);
|
||||
if (_aggregate!=null)
|
||||
_channel.getConnector().getByteBufferPool().release(_aggregate);
|
||||
_aggregate=r;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void resetBuffer()
|
||||
{
|
||||
if (BufferUtil.hasContent(_aggregate))
|
||||
BufferUtil.clear(_aggregate);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
package org.eclipse.jetty.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.nio.channels.IllegalSelectorException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
@ -454,7 +456,20 @@ public class Response implements HttpServletResponse
|
|||
public void sendProcessing() throws IOException
|
||||
{
|
||||
if (_channel.isExpecting102Processing() && !isCommitted())
|
||||
_channel.commitResponse(HttpGenerator.PROGRESS_102_INFO,null);
|
||||
{
|
||||
try
|
||||
{
|
||||
_channel.write(HttpGenerator.PROGRESS_102_INFO,null).get();
|
||||
}
|
||||
catch (final InterruptedException e)
|
||||
{
|
||||
throw new InterruptedIOException(){{this.initCause(e);}};
|
||||
}
|
||||
catch (final ExecutionException e)
|
||||
{
|
||||
throw new IOException(){{this.initCause(e);}};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -847,7 +862,7 @@ public class Response implements HttpServletResponse
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void checkAllContentWritten(long written)
|
||||
public boolean checkAllContentWritten(long written)
|
||||
{
|
||||
if (_contentLength>=0 && written>=_contentLength)
|
||||
{
|
||||
|
@ -867,7 +882,9 @@ public class Response implements HttpServletResponse
|
|||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1007,7 +1024,7 @@ public class Response implements HttpServletResponse
|
|||
{
|
||||
if (isCommitted() || getContentCount()>0 )
|
||||
throw new IllegalStateException("Committed or content written");
|
||||
_channel.increaseContentBufferSize(size);
|
||||
_out.increaseContentBufferSize(size);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1017,7 +1034,7 @@ public class Response implements HttpServletResponse
|
|||
@Override
|
||||
public int getBufferSize()
|
||||
{
|
||||
return _channel.getContentBufferSize();
|
||||
return _out.getContentBufferSize();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1027,7 +1044,7 @@ public class Response implements HttpServletResponse
|
|||
@Override
|
||||
public void flushBuffer() throws IOException
|
||||
{
|
||||
_channel.flushResponse();
|
||||
_out.flush();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1104,7 +1121,7 @@ public class Response implements HttpServletResponse
|
|||
_out.reset();
|
||||
}
|
||||
|
||||
_channel.resetBuffer();
|
||||
_out.resetBuffer();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -1193,7 +1210,7 @@ public class Response implements HttpServletResponse
|
|||
public void complete()
|
||||
throws IOException
|
||||
{
|
||||
_channel.completeResponse();
|
||||
_out.close();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -18,14 +18,10 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
public class ChannelHttpServer
|
||||
{
|
||||
public static void main(String[] s) throws Exception
|
||||
{
|
||||
System.setProperty("org.eclipse.jetty.LEVEL","DEBUG");
|
||||
Log.getRootLogger().setDebugEnabled(true);
|
||||
Server server = new Server();
|
||||
SelectChannelConnector connector = new SelectChannelConnector(server);
|
||||
connector.setPort(8080);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,6 +26,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||
|
||||
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
|
@ -50,44 +51,6 @@ public class HttpWriterTest
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int write(ByteBuffer content) throws IOException
|
||||
{
|
||||
return BufferUtil.append(content,_bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commitResponse(ResponseInfo info, ByteBuffer content) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentBufferSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void increaseContentBufferSize(int size)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetBuffer()
|
||||
{
|
||||
BufferUtil.clear(_bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void flushResponse() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeResponse() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completed()
|
||||
{
|
||||
|
@ -111,6 +74,21 @@ public class HttpWriterTest
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void write(ByteBuffer content, boolean last) throws IOException
|
||||
{
|
||||
BufferUtil.flipPutFlip(content,_bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FutureCallback<Void> write(ResponseInfo info, ByteBuffer content) throws IOException
|
||||
{
|
||||
BufferUtil.flipPutFlip(content,_bytes);
|
||||
FutureCallback<Void> fcb = new FutureCallback<>();
|
||||
fcb.completed(null);
|
||||
return fcb;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
_httpOut = new HttpOutput(channel);
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.server;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
@ -35,6 +36,7 @@ public class LocalConnectorTest
|
|||
{
|
||||
_server = new Server();
|
||||
_connector = new LocalConnector(_server);
|
||||
_connector.setIdleTimeout(60000);
|
||||
_server.addConnector(_connector);
|
||||
_server.setHandler(new DumpHandler());
|
||||
_server.start();
|
||||
|
@ -51,9 +53,8 @@ public class LocalConnectorTest
|
|||
|
||||
@Test
|
||||
public void testOneGET() throws Exception
|
||||
{
|
||||
{
|
||||
String response=_connector.getResponses("GET /R1 HTTP/1.0\r\n\r\n");
|
||||
|
||||
assertThat(response,containsString("HTTP/1.1 200 OK"));
|
||||
assertThat(response,containsString("pathInfo=/R1"));
|
||||
}
|
||||
|
|
|
@ -217,18 +217,16 @@ public class RequestTest
|
|||
_server.start();
|
||||
|
||||
// Request with illegal Host header
|
||||
String request="GET / HTTP/1.1\r\n"+
|
||||
"Host: whatever.com:\r\n"+
|
||||
String request="GET / HTTP/1.1\n"+
|
||||
"Host: whatever.com:\n"+
|
||||
"Content-Type: text/html;charset=utf8\n"+
|
||||
"Connection: close\n"+
|
||||
"\n";
|
||||
|
||||
String responses=_connector.getResponses(request);
|
||||
assertTrue("400 Bad Request response expected",responses.startsWith("HTTP/1.1 400"));
|
||||
assertThat(responses,Matchers.startsWith("HTTP/1.1 400"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testContentTypeEncoding() throws Exception
|
||||
{
|
||||
|
|
|
@ -52,6 +52,7 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
|||
import org.eclipse.jetty.server.session.HashSessionIdManager;
|
||||
import org.eclipse.jetty.server.session.HashSessionManager;
|
||||
import org.eclipse.jetty.server.session.HashedSession;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
|
@ -106,21 +107,18 @@ public class ResponseTest
|
|||
_channel = new HttpChannel(_server,connection,input)
|
||||
{
|
||||
@Override
|
||||
protected int write(ByteBuffer content) throws IOException
|
||||
{
|
||||
int length=content.remaining();
|
||||
protected void write(ByteBuffer content, boolean last) throws IOException
|
||||
{
|
||||
content.clear();
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetBuffer()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void increaseContentBufferSize(int size)
|
||||
protected FutureCallback<Void> write(ResponseInfo info, ByteBuffer content) throws IOException
|
||||
{
|
||||
content.clear();
|
||||
FutureCallback<Void> fcb = new FutureCallback<>();
|
||||
fcb.completed(null);
|
||||
return fcb;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,19 +133,6 @@ public class ResponseTest
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getContentBufferSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void flushResponse() throws IOException
|
||||
{
|
||||
if (!_channel.getResponse().isCommitted())
|
||||
_channel.getResponse().commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void execute(Runnable task)
|
||||
{
|
||||
|
@ -158,16 +143,6 @@ public class ResponseTest
|
|||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void completeResponse() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void commitResponse(ResponseInfo info, ByteBuffer content) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connector getConnector()
|
||||
{
|
||||
|
|
|
@ -306,7 +306,7 @@ public class BufferUtil
|
|||
* @param to Buffer to put bytes to in flush mode. The buffer is flipToFill before the put and flipToFlush after.
|
||||
* @return number of bytes moved
|
||||
*/
|
||||
public static int append(ByteBuffer from, ByteBuffer to)
|
||||
public static int flipPutFlip(ByteBuffer from, ByteBuffer to)
|
||||
{
|
||||
int pos= flipToFill(to);
|
||||
try
|
||||
|
@ -318,6 +318,32 @@ public class BufferUtil
|
|||
flipToFlush(to,pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public static void append(ByteBuffer to, byte[] b,int off,int len)
|
||||
{
|
||||
int pos= flipToFill(to);
|
||||
try
|
||||
{
|
||||
to.put(b,off,len);
|
||||
}
|
||||
finally
|
||||
{
|
||||
flipToFlush(to,pos);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public static void append(ByteBuffer to, byte b)
|
||||
{
|
||||
int limit=to.limit();
|
||||
to.put(limit,b);
|
||||
to.limit(limit+1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void readFrom(File file, ByteBuffer buffer) throws IOException
|
||||
|
|
|
@ -31,7 +31,6 @@ import java.util.concurrent.atomic.AtomicReference;
|
|||
//TODO: Simplify, get rid of DOING. Probably replace states with AtomicBoolean
|
||||
public class FutureCallback<C> implements Future<C>,Callback<C>
|
||||
{
|
||||
// TODO investigate use of a phasor
|
||||
private enum State {NOT_DONE,DOING,DONE};
|
||||
private final AtomicReference<State> _state=new AtomicReference<>(State.NOT_DONE);
|
||||
private CountDownLatch _done= new CountDownLatch(1);
|
||||
|
@ -39,17 +38,6 @@ public class FutureCallback<C> implements Future<C>,Callback<C>
|
|||
private C _context;
|
||||
private boolean _completed;
|
||||
|
||||
private void recycle()
|
||||
{
|
||||
// TODO make this public?
|
||||
if (!isDone())
|
||||
throw new IllegalStateException();
|
||||
_cause=null;
|
||||
_context=null;
|
||||
_completed=false;
|
||||
_done=new CountDownLatch(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completed(C context)
|
||||
{
|
||||
|
|
|
@ -132,14 +132,14 @@ public class BufferUtilTest
|
|||
ByteBuffer from=BufferUtil.toBuffer("12345");
|
||||
|
||||
BufferUtil.clear(to);
|
||||
assertEquals(5,BufferUtil.append(from,to));
|
||||
assertEquals(5,BufferUtil.flipPutFlip(from,to));
|
||||
assertTrue(BufferUtil.isEmpty(from));
|
||||
assertEquals("12345",BufferUtil.toString(to));
|
||||
|
||||
from=BufferUtil.toBuffer("XX67890ZZ");
|
||||
from.position(2);
|
||||
|
||||
assertEquals(5,BufferUtil.append(from,to));
|
||||
assertEquals(5,BufferUtil.flipPutFlip(from,to));
|
||||
assertEquals(2,from.remaining());
|
||||
assertEquals("1234567890",BufferUtil.toString(to));
|
||||
}
|
||||
|
@ -151,14 +151,14 @@ public class BufferUtilTest
|
|||
ByteBuffer from=BufferUtil.toBuffer("12345");
|
||||
|
||||
BufferUtil.clear(to);
|
||||
assertEquals(5,BufferUtil.append(from,to));
|
||||
assertEquals(5,BufferUtil.flipPutFlip(from,to));
|
||||
assertTrue(BufferUtil.isEmpty(from));
|
||||
assertEquals("12345",BufferUtil.toString(to));
|
||||
|
||||
from=BufferUtil.toBuffer("XX67890ZZ");
|
||||
from.position(2);
|
||||
|
||||
assertEquals(5,BufferUtil.append(from,to));
|
||||
assertEquals(5,BufferUtil.flipPutFlip(from,to));
|
||||
assertEquals(2,from.remaining());
|
||||
assertEquals("1234567890",BufferUtil.toString(to));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue