diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java index e04fd82441f..2adb6a5cda8 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -16,8 +16,10 @@ package org.eclipse.jetty.io; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; +import java.nio.charset.Charset; import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.StringUtil; /* ------------------------------------------------------------ */ @@ -26,9 +28,9 @@ import org.eclipse.jetty.util.BufferUtil; */ public class ByteArrayEndPoint extends AbstractEndPoint { - protected byte[] _inBytes; protected ByteBuffer _in; protected ByteBuffer _out; + protected boolean _oshut; protected boolean _closed; protected boolean _growOutput; @@ -39,6 +41,8 @@ public class ByteArrayEndPoint extends AbstractEndPoint public ByteArrayEndPoint() { super(null,null); + _in=BufferUtil.EMPTY_BUFFER; + _out=BufferUtil.allocate(1024); } /* ------------------------------------------------------------ */ @@ -48,10 +52,21 @@ public class ByteArrayEndPoint extends AbstractEndPoint public ByteArrayEndPoint(byte[] input, int outputSize) { super(null,null); - _inBytes=input; - _in=ByteBuffer.wrap(input); - _out=ByteBuffer.allocate(outputSize); + _in=input==null?null:ByteBuffer.wrap(input); + _out=BufferUtil.allocate(outputSize); } + + /* ------------------------------------------------------------ */ + /** + * + */ + public ByteArrayEndPoint(String input, int outputSize) + { + super(null,null); + setInput(input); + _out=BufferUtil.allocate(outputSize); + } + /* ------------------------------------------------------------ */ /** @@ -61,30 +76,68 @@ public class ByteArrayEndPoint extends AbstractEndPoint { return _in; } + + /* ------------------------------------------------------------ */ + /** + */ + public void setInputEOF() + { + _in = null; + } /* ------------------------------------------------------------ */ /** * @param in The in to set. */ - public void setIn(ByteBuffer in) + public void setInput(ByteBuffer in) { _in = in; } + /* ------------------------------------------------------------ */ + public void setInput(String s) + { + setInput(BufferUtil.toBuffer(s,StringUtil.__UTF8_CHARSET)); + } + + /* ------------------------------------------------------------ */ + public void setInput(String s,Charset charset) + { + setInput(BufferUtil.toBuffer(s,charset)); + } + /* ------------------------------------------------------------ */ /** * @return Returns the out. */ - public ByteBuffer getOut() + public ByteBuffer getOutput() { return _out; } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the out. + */ + public String getOutputString() + { + return BufferUtil.toString(_out,StringUtil.__UTF8_CHARSET); + } + + /* ------------------------------------------------------------ */ + /** + * @return Returns the out. + */ + public String getOutputString(Charset charset) + { + return BufferUtil.toString(_out,charset); + } /* ------------------------------------------------------------ */ /** * @param out The out to set. */ - public void setOut(ByteBuffer out) + public void setOutput(ByteBuffer out) { _out = out; } @@ -106,7 +159,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint @Override public boolean isOutputShutdown() { - return _closed; + return _oshut||_closed; } /* ------------------------------------------------------------ */ @@ -116,7 +169,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint @Override public void shutdownOutput() throws IOException { - close(); + _oshut=true; } /* ------------------------------------------------------------ */ @@ -128,7 +181,16 @@ public class ByteArrayEndPoint extends AbstractEndPoint { _closed=true; } - + + /* ------------------------------------------------------------ */ + /** + * @return true if there are bytes remaining to be read from the encoded input + */ + public boolean hasMore() + { + return getOutput().position()>0; + } + /* ------------------------------------------------------------ */ /* * @see org.eclipse.io.EndPoint#fill(org.eclipse.io.Buffer) @@ -138,10 +200,9 @@ public class ByteArrayEndPoint extends AbstractEndPoint { if (_closed) throw new IOException("CLOSED"); - if (_in!=null) - return BufferUtil.append(_in,buffer); - - return 0; + if (_in==null) + return -1; + return BufferUtil.append(_in,buffer); } /* ------------------------------------------------------------ */ @@ -151,34 +212,31 @@ public class ByteArrayEndPoint extends AbstractEndPoint @Override public int flush(ByteBuffer... buffers) throws IOException { + if (_oshut) + throw new IOException("oshut"); if (_closed) throw new IOException("CLOSED"); int len=0; + for (ByteBuffer b : buffers) { - if (b.hasRemaining()) + if (BufferUtil.hasContent(b)) { - if (_growOutput && b.remaining()>_out.remaining()) + if (_growOutput && b.remaining()>BufferUtil.space(_out)) { - _out.compact(); - - if (b.remaining()>_out.remaining()) + BufferUtil.compact(_out); + if (b.remaining()>BufferUtil.space(_out)) { - ByteBuffer n = ByteBuffer.allocate(_out.capacity()+b.remaining()*2); - n.put(_out); + ByteBuffer n = BufferUtil.allocate(_out.capacity()+b.remaining()*2); + BufferUtil.append(_out,n); _out=n; } } - int put=b.remaining(); + len+=BufferUtil.append(b,_out); - if (put>0) - { - _out.put(b); - len+=put; - } - else + if (BufferUtil.hasContent(b)) break; } } @@ -191,9 +249,10 @@ public class ByteArrayEndPoint extends AbstractEndPoint */ public void reset() { + _oshut=false; _closed=false; - _in.rewind(); - _out.clear(); + _in=null; + BufferUtil.clear(_out); } /* ------------------------------------------------------------ */ @@ -203,7 +262,7 @@ public class ByteArrayEndPoint extends AbstractEndPoint @Override public Object getTransport() { - return _inBytes; + return null; } /* ------------------------------------------------------------ */ diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/RecycledIOFuture.java b/jetty-io/src/main/java/org/eclipse/jetty/io/DispatchedIOFuture.java similarity index 87% rename from jetty-io/src/main/java/org/eclipse/jetty/io/RecycledIOFuture.java rename to jetty-io/src/main/java/org/eclipse/jetty/io/DispatchedIOFuture.java index 7eb299a3521..6659dc3b4e7 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/RecycledIOFuture.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/DispatchedIOFuture.java @@ -1,12 +1,21 @@ package org.eclipse.jetty.io; +import java.io.IOException; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -public class RecycledIOFuture implements IOFuture + +/* ------------------------------------------------------------ */ +/** Dispatched IOFuture. + *

An implementation of IOFuture that can be extended to implement the + * {@link #dispatch(Runnable)} method so that callbacks can be dispatched. + * By default, the callbacks are called by the thread that called {@link #ready()} or + * {@link #fail(Throwable)} + */ +public class DispatchedIOFuture implements IOFuture { private final Lock _lock; private final Condition _block; @@ -17,21 +26,21 @@ public class RecycledIOFuture implements IOFuture private Callback _callback; - public RecycledIOFuture() + public DispatchedIOFuture() { // System.err.println(this);new Throwable().printStackTrace(); _lock = new ReentrantLock(); _block = _lock.newCondition(); } - public RecycledIOFuture(Lock lock) + public DispatchedIOFuture(Lock lock) { // System.err.println(this);new Throwable().printStackTrace(); _lock = lock; _block = _lock.newCondition(); } - public RecycledIOFuture(boolean ready,Lock lock) + public DispatchedIOFuture(boolean ready,Lock lock) { _ready=ready; _complete=ready; @@ -262,4 +271,11 @@ public class RecycledIOFuture implements IOFuture _ready, _cause); } + + public static void rethrow(ExecutionException e) throws IOException + { + if (e.getCause() instanceof IOException) + throw (IOException)e.getCause(); + throw new RuntimeException(e); + } } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java index c432d52b7eb..91674325f68 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SelectChannelEndPoint.java @@ -57,7 +57,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo private volatile long _lastNotIdleTimestamp; private volatile AbstractAsyncConnection _connection; - private RecycledIOFuture _readFuture = new RecycledIOFuture(true,_lock) + private DispatchedIOFuture _readFuture = new DispatchedIOFuture(true,_lock) { @Override protected void dispatch(Runnable task) @@ -83,7 +83,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo }; private ByteBuffer[] _writeBuffers; - private RecycledIOFuture _writeFuture = new RecycledIOFuture(true,_lock) + private DispatchedIOFuture _writeFuture = new DispatchedIOFuture(true,_lock) { @Override protected void dispatch(Runnable task) diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/SslConnection.java index 6cb5517a5c2..095d87647a8 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/SslConnection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/SslConnection.java @@ -52,7 +52,7 @@ public class SslConnection extends AbstractAsyncConnection private final Lock _lock = new ReentrantLock(); - private final RecycledIOFuture _appReadFuture = new RecycledIOFuture(true,_lock) + private final DispatchedIOFuture _appReadFuture = new DispatchedIOFuture(true,_lock) { @Override protected void dispatch(Runnable callback) @@ -63,7 +63,7 @@ public class SslConnection extends AbstractAsyncConnection } }; - private IOFuture.Callback _writeable = new IOFuture.Callback() + private IOFuture.Callback _writeCallback = new IOFuture.Callback() { @Override public void onReady() @@ -82,7 +82,7 @@ public class SslConnection extends AbstractAsyncConnection } }; - private final RecycledIOFuture _appWriteFuture = new RecycledIOFuture(true,_lock); + private final DispatchedIOFuture _appWriteFuture = new DispatchedIOFuture(true,_lock); private Runnable _appReadTask; private final SSLEngine _engine; @@ -489,7 +489,7 @@ public class SslConnection extends AbstractAsyncConnection return true; _netWriteFuture=write; - _netWriteFuture.setCallback(_writeable); + _netWriteFuture.setCallback(_writeCallback); } return result.bytesConsumed()>0 || result.bytesProduced()>0 ; diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/StringEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/StringEndPoint.java deleted file mode 100644 index cda32506825..00000000000 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/StringEndPoint.java +++ /dev/null @@ -1,71 +0,0 @@ -// ======================================================================== -// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - -package org.eclipse.jetty.io; - -import java.nio.ByteBuffer; -import java.nio.charset.Charset; - -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.StringUtil; - -/** - * - * - * To change the template for this generated type comment go to - * Window - Preferences - Java - Code Generation - Code and Comments - */ -public class StringEndPoint extends ByteArrayEndPoint -{ - Charset _charset=StringUtil.__UTF8_CHARSET; - - public StringEndPoint() - { - } - - public StringEndPoint(String encoding) - { - this(); - if (encoding!=null) - _charset=Charset.forName(encoding); - } - - public void setInput(String s) - { - try - { - super.setIn(BufferUtil.toBuffer(s,_charset)); - } - catch(Exception e) - { - throw new IllegalStateException(e.toString()); - } - } - - public String getOutput() - { - ByteBuffer b = getOut(); - b.flip(); - String s=BufferUtil.toString(b,_charset); - b.clear(); - return s; - } - - /** - * @return true if there are bytes remaining to be read from the encoded input - */ - public boolean hasMore() - { - return getOut().position()>0; - } -} diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/IOFutureTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/IOFutureTest.java index 4b3f8ae9562..1d13e112ad0 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/IOFutureTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/IOFutureTest.java @@ -128,7 +128,7 @@ public class IOFutureTest @Test public void testInCompleted() throws Exception { - IOFuture future = new RecycledIOFuture(); + IOFuture future = new DispatchedIOFuture(); assertFalse(future.isComplete()); assertFalse(future.isReady()); @@ -163,7 +163,7 @@ public class IOFutureTest @Test public void testReady() throws Exception { - final RecycledIOFuture future = new RecycledIOFuture(); + final DispatchedIOFuture future = new DispatchedIOFuture(); assertFalse(future.isComplete()); assertFalse(future.isReady()); @@ -243,7 +243,7 @@ public class IOFutureTest @Test public void testFail() throws Exception { - final RecycledIOFuture future = new RecycledIOFuture(); + final DispatchedIOFuture future = new DispatchedIOFuture(); final Exception ex=new Exception("failed"); assertFalse(future.isComplete()); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java index b898772700b..62c2512ec54 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java @@ -229,31 +229,6 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Ht _lowResourceMaxIdleTime = maxIdleTime; } - /* ------------------------------------------------------------ */ - /** - * @return Returns the maxIdleTime when resources are low. - * @deprecated - */ - @Deprecated - @Override - public final int getLowResourceMaxIdleTime() - { - return getLowResourcesMaxIdleTime(); - } - - /* ------------------------------------------------------------ */ - /** - * @param maxIdleTime - * The maxIdleTime to set when resources are low. - * @deprecated - */ - @Deprecated - @Override - public final void setLowResourceMaxIdleTime(int maxIdleTime) - { - setLowResourcesMaxIdleTime(maxIdleTime); - } - /* ------------------------------------------------------------ */ /** * @return Returns the soLingerTime. @@ -1187,7 +1162,7 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Ht if (_statsStartedAt.get() == -1) return; - long duration = System.currentTimeMillis() - connection.getCreatedTimeStamp(); + long duration = System.currentTimeMillis() - connection.getEndPoint().getCreatedTimeStamp(); int requests = (connection instanceof HttpConnection)?((HttpConnection)connection).getHttpChannel().getRequests():0; _requestStats.set(requests); _connectionStats.decrement(); @@ -1235,14 +1210,6 @@ public abstract class AbstractConnector extends AggregateLifeCycle implements Ht _reuseAddress = reuseAddress; } - /* ------------------------------------------------------------ */ - @Override - public boolean isLowResources() - { - if (_threadPool != null) - return _threadPool.isLowOnThreads(); - return _server.getThreadPool().isLowOnThreads(); - } /* ------------------------------------------------------------ */ private void updateNotEqual(AtomicLong valueHolder, long compare, long value) 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 8f114ce5348..40b29bdef4d 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 @@ -863,7 +863,7 @@ public abstract class HttpChannel protected abstract int write(ByteBuffer content) throws IOException; - protected abstract int send(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; 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 efde5795b3b..350a28822af 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,9 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.nio.ByteBuffer; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import org.eclipse.jetty.http.HttpException; import org.eclipse.jetty.http.HttpFields; @@ -26,7 +29,10 @@ import org.eclipse.jetty.http.HttpStatus; import org.eclipse.jetty.io.AbstractAsyncConnection; import org.eclipse.jetty.io.AsyncConnection; import org.eclipse.jetty.io.AsyncEndPoint; +import org.eclipse.jetty.io.CompleteIOFuture; import org.eclipse.jetty.io.EofException; +import org.eclipse.jetty.io.IOFuture; +import org.eclipse.jetty.io.DispatchedIOFuture; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -46,13 +52,14 @@ public class HttpConnection extends AbstractAsyncConnection private final HttpParser _parser; private final HttpGenerator _generator; private final HttpChannel _channel; + private final Lock _lock = new ReentrantLock(); + + private IOFuture _writeFuture; - int _toFlush; ByteBuffer _requestBuffer=null; ByteBuffer _responseHeader=null; ByteBuffer _chunk=null; ByteBuffer _responseBuffer=null; - ByteBuffer _content=null; /* ------------------------------------------------------------ */ @@ -251,201 +258,208 @@ public class HttpConnection extends AbstractAsyncConnection /* ------------------------------------------------------------ */ - private int send(HttpGenerator.ResponseInfo info, ByteBuffer content) throws IOException + private void send(HttpGenerator.ResponseInfo info, ByteBuffer content) throws IOException { - if (_generator.isCommitted() || BufferUtil.hasContent(_responseBuffer) || _toFlush!=0) - throw new IllegalStateException("!send after append"); - if (_generator.isComplete()) - throw new EofException(); - - long prepared=_generator.getContentPrepared(); - - do + _lock.lock(); + try { - if (LOG.isDebugEnabled()) - LOG.debug("{}: send({},{},{})@{}", - this, - BufferUtil.toSummaryString(_responseHeader), - BufferUtil.toSummaryString(_responseBuffer), - BufferUtil.toSummaryString(content), - _generator.getState()); - - HttpGenerator.Result result=_generator.generate(info,_responseHeader,null,_responseBuffer,content,Action.COMPLETE); - if (LOG.isDebugEnabled()) - LOG.debug("{}: {} ({},{},{})@{}", - this, - result, - BufferUtil.toSummaryString(_responseHeader), - BufferUtil.toSummaryString(_responseBuffer), - BufferUtil.toSummaryString(content), - _generator.getState()); + if (_generator.isCommitted() || BufferUtil.hasContent(_responseBuffer)) + throw new IllegalStateException("!send after append"); + if (_generator.isComplete()) + throw new EofException(); - switch(result) + do { - case NEED_HEADER: - _responseHeader=_connector.getResponseBuffers().getHeader(); - break; + if (LOG.isDebugEnabled()) + LOG.debug("{}: send({},{},{})@{}", + this, + BufferUtil.toSummaryString(_responseHeader), + BufferUtil.toSummaryString(_responseBuffer), + BufferUtil.toSummaryString(content), + _generator.getState()); - case NEED_BUFFER: - _responseBuffer=_connector.getResponseBuffers().getBuffer(); - break; + HttpGenerator.Result result=_generator.generate(info,_responseHeader,null,_responseBuffer,content,Action.COMPLETE); + if (LOG.isDebugEnabled()) + LOG.debug("{}: {} ({},{},{})@{}", + this, + result, + BufferUtil.toSummaryString(_responseHeader), + BufferUtil.toSummaryString(_responseBuffer), + BufferUtil.toSummaryString(content), + _generator.getState()); - case NEED_CHUNK: - throw new IllegalStateException("!chunk when content length known"); - - case FLUSH: - _toFlush= - (BufferUtil.hasContent(_responseHeader)?8:0)+ - (BufferUtil.hasContent(_chunk)?4:0)+ - (BufferUtil.hasContent(_responseBuffer)?2:0); - flush(true); - break; - - case FLUSH_CONTENT: - _content=content; - _toFlush= - (BufferUtil.hasContent(_responseHeader)?8:0)+ - (BufferUtil.hasContent(_chunk)?4:0)+ - (BufferUtil.hasContent(_content)?1:0); - flush(false); - break; - - case SHUTDOWN_OUT: - getEndPoint().shutdownOutput(); - break; - - case OK: - break; + switch(result) + { + case NEED_HEADER: + _responseHeader=_connector.getResponseBuffers().getHeader(); + break; + + case NEED_BUFFER: + _responseBuffer=_connector.getResponseBuffers().getBuffer(); + break; + + case NEED_CHUNK: + throw new IllegalStateException("!chunk when content length known"); + + case FLUSH: + write(_responseHeader,_chunk,_responseBuffer).block(); + break; + + case FLUSH_CONTENT: + _writeFuture=write(_responseHeader,_chunk,content); + return; + + case SHUTDOWN_OUT: + getEndPoint().shutdownOutput(); + break; + + case OK: + break; + } + } + while(BufferUtil.hasContent(content)); + } + catch(InterruptedException e) + { + LOG.debug(e); + } + catch(ExecutionException e) + { + LOG.debug(e); + DispatchedIOFuture.rethrow(e); + } + finally + { + _lock.unlock(); + } + } + + /* ------------------------------------------------------------ */ + private int generate(HttpGenerator.ResponseInfo info, ByteBuffer content, Action action) throws IOException + { + boolean hasContent=BufferUtil.hasContent(content); + long preparedBefore=0; + long preparedAfter; + _lock.lock(); + try + { + preparedBefore=_generator.getContentPrepared(); + + if (_generator.isComplete()) + throw new EofException(); + + do + { + // block if the last write is not complete + if (_writeFuture!=null && !_writeFuture.isComplete()) + _writeFuture.block(); + + if (LOG.isDebugEnabled()) + LOG.debug("{}: generate({},{},{},{},{})@{}", + this, + BufferUtil.toSummaryString(_responseHeader), + BufferUtil.toSummaryString(_chunk), + BufferUtil.toSummaryString(_responseBuffer), + BufferUtil.toSummaryString(content), + action,_generator.getState()); + + HttpGenerator.Result result=_generator.generate(info,_responseHeader,_chunk,_responseBuffer,content,action); + if (LOG.isDebugEnabled()) + LOG.debug("{}: {} ({},{},{},{},{})@{}", + this, + result, + BufferUtil.toSummaryString(_responseHeader), + BufferUtil.toSummaryString(_chunk), + BufferUtil.toSummaryString(_responseBuffer), + BufferUtil.toSummaryString(content), + action,_generator.getState()); + + switch(result) + { + case NEED_HEADER: + _responseHeader=_connector.getResponseBuffers().getHeader(); + break; + + case NEED_BUFFER: + _responseBuffer=_connector.getResponseBuffers().getBuffer(); + break; + + case NEED_CHUNK: + _responseHeader=null; + _chunk=_connector.getResponseBuffers().getBuffer(HttpGenerator.CHUNK_SIZE); + break; + + case FLUSH: + if (hasContent) + write(_responseHeader,_chunk,_responseBuffer).block(); + else + _writeFuture=write(_responseHeader,_chunk,_responseBuffer); + break; + + case FLUSH_CONTENT: + write(_responseHeader,_chunk,content).block(); + break; + + case SHUTDOWN_OUT: + getEndPoint().shutdownOutput(); + break; + + case OK: + break; + } + } + while(BufferUtil.hasContent(content)); + } + catch(InterruptedException e) + { + LOG.debug(e); + } + catch(ExecutionException e) + { + LOG.debug(e); + if (e.getCause() instanceof IOException) + throw (IOException)e.getCause(); + throw new RuntimeException(e); + } + finally + { + preparedAfter=_generator.getContentPrepared(); + _lock.unlock(); + } + return (int)(preparedAfter-preparedBefore); + } + + private IOFuture write(ByteBuffer b0,ByteBuffer b1,ByteBuffer b2) + { + if (BufferUtil.hasContent(b0)) + { + if (BufferUtil.hasContent(b1)) + { + if (BufferUtil.hasContent(b2)) + return _endp.write(b0,b1,b2); + return _endp.write(b0,b1); + } + else + { + if (BufferUtil.hasContent(b2)) + return _endp.write(b0,b2); + return _endp.write(b0); } } - while(BufferUtil.hasContent(content)); - - return (int)(prepared-_generator.getContentPrepared()); - } - - /* ------------------------------------------------------------ */ - private int write(HttpGenerator.ResponseInfo info, ByteBuffer content, Action action) throws IOException - { - if (_generator.isComplete()) - throw new EofException(); - - long prepared=_generator.getContentPrepared(); - - do + else { - if (_toFlush!=0) - flush(true); - - if (LOG.isDebugEnabled()) - LOG.debug("{}: generate({},{},{},{},{})@{}", - this, - BufferUtil.toSummaryString(_responseHeader), - BufferUtil.toSummaryString(_chunk), - BufferUtil.toSummaryString(_responseBuffer), - BufferUtil.toSummaryString(content), - action,_generator.getState()); - - HttpGenerator.Result result=_generator.generate(info,_responseHeader,_chunk,_responseBuffer,content,action); - if (LOG.isDebugEnabled()) - LOG.debug("{}: {} ({},{},{},{},{})@{}", - this, - result, - BufferUtil.toSummaryString(_responseHeader), - BufferUtil.toSummaryString(_chunk), - BufferUtil.toSummaryString(_responseBuffer), - BufferUtil.toSummaryString(content), - action,_generator.getState()); - - switch(result) + if (BufferUtil.hasContent(b1)) { - case NEED_HEADER: - _responseHeader=_connector.getResponseBuffers().getHeader(); - break; - - case NEED_BUFFER: - _responseBuffer=_connector.getResponseBuffers().getBuffer(); - break; - - case NEED_CHUNK: - _responseHeader=null; - _chunk=_connector.getResponseBuffers().getBuffer(HttpGenerator.CHUNK_SIZE); - break; - - case FLUSH: - _toFlush= - (BufferUtil.hasContent(_responseHeader)?8:0)+ - (BufferUtil.hasContent(_chunk)?4:0)+ - (BufferUtil.hasContent(_responseBuffer)?2:0); - flush(false); - break; - - case FLUSH_CONTENT: - _content=content; - _toFlush= - (BufferUtil.hasContent(_responseHeader)?8:0)+ - (BufferUtil.hasContent(_chunk)?4:0)+ - (BufferUtil.hasContent(_content)?1:0); - flush(false); - break; - - case SHUTDOWN_OUT: - getEndPoint().shutdownOutput(); - break; - - case OK: - break; + if (BufferUtil.hasContent(b2)) + return _endp.write(b1,b2); + return _endp.write(b1); } - } - while(BufferUtil.hasContent(content)); - - return (int)(prepared-_generator.getContentPrepared()); - } - - /* ------------------------------------------------------------ */ - private void flush(boolean block) throws IOException - { - while (_toFlush>0) - { - switch(_toFlush) + else { - case 10: - _endp.write(_responseHeader,_responseBuffer); - break; - case 9: - _endp.write(_responseHeader,_content); - _content=null; - break; - case 8: - _endp.write(_responseHeader); - break; - case 6: - _endp.write(_chunk,_responseBuffer); - break; - case 5: - _endp.write(_chunk,_content); - _content=null; - break; - case 4: - _endp.write(_chunk); - break; - case 2: - _endp.write(_responseBuffer); - break; - case 1: - _endp.write(_content); - _content=null; - break; - case 0: - default: - throw new IllegalStateException(); + if (BufferUtil.hasContent(b2)) + return _endp.write(b2); + return CompleteIOFuture.COMPLETE; } - - if (!block) - break; - - if (_toFlush>0) - blockWriteable(); - } } @@ -519,13 +533,13 @@ public class HttpConnection extends AbstractAsyncConnection @Override protected int write(ByteBuffer content) throws IOException { - return HttpConnection.this.write(getResponseInfo(),content,Action.PREPARE); + return HttpConnection.this.generate(getResponseInfo(),content,Action.PREPARE); } @Override - protected int send(ByteBuffer content) throws IOException + protected void send(ByteBuffer content) throws IOException { - return HttpConnection.this.send(getResponseInfo(),content); + HttpConnection.this.send(getResponseInfo(),content); } @Override @@ -622,25 +636,25 @@ public class HttpConnection extends AbstractAsyncConnection @Override protected void flushResponse() throws IOException { - HttpConnection.this.write(getResponseInfo(),null,Action.FLUSH); + HttpConnection.this.generate(getResponseInfo(),null,Action.FLUSH); } @Override protected void completeResponse() throws IOException { - HttpConnection.this.write(getResponseInfo(),null,Action.COMPLETE); + HttpConnection.this.generate(getResponseInfo(),null,Action.COMPLETE); } @Override protected void blockForContent() throws IOException { // While progress and the connection has not changed - while (!_endp.isInputShutdown()) + while (_endp.isOpen()) { try { // Wait until we can read - getEndPoint().blockReadable(); + getEndPoint().read().block(); // We will need a buffer to read into if (_requestBuffer==null) @@ -650,6 +664,15 @@ public class HttpConnection extends AbstractAsyncConnection if (BufferUtil.hasContent(_requestBuffer) && _parser.parseNext(_requestBuffer)) return; } + catch (InterruptedException e) + { + LOG.debug(e); + } + catch (ExecutionException e) + { + LOG.debug(e); + DispatchedIOFuture.rethrow(e); + } finally { // Return empty request buffer diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java index 7a21dafcc9d..4861b4e59bc 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/LocalConnector.java @@ -152,7 +152,7 @@ public class LocalConnector extends AbstractConnector { if (!leaveOpen) connectionClosed(connection); - _responsesBuffer = endPoint.getOut(); + _responsesBuffer = endPoint.getOutput(); } } finally diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index 695580af879..c38f31cf89d 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -154,7 +154,7 @@ public class HttpConnectionTest { try { - ((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(true); + ((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true); String response; @@ -185,7 +185,7 @@ public class HttpConnectionTest } finally { - ((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(false); + ((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(false); } } @@ -335,7 +335,7 @@ public class HttpConnectionTest Logger logger=null; try { - ((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(true); + ((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(true); response=connector.getResponses(requests); offset = checkContains(response,offset,"HTTP/1.1 500"); offset = checkContains(response,offset,"Connection: close"); @@ -343,7 +343,7 @@ public class HttpConnectionTest } finally { - ((StdErrLog)Log.getLogger(AbstractHttpConnection.class)).setHideStacks(false); + ((StdErrLog)Log.getLogger(HttpConnection.class)).setHideStacks(false); } } @@ -443,7 +443,7 @@ public class HttpConnectionTest try { baseRequest.setHandled(true); - response.setHeader(HttpHeader.CONTENT_TYPE,MimeTypes.TEXT_HTML); + response.setHeader(HttpHeader.CONTENT_TYPE.toString(),MimeTypes.Type.TEXT_HTML.toString()); response.setHeader("LongStr", longstr); PrintWriter writer = response.getWriter(); writer.write("

FOO

"); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java index afb9bf3e43e..b89007f0120 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpWriterTest.java @@ -188,7 +188,7 @@ public class HttpWriterTest hb.completeHeader(fields,true); hb.flush(10000); - String response = new String(endp.getOut().asArray(),StringUtil.__UTF8); + String response = new String(endp.getOutput().asArray(),StringUtil.__UTF8); assertTrue(response.startsWith("HTTP/1.1 200 OK\r\nContent-Length: 1025\r\n\r\n\u05531234567890")); } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index df78045dee5..a38cb342efa 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -411,7 +411,7 @@ public class ResponseTest response.sendRedirect(tests[i][0]); - String location = out.getOut().toString(); + String location = out.getOutput().toString(); int l=location.indexOf("Location: "); int e=location.indexOf('\n',l); location=location.substring(l+10,e).trim(); @@ -504,7 +504,7 @@ public class ResponseTest private Response newResponse() { ByteArrayEndPoint endPoint = new ByteArrayEndPoint(); - endPoint.setOut(new ByteArrayBuffer(1024)); + endPoint.setOutput(new ByteArrayBuffer(1024)); endPoint.setGrowOutput(true); AbstractHttpConnection connection=new TestHttpConnection(connector, endPoint, connector.getServer()); connection.getGenerator().reset(); diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java index da2b21a82e1..9a07562ee57 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/BufferUtil.java @@ -225,6 +225,27 @@ public class BufferUtil return buffer==null?0:buffer.remaining(); } + /* ------------------------------------------------------------ */ + /** Get the space from the limit to the capacity + * @param buffer + * @return space + */ + public static int space(ByteBuffer buffer) + { + if (buffer==null) + return 0; + return buffer.capacity()-buffer.limit(); + } + + /* ------------------------------------------------------------ */ + /** Compact the buffer + * @param buffer + */ + public static void compact(ByteBuffer buffer) + { + buffer.compact().flip(); + } + /* ------------------------------------------------------------ */ /** * Put data from one buffer into another, avoiding over/under flows @@ -733,4 +754,5 @@ public class BufferUtil } + }