jetty-9 more HttpChannel refactoring
This commit is contained in:
parent
d7729422f6
commit
cc0266f733
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue