diff --git a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod index 71ab903803e..2716e27fb22 100644 --- a/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod +++ b/jetty-gcloud/jetty-gcloud-session-manager/src/main/config-template/modules/gcloud.mod @@ -15,4 +15,4 @@ http://www.apache.org/licenses/LICENSE-2.0.html [ini-template] ## Hide the gcloud libraries from deployed webapps -jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/gcloud/ +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/gcloud/ diff --git a/jetty-gcloud/pom.xml b/jetty-gcloud/pom.xml index afb7fca7710..ebdb8b987ac 100644 --- a/jetty-gcloud/pom.xml +++ b/jetty-gcloud/pom.xml @@ -13,7 +13,7 @@ Jetty :: GCloud - 0.8.3-beta + 0.9.2-beta diff --git a/jetty-home/src/main/resources/bin/jetty.sh b/jetty-home/src/main/resources/bin/jetty.sh index 20949ba0db7..eec8b767ec2 100755 --- a/jetty-home/src/main/resources/bin/jetty.sh +++ b/jetty-home/src/main/resources/bin/jetty.sh @@ -150,6 +150,24 @@ readConfig() source "$1" } +dumpEnv() +{ + echo "JAVA = $JAVA" + echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}" + echo "JETTY_HOME = $JETTY_HOME" + echo "JETTY_BASE = $JETTY_BASE" + echo "START_D = $START_D" + echo "START_INI = $START_INI" + echo "JETTY_START = $JETTY_START" + echo "JETTY_CONF = $JETTY_CONF" + echo "JETTY_ARGS = ${JETTY_ARGS[*]}" + echo "JETTY_RUN = $JETTY_RUN" + echo "JETTY_PID = $JETTY_PID" + echo "JETTY_START_LOG= $JETTY_START_LOG" + echo "JETTY_STATE = $JETTY_STATE" + echo "RUN_CMD = ${RUN_CMD[*]}" +} + ################################################## @@ -278,6 +296,14 @@ then [ -d "$JETTY_RUN" ] || mkdir $JETTY_RUN fi +##################################################### +# define start log location +##################################################### +if [ -z "$JETTY_START_LOG" ] +then + JETTY_START_LOG="$JETTY_RUN/$NAME-start.log" +fi + ##################################################### # Find a pid and state file ##################################################### @@ -401,17 +427,7 @@ RUN_CMD=("$JAVA" ${RUN_ARGS[@]}) ##################################################### if (( DEBUG )) then - echo "START_INI = $START_INI" - echo "START_D = $START_D" - echo "JETTY_HOME = $JETTY_HOME" - echo "JETTY_BASE = $JETTY_BASE" - echo "JETTY_CONF = $JETTY_CONF" - echo "JETTY_PID = $JETTY_PID" - echo "JETTY_START = $JETTY_START" - echo "JETTY_ARGS = ${JETTY_ARGS[*]}" - echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}" - echo "JAVA = $JAVA" - echo "RUN_CMD = ${RUN_CMD[*]}" + dumpEnv fi ################################################## @@ -434,7 +450,7 @@ case "$ACTION" in CH_USER="-c$JETTY_USER" fi - start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_BASE" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" start-log-file="$JETTY_RUN/start.log" + start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_BASE" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" start-log-file="$JETTY_START_LOG" else @@ -456,7 +472,7 @@ case "$ACTION" in chown "$JETTY_USER" "$JETTY_PID" # FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc. su - "$JETTY_USER" $SU_SHELL -c " - exec ${RUN_CMD[*]} start-log-file="$JETTY_RUN/start.log" > /dev/null & + exec ${RUN_CMD[*]} start-log-file="$JETTY_START_LOG" > /dev/null & disown \$! echo \$! > '$JETTY_PID'" else @@ -569,20 +585,7 @@ case "$ACTION" in echo "Jetty NOT running" fi echo - echo "START_INI = $START_INI" - echo "START_D = $START_D" - echo "JETTY_HOME = $JETTY_HOME" - echo "JETTY_BASE = $JETTY_BASE" - echo "JETTY_CONF = $JETTY_CONF" - echo "JETTY_PID = $JETTY_PID" - echo "JETTY_START = $JETTY_START" - echo "JETTY_LOGS = $JETTY_LOGS" - echo "JETTY_STATE = $JETTY_STATE" - echo "CLASSPATH = $CLASSPATH" - echo "JAVA = $JAVA" - echo "JAVA_OPTIONS = ${JAVA_OPTIONS[*]}" - echo "JETTY_ARGS = ${JETTY_ARGS[*]}" - echo "RUN_CMD = ${RUN_CMD[*]}" + dumpEnv echo if running "$JETTY_PID" 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 d6ca0436c9e..63994a335d1 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 @@ -55,8 +55,25 @@ public class HttpGenerator new MetaData.Response(HttpVersion.HTTP_1_1,INTERNAL_SERVER_ERROR_500,null,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0); // states - public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END } - public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,NEED_CHUNK_TRAILER, FLUSH,CONTINUE,SHUTDOWN_OUT,DONE} + public enum State + { + START, + COMMITTED, + COMPLETING, + COMPLETING_1XX, + END + } + public enum Result + { + NEED_CHUNK, // Need a small chunk buffer of CHUNK_SIZE + NEED_INFO, // Need the request/response metadata info + NEED_HEADER, // Need a buffer to build HTTP headers into + NEED_CHUNK_TRAILER, // Need a large chunk buffer for last chunk and trailers + FLUSH, // The buffers previously generated should be flushed + CONTINUE, // Continue generating the message + SHUTDOWN_OUT, // Need EOF to be signaled + DONE // Message generation complete + } // other statics public static final int CHUNK_SIZE = 12; diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java index 9abd36016c1..f743cd6620f 100644 --- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java +++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AsyncProxyServlet.java @@ -125,7 +125,7 @@ public class AsyncProxyServlet extends ProxyServlet return delegate.rewriteTarget(clientRequest); } } - + protected class StreamReader extends IteratingCallback implements ReadListener { private final byte[] buffer = new byte[getHttpClient().getRequestBufferSize()]; @@ -133,6 +133,7 @@ public class AsyncProxyServlet extends ProxyServlet private final HttpServletResponse response; private final Request proxyRequest; private final DeferredContentProvider provider; + protected StreamReader(HttpServletRequest request, HttpServletResponse response, Request proxyRequest, DeferredContentProvider provider) { @@ -168,9 +169,7 @@ public class AsyncProxyServlet extends ProxyServlet int requestId = _log.isDebugEnabled() ? getRequestId(request) : 0; ServletInputStream input = request.getInputStream(); - // First check for isReady() because it has - // side effects, and then for isFinished(). - while (input.isReady() && !input.isFinished()) + while (input.isReady()) { int read = input.read(buffer); if (_log.isDebugEnabled()) @@ -182,20 +181,17 @@ public class AsyncProxyServlet extends ProxyServlet onRequestContent(request, proxyRequest, provider, buffer, 0, read, this); return Action.SCHEDULED; } + else if (read < 0) + { + if (_log.isDebugEnabled()) + _log.debug("{} asynchronous read complete on {}", requestId, input); + return Action.SUCCEEDED; + } } - if (input.isFinished()) - { - if (_log.isDebugEnabled()) - _log.debug("{} asynchronous read complete on {}", requestId, input); - return Action.SUCCEEDED; - } - else - { - if (_log.isDebugEnabled()) - _log.debug("{} asynchronous read pending on {}", requestId, input); - return Action.IDLE; - } + if (_log.isDebugEnabled()) + _log.debug("{} asynchronous read pending on {}", requestId, input); + return Action.IDLE; } protected void onRequestContent(HttpServletRequest request, Request proxyRequest, DeferredContentProvider provider, byte[] buffer, int offset, int length, Callback callback) diff --git a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncProxyServletLoadTest.java b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletLoadTest.java similarity index 94% rename from jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncProxyServletLoadTest.java rename to jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletLoadTest.java index e1f46197ac4..af4a42785a0 100644 --- a/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/AsyncProxyServletLoadTest.java +++ b/jetty-proxy/src/test/java/org/eclipse/jetty/proxy/ProxyServletLoadTest.java @@ -52,18 +52,19 @@ import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @RunWith(Parameterized.class) -public class AsyncProxyServletLoadTest +public class ProxyServletLoadTest { @Parameterized.Parameters(name = "{0}") public static Iterable data() { return Arrays.asList(new Object[][]{ + {ProxyServlet.class}, {AsyncProxyServlet.class}, {AsyncMiddleManServlet.class} }); } - private static final Logger LOG = Log.getLogger(AsyncProxyServletLoadTest.class); + private static final Logger LOG = Log.getLogger(ProxyServletLoadTest.class); private static final String PROXIED_HEADER = "X-Proxied"; private HttpClient client; @@ -73,7 +74,7 @@ public class AsyncProxyServletLoadTest private Server server; private ServerConnector serverConnector; - public AsyncProxyServletLoadTest(Class proxyServletClass) throws Exception + public ProxyServletLoadTest(Class proxyServletClass) throws Exception { proxyServlet = (AbstractProxyServlet)proxyServletClass.newInstance(); } @@ -170,7 +171,7 @@ public class AsyncProxyServletLoadTest thread.start(); } - Assert.assertTrue(activeClientLatch.await(clientCount * iterations * 10, TimeUnit.MILLISECONDS)); + Assert.assertTrue(activeClientLatch.await(Math.max(clientCount * iterations * 10, 5000), TimeUnit.MILLISECONDS)); Assert.assertTrue(success.get()); } @@ -211,7 +212,7 @@ public class AsyncProxyServletLoadTest if (response.getStatus() != 200) { - LOG.warn("Got response <{}>, expecting <{}>", response.getStatus(), 200); + LOG.warn("Got response <{}>, expecting <{}> iteration=", response.getStatus(), 200,iterations); // allow all ClientLoops to finish success.set(false); } @@ -224,7 +225,7 @@ public class AsyncProxyServletLoadTest } catch (Throwable x) { - LOG.warn("Error processing request", x); + LOG.warn("Error processing request "+iterations, x); success.set(false); } finally 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 223cd3c9c53..331ce27130b 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 @@ -417,7 +417,12 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor status == HttpStatus.NO_CONTENT_204 || status == HttpStatus.NOT_MODIFIED_304); if (hasContent && !_response.isContentComplete(_response.getHttpOutput().getWritten())) - _transport.abort(new IOException("insufficient content written")); + { + if (isCommitted()) + _transport.abort(new IOException("insufficient content written")); + else + _response.sendError(HttpStatus.INTERNAL_SERVER_ERROR_500,"insufficient content written"); + } } _response.closeOutput(); _request.setHandled(true); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java index b504ec5fa34..79153650dec 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java @@ -18,10 +18,6 @@ package org.eclipse.jetty.server; -import static javax.servlet.RequestDispatcher.ERROR_EXCEPTION; -import static javax.servlet.RequestDispatcher.ERROR_MESSAGE; -import static javax.servlet.RequestDispatcher.ERROR_STATUS_CODE; - import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; @@ -42,6 +38,10 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Locker; import org.eclipse.jetty.util.thread.Scheduler; +import static javax.servlet.RequestDispatcher.ERROR_EXCEPTION; +import static javax.servlet.RequestDispatcher.ERROR_MESSAGE; +import static javax.servlet.RequestDispatcher.ERROR_STATUS_CODE; + /** * Implementation of AsyncContext interface that holds the state of request-response cycle. */ @@ -87,7 +87,7 @@ public class HttpChannelState /** * The state of the servlet async API. */ - public enum Async + private enum Async { NOT_ASYNC, STARTED, // AsyncContext.startAsync() has been called @@ -99,27 +99,24 @@ public class HttpChannelState ERRORED // The error has been processed } - public enum Interest + private enum Interest { NONE(false), NEEDED(true), - INTERESTED(true); - - final boolean _interested; - boolean isInterested() { return _interested;} - boolean notInterested() { return !_interested;} + REGISTERED(true); + private final boolean _interested; + Interest(boolean interest) { _interested = interest; } + private boolean isInterested() { return _interested;} } - - private final boolean DEBUG=LOG.isDebugEnabled(); + private final Locker _locker=new Locker(); private final HttpChannel _channel; - private List _asyncListeners; private State _state; private Async _async; @@ -223,7 +220,7 @@ public class HttpChannelState { try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("handling {}",toStringLocked()); switch(_state) @@ -298,7 +295,7 @@ public class HttpChannelState try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("startAsync {}",toStringLocked()); if (_state!=State.DISPATCHED || _async!=Async.NOT_ASYNC) throw new IllegalStateException(this.getStatusStringLocked()); @@ -340,7 +337,6 @@ public class HttpChannelState } } - public void asyncError(Throwable failure) { AsyncContextEvent event = null; @@ -394,7 +390,7 @@ public class HttpChannelState try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("unhandle {}",toStringLocked()); switch(_state) @@ -432,7 +428,9 @@ public class HttpChannelState break; case STARTED: - if (_asyncRead.isInterested() && _asyncReadPossible) + // If a read is possible and either we are interested in reads or we have + // to call onAllDataRead, then we need a READ_CALLBACK + if (_asyncReadPossible && (_asyncRead.isInterested() || _channel.getRequest().getHttpInput().isAsyncEOF())) { _state=State.ASYNC_IO; _asyncRead=Interest.NONE; @@ -450,7 +448,7 @@ public class HttpChannelState action=Action.WAIT; if (_asyncRead==Interest.NEEDED) { - _asyncRead=Interest.INTERESTED; + _asyncRead=Interest.REGISTERED; read_interested=true; } Scheduler scheduler=_channel.getScheduler(); @@ -503,7 +501,7 @@ public class HttpChannelState AsyncContextEvent event; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("dispatch {} -> {}",toStringLocked(),path); boolean started=false; @@ -557,7 +555,7 @@ public class HttpChannelState AsyncContextEvent event; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onTimeout {}",toStringLocked()); if (_async!=Async.STARTED) @@ -656,7 +654,7 @@ public class HttpChannelState AsyncContextEvent event; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("complete {}",toStringLocked()); boolean started=false; @@ -694,7 +692,7 @@ public class HttpChannelState { try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("error complete {}",toStringLocked()); _async=Async.COMPLETE; @@ -729,7 +727,7 @@ public class HttpChannelState try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onError {} {}",toStringLocked(),failure); // Set error on request. @@ -739,8 +737,7 @@ public class HttpChannelState _event.getSuppliedRequest().setAttribute(ERROR_STATUS_CODE,code); _event.getSuppliedRequest().setAttribute(ERROR_EXCEPTION,failure); _event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,failure==null?null:failure.getClass()); - - _event.getSuppliedRequest().setAttribute(ERROR_MESSAGE,reason!=null?reason:null); + _event.getSuppliedRequest().setAttribute(ERROR_MESSAGE,reason); } else { @@ -750,7 +747,7 @@ public class HttpChannelState baseRequest.setAttribute(ERROR_STATUS_CODE,code); baseRequest.setAttribute(ERROR_EXCEPTION,failure); baseRequest.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,failure==null?null:failure.getClass()); - baseRequest.setAttribute(ERROR_MESSAGE,reason!=null?reason:null); + baseRequest.setAttribute(ERROR_MESSAGE,reason); } // Are we blocking? @@ -847,7 +844,7 @@ public class HttpChannelState try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onComplete {}",toStringLocked()); switch(_state) @@ -904,7 +901,7 @@ public class HttpChannelState cancelTimeout(); try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("recycle {}",toStringLocked()); switch(_state) @@ -934,7 +931,7 @@ public class HttpChannelState cancelTimeout(); try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("upgrade {}",toStringLocked()); switch(_state) @@ -1124,9 +1121,8 @@ public class HttpChannelState _channel.getRequest().setAttribute(name,attribute); } - - /* ------------------------------------------------------------ */ - /** Called to signal async read isReady() has returned false. + /** + * Called to signal async read isReady() has returned false. * This indicates that there is no content available to be consumed * and that once the channel enteres the ASYNC_WAIT state it will * register for read interest by calling {@link HttpChannel#asyncReadFillInterested()} @@ -1137,17 +1133,17 @@ public class HttpChannelState boolean interested=false; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onReadUnready {}",toStringLocked()); // We were already unready, this is not a state change, so do nothing - if (_asyncRead!=Interest.INTERESTED) + if (_asyncRead!=Interest.REGISTERED) { _asyncReadPossible=false; // Assumes this has been checked in isReady() with lock held if (_state==State.ASYNC_WAIT) { interested=true; - _asyncRead=Interest.INTERESTED; + _asyncRead=Interest.REGISTERED; } else _asyncRead=Interest.NEEDED; @@ -1158,8 +1154,8 @@ public class HttpChannelState _channel.asyncReadFillInterested(); } - /* ------------------------------------------------------------ */ - /** Called to signal that content is now available to read. + /** + * Called to signal that content is now available to read. * If the channel is in ASYNC_WAIT state and unready (ie isReady() has * returned false), then the state is changed to ASYNC_WOKEN and true * is returned. @@ -1170,7 +1166,7 @@ public class HttpChannelState boolean woken=false; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onReadPossible {}",toStringLocked()); _asyncReadPossible=true; @@ -1183,8 +1179,8 @@ public class HttpChannelState return woken; } - /* ------------------------------------------------------------ */ - /** Called to signal that the channel is ready for a callback. + /** + * Called to signal that the channel is ready for a callback. * This is similar to calling {@link #onReadUnready()} followed by * {@link #onReadPossible()}, except that as content is already * available, read interest is never set. @@ -1195,10 +1191,10 @@ public class HttpChannelState boolean woken=false; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onReadReady {}",toStringLocked()); - _asyncRead=Interest.INTERESTED; + _asyncRead=Interest.REGISTERED; _asyncReadPossible=true; if (_state==State.ASYNC_WAIT) { @@ -1209,8 +1205,8 @@ public class HttpChannelState return woken; } - /* ------------------------------------------------------------ */ - /** Called to signal that a read has read -1. + /** + * Called to signal that a read has read -1. * Will wake if the read was called while in ASYNC_WAIT state * @return true if woken */ @@ -1219,21 +1215,20 @@ public class HttpChannelState boolean woken=false; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onReadEof {}",toStringLocked()); if (_state==State.ASYNC_WAIT) { woken=true; _state=State.ASYNC_WOKEN; - _asyncRead=Interest.INTERESTED; + _asyncRead=Interest.REGISTERED; _asyncReadPossible=true; } } return woken; } - /* ------------------------------------------------------------ */ public boolean isReadPossible() { try(Locker.Lock lock= _locker.lock()) @@ -1242,14 +1237,13 @@ public class HttpChannelState } } - /* ------------------------------------------------------------ */ public boolean onWritePossible() { boolean handle=false; try(Locker.Lock lock= _locker.lock()) { - if(DEBUG) + if (LOG.isDebugEnabled()) LOG.debug("onWritePossible {}",toStringLocked()); _asyncWritePossible=true; @@ -1262,5 +1256,4 @@ public class HttpChannelState return handle; } - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java index 3a439804a94..229d0936604 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java @@ -709,6 +709,14 @@ public class HttpInput extends ServletInputStream implements Runnable } } + public boolean isAsyncEOF() + { + synchronized (_inputQ) + { + return _state == AEOF; + } + } + @Override public boolean isReady() { @@ -1121,4 +1129,5 @@ public class HttpInput extends ServletInputStream implements Runnable return "AEOF"; } }; + } 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 544665efa39..8f1d16e5a03 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 @@ -1114,8 +1114,10 @@ public class Response implements HttpServletResponse @Override public void setBufferSize(int size) { - if (isCommitted() || getContentCount() > 0) - throw new IllegalStateException("cannot set buffer size when response is committed or written to"); + if (isCommitted()) + throw new IllegalStateException("cannot set buffer size after response is in committed state"); + if (getContentCount() > 0) + throw new IllegalStateException("cannot set buffer size after response has " + getContentCount() + " bytes already written"); if (size < __MIN_BUFFER_SIZE) size = __MIN_BUFFER_SIZE; _out.setBufferSize(size); @@ -1215,7 +1217,9 @@ public class Response implements HttpServletResponse protected MetaData.Response newResponseMetaData() { - return new MetaData.Response(_channel.getRequest().getHttpVersion(), getStatus(), getReason(), _fields, getLongContentLength()); + MetaData.Response info = new MetaData.Response(_channel.getRequest().getHttpVersion(), getStatus(), getReason(), _fields, getLongContentLength()); + // TODO info.setTrailerSupplier(trailers); + return info; } /** Get the MetaData.Response committed for this response. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index f4b9a1416af..d112b3bdc6e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -761,7 +761,18 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu throw new IllegalStateException("Null contextPath"); if (_logger==null) - _logger = Log.getLogger(getDisplayName() == null?getContextPath():getDisplayName()); + { + String log_name = getDisplayName(); + if (log_name == null || log_name.isEmpty()) + { + log_name = getContextPath(); + if (log_name!=null || log_name.startsWith("/")) + log_name = log_name.substring(1); + if (log_name==null || log_name.isEmpty()) + log_name = Integer.toHexString(hashCode()); + } + _logger = Log.getLogger("org.eclipse.jetty.ContextHandler."+log_name); + } ClassLoader old_classloader = null; Thread current_thread = null; Context old_context = null; diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToCommitTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToCommitTest.java index 9cb27c4d48e..37963cecb95 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToCommitTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpManyWaysToCommitTest.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.server; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; @@ -442,10 +443,22 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest server.start(); HttpTester.Response response = executeRequest(); - assertThat("response has no status", response.getStatus(), is(0)); + assertThat("response is error", response.getStatus(), is(500)); + assertFalse("response not eof", response.isEarlyEOF()); + } + + @Test + public void testSetContentLengthAndFlushWriteInsufficientBytes() throws Exception + { + server.setHandler(new SetContentLengthAndWriteInsufficientBytesHandler(true)); + server.start(); + + HttpTester.Response response = executeRequest(); + assertThat("response has no status", response.getStatus(), is(200)); assertTrue("response eof", response.isEarlyEOF()); } + @Test public void testSetContentLengthAndWriteExactlyThatAmountOfBytes() throws Exception { diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java index 3b838210b42..863c4486ed2 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Main.java @@ -18,6 +18,8 @@ package org.eclipse.jetty.start; +import static org.eclipse.jetty.start.UsageException.ERR_BAD_GRAPH; +import static org.eclipse.jetty.start.UsageException.ERR_BAD_STOP_PROPS; import static org.eclipse.jetty.start.UsageException.ERR_INVOKE_MAIN; import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED; import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN; @@ -492,19 +494,38 @@ public class Main private void doStop(StartArgs args) { - String stopHost = args.getProperties().getString("STOP.HOST"); - int stopPort = Integer.parseInt(args.getProperties().getString("STOP.PORT")); - String stopKey = args.getProperties().getString("STOP.KEY"); - - if (args.getProperties().getString("STOP.WAIT") != null) + Props.Prop stopHostProp = args.getProperties().getProp("STOP.HOST", true); + Props.Prop stopPortProp = args.getProperties().getProp("STOP.PORT", true); + Props.Prop stopKeyProp = args.getProperties().getProp("STOP.KEY", true); + Props.Prop stopWaitProp = args.getProperties().getProp("STOP.WAIT", true); + + String stopHost = "127.0.0.1"; + int stopPort = -1; + String stopKey = ""; + + if (stopHostProp != null) { - int stopWait = Integer.parseInt(args.getProperties().getString("STOP.WAIT")); + stopHost = stopHostProp.value; + } + + if (stopPortProp != null) + { + stopPort = Integer.parseInt(stopPortProp.value); + } + + if(stopKeyProp != null) + { + stopKey = stopKeyProp.value; + } - stop(stopHost,stopPort,stopKey,stopWait); + if (stopWaitProp != null) + { + int stopWait = Integer.parseInt(stopWaitProp.value); + stop(stopHost, stopPort, stopKey, stopWait); } else { - stop(stopHost,stopPort,stopKey); + stop(stopHost, stopPort, stopKey); } } @@ -522,19 +543,22 @@ public class Main public void stop(String host, int port, String key, int timeout) { if (host==null || host.length()==0) - host="127.0.0.1"; + { + host = "127.0.0.1"; + } try { - if (port <= 0) + if ( (port <= 0) || (port > 65535) ) { - StartLog.error("STOP.PORT system property must be specified"); + System.err.println("STOP.PORT property must be specified with a valid port number"); + usageExit(ERR_BAD_STOP_PROPS); } if (key == null) { key = ""; - StartLog.info("STOP.KEY system property must be specified"); - StartLog.info("Using empty key"); + System.err.println("STOP.KEY property must be specified"); + System.err.println("Using empty key"); } try (Socket s = new Socket(InetAddress.getByName(host),port)) diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java b/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java index 914533d0128..75f124bd82f 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/UsageException.java @@ -29,6 +29,7 @@ public class UsageException extends RuntimeException public static final int ERR_NOT_STOPPED = -4; public static final int ERR_BAD_ARG = -5; public static final int ERR_BAD_GRAPH = -6; + public static final int ERR_BAD_STOP_PROPS = -7; public static final int ERR_UNKNOWN = -9; private int exitCode; diff --git a/jetty-util/src/main/config/modules/logging-jul.mod b/jetty-util/src/main/config/modules/logging-jul.mod index 4a16acdeb41..17391fd1a02 100644 --- a/jetty-util/src/main/config/modules/logging-jul.mod +++ b/jetty-util/src/main/config/modules/logging-jul.mod @@ -16,4 +16,4 @@ logging -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog [ini] -jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/ +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/ diff --git a/jetty-util/src/main/config/modules/logging-log4j.mod b/jetty-util/src/main/config/modules/logging-log4j.mod index 4d5ee4ef692..55d68bc2243 100644 --- a/jetty-util/src/main/config/modules/logging-log4j.mod +++ b/jetty-util/src/main/config/modules/logging-log4j.mod @@ -16,4 +16,4 @@ logging -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog [ini] -jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j/ +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/,${jetty.base.uri}/lib/log4j/ diff --git a/jetty-util/src/main/config/modules/logging-log4j2.mod b/jetty-util/src/main/config/modules/logging-log4j2.mod index 17cf3310462..5c68f013479 100644 --- a/jetty-util/src/main/config/modules/logging-log4j2.mod +++ b/jetty-util/src/main/config/modules/logging-log4j2.mod @@ -16,4 +16,4 @@ logging -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog [ini] -jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/log4j2/ +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/,${jetty.base.uri}/lib/log4j2/ diff --git a/jetty-util/src/main/config/modules/logging-logback.mod b/jetty-util/src/main/config/modules/logging-logback.mod index ccc1aea998b..6fc453669ef 100644 --- a/jetty-util/src/main/config/modules/logging-logback.mod +++ b/jetty-util/src/main/config/modules/logging-logback.mod @@ -16,4 +16,4 @@ logging -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog [ini] -jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/,file:${jetty.base}/lib/logback/ +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/,${jetty.base.uri}/lib/logback/ diff --git a/jetty-util/src/main/config/modules/logging-slf4j.mod b/jetty-util/src/main/config/modules/logging-slf4j.mod index fb26486e9da..5dde76f6e37 100644 --- a/jetty-util/src/main/config/modules/logging-slf4j.mod +++ b/jetty-util/src/main/config/modules/logging-slf4j.mod @@ -16,4 +16,4 @@ logging -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog [ini] -jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/ +jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/ diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java index c07211ffbcd..5d67ee34fa0 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/TypeUtilTest.java @@ -19,8 +19,10 @@ package org.eclipse.jetty.util; +import org.eclipse.jetty.toolchain.test.JDK; import org.hamcrest.Matchers; import org.junit.Assert; +import org.junit.Assume; import org.junit.Test; public class TypeUtilTest @@ -124,8 +126,18 @@ public class TypeUtilTest @Test public void testLoadedFrom() throws Exception { + Assume.assumeFalse(JDK.IS_9); Assert.assertThat(TypeUtil.getLoadedFrom(String.class).toString(),Matchers.containsString("/rt.jar")); Assert.assertThat(TypeUtil.getLoadedFrom(Assert.class).toString(),Matchers.containsString(".jar")); Assert.assertThat(TypeUtil.getLoadedFrom(TypeUtil.class).toString(),Matchers.containsString("/classes/")); } + + @Test + public void testLoadedFrom9() throws Exception + { + Assume.assumeTrue(JDK.IS_9); + Assert.assertThat(TypeUtil.getLoadedFrom(String.class).toString(),Matchers.containsString("jrt:/java.base/java/lang/String.clas")); + Assert.assertThat(TypeUtil.getLoadedFrom(Assert.class).toString(),Matchers.containsString(".jar")); + Assert.assertThat(TypeUtil.getLoadedFrom(TypeUtil.class).toString(),Matchers.containsString("/classes/")); + } } diff --git a/jetty-webapp/src/main/config/modules/webapp.mod b/jetty-webapp/src/main/config/modules/webapp.mod index 22d5ed8d5b2..59f067f8118 100644 --- a/jetty-webapp/src/main/config/modules/webapp.mod +++ b/jetty-webapp/src/main/config/modules/webapp.mod @@ -20,8 +20,8 @@ lib/jetty-webapp-${jetty.version}.jar ## Lists of patterns are comma separated and may be either: ## + a qualified classname e.g. 'com.acme.Foo' ## + a package name e.g. 'net.example.' -## + a jar file e.g. 'file:${jetty.base}/lib/dependency.jar' -## + a directory of jars,resource or classes e.g. 'file:${jetty.base}/resources' +## + a jar file e.g. '${jetty.base.uri}/lib/dependency.jar' +## + a directory of jars,resource or classes e.g. '${jetty.base.uri}/resources' ## + A pattern preceeded with a '-' is an exclusion, all other patterns are inclusions ## ## The +=, operator appends to a CSV list with a comma as needed. diff --git a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java index 9454ffd1e10..c021b223839 100644 --- a/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java +++ b/tests/test-http-client-transport/src/test/java/org/eclipse/jetty/http/client/AsyncIOServletTest.java @@ -1252,7 +1252,7 @@ public class AsyncIOServletTest extends AbstractTest @Override public void onDataAvailable() throws IOException { - while (input.isReady() && !input.isFinished()) + while (input.isReady()) { int b = input.read(); if (b>0) @@ -1260,8 +1260,8 @@ public class AsyncIOServletTest extends AbstractTest // System.err.printf("0x%2x %s %n", b, Character.isISOControl(b)?"?":(""+(char)b)); out.write(b); } - else - onAllDataRead(); + else if (b<0) + return; } } diff --git a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java index 3ca332586a2..d21b9493af2 100644 --- a/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java +++ b/tests/test-sessions/test-sessions-common/src/test/java/org/eclipse/jetty/server/session/SessionEvictionFailureTest.java @@ -59,11 +59,12 @@ public class SessionEvictionFailureTest */ public static class MockSessionDataStore extends AbstractSessionDataStore { - public boolean _nextResult; + public boolean[] _nextStoreResult; + public int i = 0; - public void setNextResult (boolean goodOrBad) + public MockSessionDataStore (boolean[] results) { - _nextResult = goodOrBad; + _nextStoreResult = results; } /** @@ -108,7 +109,7 @@ public class SessionEvictionFailureTest @Override public void doStore(String id, SessionData data, long lastSaveTime) throws Exception { - if (!_nextResult) + if (_nextStoreResult != null && !_nextStoreResult[i++]) { throw new IllegalStateException("Testing store"); } @@ -132,6 +133,12 @@ public class SessionEvictionFailureTest */ public static class MockSessionDataStoreFactory extends AbstractSessionDataStoreFactory { + public boolean[] _nextStoreResults; + + public void setNextStoreResults(boolean[] storeResults) + { + _nextStoreResults = storeResults; + } /** * @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler) @@ -139,7 +146,7 @@ public class SessionEvictionFailureTest @Override public SessionDataStore getSessionDataStore(SessionHandler handler) throws Exception { - return new MockSessionDataStore(); + return new MockSessionDataStore(_nextStoreResults); } } @@ -208,7 +215,7 @@ public class SessionEvictionFailureTest TestServer server = new TestServer (0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory); ServletContextHandler context = server.addContext(contextPath); context.getSessionHandler().getSessionCache().setSaveOnInactiveEviction(true); - MockSessionDataStore ds = new MockSessionDataStore(); + MockSessionDataStore ds = new MockSessionDataStore(new boolean[] {true, false, true, false, true}); context.getSessionHandler().getSessionCache().setSessionDataStore(ds); TestServlet servlet = new TestServlet(); @@ -226,7 +233,6 @@ public class SessionEvictionFailureTest String url = "http://localhost:" + port1 + contextPath + servletMapping; // Create the session - ds.setNextResult(true); ContentResponse response = client.GET(url + "?action=init"); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); String sessionCookie = response.getHeaders().get("Set-Cookie"); @@ -234,13 +240,10 @@ public class SessionEvictionFailureTest // Mangle the cookie, replacing Path with $Path, etc. sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); - ds.setNextResult(false); - //Wait for the eviction period to expire - save on evict should fail but session //should remain in the cache - pause(evictionPeriod); + pause(evictionPeriod+(int)(evictionPeriod*0.5)); - ds.setNextResult(true); // Make another request to see if the session is still in the cache and can be used, //allow it to be saved this time @@ -249,12 +252,11 @@ public class SessionEvictionFailureTest response = request.send(); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); assertNull(response.getHeaders().get("Set-Cookie")); //check that the cookie wasn't reset - ds.setNextResult(false); + //Wait for the eviction period to expire again - pause(evictionPeriod); - - ds.setNextResult(true); + pause(evictionPeriod+(int)(evictionPeriod*0.5)); + request = client.newRequest(url + "?action=test"); request.header("Cookie", sessionCookie);