Merge remote-tracking branch 'origin/jetty-9.4.x'

This commit is contained in:
Joakim Erdfelt 2017-02-15 11:54:57 -07:00
commit 3c29947a0d
23 changed files with 240 additions and 149 deletions

View File

@ -15,4 +15,4 @@ http://www.apache.org/licenses/LICENSE-2.0.html
[ini-template] [ini-template]
## Hide the gcloud libraries from deployed webapps ## Hide the gcloud libraries from deployed webapps
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/gcloud/ jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/gcloud/

View File

@ -13,7 +13,7 @@
<name>Jetty :: GCloud</name> <name>Jetty :: GCloud</name>
<properties> <properties>
<gcloud.version>0.8.3-beta</gcloud.version> <gcloud.version>0.9.2-beta</gcloud.version>
</properties> </properties>
<modules> <modules>

View File

@ -150,6 +150,24 @@ readConfig()
source "$1" 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 [ -d "$JETTY_RUN" ] || mkdir $JETTY_RUN
fi 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 # Find a pid and state file
##################################################### #####################################################
@ -401,17 +427,7 @@ RUN_CMD=("$JAVA" ${RUN_ARGS[@]})
##################################################### #####################################################
if (( DEBUG )) if (( DEBUG ))
then then
echo "START_INI = $START_INI" dumpEnv
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[*]}"
fi fi
################################################## ##################################################
@ -434,7 +450,7 @@ case "$ACTION" in
CH_USER="-c$JETTY_USER" CH_USER="-c$JETTY_USER"
fi 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 else
@ -456,7 +472,7 @@ case "$ACTION" in
chown "$JETTY_USER" "$JETTY_PID" chown "$JETTY_USER" "$JETTY_PID"
# FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc. # FIXME: Broken solution: wordsplitting, pathname expansion, arbitrary command execution, etc.
su - "$JETTY_USER" $SU_SHELL -c " 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 \$! disown \$!
echo \$! > '$JETTY_PID'" echo \$! > '$JETTY_PID'"
else else
@ -569,20 +585,7 @@ case "$ACTION" in
echo "Jetty NOT running" echo "Jetty NOT running"
fi fi
echo echo
echo "START_INI = $START_INI" dumpEnv
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[*]}"
echo echo
if running "$JETTY_PID" if running "$JETTY_PID"

View File

@ -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); new MetaData.Response(HttpVersion.HTTP_1_1,INTERNAL_SERVER_ERROR_500,null,new HttpFields(){{put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);}},0);
// states // states
public enum State { START, COMMITTED, COMPLETING, COMPLETING_1XX, END } public enum State
public enum Result { NEED_CHUNK,NEED_INFO,NEED_HEADER,NEED_CHUNK_TRAILER, FLUSH,CONTINUE,SHUTDOWN_OUT,DONE} {
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 // other statics
public static final int CHUNK_SIZE = 12; public static final int CHUNK_SIZE = 12;

View File

@ -125,7 +125,7 @@ public class AsyncProxyServlet extends ProxyServlet
return delegate.rewriteTarget(clientRequest); return delegate.rewriteTarget(clientRequest);
} }
} }
protected class StreamReader extends IteratingCallback implements ReadListener protected class StreamReader extends IteratingCallback implements ReadListener
{ {
private final byte[] buffer = new byte[getHttpClient().getRequestBufferSize()]; private final byte[] buffer = new byte[getHttpClient().getRequestBufferSize()];
@ -133,6 +133,7 @@ public class AsyncProxyServlet extends ProxyServlet
private final HttpServletResponse response; private final HttpServletResponse response;
private final Request proxyRequest; private final Request proxyRequest;
private final DeferredContentProvider provider; private final DeferredContentProvider provider;
protected StreamReader(HttpServletRequest request, HttpServletResponse response, Request proxyRequest, 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; int requestId = _log.isDebugEnabled() ? getRequestId(request) : 0;
ServletInputStream input = request.getInputStream(); ServletInputStream input = request.getInputStream();
// First check for isReady() because it has while (input.isReady())
// side effects, and then for isFinished().
while (input.isReady() && !input.isFinished())
{ {
int read = input.read(buffer); int read = input.read(buffer);
if (_log.isDebugEnabled()) if (_log.isDebugEnabled())
@ -182,20 +181,17 @@ public class AsyncProxyServlet extends ProxyServlet
onRequestContent(request, proxyRequest, provider, buffer, 0, read, this); onRequestContent(request, proxyRequest, provider, buffer, 0, read, this);
return Action.SCHEDULED; 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 pending on {}", requestId, input);
if (_log.isDebugEnabled()) return Action.IDLE;
_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;
}
} }
protected void onRequestContent(HttpServletRequest request, Request proxyRequest, DeferredContentProvider provider, byte[] buffer, int offset, int length, Callback callback) protected void onRequestContent(HttpServletRequest request, Request proxyRequest, DeferredContentProvider provider, byte[] buffer, int offset, int length, Callback callback)

View File

@ -52,18 +52,19 @@ import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
@RunWith(Parameterized.class) @RunWith(Parameterized.class)
public class AsyncProxyServletLoadTest public class ProxyServletLoadTest
{ {
@Parameterized.Parameters(name = "{0}") @Parameterized.Parameters(name = "{0}")
public static Iterable<Object[]> data() public static Iterable<Object[]> data()
{ {
return Arrays.asList(new Object[][]{ return Arrays.asList(new Object[][]{
{ProxyServlet.class},
{AsyncProxyServlet.class}, {AsyncProxyServlet.class},
{AsyncMiddleManServlet.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 static final String PROXIED_HEADER = "X-Proxied";
private HttpClient client; private HttpClient client;
@ -73,7 +74,7 @@ public class AsyncProxyServletLoadTest
private Server server; private Server server;
private ServerConnector serverConnector; private ServerConnector serverConnector;
public AsyncProxyServletLoadTest(Class<?> proxyServletClass) throws Exception public ProxyServletLoadTest(Class<?> proxyServletClass) throws Exception
{ {
proxyServlet = (AbstractProxyServlet)proxyServletClass.newInstance(); proxyServlet = (AbstractProxyServlet)proxyServletClass.newInstance();
} }
@ -170,7 +171,7 @@ public class AsyncProxyServletLoadTest
thread.start(); 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()); Assert.assertTrue(success.get());
} }
@ -211,7 +212,7 @@ public class AsyncProxyServletLoadTest
if (response.getStatus() != 200) 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 // allow all ClientLoops to finish
success.set(false); success.set(false);
} }
@ -224,7 +225,7 @@ public class AsyncProxyServletLoadTest
} }
catch (Throwable x) catch (Throwable x)
{ {
LOG.warn("Error processing request", x); LOG.warn("Error processing request "+iterations, x);
success.set(false); success.set(false);
} }
finally finally

View File

@ -417,7 +417,12 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor
status == HttpStatus.NO_CONTENT_204 || status == HttpStatus.NO_CONTENT_204 ||
status == HttpStatus.NOT_MODIFIED_304); status == HttpStatus.NOT_MODIFIED_304);
if (hasContent && !_response.isContentComplete(_response.getHttpOutput().getWritten())) 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(); _response.closeOutput();
_request.setHandled(true); _request.setHandled(true);

View File

@ -18,10 +18,6 @@
package org.eclipse.jetty.server; 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.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; 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.Locker;
import org.eclipse.jetty.util.thread.Scheduler; 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. * 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. * The state of the servlet async API.
*/ */
public enum Async private enum Async
{ {
NOT_ASYNC, NOT_ASYNC,
STARTED, // AsyncContext.startAsync() has been called STARTED, // AsyncContext.startAsync() has been called
@ -99,27 +99,24 @@ public class HttpChannelState
ERRORED // The error has been processed ERRORED // The error has been processed
} }
public enum Interest private enum Interest
{ {
NONE(false), NONE(false),
NEEDED(true), NEEDED(true),
INTERESTED(true); REGISTERED(true);
final boolean _interested;
boolean isInterested() { return _interested;}
boolean notInterested() { return !_interested;}
private final boolean _interested;
Interest(boolean interest) Interest(boolean interest)
{ {
_interested = interest; _interested = interest;
} }
private boolean isInterested() { return _interested;}
} }
private final boolean DEBUG=LOG.isDebugEnabled();
private final Locker _locker=new Locker(); private final Locker _locker=new Locker();
private final HttpChannel _channel; private final HttpChannel _channel;
private List<AsyncListener> _asyncListeners; private List<AsyncListener> _asyncListeners;
private State _state; private State _state;
private Async _async; private Async _async;
@ -223,7 +220,7 @@ public class HttpChannelState
{ {
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("handling {}",toStringLocked()); LOG.debug("handling {}",toStringLocked());
switch(_state) switch(_state)
@ -298,7 +295,7 @@ public class HttpChannelState
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("startAsync {}",toStringLocked()); LOG.debug("startAsync {}",toStringLocked());
if (_state!=State.DISPATCHED || _async!=Async.NOT_ASYNC) if (_state!=State.DISPATCHED || _async!=Async.NOT_ASYNC)
throw new IllegalStateException(this.getStatusStringLocked()); throw new IllegalStateException(this.getStatusStringLocked());
@ -340,7 +337,6 @@ public class HttpChannelState
} }
} }
public void asyncError(Throwable failure) public void asyncError(Throwable failure)
{ {
AsyncContextEvent event = null; AsyncContextEvent event = null;
@ -394,7 +390,7 @@ public class HttpChannelState
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("unhandle {}",toStringLocked()); LOG.debug("unhandle {}",toStringLocked());
switch(_state) switch(_state)
@ -432,7 +428,9 @@ public class HttpChannelState
break; break;
case STARTED: 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; _state=State.ASYNC_IO;
_asyncRead=Interest.NONE; _asyncRead=Interest.NONE;
@ -450,7 +448,7 @@ public class HttpChannelState
action=Action.WAIT; action=Action.WAIT;
if (_asyncRead==Interest.NEEDED) if (_asyncRead==Interest.NEEDED)
{ {
_asyncRead=Interest.INTERESTED; _asyncRead=Interest.REGISTERED;
read_interested=true; read_interested=true;
} }
Scheduler scheduler=_channel.getScheduler(); Scheduler scheduler=_channel.getScheduler();
@ -503,7 +501,7 @@ public class HttpChannelState
AsyncContextEvent event; AsyncContextEvent event;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("dispatch {} -> {}",toStringLocked(),path); LOG.debug("dispatch {} -> {}",toStringLocked(),path);
boolean started=false; boolean started=false;
@ -557,7 +555,7 @@ public class HttpChannelState
AsyncContextEvent event; AsyncContextEvent event;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onTimeout {}",toStringLocked()); LOG.debug("onTimeout {}",toStringLocked());
if (_async!=Async.STARTED) if (_async!=Async.STARTED)
@ -656,7 +654,7 @@ public class HttpChannelState
AsyncContextEvent event; AsyncContextEvent event;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("complete {}",toStringLocked()); LOG.debug("complete {}",toStringLocked());
boolean started=false; boolean started=false;
@ -694,7 +692,7 @@ public class HttpChannelState
{ {
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("error complete {}",toStringLocked()); LOG.debug("error complete {}",toStringLocked());
_async=Async.COMPLETE; _async=Async.COMPLETE;
@ -729,7 +727,7 @@ public class HttpChannelState
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onError {} {}",toStringLocked(),failure); LOG.debug("onError {} {}",toStringLocked(),failure);
// Set error on request. // Set error on request.
@ -739,8 +737,7 @@ public class HttpChannelState
_event.getSuppliedRequest().setAttribute(ERROR_STATUS_CODE,code); _event.getSuppliedRequest().setAttribute(ERROR_STATUS_CODE,code);
_event.getSuppliedRequest().setAttribute(ERROR_EXCEPTION,failure); _event.getSuppliedRequest().setAttribute(ERROR_EXCEPTION,failure);
_event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,failure==null?null:failure.getClass()); _event.getSuppliedRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,failure==null?null:failure.getClass());
_event.getSuppliedRequest().setAttribute(ERROR_MESSAGE,reason);
_event.getSuppliedRequest().setAttribute(ERROR_MESSAGE,reason!=null?reason:null);
} }
else else
{ {
@ -750,7 +747,7 @@ public class HttpChannelState
baseRequest.setAttribute(ERROR_STATUS_CODE,code); baseRequest.setAttribute(ERROR_STATUS_CODE,code);
baseRequest.setAttribute(ERROR_EXCEPTION,failure); baseRequest.setAttribute(ERROR_EXCEPTION,failure);
baseRequest.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,failure==null?null:failure.getClass()); 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? // Are we blocking?
@ -847,7 +844,7 @@ public class HttpChannelState
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onComplete {}",toStringLocked()); LOG.debug("onComplete {}",toStringLocked());
switch(_state) switch(_state)
@ -904,7 +901,7 @@ public class HttpChannelState
cancelTimeout(); cancelTimeout();
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("recycle {}",toStringLocked()); LOG.debug("recycle {}",toStringLocked());
switch(_state) switch(_state)
@ -934,7 +931,7 @@ public class HttpChannelState
cancelTimeout(); cancelTimeout();
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("upgrade {}",toStringLocked()); LOG.debug("upgrade {}",toStringLocked());
switch(_state) switch(_state)
@ -1124,9 +1121,8 @@ public class HttpChannelState
_channel.getRequest().setAttribute(name,attribute); _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 * This indicates that there is no content available to be consumed
* and that once the channel enteres the ASYNC_WAIT state it will * and that once the channel enteres the ASYNC_WAIT state it will
* register for read interest by calling {@link HttpChannel#asyncReadFillInterested()} * register for read interest by calling {@link HttpChannel#asyncReadFillInterested()}
@ -1137,17 +1133,17 @@ public class HttpChannelState
boolean interested=false; boolean interested=false;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onReadUnready {}",toStringLocked()); LOG.debug("onReadUnready {}",toStringLocked());
// We were already unready, this is not a state change, so do nothing // 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 _asyncReadPossible=false; // Assumes this has been checked in isReady() with lock held
if (_state==State.ASYNC_WAIT) if (_state==State.ASYNC_WAIT)
{ {
interested=true; interested=true;
_asyncRead=Interest.INTERESTED; _asyncRead=Interest.REGISTERED;
} }
else else
_asyncRead=Interest.NEEDED; _asyncRead=Interest.NEEDED;
@ -1158,8 +1154,8 @@ public class HttpChannelState
_channel.asyncReadFillInterested(); _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 * 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 * returned false), then the state is changed to ASYNC_WOKEN and true
* is returned. * is returned.
@ -1170,7 +1166,7 @@ public class HttpChannelState
boolean woken=false; boolean woken=false;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onReadPossible {}",toStringLocked()); LOG.debug("onReadPossible {}",toStringLocked());
_asyncReadPossible=true; _asyncReadPossible=true;
@ -1183,8 +1179,8 @@ public class HttpChannelState
return woken; 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 * This is similar to calling {@link #onReadUnready()} followed by
* {@link #onReadPossible()}, except that as content is already * {@link #onReadPossible()}, except that as content is already
* available, read interest is never set. * available, read interest is never set.
@ -1195,10 +1191,10 @@ public class HttpChannelState
boolean woken=false; boolean woken=false;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onReadReady {}",toStringLocked()); LOG.debug("onReadReady {}",toStringLocked());
_asyncRead=Interest.INTERESTED; _asyncRead=Interest.REGISTERED;
_asyncReadPossible=true; _asyncReadPossible=true;
if (_state==State.ASYNC_WAIT) if (_state==State.ASYNC_WAIT)
{ {
@ -1209,8 +1205,8 @@ public class HttpChannelState
return woken; 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 * Will wake if the read was called while in ASYNC_WAIT state
* @return true if woken * @return true if woken
*/ */
@ -1219,21 +1215,20 @@ public class HttpChannelState
boolean woken=false; boolean woken=false;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onReadEof {}",toStringLocked()); LOG.debug("onReadEof {}",toStringLocked());
if (_state==State.ASYNC_WAIT) if (_state==State.ASYNC_WAIT)
{ {
woken=true; woken=true;
_state=State.ASYNC_WOKEN; _state=State.ASYNC_WOKEN;
_asyncRead=Interest.INTERESTED; _asyncRead=Interest.REGISTERED;
_asyncReadPossible=true; _asyncReadPossible=true;
} }
} }
return woken; return woken;
} }
/* ------------------------------------------------------------ */
public boolean isReadPossible() public boolean isReadPossible()
{ {
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
@ -1242,14 +1237,13 @@ public class HttpChannelState
} }
} }
/* ------------------------------------------------------------ */
public boolean onWritePossible() public boolean onWritePossible()
{ {
boolean handle=false; boolean handle=false;
try(Locker.Lock lock= _locker.lock()) try(Locker.Lock lock= _locker.lock())
{ {
if(DEBUG) if (LOG.isDebugEnabled())
LOG.debug("onWritePossible {}",toStringLocked()); LOG.debug("onWritePossible {}",toStringLocked());
_asyncWritePossible=true; _asyncWritePossible=true;
@ -1262,5 +1256,4 @@ public class HttpChannelState
return handle; return handle;
} }
} }

