jetty-9 more HttpChannel refactoring

This commit is contained in:
Greg Wilkins 2012-05-11 16:51:24 +02:00
parent d7729422f6
commit cc0266f733
6 changed files with 274 additions and 263 deletions

View File

@ -25,41 +25,23 @@ import org.eclipse.jetty.util.log.Logger;
/**
* HttpGenerator. Builds HTTP Messages.
*
*
*
*/
public class HttpGenerator
{
private static final Logger LOG = Log.getLogger(HttpGenerator.class);
public static final ResponseInfo CONTINUE_100_INFO = new ResponseInfo(HttpVersion.HTTP_1_1,null,-1,100,null,false);
public static final ResponseInfo PROGRESS_102_INFO = new ResponseInfo(HttpVersion.HTTP_1_1,null,-1,102,null,false);
// states
public enum Action { FLUSH, COMPLETE, PREPARE };
public enum State { START, COMMITTING, COMMITTING_COMPLETING, COMMITTED, COMPLETING, END };
public enum Result { NEED_CHUNK,NEED_HEADER,NEED_BUFFER,FLUSH,FLUSH_CONTENT,OK,SHUTDOWN_OUT};
public enum Result { NEED_CHUNK,NEED_COMMIT,NEED_BUFFER,FLUSH,FLUSH_CONTENT,OK,SHUTDOWN_OUT};
// other statics
public static final int CHUNK_SIZE = 12;
public interface Info
{
HttpVersion getHttpVersion();
HttpFields getHttpFields();
long getContentLength();
}
public interface RequestInfo extends Info
{
String getMethod();
String getURI();
}
public interface ResponseInfo extends Info
{
int getStatus();
String getReason();
boolean isHead();
}
private State _state = State.START;
private EndOfContent _content = EndOfContent.UNKNOWN_CONTENT;
@ -186,7 +168,7 @@ public class HttpGenerator
}
/* ------------------------------------------------------------ */
public Result generate(Info _info, ByteBuffer header, ByteBuffer chunk, ByteBuffer buffer, ByteBuffer content, Action action)
public Result generate(Info info, ByteBuffer header, ByteBuffer chunk, ByteBuffer buffer, ByteBuffer content, Action action)
{
Result result = Result.OK;
if (_state==State.END)
@ -198,10 +180,10 @@ public class HttpGenerator
if (BufferUtil.hasContent(content))
{
// Do we have too much content?
if (_content==EndOfContent.CONTENT_LENGTH && _info.getContentLength()>=0 && content.remaining()>(_info.getContentLength()-_contentPrepared))
if (_content==EndOfContent.CONTENT_LENGTH && info!=null && info.getContentLength()>=0 && content.remaining()>(info.getContentLength()-_contentPrepared))
{
LOG.warn("Content truncated. Info.getContentLength()=="+_info.getContentLength()+" prepared="+_contentPrepared+" content="+content.remaining(),new Throwable());
content.limit(content.position()+(int)(_info.getContentLength()-_contentPrepared));
LOG.warn("Content truncated. Info.getContentLength()=="+info.getContentLength()+" prepared="+_contentPrepared+" content="+content.remaining(),new Throwable());
content.limit(content.position()+(int)(info.getContentLength()-_contentPrepared));
}
// Can we do a direct flush
@ -288,27 +270,30 @@ public class HttpGenerator
case COMMITTING:
case COMMITTING_COMPLETING:
{
if (_info instanceof RequestInfo)
if (info==null)
return Result.NEED_COMMIT;
if (info instanceof RequestInfo)
{
if (header==null || header.capacity()<=CHUNK_SIZE)
return Result.NEED_HEADER;
return Result.NEED_COMMIT;
if(_info.getHttpVersion()==HttpVersion.HTTP_0_9)
if(info.getHttpVersion()==HttpVersion.HTTP_0_9)
{
_noContent=true;
generateRequestLine((RequestInfo)_info,header);
generateRequestLine((RequestInfo)info,header);
_state = State.END;
return Result.OK;
}
_persistent=true;
generateRequestLine((RequestInfo)_info,header);
generateRequestLine((RequestInfo)info,header);
}
else
{
// Responses
// Do we need a response header?
if (_info.getHttpVersion() == HttpVersion.HTTP_0_9)
if (info.getHttpVersion() == HttpVersion.HTTP_0_9)
{
_persistent = false;
_content=EndOfContent.EOF_CONTENT;
@ -320,16 +305,16 @@ public class HttpGenerator
// yes we need a response header
if (header==null || header.capacity()<=CHUNK_SIZE)
return Result.NEED_HEADER;
return Result.NEED_COMMIT;
// Are we persistent by default?
if (_persistent==null)
_persistent=(_info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
_persistent=(info.getHttpVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal());
generateResponseLine(((ResponseInfo)_info),header);
generateResponseLine(((ResponseInfo)info),header);
// Handle 1xx
int status=((ResponseInfo)_info).getStatus();
int status=((ResponseInfo)info).getStatus();
if (status>=100 && status<200 )
{
_noContent=true;
@ -348,7 +333,7 @@ public class HttpGenerator
}
boolean completing=action==Action.COMPLETE||_state==State.COMMITTING_COMPLETING;
generateHeaders(_info,header,content,completing);
generateHeaders(info,header,content,completing);
_state = completing?State.COMPLETING:State.COMMITTED;
// handle result
@ -469,7 +454,7 @@ public class HttpGenerator
{
header.put(StringUtil.getBytes(request.getMethod()));
header.put((byte)' ');
header.put(StringUtil.getBytes(request.getURI()));
header.put(StringUtil.getBytes(request.getUri()));
switch(request.getHttpVersion())
{
case HTTP_1_0:
@ -824,10 +809,8 @@ public class HttpGenerator
// end the header.
header.put(HttpTokens.CRLF);
}
/* ------------------------------------------------------------------------------- */
public static byte[] getReasonBuffer(int code)
{
@ -903,4 +886,87 @@ public class HttpGenerator
}
}
public static class Info
{
final HttpVersion _httpVersion;
final HttpFields _httpFields;
final long _contentLength;
public Info(HttpVersion httpVersion, HttpFields httpFields, long contentLength)
{
_httpVersion = httpVersion;
_httpFields = httpFields;
_contentLength = contentLength;
}
public HttpVersion getHttpVersion()
{
return _httpVersion;
}
public HttpFields getHttpFields()
{
return _httpFields;
}
public long getContentLength()
{
return _contentLength;
}
}
public static class RequestInfo extends Info
{
private final String _method;
private final String _uri;
public RequestInfo(HttpVersion httpVersion, HttpFields httpFields, long contentLength, String method, String uri)
{
super(httpVersion,httpFields,contentLength);
_method = method;
_uri = uri;
}
public String getMethod()
{
return _method;
}
public String getUri()
{
return _uri;
}
}
public static class ResponseInfo extends Info
{
private final int _status;
private final String _reason;
private final boolean _head;
public ResponseInfo(HttpVersion httpVersion, HttpFields httpFields, long contentLength, int status, String reason, boolean head)
{
super(httpVersion,httpFields,contentLength);
_status = status;
_reason = reason;
_head = head;
}
boolean isInformational()
{
return _status>=100 && _status<200;
}
public int getStatus()
{
return _status;
}
public String getReason()
{
return _reason;
}
public boolean isHead()
{
return _head;
}
}
}

View File

@ -15,7 +15,10 @@ package org.eclipse.jetty.server;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import javax.management.timer.TimerMBean;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
@ -74,7 +77,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
};
/* ------------------------------------------------------------ */
protected HttpChannel _connection;
protected HttpChannel _channel;
private List<AsyncListener> _lastAsyncListeners;
private List<AsyncListener> _asyncListeners;
private List<ContinuationListener> _continuationListeners;
@ -102,7 +105,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
{
synchronized(this)
{
_connection=connection;
_channel=connection;
}
}
@ -679,19 +682,23 @@ public class AsyncContinuation implements AsyncContext, Continuation
/* ------------------------------------------------------------ */
protected void scheduleDispatch()
{
_connection.asyncDispatch();
// _channel.asyncDispatch();
}
/* ------------------------------------------------------------ */
protected void scheduleTimeout()
{
_connection.scheduleTimeout(_event._timeout,_timeoutMs);
Timer timer = _channel.getTimer();
timer.schedule(_event._timeout,_timeoutMs);
}
/* ------------------------------------------------------------ */
protected void cancelTimeout()
{
_connection.cancelTimeout(_event._timeout);
AsyncEventState event=_event;
if (event!=null)
event._timeout.cancel();
}
/* ------------------------------------------------------------ */
@ -779,7 +786,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
/* ------------------------------------------------------------ */
public Request getBaseRequest()
{
return _connection.getRequest();
return _channel.getRequest();
}
/* ------------------------------------------------------------ */
@ -787,7 +794,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
{
if (_event!=null)
return _event.getSuppliedRequest();
return _connection.getRequest();
return _channel.getRequest();
}
/* ------------------------------------------------------------ */
@ -795,7 +802,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
{
if (_responseWrapped && _event!=null && _event.getSuppliedResponse()!=null)
return _event.getSuppliedResponse();
return _connection.getResponse();
return _channel.getResponse();
}
/* ------------------------------------------------------------ */
@ -804,7 +811,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
final AsyncEventState event=_event;
if (event!=null)
{
_connection.getServer().getThreadPool().dispatch(new Runnable()
_channel.getServer().getThreadPool().dispatch(new Runnable()
{
public void run()
{
@ -819,7 +826,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
{
synchronized (this)
{
return (_event!=null && _event.getSuppliedRequest()==_connection.getRequest() && _event.getSuppliedResponse()==_connection.getResponse());
return (_event!=null && _event.getSuppliedRequest()==_channel.getRequest() && _event.getSuppliedResponse()==_channel.getResponse());
}
}
@ -875,12 +882,12 @@ public class AsyncContinuation implements AsyncContext, Continuation
if (response instanceof ServletResponseWrapper)
{
_responseWrapped=true;
AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),response);
AsyncContinuation.this.suspend(_channel.getRequest().getServletContext(),_channel.getRequest(),response);
}
else
{
_responseWrapped=false;
AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
AsyncContinuation.this.suspend(_channel.getRequest().getServletContext(),_channel.getRequest(),_channel.getResponse());
}
}
@ -892,7 +899,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
{
_responseWrapped=false;
_continuation=true;
AsyncContinuation.this.suspend(_connection.getRequest().getServletContext(),_connection.getRequest(),_connection.getResponse());
AsyncContinuation.this.suspend(_channel.getRequest().getServletContext(),_channel.getRequest(),_channel.getResponse());
}
/* ------------------------------------------------------------ */
@ -903,7 +910,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
{
if (_responseWrapped && _event!=null && _event.getSuppliedResponse()!=null)
return _event.getSuppliedResponse();
return _connection.getResponse();
return _channel.getResponse();
}
/* ------------------------------------------------------------ */
@ -912,7 +919,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
*/
public Object getAttribute(String name)
{
return _connection.getRequest().getAttribute(name);
return _channel.getRequest().getAttribute(name);
}
/* ------------------------------------------------------------ */
@ -921,7 +928,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
*/
public void removeAttribute(String name)
{
_connection.getRequest().removeAttribute(name);
_channel.getRequest().removeAttribute(name);
}
/* ------------------------------------------------------------ */
@ -930,7 +937,7 @@ public class AsyncContinuation implements AsyncContext, Continuation
*/
public void setAttribute(String name, Object attribute)
{
_connection.getRequest().setAttribute(name,attribute);
_channel.getRequest().setAttribute(name,attribute);
}
/* ------------------------------------------------------------ */
@ -951,29 +958,23 @@ public class AsyncContinuation implements AsyncContext, Continuation
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
public class AsyncTimeout extends Timeout.Task implements Runnable
public class AsyncTimeout extends TimerTask
{
@Override
public void expired()
{
AsyncContinuation.this.expired();
}
@Override
public void run()
{
AsyncContinuation.this.expired();
}
@Override
public void run()
{
AsyncContinuation.this.expired();
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
public class AsyncEventState extends AsyncEvent
{
private final TimerTask _timeout= new AsyncTimeout();
private final ServletContext _suspendedContext;
private ServletContext _dispatchContext;
private String _path;
private Timeout.Task _timeout= new AsyncTimeout();
public AsyncEventState(ServletContext context, ServletRequest request, ServletResponse response)
{

View File

@ -18,6 +18,7 @@ import java.io.InputStream;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.Timer;
import javax.servlet.DispatcherType;
import javax.servlet.ServletInputStream;
@ -28,6 +29,7 @@ import org.eclipse.jetty.http.HttpContent;
import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpMethod;
@ -42,6 +44,8 @@ import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.RuntimeIOException;
import org.eclipse.jetty.io.UncheckedPrintWriter;
import org.eclipse.jetty.util.ArrayQueue;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -101,7 +105,6 @@ public abstract class HttpChannel
private final RequestHandler _handler = new RequestHandler();
private final HttpGenerator.ResponseInfo _info = new Info();
/* ------------------------------------------------------------ */
@ -120,17 +123,17 @@ public abstract class HttpChannel
_async = _request.getAsyncContinuation();
}
public interface EventHandler extends HttpParser.RequestHandler
{
ResponseInfo commit();
}
/* ------------------------------------------------------------ */
public HttpParser.RequestHandler getRequestHandler()
public EventHandler getEventHandler()
{
return _handler;
}
/* ------------------------------------------------------------ */
public HttpGenerator.ResponseInfo getResponseInfo()
{
return _info;
}
/* ------------------------------------------------------------ */
/**
@ -227,10 +230,9 @@ public abstract class HttpChannel
// is content missing?
if (available()==0)
{
if (isResponseCommitted())
if (_response.isCommitted())
throw new IllegalStateException("Committed before 100 Continues");
send1xx(HttpStatus.CONTINUE_100);
commit(HttpGenerator.CONTINUE_100_INFO,null);
}
_expect100Continue=false;
}
@ -427,6 +429,21 @@ public abstract class HttpChannel
}
}
/* ------------------------------------------------------------ */
protected void sendError(final int status, final String reason, String content, boolean close) throws IOException
{
if (_response.isCommitted())
throw new IllegalStateException("Committed");
_response.setStatus(status,reason);
if (close)
_responseFields.add(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
ByteBuffer buffer=BufferUtil.toBuffer(content,StringUtil.__UTF8_CHARSET);
_response.setContentLength(buffer.remaining());
HttpGenerator.ResponseInfo info = _handler.commit();
commit(info,buffer);
}
/* ------------------------------------------------------------ */
public boolean isIncluding()
@ -536,49 +553,7 @@ public abstract class HttpChannel
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private final class Info implements HttpGenerator.ResponseInfo
{
@Override
public HttpVersion getHttpVersion()
{
return getRequest().getHttpVersion();
}
@Override
public HttpFields getHttpFields()
{
return _responseFields;
}
@Override
public long getContentLength()
{
return _response.getLongContentLength();
}
@Override
public boolean isHead()
{
return getRequest().isHead();
}
@Override
public int getStatus()
{
return _response.getStatus();
}
@Override
public String getReason()
{
return _response.getReason();
}
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private class RequestHandler implements HttpParser.RequestHandler
private class RequestHandler implements EventHandler
{
@Override
public boolean startRequest(String method, String uri, String version) throws IOException
@ -759,6 +734,12 @@ public abstract class HttpChannel
return true;
}
@Override
public ResponseInfo commit()
{
return _response.commit();
}
}
@ -832,7 +813,7 @@ public abstract class HttpChannel
// Process content.
if (content instanceof ByteBuffer)
{
send((ByteBuffer)content);
commit(_handler.commit(),(ByteBuffer)content);
}
else if (content instanceof InputStream)
{
@ -840,43 +821,30 @@ public abstract class HttpChannel
}
else
throw new IllegalArgumentException("unknown content type?");
}
}
public abstract HttpConnector getHttpConnector();
public abstract long getMaxIdleTime();
public abstract void asyncDispatch();
public abstract void scheduleTimeout(Task timeout, long timeoutMs);
public abstract void cancelTimeout(Task timeout);
protected abstract void blockForContent() throws IOException;
protected abstract void contentConsumed();
protected abstract int write(ByteBuffer content) throws IOException;
protected abstract void send(ByteBuffer content) throws IOException;
protected abstract void sendError(int status, String reason, String content, boolean close) throws IOException;
protected abstract void send1xx(int processing102);
protected abstract void commit(ResponseInfo info, ByteBuffer content) throws IOException;
protected abstract int getContentBufferSize();
protected abstract void increaseContentBufferSize(int size);
protected abstract void resetBuffer();
protected abstract boolean isResponseCommitted();
protected abstract void flushResponse() throws IOException;
protected abstract void completeResponse() throws IOException;
public abstract Timer getTimer();
}

View File

@ -15,6 +15,7 @@ package org.eclipse.jetty.server;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Timer;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@ -23,6 +24,7 @@ import org.eclipse.jetty.http.HttpException;
import org.eclipse.jetty.http.HttpFields;
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;
import org.eclipse.jetty.http.HttpVersion;
@ -53,8 +55,8 @@ public class HttpConnection extends AbstractAsyncConnection
private final HttpGenerator _generator;
private final HttpChannel _channel;
private final ByteBufferPool _bufferPool;
private ResponseInfo _info;
FutureCallback<Void> _writeFuture;
ByteBuffer _requestBuffer=null;
ByteBuffer _responseHeader=null;
@ -88,9 +90,9 @@ public class HttpConnection extends AbstractAsyncConnection
_server = server;
_channel = new HttpOverHttpChannel(server);
_channel = new HttpChannelOverHttp(server);
_parser = new HttpParser(_channel.getRequestHandler());
_parser = new HttpParser(_channel.getEventHandler());
_generator = new HttpGenerator();
LOG.debug("New HTTP Connection {}",this);
}
@ -276,13 +278,13 @@ public class HttpConnection extends AbstractAsyncConnection
}
/* ------------------------------------------------------------ */
private void send(HttpGenerator.ResponseInfo info, ByteBuffer content) throws IOException
private void generateComplete(ByteBuffer content) throws IOException
{
_lock.lock();
try
{
if (_generator.isCommitted() || BufferUtil.hasContent(_responseBuffer))
throw new IllegalStateException("!send after append");
throw new IllegalStateException("!empty");
if (_generator.isComplete())
throw new EofException();
@ -296,7 +298,7 @@ public class HttpConnection extends AbstractAsyncConnection
BufferUtil.toSummaryString(content),
_generator.getState());
HttpGenerator.Result result=_generator.generate(info,_responseHeader,null,_responseBuffer,content,Action.COMPLETE);
HttpGenerator.Result result=_generator.generate(_info,_responseHeader,null,_responseBuffer,content,Action.COMPLETE);
if (LOG.isDebugEnabled())
LOG.debug("{}: {} ({},{},{})@{}",
this,
@ -308,7 +310,9 @@ public class HttpConnection extends AbstractAsyncConnection
switch(result)
{
case NEED_HEADER:
case NEED_COMMIT:
if (_info==null)
_info=_channel.getEventHandler().commit();
_responseHeader=_bufferPool.acquire(_connector.getResponseHeaderSize(),false);
break;
@ -353,7 +357,7 @@ public class HttpConnection extends AbstractAsyncConnection
}
/* ------------------------------------------------------------ */
private int generate(HttpGenerator.ResponseInfo info, ByteBuffer content, Action action) throws IOException
private int generate(ByteBuffer content, Action action) throws IOException
{
boolean hasContent=BufferUtil.hasContent(content);
long preparedBefore=0;
@ -365,10 +369,8 @@ public class HttpConnection extends AbstractAsyncConnection
if (_generator.isComplete())
{
/* TODO ??
if (Action.COMPLETE==action)
return 0;
*/
throw new EofException();
}
@ -387,7 +389,7 @@ public class HttpConnection extends AbstractAsyncConnection
BufferUtil.toSummaryString(content),
action,_generator.getState());
HttpGenerator.Result result=_generator.generate(info,_responseHeader,_chunk,_responseBuffer,content,action);
HttpGenerator.Result result=_generator.generate(_info,_responseHeader,_chunk,_responseBuffer,content,action);
if (LOG.isDebugEnabled())
LOG.debug("{}: {} ({},{},{},{},{})@{}",
this,
@ -400,7 +402,9 @@ public class HttpConnection extends AbstractAsyncConnection
switch(result)
{
case NEED_HEADER:
case NEED_COMMIT:
if (_info==null)
_info=_channel.getEventHandler().commit();
_responseHeader=_bufferPool.acquire(_connector.getResponseHeaderSize(),false);
break;
@ -504,125 +508,41 @@ public class HttpConnection extends AbstractAsyncConnection
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
private class HttpOverHttpChannel extends HttpChannel
private class HttpChannelOverHttp extends HttpChannel
{
private HttpOverHttpChannel(Server server)
private HttpChannelOverHttp(Server server)
{
super(server,HttpConnection.this);
}
@Override
public long getMaxIdleTime()
{
return getEndPoint().getMaxIdleTime();
}
@Override
public void asyncDispatch()
{
// TODO Auto-generated method stub
}
@Override
public void scheduleTimeout(Task timeout, long timeoutMs)
{
// TODO Auto-generated method stub
}
@Override
public void cancelTimeout(Task timeout)
{
// TODO Auto-generated method stub
}
@Override
protected int write(ByteBuffer content) throws IOException
{
return HttpConnection.this.generate(getResponseInfo(),content,Action.PREPARE);
}
@Override
protected void send(ByteBuffer content) throws IOException
{
HttpConnection.this.send(getResponseInfo(),content);
}
@Override
protected void sendError(final int status, final String reason, String content, boolean close) throws IOException
{
if (_generator.isCommitted())
throw new IllegalStateException("Committed");
HttpGenerator.ResponseInfo response =new HttpGenerator.ResponseInfo()
{
@Override
public HttpVersion getHttpVersion()
{
return HttpVersion.HTTP_1_1;
}
@Override
public HttpFields getHttpFields()
{
return getResponseFields();
}
@Override
public long getContentLength()
{
return -1;
}
@Override
public boolean isHead()
{
return getRequest().isHead();
}
@Override
public int getStatus()
{
return status;
}
@Override
public String getReason()
{
return reason;
}
};
if (close)
_generator.setPersistent(false);
HttpConnection.this.send(response,BufferUtil.toBuffer(content));
}
@Override
protected void send1xx(int processing102)
{
// TODO Auto-generated method stub
return HttpConnection.this.generate(content,Action.PREPARE);
}
@Override
protected void resetBuffer()
{
// TODO Auto-generated method stub
if (_responseBuffer!=null)
BufferUtil.clear(_responseBuffer);
}
@Override
protected boolean isResponseCommitted()
{
return _generator.isCommitted();
}
@Override
protected void increaseContentBufferSize(int size)
{
// TODO Auto-generated method stub
if (_responseBuffer!=null && _responseBuffer.capacity()>=size)
return;
if (_responseBuffer==null && _connector.getResponseBufferSize()>=size)
return;
ByteBuffer r=_bufferPool.acquire(size,false);
if (_responseBuffer!=null)
{
BufferUtil.append(_responseBuffer,r);
_bufferPool.release(_responseBuffer);
}
_responseBuffer=r;
}
@Override
@ -644,13 +564,13 @@ public class HttpConnection extends AbstractAsyncConnection
@Override
protected void flushResponse() throws IOException
{
HttpConnection.this.generate(getResponseInfo(),null,Action.FLUSH);
HttpConnection.this.generate(null,Action.FLUSH);
}
@Override
protected void completeResponse() throws IOException
{
HttpConnection.this.generate(getResponseInfo(),null,Action.COMPLETE);
HttpConnection.this.generate(null,Action.COMPLETE);
}
@Override
@ -695,5 +615,27 @@ public class HttpConnection extends AbstractAsyncConnection
}
}
@Override
protected void contentConsumed()
{
// TODO Auto-generated method stub
}
@Override
protected void commit(ResponseInfo info, ByteBuffer content) throws IOException
{
_info=info;
HttpConnection.this.generateComplete(content);
}
@Override
public Timer getTimer()
{
// TODO Auto-generated method stub
return null;
}
};
}

View File

@ -18,6 +18,8 @@ import java.io.PrintWriter;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
@ -26,6 +28,7 @@ import javax.servlet.http.HttpSession;
import org.eclipse.jetty.http.HttpCookie;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpGenerator;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpHeaderValue;
import org.eclipse.jetty.http.HttpScheme;
@ -33,6 +36,7 @@ import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.http.HttpGenerator.ResponseInfo;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.util.ByteArrayISO8859Writer;
@ -67,6 +71,7 @@ public class Response implements HttpServletResponse
private final HttpChannel _channel;
private final HttpFields _fields;
private final AtomicBoolean _committed = new AtomicBoolean(false);
private int _status=SC_OK;
private String _reason;
private Locale _locale;
@ -105,6 +110,7 @@ public class Response implements HttpServletResponse
_writer=null;
_outputState=OutputState.NONE;
_contentLength=-1;
_committed.set(false);
}
/* ------------------------------------------------------------ */
@ -412,7 +418,7 @@ public class Response implements HttpServletResponse
public void sendProcessing() throws IOException
{
if (_channel.isExpecting102Processing() && !isCommitted())
_channel.send1xx(HttpStatus.PROCESSING_102);
_channel.commit(HttpGenerator.PROGRESS_102_INFO,null);
}
/* ------------------------------------------------------------ */
@ -1014,7 +1020,16 @@ public class Response implements HttpServletResponse
_channel.resetBuffer();
}
/* ------------------------------------------------------------ */
public ResponseInfo commit()
{
if (!_committed.compareAndSet(false,true))
throw new IllegalStateException();
return new ResponseInfo(_channel.getRequest().getHttpVersion(),_fields,getLongContentLength(),getStatus(),getReason(),_channel.getRequest().isHead());
}
/* ------------------------------------------------------------ */
/*
* @see javax.servlet.ServletResponse#isCommitted()
@ -1022,7 +1037,7 @@ public class Response implements HttpServletResponse
@Override
public boolean isCommitted()
{
return _channel.isResponseCommitted();
return _committed.get();
}
/* ------------------------------------------------------------ */

View File

@ -0,0 +1,19 @@
package org.eclipse.jetty.server;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.util.log.Log;
public class SelectChannelServer
{
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();
connector.setPort(8080);
server.addConnector(connector);
server.start();
server.join();
}
}