From cc0266f73326fc2f3003b635c9f069e4c85d0613 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 11 May 2012 16:51:24 +0200 Subject: [PATCH] jetty-9 more HttpChannel refactoring --- .../org/eclipse/jetty/http/HttpGenerator.java | 148 ++++++++++----- .../jetty/server/AsyncContinuation.java | 61 +++--- .../org/eclipse/jetty/server/HttpChannel.java | 114 +++++------- .../eclipse/jetty/server/HttpConnection.java | 174 ++++++------------ .../org/eclipse/jetty/server/Response.java | 21 ++- .../jetty/server/SelectChannelServer.java | 19 ++ 6 files changed, 274 insertions(+), 263 deletions(-) create mode 100644 jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServer.java diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java index a5201436c2f..465e2e6f672 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpGenerator.java @@ -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; + } + } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java index 8879adcc8c9..8d7d3316420 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java @@ -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 _lastAsyncListeners; private List _asyncListeners; private List _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) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index d1d9dba063e..7bebe9bf9db 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -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(); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index dfa0d341ef8..4e60fa9e1df 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -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 _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; + } + }; } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index 81849965d06..93d8b659aa4 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -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(); } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServer.java b/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServer.java new file mode 100644 index 00000000000..364664c010e --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/SelectChannelServer.java @@ -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(); + } +}