View File

@ -709,6 +709,14 @@ public class HttpInput extends ServletInputStream implements Runnable
} }
} }
public boolean isAsyncEOF()
{
synchronized (_inputQ)
{
return _state == AEOF;
}
}
@Override @Override
public boolean isReady() public boolean isReady()
{ {
@ -1121,4 +1129,5 @@ public class HttpInput extends ServletInputStream implements Runnable
return "AEOF"; return "AEOF";
} }
}; };
} }

View File

@ -1114,8 +1114,10 @@ public class Response implements HttpServletResponse
@Override @Override
public void setBufferSize(int size) public void setBufferSize(int size)
{ {
if (isCommitted() || getContentCount() > 0) if (isCommitted())
throw new IllegalStateException("cannot set buffer size when response is committed or written to"); 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) if (size < __MIN_BUFFER_SIZE)
size = __MIN_BUFFER_SIZE; size = __MIN_BUFFER_SIZE;
_out.setBufferSize(size); _out.setBufferSize(size);
@ -1215,7 +1217,9 @@ public class Response implements HttpServletResponse
protected MetaData.Response newResponseMetaData() 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. /** Get the MetaData.Response committed for this response.

View File

@ -761,7 +761,18 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
throw new IllegalStateException("Null contextPath"); throw new IllegalStateException("Null contextPath");
if (_logger==null) 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; ClassLoader old_classloader = null;
Thread current_thread = null; Thread current_thread = null;
Context old_context = null; Context old_context = null;

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.server;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
@ -442,10 +443,22 @@ public class HttpManyWaysToCommitTest extends AbstractHttpTest
server.start(); server.start();
HttpTester.Response response = executeRequest(); 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()); assertTrue("response eof", response.isEarlyEOF());
} }
@Test @Test
public void testSetContentLengthAndWriteExactlyThatAmountOfBytes() throws Exception public void testSetContentLengthAndWriteExactlyThatAmountOfBytes() throws Exception
{ {

View File

@ -18,6 +18,8 @@
package org.eclipse.jetty.start; 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_INVOKE_MAIN;
import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED; import static org.eclipse.jetty.start.UsageException.ERR_NOT_STOPPED;
import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN; import static org.eclipse.jetty.start.UsageException.ERR_UNKNOWN;
@ -492,19 +494,38 @@ public class Main
private void doStop(StartArgs args) private void doStop(StartArgs args)
{ {
String stopHost = args.getProperties().getString("STOP.HOST"); Props.Prop stopHostProp = args.getProperties().getProp("STOP.HOST", true);
int stopPort = Integer.parseInt(args.getProperties().getString("STOP.PORT")); Props.Prop stopPortProp = args.getProperties().getProp("STOP.PORT", true);
String stopKey = args.getProperties().getString("STOP.KEY"); Props.Prop stopKeyProp = args.getProperties().getProp("STOP.KEY", true);
Props.Prop stopWaitProp = args.getProperties().getProp("STOP.WAIT", true);
if (args.getProperties().getString("STOP.WAIT") != null)
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 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) public void stop(String host, int port, String key, int timeout)
{ {
if (host==null || host.length()==0) if (host==null || host.length()==0)
host="127.0.0.1"; {
host = "127.0.0.1";
}
try 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) if (key == null)
{ {
key = ""; key = "";
StartLog.info("STOP.KEY system property must be specified"); System.err.println("STOP.KEY property must be specified");
StartLog.info("Using empty key"); System.err.println("Using empty key");
} }
try (Socket s = new Socket(InetAddress.getByName(host),port)) try (Socket s = new Socket(InetAddress.getByName(host),port))

View File

@ -29,6 +29,7 @@ public class UsageException extends RuntimeException
public static final int ERR_NOT_STOPPED = -4; public static final int ERR_NOT_STOPPED = -4;
public static final int ERR_BAD_ARG = -5; public static final int ERR_BAD_ARG = -5;
public static final int ERR_BAD_GRAPH = -6; public static final int ERR_BAD_GRAPH = -6;
public static final int ERR_BAD_STOP_PROPS = -7;
public static final int ERR_UNKNOWN = -9; public static final int ERR_UNKNOWN = -9;
private int exitCode; private int exitCode;

View File

@ -16,4 +16,4 @@ logging
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [ini]
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/ jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/

View File

@ -16,4 +16,4 @@ logging
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [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/

View File

@ -16,4 +16,4 @@ logging
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [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/

View File

@ -16,4 +16,4 @@ logging
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [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/

View File

@ -16,4 +16,4 @@ logging
-Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog -Dorg.eclipse.jetty.util.log.class?=org.eclipse.jetty.util.log.Slf4jLog
[ini] [ini]
jetty.webapp.addServerClasses+=,file:${jetty.base}/lib/slf4j/ jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/slf4j/

View File

@ -19,8 +19,10 @@
package org.eclipse.jetty.util; package org.eclipse.jetty.util;
import org.eclipse.jetty.toolchain.test.JDK;
import org.hamcrest.Matchers; import org.hamcrest.Matchers;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test; import org.junit.Test;
public class TypeUtilTest public class TypeUtilTest
@ -124,8 +126,18 @@ public class TypeUtilTest
@Test @Test
public void testLoadedFrom() throws Exception 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(String.class).toString(),Matchers.containsString("/rt.jar"));
Assert.assertThat(TypeUtil.getLoadedFrom(Assert.class).toString(),Matchers.containsString(".jar")); Assert.assertThat(TypeUtil.getLoadedFrom(Assert.class).toString(),Matchers.containsString(".jar"));
Assert.assertThat(TypeUtil.getLoadedFrom(TypeUtil.class).toString(),Matchers.containsString("/classes/")); 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/"));
}
} }

View File

@ -20,8 +20,8 @@ lib/jetty-webapp-${jetty.version}.jar
## Lists of patterns are comma separated and may be either: ## Lists of patterns are comma separated and may be either:
## + a qualified classname e.g. 'com.acme.Foo' ## + a qualified classname e.g. 'com.acme.Foo'
## + a package name e.g. 'net.example.' ## + a package name e.g. 'net.example.'
## + a jar file e.g. 'file:${jetty.base}/lib/dependency.jar' ## + a jar file e.g. '${jetty.base.uri}/lib/dependency.jar'
## + a directory of jars,resource or classes e.g. 'file:${jetty.base}/resources' ## + 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 ## + 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. ## The +=, operator appends to a CSV list with a comma as needed.

View File

@ -1252,7 +1252,7 @@ public class AsyncIOServletTest extends AbstractTest
@Override @Override
public void onDataAvailable() throws IOException public void onDataAvailable() throws IOException
{ {
while (input.isReady() && !input.isFinished()) while (input.isReady())
{ {
int b = input.read(); int b = input.read();
if (b>0) 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)); // System.err.printf("0x%2x %s %n", b, Character.isISOControl(b)?"?":(""+(char)b));
out.write(b); out.write(b);
} }
else else if (b<0)
onAllDataRead(); return;
} }
} }

View File

@ -59,11 +59,12 @@ public class SessionEvictionFailureTest
*/ */
public static class MockSessionDataStore extends AbstractSessionDataStore 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 @Override
public void doStore(String id, SessionData data, long lastSaveTime) throws Exception public void doStore(String id, SessionData data, long lastSaveTime) throws Exception
{ {
if (!_nextResult) if (_nextStoreResult != null && !_nextStoreResult[i++])
{ {
throw new IllegalStateException("Testing store"); throw new IllegalStateException("Testing store");
} }
@ -132,6 +133,12 @@ public class SessionEvictionFailureTest
*/ */
public static class MockSessionDataStoreFactory extends AbstractSessionDataStoreFactory 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) * @see org.eclipse.jetty.server.session.SessionDataStoreFactory#getSessionDataStore(org.eclipse.jetty.server.session.SessionHandler)
@ -139,7 +146,7 @@ public class SessionEvictionFailureTest
@Override @Override
public SessionDataStore getSessionDataStore(SessionHandler handler) throws Exception 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); TestServer server = new TestServer (0, inactivePeriod, scavengePeriod, cacheFactory, storeFactory);
ServletContextHandler context = server.addContext(contextPath); ServletContextHandler context = server.addContext(contextPath);
context.getSessionHandler().getSessionCache().setSaveOnInactiveEviction(true); 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); context.getSessionHandler().getSessionCache().setSessionDataStore(ds);
TestServlet servlet = new TestServlet(); TestServlet servlet = new TestServlet();
@ -226,7 +233,6 @@ public class SessionEvictionFailureTest
String url = "http://localhost:" + port1 + contextPath + servletMapping; String url = "http://localhost:" + port1 + contextPath + servletMapping;
// Create the session // Create the session
ds.setNextResult(true);
ContentResponse response = client.GET(url + "?action=init"); ContentResponse response = client.GET(url + "?action=init");
assertEquals(HttpServletResponse.SC_OK,response.getStatus()); assertEquals(HttpServletResponse.SC_OK,response.getStatus());
String sessionCookie = response.getHeaders().get("Set-Cookie"); String sessionCookie = response.getHeaders().get("Set-Cookie");
@ -234,13 +240,10 @@ public class SessionEvictionFailureTest
// Mangle the cookie, replacing Path with $Path, etc. // Mangle the cookie, replacing Path with $Path, etc.
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); 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 //Wait for the eviction period to expire - save on evict should fail but session
//should remain in the cache //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, // Make another request to see if the session is still in the cache and can be used,
//allow it to be saved this time //allow it to be saved this time
@ -249,12 +252,11 @@ public class SessionEvictionFailureTest
response = request.send(); response = request.send();
assertEquals(HttpServletResponse.SC_OK,response.getStatus()); assertEquals(HttpServletResponse.SC_OK,response.getStatus());
assertNull(response.getHeaders().get("Set-Cookie")); //check that the cookie wasn't reset assertNull(response.getHeaders().get("Set-Cookie")); //check that the cookie wasn't reset
ds.setNextResult(false);
//Wait for the eviction period to expire again //Wait for the eviction period to expire again
pause(evictionPeriod); pause(evictionPeriod+(int)(evictionPeriod*0.5));
ds.setNextResult(true);
request = client.newRequest(url + "?action=test"); request = client.newRequest(url + "?action=test");
request.header("Cookie", sessionCookie); request.header("Cookie", sessionCookie);