Merge branch 'jetty-7' into release-7
This commit is contained in:
commit
67f55ec8e5
|
@ -0,0 +1,4 @@
|
||||||
|
language: java
|
||||||
|
jdk:
|
||||||
|
- openjdk7
|
||||||
|
- oraclejdk7
|
|
@ -25,6 +25,7 @@ import org.eclipse.jetty.deploy.providers.ContextProvider;
|
||||||
import org.eclipse.jetty.deploy.providers.WebAppProvider;
|
import org.eclipse.jetty.deploy.providers.WebAppProvider;
|
||||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||||
import org.eclipse.jetty.security.HashLoginService;
|
import org.eclipse.jetty.security.HashLoginService;
|
||||||
|
import org.eclipse.jetty.server.AsyncNCSARequestLog;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.Handler;
|
import org.eclipse.jetty.server.Handler;
|
||||||
import org.eclipse.jetty.server.NCSARequestLog;
|
import org.eclipse.jetty.server.NCSARequestLog;
|
||||||
|
@ -154,13 +155,13 @@ public class LikeJettyXml
|
||||||
login.setConfig(jetty_home + "/etc/realm.properties");
|
login.setConfig(jetty_home + "/etc/realm.properties");
|
||||||
server.addBean(login);
|
server.addBean(login);
|
||||||
|
|
||||||
NCSARequestLog requestLog = new NCSARequestLog(jetty_home + "/logs/jetty-yyyy_mm_dd.log");
|
NCSARequestLog requestLog = new AsyncNCSARequestLog();
|
||||||
|
requestLog.setFilename(jetty_home + "/logs/jetty-yyyy_mm_dd.log");
|
||||||
requestLog.setExtended(false);
|
requestLog.setExtended(false);
|
||||||
requestLogHandler.setRequestLog(requestLog);
|
requestLogHandler.setRequestLog(requestLog);
|
||||||
|
|
||||||
server.setStopAtShutdown(true);
|
server.setStopAtShutdown(true);
|
||||||
server.setSendServerVersion(true);
|
server.setSendServerVersion(true);
|
||||||
|
|
||||||
|
|
||||||
server.start();
|
server.start();
|
||||||
|
|
||||||
|
|
|
@ -18,12 +18,8 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.client;
|
package org.eclipse.jetty.client;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.matchers.JUnitMatchers.*;
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.junit.matchers.JUnitMatchers.containsString;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -46,7 +42,7 @@ import org.eclipse.jetty.io.Connection;
|
||||||
import org.eclipse.jetty.io.EofException;
|
import org.eclipse.jetty.io.EofException;
|
||||||
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.toolchain.test.Stress;
|
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -115,7 +111,7 @@ public class HttpExchangeTest
|
||||||
sender(10,false);
|
sender(10,false);
|
||||||
sender(10,true);
|
sender(10,true);
|
||||||
|
|
||||||
if (Stress.isEnabled())
|
if (PropertyFlag.isEnabled("test.stress"))
|
||||||
{
|
{
|
||||||
sender(100,false);
|
sender(100,false);
|
||||||
sender(100,true);
|
sender(100,true);
|
||||||
|
|
|
@ -1633,9 +1633,6 @@ public class SslBytesServerTest extends SslBytesTest
|
||||||
Assert.assertThat(sslFlushes.get(), lessThan(20));
|
Assert.assertThat(sslFlushes.get(), lessThan(20));
|
||||||
Assert.assertThat(httpParses.get(), lessThan(50));
|
Assert.assertThat(httpParses.get(), lessThan(50));
|
||||||
|
|
||||||
//System.err.println(((Dumpable)server.getConnectors()[0]).dump());
|
|
||||||
Assert.assertThat(((Dumpable)server.getConnectors()[0]).dump(),containsString("SCEP@"));
|
|
||||||
|
|
||||||
completeClose(client);
|
completeClose(client);
|
||||||
|
|
||||||
TimeUnit.MILLISECONDS.sleep(200);
|
TimeUnit.MILLISECONDS.sleep(200);
|
||||||
|
@ -1772,7 +1769,14 @@ public class SslBytesServerTest extends SslBytesTest
|
||||||
proxy.flushToServer(record);
|
proxy.flushToServer(record);
|
||||||
|
|
||||||
// Close Alert
|
// Close Alert
|
||||||
record = proxy.readFromServer();
|
try
|
||||||
|
{
|
||||||
|
record = proxy.readFromServer();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
proxy.flushToClient(record);
|
proxy.flushToClient(record);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,24 @@ running()
|
||||||
kill -0 "$PID" 2>/dev/null
|
kill -0 "$PID" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
started()
|
||||||
|
{
|
||||||
|
# wait for 60s to see "STARTED" in PID file, needs jetty-started.xml as argument
|
||||||
|
for T in 1 2 3 4 5 6 7 9 10 11 12 13 14 15
|
||||||
|
do
|
||||||
|
sleep 4
|
||||||
|
[ -z "$(grep STARTED $1 2>/dev/null)" ] || return 0
|
||||||
|
[ -z "$(grep STOPPED $1 2>/dev/null)" ] || return 1
|
||||||
|
[ -z "$(grep FAILED $1 2>/dev/null)" ] || return 1
|
||||||
|
local PID=$(cat "$2" 2>/dev/null) || return 1
|
||||||
|
kill -0 "$PID" 2>/dev/null || return 1
|
||||||
|
echo -n ". "
|
||||||
|
done
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
readConfig()
|
readConfig()
|
||||||
{
|
{
|
||||||
(( DEBUG )) && echo "Reading $1.."
|
(( DEBUG )) && echo "Reading $1.."
|
||||||
|
@ -137,7 +155,13 @@ shift
|
||||||
##################################################
|
##################################################
|
||||||
# Read any configuration files
|
# Read any configuration files
|
||||||
##################################################
|
##################################################
|
||||||
for CONFIG in /etc/default/jetty{,7} $HOME/.jettyrc; do
|
ETC=/etc
|
||||||
|
if [ $UID != 0 ]
|
||||||
|
then
|
||||||
|
ETC=$HOME/etc
|
||||||
|
fi
|
||||||
|
|
||||||
|
for CONFIG in $ETC/default/jetty{,7} $HOME/.jettyrc; do
|
||||||
if [ -f "$CONFIG" ] ; then
|
if [ -f "$CONFIG" ] ; then
|
||||||
readConfig "$CONFIG"
|
readConfig "$CONFIG"
|
||||||
fi
|
fi
|
||||||
|
@ -262,9 +286,9 @@ fi
|
||||||
##################################################
|
##################################################
|
||||||
if [ -z "$JETTY_CONF" ]
|
if [ -z "$JETTY_CONF" ]
|
||||||
then
|
then
|
||||||
if [ -f /etc/jetty.conf ]
|
if [ -f $ETC/jetty.conf ]
|
||||||
then
|
then
|
||||||
JETTY_CONF=/etc/jetty.conf
|
JETTY_CONF=$ETC/jetty.conf
|
||||||
elif [ -f "$JETTY_HOME/etc/jetty.conf" ]
|
elif [ -f "$JETTY_HOME/etc/jetty.conf" ]
|
||||||
then
|
then
|
||||||
JETTY_CONF=$JETTY_HOME/etc/jetty.conf
|
JETTY_CONF=$JETTY_HOME/etc/jetty.conf
|
||||||
|
@ -312,13 +336,20 @@ then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
#####################################################
|
#####################################################
|
||||||
# Find a PID for the pid file
|
# Find a pid and state file
|
||||||
#####################################################
|
#####################################################
|
||||||
if [ -z "$JETTY_PID" ]
|
if [ -z "$JETTY_PID" ]
|
||||||
then
|
then
|
||||||
JETTY_PID="$JETTY_RUN/jetty.pid"
|
JETTY_PID="$JETTY_RUN/jetty.pid"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ -z "$JETTY_STATE" ]
|
||||||
|
then
|
||||||
|
JETTY_STATE=$JETTY_HOME/jetty.state
|
||||||
|
fi
|
||||||
|
JAVA_OPTIONS+=("-Djetty.state=$JETTY_STATE")
|
||||||
|
rm -f $JETTY_STATE
|
||||||
|
|
||||||
##################################################
|
##################################################
|
||||||
# Setup JAVA if unset
|
# Setup JAVA if unset
|
||||||
##################################################
|
##################################################
|
||||||
|
@ -407,23 +438,15 @@ case "$ACTION" in
|
||||||
exit
|
exit
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if type start-stop-daemon > /dev/null 2>&1
|
if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1
|
||||||
then
|
then
|
||||||
unset CH_USER
|
unset CH_USER
|
||||||
if [ -n "$JETTY_USER" ]
|
if [ -n "$JETTY_USER" ]
|
||||||
then
|
then
|
||||||
CH_USER="-c$JETTY_USER"
|
CH_USER="-c$JETTY_USER"
|
||||||
fi
|
fi
|
||||||
if start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
|
|
||||||
then
|
start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
|
||||||
sleep 1
|
|
||||||
if running "$JETTY_PID"
|
|
||||||
then
|
|
||||||
echo "OK"
|
|
||||||
else
|
|
||||||
echo "FAILED"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
|
@ -454,14 +477,25 @@ case "$ACTION" in
|
||||||
echo $! > "$JETTY_PID"
|
echo $! > "$JETTY_PID"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "STARTED Jetty `date`"
|
fi
|
||||||
|
|
||||||
|
if expr "${CONFIGS[*]}" : '.*etc/jetty-started.xml.*' >/dev/null
|
||||||
|
then
|
||||||
|
if started "$JETTY_STATE" "$JETTY_PID"
|
||||||
|
then
|
||||||
|
echo "OK `date`"
|
||||||
|
else
|
||||||
|
echo "FAILED `date`"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "ok `date`"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
stop)
|
stop)
|
||||||
echo -n "Stopping Jetty: "
|
echo -n "Stopping Jetty: "
|
||||||
if type start-stop-daemon > /dev/null 2>&1; then
|
if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1; then
|
||||||
start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP
|
start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP
|
||||||
|
|
||||||
TIMEOUT=30
|
TIMEOUT=30
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
|
||||||
|
|
||||||
|
<!-- =============================================================== -->
|
||||||
|
<!-- Mixin the Start FileNoticeLifeCycleListener -->
|
||||||
|
<!-- =============================================================== -->
|
||||||
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
<Call name="addLifeCycleListener">
|
||||||
|
<Arg>
|
||||||
|
<New class="org.eclipse.jetty.util.component.FileNoticeLifeCycleListener">
|
||||||
|
<Arg><SystemProperty name="jetty.state" default="./jetty.state"/></Arg>
|
||||||
|
</New>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
</Configure>
|
|
@ -6,8 +6,7 @@
|
||||||
# created by that script.
|
# created by that script.
|
||||||
#
|
#
|
||||||
# Each line in this file becomes an arguement to start.jar
|
# Each line in this file becomes an arguement to start.jar
|
||||||
# unless this file contains an --ini option, then these
|
# in addition to those found in the start.ini file
|
||||||
# arguments will be in addition to those found in the
|
|
||||||
# start.ini file
|
|
||||||
# =======================================================
|
# =======================================================
|
||||||
--pre=etc/jetty-logging.xml
|
etc/jetty-logging.xml
|
||||||
|
etc/jetty-started.xml
|
||||||
|
|
|
@ -350,10 +350,14 @@ public class HttpParser implements Parser
|
||||||
|
|
||||||
ch=_buffer.get();
|
ch=_buffer.get();
|
||||||
|
|
||||||
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
|
if (_eol == HttpTokens.CARRIAGE_RETURN)
|
||||||
{
|
{
|
||||||
_eol=HttpTokens.LINE_FEED;
|
if (ch == HttpTokens.LINE_FEED)
|
||||||
continue;
|
{
|
||||||
|
_eol=HttpTokens.LINE_FEED;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
throw new HttpException(HttpStatus.BAD_REQUEST_400);
|
||||||
}
|
}
|
||||||
_eol=0;
|
_eol=0;
|
||||||
|
|
||||||
|
|
|
@ -234,7 +234,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
||||||
setHeader("Content-Encoding", _encoding);
|
setHeader("Content-Encoding", _encoding);
|
||||||
if (_response.containsHeader("Content-Encoding"))
|
if (_response.containsHeader("Content-Encoding"))
|
||||||
{
|
{
|
||||||
setHeader("Vary",_vary);
|
addHeader("Vary",_vary);
|
||||||
_out=_compressedOutputStream=createStream();
|
_out=_compressedOutputStream=createStream();
|
||||||
if (_out!=null)
|
if (_out!=null)
|
||||||
{
|
{
|
||||||
|
@ -269,7 +269,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
||||||
if (_out == null || _bOut != null)
|
if (_out == null || _bOut != null)
|
||||||
{
|
{
|
||||||
if (sendVary)
|
if (sendVary)
|
||||||
setHeader("Vary",_vary);
|
addHeader("Vary",_vary);
|
||||||
if (_wrapper.getETag()!=null)
|
if (_wrapper.getETag()!=null)
|
||||||
setHeader("ETag",_wrapper.getETag());
|
setHeader("ETag",_wrapper.getETag());
|
||||||
|
|
||||||
|
@ -341,6 +341,11 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
||||||
return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
|
return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void addHeader(String name,String value)
|
||||||
|
{
|
||||||
|
_response.addHeader(name, value);
|
||||||
|
}
|
||||||
|
|
||||||
protected void setHeader(String name,String value)
|
protected void setHeader(String name,String value)
|
||||||
{
|
{
|
||||||
_response.setHeader(name, value);
|
_response.setHeader(name, value);
|
||||||
|
|
|
@ -23,6 +23,8 @@ import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
import junit.framework.Assert;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.Buffer;
|
import org.eclipse.jetty.io.Buffer;
|
||||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||||
import org.eclipse.jetty.io.SimpleBuffers;
|
import org.eclipse.jetty.io.SimpleBuffers;
|
||||||
|
@ -179,6 +181,88 @@ public class HttpParserTest
|
||||||
assertEquals(5, h);
|
assertEquals(5, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHeaderParseLF() throws Exception
|
||||||
|
{
|
||||||
|
StringEndPoint io=new StringEndPoint();
|
||||||
|
io.setInput(
|
||||||
|
"GET / HTTP/1.0\012"
|
||||||
|
+ "Host: localhost\012"
|
||||||
|
+ "Header1: value1\012"
|
||||||
|
+ "Header2 : value 2a \012"
|
||||||
|
+ " value 2b \012"
|
||||||
|
+ "Header3: \012"
|
||||||
|
+ "Header4 \012"
|
||||||
|
+ " value4\012"
|
||||||
|
+ "Server5: notServer\012"
|
||||||
|
+ "\012");
|
||||||
|
ByteArrayBuffer buffer= new ByteArrayBuffer(4096);
|
||||||
|
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
|
||||||
|
|
||||||
|
Handler handler = new Handler();
|
||||||
|
HttpParser parser= new HttpParser(buffers,io, handler);
|
||||||
|
parser.parse();
|
||||||
|
assertEquals("GET", f0);
|
||||||
|
assertEquals("/", f1);
|
||||||
|
assertEquals("HTTP/1.0", f2);
|
||||||
|
assertEquals("Host", hdr[0]);
|
||||||
|
assertEquals("localhost", val[0]);
|
||||||
|
assertEquals("Header1", hdr[1]);
|
||||||
|
assertEquals("value1", val[1]);
|
||||||
|
assertEquals("Header2", hdr[2]);
|
||||||
|
assertEquals("value 2a value 2b", val[2]);
|
||||||
|
assertEquals("Header3", hdr[3]);
|
||||||
|
assertEquals("", val[3]);
|
||||||
|
assertEquals("Header4", hdr[4]);
|
||||||
|
assertEquals("value4", val[4]);
|
||||||
|
assertEquals("Server5", hdr[5]);
|
||||||
|
assertEquals("notServer", val[5]);
|
||||||
|
assertEquals(5, h);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testHeaderParseCR() throws Exception
|
||||||
|
{
|
||||||
|
StringEndPoint io=new StringEndPoint();
|
||||||
|
io.setInput(
|
||||||
|
"GET / HTTP/1.0\015"
|
||||||
|
+ "Host: localhost\015"
|
||||||
|
+ "Header1: value1\015"
|
||||||
|
+ "\015");
|
||||||
|
ByteArrayBuffer buffer= new ByteArrayBuffer(4096);
|
||||||
|
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
|
||||||
|
|
||||||
|
Handler handler = new Handler();
|
||||||
|
HttpParser parser= new HttpParser(buffers,io, handler);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser.parse();
|
||||||
|
Assert.fail();
|
||||||
|
}
|
||||||
|
catch(HttpException e)
|
||||||
|
{
|
||||||
|
assertEquals(400,e._status);
|
||||||
|
}
|
||||||
|
|
||||||
|
io.setInput(
|
||||||
|
"GET / HTTP/1.0\r\n"
|
||||||
|
+ "Host: localhost\r\r\n"
|
||||||
|
+ "Header1: value1\r\n"
|
||||||
|
+ "\r\n");
|
||||||
|
|
||||||
|
parser= new HttpParser(buffers,io, handler);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
parser.parse();
|
||||||
|
Assert.fail();
|
||||||
|
}
|
||||||
|
catch(HttpException e)
|
||||||
|
{
|
||||||
|
assertEquals(400,e._status);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testChunkParse() throws Exception
|
public void testChunkParse() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -63,11 +63,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
*/
|
*/
|
||||||
private volatile AsyncConnection _connection;
|
private volatile AsyncConnection _connection;
|
||||||
|
|
||||||
/** true if a thread has been dispatched to handle this endpoint */
|
private static final int STATE_NEEDS_DISPATCH=-1;
|
||||||
private boolean _dispatched = false;
|
private static final int STATE_UNDISPATCHED=0;
|
||||||
|
private static final int STATE_DISPATCHED=1;
|
||||||
/** true if a non IO dispatch (eg async resume) is outstanding */
|
private static final int STATE_ASYNC=2;
|
||||||
private boolean _asyncDispatch = false;
|
private int _state;
|
||||||
|
|
||||||
|
private boolean _onIdle;
|
||||||
|
|
||||||
/** true if the last write operation succeed and wrote all offered bytes */
|
/** true if the last write operation succeed and wrote all offered bytes */
|
||||||
private volatile boolean _writable = true;
|
private volatile boolean _writable = true;
|
||||||
|
@ -83,6 +85,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
private boolean _open;
|
private boolean _open;
|
||||||
|
|
||||||
private volatile long _idleTimestamp;
|
private volatile long _idleTimestamp;
|
||||||
|
private volatile boolean _checkIdle;
|
||||||
|
|
||||||
private boolean _ishut;
|
private boolean _ishut;
|
||||||
|
|
||||||
|
@ -94,8 +97,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
|
|
||||||
_manager = selectSet.getManager();
|
_manager = selectSet.getManager();
|
||||||
_selectSet = selectSet;
|
_selectSet = selectSet;
|
||||||
_dispatched = false;
|
_state=STATE_UNDISPATCHED;
|
||||||
_asyncDispatch = false;
|
_onIdle=false;
|
||||||
_open=true;
|
_open=true;
|
||||||
_key = key;
|
_key = key;
|
||||||
|
|
||||||
|
@ -169,7 +172,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
|
|
||||||
// we are not interested in further selecting
|
// we are not interested in further selecting
|
||||||
_key.interestOps(0);
|
_key.interestOps(0);
|
||||||
if (!_dispatched)
|
if (_state<STATE_DISPATCHED)
|
||||||
updateKey();
|
updateKey();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -184,13 +187,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
}
|
}
|
||||||
|
|
||||||
// If dispatched, then deregister interest
|
// If dispatched, then deregister interest
|
||||||
if (_dispatched)
|
if (_state>=STATE_DISPATCHED)
|
||||||
_key.interestOps(0);
|
_key.interestOps(0);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// other wise do the dispatch
|
// other wise do the dispatch
|
||||||
dispatch();
|
dispatch();
|
||||||
if (_dispatched && !_selectSet.getManager().isDeferringInterestedOps0())
|
if (_state>=STATE_DISPATCHED && !_selectSet.getManager().isDeferringInterestedOps0())
|
||||||
{
|
{
|
||||||
_key.interestOps(0);
|
_key.interestOps(0);
|
||||||
}
|
}
|
||||||
|
@ -203,10 +206,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
{
|
{
|
||||||
synchronized(this)
|
synchronized(this)
|
||||||
{
|
{
|
||||||
if (_dispatched)
|
switch(_state)
|
||||||
_asyncDispatch=true;
|
{
|
||||||
else
|
case STATE_NEEDS_DISPATCH:
|
||||||
dispatch();
|
case STATE_UNDISPATCHED:
|
||||||
|
dispatch();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STATE_DISPATCHED:
|
||||||
|
case STATE_ASYNC:
|
||||||
|
_state=STATE_ASYNC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,15 +226,20 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
{
|
{
|
||||||
synchronized(this)
|
synchronized(this)
|
||||||
{
|
{
|
||||||
if (!_dispatched)
|
if (_state<=STATE_UNDISPATCHED)
|
||||||
{
|
{
|
||||||
_dispatched = true;
|
if (_onIdle)
|
||||||
boolean dispatched = _manager.dispatch(_handler);
|
_state = STATE_NEEDS_DISPATCH;
|
||||||
if(!dispatched)
|
else
|
||||||
{
|
{
|
||||||
_dispatched = false;
|
_state = STATE_DISPATCHED;
|
||||||
LOG.warn("Dispatched Failed! "+this+" to "+_manager);
|
boolean dispatched = _manager.dispatch(_handler);
|
||||||
updateKey();
|
if(!dispatched)
|
||||||
|
{
|
||||||
|
_state = STATE_NEEDS_DISPATCH;
|
||||||
|
LOG.warn("Dispatched Failed! "+this+" to "+_manager);
|
||||||
|
updateKey();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -240,15 +256,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
{
|
{
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
if (_asyncDispatch)
|
switch(_state)
|
||||||
{
|
{
|
||||||
_asyncDispatch=false;
|
case STATE_ASYNC:
|
||||||
return false;
|
_state=STATE_DISPATCHED;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
_state=STATE_UNDISPATCHED;
|
||||||
|
updateKey();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
_dispatched = false;
|
|
||||||
updateKey();
|
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -266,30 +285,33 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void setCheckForIdle(boolean check)
|
public void setCheckForIdle(boolean check)
|
||||||
{
|
{
|
||||||
_idleTimestamp=check?System.currentTimeMillis():0;
|
if (check)
|
||||||
|
{
|
||||||
|
_idleTimestamp=System.currentTimeMillis();
|
||||||
|
_checkIdle=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_checkIdle=false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public boolean isCheckForIdle()
|
public boolean isCheckForIdle()
|
||||||
{
|
{
|
||||||
return _idleTimestamp!=0;
|
return _checkIdle;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
protected void notIdle()
|
protected void notIdle()
|
||||||
{
|
{
|
||||||
if (_idleTimestamp!=0)
|
_idleTimestamp=System.currentTimeMillis();
|
||||||
_idleTimestamp=System.currentTimeMillis();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void checkIdleTimestamp(long now)
|
public void checkIdleTimestamp(long now)
|
||||||
{
|
{
|
||||||
long idleTimestamp=_idleTimestamp;
|
if (isCheckForIdle() && _maxIdleTime>0)
|
||||||
|
|
||||||
if (idleTimestamp!=0 && _maxIdleTime>0)
|
|
||||||
{
|
{
|
||||||
final long idleForMs=now-idleTimestamp;
|
final long idleForMs=now-_idleTimestamp;
|
||||||
|
|
||||||
if (idleForMs>_maxIdleTime)
|
if (idleForMs>_maxIdleTime)
|
||||||
{
|
{
|
||||||
|
@ -316,7 +338,25 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public void onIdleExpired(long idleForMs)
|
public void onIdleExpired(long idleForMs)
|
||||||
{
|
{
|
||||||
_connection.onIdleExpired(idleForMs);
|
try
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
_onIdle=true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_maxIdleTime>0 && (System.currentTimeMillis()-_idleTimestamp)>_maxIdleTime)
|
||||||
|
_connection.onIdleExpired(idleForMs);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
_onIdle=false;
|
||||||
|
if (_state==STATE_NEEDS_DISPATCH)
|
||||||
|
dispatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
@ -341,7 +381,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
_writable=false;
|
_writable=false;
|
||||||
if (!_dispatched)
|
if (_state<STATE_DISPATCHED)
|
||||||
updateKey();
|
updateKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,7 +407,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
synchronized (this)
|
synchronized (this)
|
||||||
{
|
{
|
||||||
_writable=false;
|
_writable=false;
|
||||||
if (!_dispatched)
|
if (_state<STATE_DISPATCHED)
|
||||||
updateKey();
|
updateKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -514,8 +554,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
int current_ops=-1;
|
int current_ops=-1;
|
||||||
if (getChannel().isOpen())
|
if (getChannel().isOpen())
|
||||||
{
|
{
|
||||||
boolean read_interest = _readBlocked || (!_dispatched && !_connection.isSuspended());
|
boolean read_interest = _readBlocked || (_state<STATE_DISPATCHED && !_connection.isSuspended());
|
||||||
boolean write_interest= _writeBlocked || (!_dispatched && !_writable);
|
boolean write_interest= _writeBlocked || (_state<STATE_DISPATCHED && !_writable);
|
||||||
|
|
||||||
_interestOps =
|
_interestOps =
|
||||||
((!_socket.isInputShutdown() && read_interest ) ? SelectionKey.OP_READ : 0)
|
((!_socket.isInputShutdown() && read_interest ) ? SelectionKey.OP_READ : 0)
|
||||||
|
@ -764,11 +804,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
||||||
{
|
{
|
||||||
keyString += "-";
|
keyString += "-";
|
||||||
}
|
}
|
||||||
return String.format("SCEP@%x{l(%s)<->r(%s),d=%b,open=%b,ishut=%b,oshut=%b,rb=%b,wb=%b,w=%b,i=%d%s}-{%s}",
|
return String.format("SCEP@%x{l(%s)<->r(%s),s=%d,open=%b,ishut=%b,oshut=%b,rb=%b,wb=%b,w=%b,i=%d%s}-{%s}",
|
||||||
hashCode(),
|
hashCode(),
|
||||||
_socket.getRemoteSocketAddress(),
|
_socket.getRemoteSocketAddress(),
|
||||||
_socket.getLocalSocketAddress(),
|
_socket.getLocalSocketAddress(),
|
||||||
_dispatched,
|
_state,
|
||||||
isOpen(),
|
isOpen(),
|
||||||
isInputShutdown(),
|
isInputShutdown(),
|
||||||
isOutputShutdown(),
|
isOutputShutdown(),
|
||||||
|
|
|
@ -24,15 +24,15 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
|
|
||||||
import org.eclipse.jetty.toolchain.test.Stress;
|
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class ThreadLocalBuffersTest
|
public class ThreadLocalBuffersTest
|
||||||
{
|
{
|
||||||
private Buffers httpBuffers;
|
private Buffers httpBuffers;
|
||||||
private List<Thread> threadList = new ArrayList<Thread>();
|
private List<Thread> threadList = new ArrayList<Thread>();
|
||||||
private int numThreads = Stress.isEnabled()?100:10;
|
private int numThreads = PropertyFlag.isEnabled("test.stress")?100:10;
|
||||||
private int runTestLength = Stress.isEnabled()?5000:1000;
|
private int runTestLength = PropertyFlag.isEnabled("test.stress")?5000:1000;
|
||||||
private boolean runTest = false;
|
private boolean runTest = false;
|
||||||
private AtomicLong buffersRetrieved;
|
private AtomicLong buffersRetrieved;
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ public class MongoSessionManager extends NoSqlSessionManager
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
version = new Long(((Long)version).intValue() + 1);
|
version = new Long(((Number)version).longValue() + 1);
|
||||||
update.put("$inc",__version_1);
|
update.put("$inc",__version_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
|
||||||
<parent>
|
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
|
||||||
<artifactId>jetty-parent</artifactId>
|
|
||||||
<version>19</version>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<groupId>org.eclipse.jetty.npn</groupId>
|
|
||||||
<artifactId>npn-api</artifactId>
|
|
||||||
<version>1.1.1-SNAPSHOT</version>
|
|
||||||
<name>Jetty :: Next Protocol Negotiation :: API</name>
|
|
||||||
|
|
||||||
<scm>
|
|
||||||
<connection>scm:git:http://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</connection>
|
|
||||||
<developerConnection>scm:git:ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</developerConnection>
|
|
||||||
<url>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-npn</url>
|
|
||||||
</scm>
|
|
||||||
|
|
||||||
<build>
|
|
||||||
<plugins>
|
|
||||||
<plugin>
|
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
|
||||||
<artifactId>maven-release-plugin</artifactId>
|
|
||||||
<version>2.2.1</version>
|
|
||||||
<configuration>
|
|
||||||
<useReleaseProfile>false</useReleaseProfile>
|
|
||||||
<goals>deploy</goals>
|
|
||||||
<arguments>-Peclipse-release</arguments>
|
|
||||||
<preparationGoals>clean install</preparationGoals>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
</project>
|
|
|
@ -1,248 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995-2013 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.npn;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.WeakHashMap;
|
|
||||||
import javax.net.ssl.SSLEngine;
|
|
||||||
import javax.net.ssl.SSLSocket;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>{@link NextProtoNego} provides an API to applications that want to make use of the
|
|
||||||
* <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next Protocol Negotiation</a>.</p>
|
|
||||||
* <p>The NPN extension is only available when using the TLS protocol, therefore applications must
|
|
||||||
* ensure that the TLS protocol is used:</p>
|
|
||||||
* <pre>
|
|
||||||
* SSLContext context = SSLContext.getInstance("TLSv1");
|
|
||||||
* </pre>
|
|
||||||
* <p>Refer to the
|
|
||||||
* <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext">list
|
|
||||||
* of standard SSLContext protocol names</a> for further information on TLS protocol versions supported.</p>
|
|
||||||
* <p>Applications must register instances of either {@link SSLSocket} or {@link SSLEngine} with a
|
|
||||||
* {@link ClientProvider} or with a {@link ServerProvider}, depending whether they are on client or
|
|
||||||
* server side.</p>
|
|
||||||
* <p>The NPN implementation will invoke the provider callbacks to allow applications to interact
|
|
||||||
* with the negotiation of the next protocol.</p>
|
|
||||||
* <p>Client side typical usage:</p>
|
|
||||||
* <pre>
|
|
||||||
* SSLSocket sslSocket = ...;
|
|
||||||
* NextProtoNego.put(sslSocket, new NextProtoNego.ClientProvider()
|
|
||||||
* {
|
|
||||||
* @Override
|
|
||||||
* public boolean supports()
|
|
||||||
* {
|
|
||||||
* return true;
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @Override
|
|
||||||
* public void unsupported()
|
|
||||||
* {
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @Override
|
|
||||||
* public String selectProtocol(List<String> protocols)
|
|
||||||
* {
|
|
||||||
* return protocols.get(0);
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
* </pre>
|
|
||||||
* <p>Server side typical usage:</p>
|
|
||||||
* <pre>
|
|
||||||
* SSLSocket sslSocket = ...;
|
|
||||||
* NextProtoNego.put(sslSocket, new NextProtoNego.ServerProvider()
|
|
||||||
* {
|
|
||||||
* @Override
|
|
||||||
* public void unsupported()
|
|
||||||
* {
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @Override
|
|
||||||
* public List<String> protocols()
|
|
||||||
* {
|
|
||||||
* return Arrays.asList("http/1.1");
|
|
||||||
* }
|
|
||||||
*
|
|
||||||
* @Override
|
|
||||||
* public void protocolSelected(String protocol)
|
|
||||||
* {
|
|
||||||
* System.out.println("Protocol Selected is: " + protocol);
|
|
||||||
* }
|
|
||||||
* });
|
|
||||||
* </pre>
|
|
||||||
* <p>There is no need to unregister {@link SSLSocket} or {@link SSLEngine} instances, as they
|
|
||||||
* are kept in a {@link WeakHashMap} and will be garbage collected when the application does not
|
|
||||||
* hard reference them anymore. However, methods to explicitly unregister {@link SSLSocket} or
|
|
||||||
* {@link SSLEngine} instances are provided.</p>
|
|
||||||
* <p>In order to help application development, you can set the {@link NextProtoNego#debug} field
|
|
||||||
* to {@code true} to have debug code printed to {@link System#err}.</p>
|
|
||||||
*/
|
|
||||||
public class NextProtoNego
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* <p>Enables debug logging on {@link System#err}.</p>
|
|
||||||
*/
|
|
||||||
public static boolean debug = false;
|
|
||||||
|
|
||||||
private static Map<Object, Provider> objects = Collections.synchronizedMap(new WeakHashMap<Object, Provider>());
|
|
||||||
|
|
||||||
private NextProtoNego()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Registers a SSLSocket with a provider.</p>
|
|
||||||
*
|
|
||||||
* @param socket the socket to register with the provider
|
|
||||||
* @param provider the provider to register with the socket
|
|
||||||
* @see #remove(SSLSocket)
|
|
||||||
*/
|
|
||||||
public static void put(SSLSocket socket, Provider provider)
|
|
||||||
{
|
|
||||||
objects.put(socket, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param socket a socket registered with {@link #put(SSLSocket, Provider)}
|
|
||||||
* @return the provider registered with the given socket
|
|
||||||
*/
|
|
||||||
public static Provider get(SSLSocket socket)
|
|
||||||
{
|
|
||||||
return objects.get(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Unregisters the given SSLSocket.</p>
|
|
||||||
*
|
|
||||||
* @param socket the socket to unregister
|
|
||||||
* @return the provider registered with the socket
|
|
||||||
* @see #put(SSLSocket, Provider)
|
|
||||||
*/
|
|
||||||
public static Provider remove(SSLSocket socket)
|
|
||||||
{
|
|
||||||
return objects.remove(socket);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Registers a SSLEngine with a provider.</p>
|
|
||||||
*
|
|
||||||
* @param engine the engine to register with the provider
|
|
||||||
* @param provider the provider to register with the engine
|
|
||||||
* @see #remove(SSLEngine)
|
|
||||||
*/
|
|
||||||
public static void put(SSLEngine engine, Provider provider)
|
|
||||||
{
|
|
||||||
objects.put(engine, provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param engine an engine registered with {@link #put(SSLEngine, Provider)}
|
|
||||||
* @return the provider registered with the given engine
|
|
||||||
*/
|
|
||||||
public static Provider get(SSLEngine engine)
|
|
||||||
{
|
|
||||||
return objects.get(engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Unregisters the given SSLEngine.</p>
|
|
||||||
*
|
|
||||||
* @param engine the engine to unregister
|
|
||||||
* @return the provider registered with the engine
|
|
||||||
* @see #put(SSLEngine, Provider)
|
|
||||||
*/
|
|
||||||
public static Provider remove(SSLEngine engine)
|
|
||||||
{
|
|
||||||
return objects.remove(engine);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Base, empty, interface for providers.</p>
|
|
||||||
*/
|
|
||||||
public interface Provider
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>The client-side provider interface that applications must implement to interact
|
|
||||||
* with the negotiation of the next protocol.</p>
|
|
||||||
*/
|
|
||||||
public interface ClientProvider extends Provider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* <p>Callback invoked to let the implementation know whether an
|
|
||||||
* empty NPN extension should be added to a ClientHello SSL message.</p>
|
|
||||||
*
|
|
||||||
* @return true to add the NPN extension, false otherwise
|
|
||||||
*/
|
|
||||||
public boolean supports();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Callback invoked to let the application know that the server does
|
|
||||||
* not support NPN.</p>
|
|
||||||
*/
|
|
||||||
public void unsupported();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Callback invoked to let the application select a protocol
|
|
||||||
* among the ones sent by the server.</p>
|
|
||||||
*
|
|
||||||
* @param protocols the protocols sent by the server
|
|
||||||
* @return the protocol selected by the application, or null if the
|
|
||||||
* NextProtocol SSL message should not be sent to the server
|
|
||||||
*/
|
|
||||||
public String selectProtocol(List<String> protocols);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>The server-side provider interface that applications must implement to interact
|
|
||||||
* with the negotiation of the next protocol.</p>
|
|
||||||
*/
|
|
||||||
public interface ServerProvider extends Provider
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* <p>Callback invoked to let the application know that the client does not
|
|
||||||
* support NPN.</p>
|
|
||||||
*/
|
|
||||||
public void unsupported();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Callback invoked to let the implementation know the list
|
|
||||||
* of protocols that should be added to an NPN extension in a
|
|
||||||
* ServerHello SSL message.</p>
|
|
||||||
* <p>This callback is invoked only if the client sent a NPN extension.</p>
|
|
||||||
*
|
|
||||||
* @return the list of protocols, or null if no NPN extension
|
|
||||||
* should be sent to the client
|
|
||||||
*/
|
|
||||||
public List<String> protocols();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Callback invoked to let the application know the protocol selected
|
|
||||||
* by the client.</p>
|
|
||||||
* <p>This callback is invoked only if the client sent a NextProtocol SSL message.</p>
|
|
||||||
*
|
|
||||||
* @param protocol the selected protocol
|
|
||||||
*/
|
|
||||||
public void protocolSelected(String protocol);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,6 +29,7 @@ import java.util.Set;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CopyOnWriteArraySet;
|
import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.http.HttpSchemes;
|
||||||
import org.eclipse.jetty.http.PathMap;
|
import org.eclipse.jetty.http.PathMap;
|
||||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
|
@ -365,7 +366,11 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
||||||
return true;
|
return true;
|
||||||
if (connector.getIntegralPort() > 0)
|
if (connector.getIntegralPort() > 0)
|
||||||
{
|
{
|
||||||
String url = connector.getIntegralScheme() + "://" + request.getServerName() + ":" + connector.getIntegralPort() + request.getRequestURI();
|
String scheme=connector.getIntegralScheme();
|
||||||
|
int port=connector.getIntegralPort();
|
||||||
|
String url = (HttpSchemes.HTTPS.equalsIgnoreCase(scheme) && port==443)
|
||||||
|
? "https://"+request.getServerName()+request.getRequestURI()
|
||||||
|
: scheme + "://" + request.getServerName() + ":" + port + request.getRequestURI();
|
||||||
if (request.getQueryString() != null)
|
if (request.getQueryString() != null)
|
||||||
url += "?" + request.getQueryString();
|
url += "?" + request.getQueryString();
|
||||||
response.setContentLength(0);
|
response.setContentLength(0);
|
||||||
|
@ -384,11 +389,13 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
||||||
|
|
||||||
if (connector.getConfidentialPort() > 0)
|
if (connector.getConfidentialPort() > 0)
|
||||||
{
|
{
|
||||||
String url = connector.getConfidentialScheme() + "://" + request.getServerName() + ":" + connector.getConfidentialPort()
|
String scheme=connector.getConfidentialScheme();
|
||||||
+ request.getRequestURI();
|
int port=connector.getConfidentialPort();
|
||||||
|
String url = (HttpSchemes.HTTPS.equalsIgnoreCase(scheme) && port==443)
|
||||||
|
? "https://"+request.getServerName()+request.getRequestURI()
|
||||||
|
: scheme + "://" + request.getServerName() + ":" + port + request.getRequestURI();
|
||||||
if (request.getQueryString() != null)
|
if (request.getQueryString() != null)
|
||||||
url += "?" + request.getQueryString();
|
url += "?" + request.getQueryString();
|
||||||
|
|
||||||
response.setContentLength(0);
|
response.setContentLength(0);
|
||||||
response.sendRedirect(url);
|
response.sendRedirect(url);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.security.authentication;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.BitSet;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
@ -60,17 +61,32 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
|
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
|
||||||
SecureRandom _random = new SecureRandom();
|
SecureRandom _random = new SecureRandom();
|
||||||
private long _maxNonceAgeMs = 60*1000;
|
private long _maxNonceAgeMs = 60*1000;
|
||||||
private ConcurrentMap<String, Nonce> _nonceCount = new ConcurrentHashMap<String, Nonce>();
|
private int _maxNC=1024;
|
||||||
|
private ConcurrentMap<String, Nonce> _nonceMap = new ConcurrentHashMap<String, Nonce>();
|
||||||
private Queue<Nonce> _nonceQueue = new ConcurrentLinkedQueue<Nonce>();
|
private Queue<Nonce> _nonceQueue = new ConcurrentLinkedQueue<Nonce>();
|
||||||
private static class Nonce
|
private static class Nonce
|
||||||
{
|
{
|
||||||
final String _nonce;
|
final String _nonce;
|
||||||
final long _ts;
|
final long _ts;
|
||||||
AtomicInteger _nc=new AtomicInteger();
|
final BitSet _seen;
|
||||||
public Nonce(String nonce, long ts)
|
|
||||||
|
public Nonce(String nonce, long ts, int size)
|
||||||
{
|
{
|
||||||
_nonce=nonce;
|
_nonce=nonce;
|
||||||
_ts=ts;
|
_ts=ts;
|
||||||
|
_seen = new BitSet(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean seen(int count)
|
||||||
|
{
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
if (count>=_seen.size())
|
||||||
|
return true;
|
||||||
|
boolean s=_seen.get(count);
|
||||||
|
_seen.set(count);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,19 +108,35 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
String mna=configuration.getInitParameter("maxNonceAge");
|
String mna=configuration.getInitParameter("maxNonceAge");
|
||||||
if (mna!=null)
|
if (mna!=null)
|
||||||
{
|
{
|
||||||
synchronized (this)
|
_maxNonceAgeMs=Long.valueOf(mna);
|
||||||
{
|
|
||||||
_maxNonceAgeMs=Long.valueOf(mna);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public int getMaxNonceCount()
|
||||||
|
{
|
||||||
|
return _maxNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void setMaxNonceCount(int maxNC)
|
||||||
|
{
|
||||||
|
_maxNC = maxNC;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public synchronized void setMaxNonceAge(long maxNonceAgeInMillis)
|
public void setMaxNonceAge(long maxNonceAgeInMillis)
|
||||||
{
|
{
|
||||||
_maxNonceAgeMs = maxNonceAgeInMillis;
|
_maxNonceAgeMs = maxNonceAgeInMillis;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public long getMaxNonceAge()
|
||||||
|
{
|
||||||
|
return _maxNonceAgeMs;
|
||||||
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public String getAuthMethod()
|
public String getAuthMethod()
|
||||||
{
|
{
|
||||||
|
@ -233,9 +265,9 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
byte[] nounce = new byte[24];
|
byte[] nounce = new byte[24];
|
||||||
_random.nextBytes(nounce);
|
_random.nextBytes(nounce);
|
||||||
|
|
||||||
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp());
|
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp(),_maxNC);
|
||||||
}
|
}
|
||||||
while (_nonceCount.putIfAbsent(nonce._nonce,nonce)!=null);
|
while (_nonceMap.putIfAbsent(nonce._nonce,nonce)!=null);
|
||||||
_nonceQueue.add(nonce);
|
_nonceQueue.add(nonce);
|
||||||
|
|
||||||
return nonce._nonce;
|
return nonce._nonce;
|
||||||
|
@ -250,36 +282,27 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
private int checkNonce(Digest digest, Request request)
|
private int checkNonce(Digest digest, Request request)
|
||||||
{
|
{
|
||||||
// firstly let's expire old nonces
|
// firstly let's expire old nonces
|
||||||
long expired;
|
long expired = request.getTimeStamp()-_maxNonceAgeMs;
|
||||||
synchronized (this)
|
|
||||||
{
|
|
||||||
expired = request.getTimeStamp()-_maxNonceAgeMs;
|
|
||||||
}
|
|
||||||
|
|
||||||
Nonce nonce=_nonceQueue.peek();
|
Nonce nonce=_nonceQueue.peek();
|
||||||
while (nonce!=null && nonce._ts<expired)
|
while (nonce!=null && nonce._ts<expired)
|
||||||
{
|
{
|
||||||
_nonceQueue.remove(nonce);
|
_nonceQueue.remove(nonce);
|
||||||
_nonceCount.remove(nonce._nonce);
|
_nonceMap.remove(nonce._nonce);
|
||||||
nonce=_nonceQueue.peek();
|
nonce=_nonceQueue.peek();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now check the requested nonce
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
nonce = _nonceCount.get(digest.nonce);
|
nonce = _nonceMap.get(digest.nonce);
|
||||||
if (nonce==null)
|
if (nonce==null)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
long count = Long.parseLong(digest.nc,16);
|
long count = Long.parseLong(digest.nc,16);
|
||||||
if (count>Integer.MAX_VALUE)
|
if (count>=_maxNC)
|
||||||
return 0;
|
return 0;
|
||||||
int old=nonce._nc.get();
|
if (nonce.seen((int)count))
|
||||||
while (!nonce._nc.compareAndSet(old,(int)count))
|
|
||||||
old=nonce._nc.get();
|
|
||||||
if (count<=old)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -378,6 +401,7 @@ public class DigestAuthenticator extends LoginAuthenticator
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return username + "," + response;
|
return username + "," + response;
|
||||||
|
|
|
@ -22,17 +22,21 @@ import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.security.MessageDigest;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.regex.Matcher;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
|
||||||
|
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
|
||||||
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
import org.eclipse.jetty.security.authentication.FormAuthenticator;
|
||||||
import org.eclipse.jetty.server.Connector;
|
import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.LocalConnector;
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
|
@ -44,7 +48,10 @@ import org.eclipse.jetty.server.handler.ContextHandler;
|
||||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
import org.eclipse.jetty.server.session.SessionHandler;
|
import org.eclipse.jetty.server.session.SessionHandler;
|
||||||
import org.eclipse.jetty.util.B64Code;
|
import org.eclipse.jetty.util.B64Code;
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.util.TypeUtil;
|
||||||
import org.eclipse.jetty.util.security.Constraint;
|
import org.eclipse.jetty.util.security.Constraint;
|
||||||
|
import org.eclipse.jetty.util.security.Credential;
|
||||||
import org.eclipse.jetty.util.security.Password;
|
import org.eclipse.jetty.util.security.Password;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -138,7 +145,14 @@ public class ConstraintTest
|
||||||
mapping5.setPathSpec("/forbid/post");
|
mapping5.setPathSpec("/forbid/post");
|
||||||
mapping5.setConstraint(constraint5);
|
mapping5.setConstraint(constraint5);
|
||||||
mapping5.setMethod("POST");
|
mapping5.setMethod("POST");
|
||||||
|
|
||||||
|
Constraint constraint6 = new Constraint();
|
||||||
|
constraint6.setAuthenticate(false);
|
||||||
|
constraint6.setName("data constraint");
|
||||||
|
constraint6.setDataConstraint(2);
|
||||||
|
ConstraintMapping mapping6 = new ConstraintMapping();
|
||||||
|
mapping6.setPathSpec("/data/*");
|
||||||
|
mapping6.setConstraint(constraint6);
|
||||||
|
|
||||||
Set<String> knownRoles=new HashSet<String>();
|
Set<String> knownRoles=new HashSet<String>();
|
||||||
knownRoles.add("user");
|
knownRoles.add("user");
|
||||||
|
@ -146,7 +160,7 @@ public class ConstraintTest
|
||||||
|
|
||||||
_security.setConstraintMappings(Arrays.asList(new ConstraintMapping[]
|
_security.setConstraintMappings(Arrays.asList(new ConstraintMapping[]
|
||||||
{
|
{
|
||||||
mapping0, mapping1, mapping2, mapping3, mapping4, mapping5
|
mapping0, mapping1, mapping2, mapping3, mapping4, mapping5,mapping6
|
||||||
}), knownRoles);
|
}), knownRoles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +229,6 @@ public class ConstraintTest
|
||||||
"\r\n");
|
"\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
|
||||||
// test admin
|
// test admin
|
||||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
|
@ -243,6 +256,127 @@ public class ConstraintTest
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String CNONCE="1234567890";
|
||||||
|
private String digest(String nonce, String username,String password,String uri,String nc) throws Exception
|
||||||
|
{
|
||||||
|
MessageDigest md = MessageDigest.getInstance("MD5");
|
||||||
|
byte[] ha1;
|
||||||
|
// calc A1 digest
|
||||||
|
md.update(username.getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update("TestRealm".getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update(password.getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
ha1 = md.digest();
|
||||||
|
// calc A2 digest
|
||||||
|
md.reset();
|
||||||
|
md.update("GET".getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update(uri.getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
byte[] ha2 = md.digest();
|
||||||
|
|
||||||
|
// calc digest
|
||||||
|
// request-digest = <"> < KD ( H(A1), unq(nonce-value) ":"
|
||||||
|
// nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" H(A2) )
|
||||||
|
// <">
|
||||||
|
// request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2)
|
||||||
|
// ) > <">
|
||||||
|
|
||||||
|
md.update(TypeUtil.toString(ha1, 16).getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update(nonce.getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update(nc.getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update(CNONCE.getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update("auth".getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
md.update((byte) ':');
|
||||||
|
md.update(TypeUtil.toString(ha2, 16).getBytes(StringUtil.__ISO_8859_1));
|
||||||
|
byte[] digest = md.digest();
|
||||||
|
|
||||||
|
// check digest
|
||||||
|
return TypeUtil.toString(digest, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDigest() throws Exception
|
||||||
|
{
|
||||||
|
_security.setAuthenticator(new DigestAuthenticator());
|
||||||
|
_security.setStrict(false);
|
||||||
|
_server.start();
|
||||||
|
|
||||||
|
String response;
|
||||||
|
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||||
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
|
assertTrue(response.contains("WWW-Authenticate: Digest realm=\"TestRealm\""));
|
||||||
|
|
||||||
|
Pattern nonceP = Pattern.compile("nonce=\"([^\"]*)\",");
|
||||||
|
Matcher matcher = nonceP.matcher(response);
|
||||||
|
assertTrue(matcher.find());
|
||||||
|
String nonce=matcher.group(1);
|
||||||
|
|
||||||
|
|
||||||
|
//wrong password
|
||||||
|
String digest= digest(nonce,"user","WRONG","/ctx/auth/info","1");
|
||||||
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
|
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||||
|
"nc=1, "+
|
||||||
|
"nonce=\""+nonce+"\", "+
|
||||||
|
"response=\""+digest+"\"\r\n"+
|
||||||
|
"\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
|
|
||||||
|
// right password
|
||||||
|
digest= digest(nonce,"user","password","/ctx/auth/info","2");
|
||||||
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
|
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||||
|
"nc=2, "+
|
||||||
|
"nonce=\""+nonce+"\", "+
|
||||||
|
"response=\""+digest+"\"\r\n"+
|
||||||
|
"\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
|
||||||
|
// once only
|
||||||
|
digest= digest(nonce,"user","password","/ctx/auth/info","2");
|
||||||
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
|
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||||
|
"nc=2, "+
|
||||||
|
"nonce=\""+nonce+"\", "+
|
||||||
|
"response=\""+digest+"\"\r\n"+
|
||||||
|
"\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||||
|
|
||||||
|
// increasing
|
||||||
|
digest= digest(nonce,"user","password","/ctx/auth/info","4");
|
||||||
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
|
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||||
|
"nc=4, "+
|
||||||
|
"nonce=\""+nonce+"\", "+
|
||||||
|
"response=\""+digest+"\"\r\n"+
|
||||||
|
"\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
// out of order
|
||||||
|
digest= digest(nonce,"user","password","/ctx/auth/info","3");
|
||||||
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
|
||||||
|
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
|
||||||
|
"nc=3, "+
|
||||||
|
"nonce=\""+nonce+"\", "+
|
||||||
|
"response=\""+digest+"\"\r\n"+
|
||||||
|
"\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFormDispatch() throws Exception
|
public void testFormDispatch() throws Exception
|
||||||
{
|
{
|
||||||
|
@ -668,9 +802,9 @@ public class ConstraintTest
|
||||||
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
|
||||||
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
|
||||||
|
|
||||||
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
|
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\nHost:wibble.com:8888\r\n\r\n");
|
||||||
assertTrue(response.indexOf(" 302 Found") > 0);
|
assertTrue(response.indexOf(" 302 Found") > 0);
|
||||||
assertTrue(response.indexOf("/ctx/testLoginPage") > 0);
|
assertTrue(response.indexOf("http://wibble.com:8888/ctx/testLoginPage") > 0);
|
||||||
|
|
||||||
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
|
||||||
|
|
||||||
|
@ -766,6 +900,48 @@ public class ConstraintTest
|
||||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDataRedirection() throws Exception
|
||||||
|
{
|
||||||
|
_security.setAuthenticator(new BasicAuthenticator());
|
||||||
|
_server.start();
|
||||||
|
|
||||||
|
String response;
|
||||||
|
|
||||||
|
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 403"));
|
||||||
|
|
||||||
|
_connector.setConfidentialPort(8443);
|
||||||
|
_connector.setConfidentialScheme("https");
|
||||||
|
|
||||||
|
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||||
|
assertTrue(response.indexOf("Location") > 0);
|
||||||
|
assertTrue(response.indexOf(":8443/ctx/data/info") > 0);
|
||||||
|
|
||||||
|
_connector.setConfidentialPort(443);
|
||||||
|
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||||
|
assertTrue(response.indexOf("Location") > 0);
|
||||||
|
assertTrue(response.indexOf(":443/ctx/data/info") < 0);
|
||||||
|
|
||||||
|
_connector.setConfidentialPort(8443);
|
||||||
|
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\nHost: wobble.com\r\n\r\n");
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||||
|
assertTrue(response.indexOf("Location") > 0);
|
||||||
|
assertTrue(response.indexOf("https://wobble.com:8443/ctx/data/info") > 0);
|
||||||
|
|
||||||
|
_connector.setConfidentialPort(443);
|
||||||
|
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\nHost: wobble.com\r\n\r\n");
|
||||||
|
System.err.println(response);
|
||||||
|
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
|
||||||
|
assertTrue(response.indexOf("Location") > 0);
|
||||||
|
assertTrue(response.indexOf(":443") < 0);
|
||||||
|
assertTrue(response.indexOf("https://wobble.com/ctx/data/info") > 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRoleRef() throws Exception
|
public void testRoleRef() throws Exception
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
<Arg>
|
<Arg>
|
||||||
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
|
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
|
||||||
<Set name="requestLog">
|
<Set name="requestLog">
|
||||||
|
<!-- Use AsyncNCSARequestLog for improved request latency -->
|
||||||
<New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
|
<New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
|
||||||
<Set name="filename"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set>
|
<Set name="filename"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set>
|
||||||
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
|
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
|
||||||
|
|
|
@ -860,6 +860,13 @@ public abstract class AbstractHttpConnection extends AbstractConnection
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
protected void headerComplete() throws IOException
|
protected void headerComplete() throws IOException
|
||||||
{
|
{
|
||||||
|
// Handle idle race
|
||||||
|
if (_endp.isOutputShutdown())
|
||||||
|
{
|
||||||
|
_endp.close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_requests++;
|
_requests++;
|
||||||
_generator.setVersion(_version);
|
_generator.setVersion(_version);
|
||||||
switch (_version)
|
switch (_version)
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2013 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.server;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.BlockingQueue;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* An asynchronously writing NCSA Request Log
|
||||||
|
*/
|
||||||
|
public class AsyncNCSARequestLog extends NCSARequestLog
|
||||||
|
{
|
||||||
|
private static final Logger LOG = Log.getLogger(AsyncNCSARequestLog.class);
|
||||||
|
private final BlockingQueue<String> _queue;
|
||||||
|
private transient WriterThread _thread;
|
||||||
|
private boolean _warnedFull;
|
||||||
|
|
||||||
|
public AsyncNCSARequestLog()
|
||||||
|
{
|
||||||
|
this(null,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncNCSARequestLog(BlockingQueue<String> queue)
|
||||||
|
{
|
||||||
|
this(null,queue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncNCSARequestLog(String filename)
|
||||||
|
{
|
||||||
|
this(filename,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AsyncNCSARequestLog(String filename,BlockingQueue<String> queue)
|
||||||
|
{
|
||||||
|
super(filename);
|
||||||
|
if (queue==null)
|
||||||
|
queue=new BlockingArrayQueue<String>(1024);
|
||||||
|
_queue=queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class WriterThread extends Thread
|
||||||
|
{
|
||||||
|
WriterThread()
|
||||||
|
{
|
||||||
|
setName("AsyncNCSARequestLog@"+Integer.toString(AsyncNCSARequestLog.this.hashCode(),16));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
while (isRunning())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
String log = _queue.poll(10,TimeUnit.SECONDS);
|
||||||
|
if (log!=null)
|
||||||
|
AsyncNCSARequestLog.super.write(log);
|
||||||
|
|
||||||
|
while(!_queue.isEmpty())
|
||||||
|
{
|
||||||
|
log=_queue.poll();
|
||||||
|
if (log!=null)
|
||||||
|
AsyncNCSARequestLog.super.write(log);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e)
|
||||||
|
{
|
||||||
|
LOG.ignore(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected synchronized void doStart() throws Exception
|
||||||
|
{
|
||||||
|
super.doStart();
|
||||||
|
_thread = new WriterThread();
|
||||||
|
_thread.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doStop() throws Exception
|
||||||
|
{
|
||||||
|
_thread.interrupt();
|
||||||
|
_thread.join();
|
||||||
|
super.doStop();
|
||||||
|
_thread=null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void write(String log) throws IOException
|
||||||
|
{
|
||||||
|
if (!_queue.offer(log))
|
||||||
|
{
|
||||||
|
if (_warnedFull)
|
||||||
|
LOG.warn("Log Queue overflow");
|
||||||
|
_warnedFull=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -53,6 +53,14 @@ import org.eclipse.jetty.util.log.Logger;
|
||||||
public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(NCSARequestLog.class);
|
private static final Logger LOG = Log.getLogger(NCSARequestLog.class);
|
||||||
|
private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
protected StringBuilder initialValue()
|
||||||
|
{
|
||||||
|
return new StringBuilder(256);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
private String _filename;
|
private String _filename;
|
||||||
private boolean _extended;
|
private boolean _extended;
|
||||||
|
@ -461,7 +469,8 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
||||||
if (_fileOut == null)
|
if (_fileOut == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
StringBuilder buf= new StringBuilder(256);
|
StringBuilder buf= _buffers.get();
|
||||||
|
buf.setLength(0);
|
||||||
|
|
||||||
if (_logServer)
|
if (_logServer)
|
||||||
{
|
{
|
||||||
|
@ -577,22 +586,29 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
||||||
}
|
}
|
||||||
|
|
||||||
buf.append(StringUtil.__LINE_SEPARATOR);
|
buf.append(StringUtil.__LINE_SEPARATOR);
|
||||||
|
|
||||||
String log = buf.toString();
|
String log = buf.toString();
|
||||||
synchronized(this)
|
write(log);
|
||||||
{
|
|
||||||
if (_writer==null)
|
|
||||||
return;
|
|
||||||
_writer.write(log);
|
|
||||||
_writer.flush();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
{
|
{
|
||||||
LOG.warn(e);
|
LOG.warn(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
protected void write(String log) throws IOException
|
||||||
|
{
|
||||||
|
synchronized(this)
|
||||||
|
{
|
||||||
|
if (_writer==null)
|
||||||
|
return;
|
||||||
|
_writer.write(log);
|
||||||
|
_writer.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
/**
|
/**
|
||||||
* Writes extended request and response information to the output stream.
|
* Writes extended request and response information to the output stream.
|
||||||
|
@ -662,7 +678,10 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
||||||
else
|
else
|
||||||
_ignorePathMap = null;
|
_ignorePathMap = null;
|
||||||
|
|
||||||
_writer = new OutputStreamWriter(_out);
|
synchronized(this)
|
||||||
|
{
|
||||||
|
_writer = new OutputStreamWriter(_out);
|
||||||
|
}
|
||||||
super.doStart();
|
super.doStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,6 +78,7 @@ public class ResourceCache
|
||||||
_mimeTypes=mimeTypes;
|
_mimeTypes=mimeTypes;
|
||||||
_parent=parent;
|
_parent=parent;
|
||||||
_etags=etags;
|
_etags=etags;
|
||||||
|
_useFileMappedBuffer=useFileMappedBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -261,10 +261,12 @@ public class Server extends HandlerWrapper implements Attributes
|
||||||
@Override
|
@Override
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
if (getStopAtShutdown()) {
|
if (getStopAtShutdown())
|
||||||
ShutdownThread.register(this);
|
{
|
||||||
ShutdownMonitor.getInstance().start(); // initialize
|
ShutdownThread.register(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShutdownMonitor.getInstance().start(); // initialize
|
||||||
|
|
||||||
LOG.info("jetty-"+__version);
|
LOG.info("jetty-"+__version);
|
||||||
HttpGenerator.setServerVersion(__version);
|
HttpGenerator.setServerVersion(__version);
|
||||||
|
|
|
@ -40,7 +40,7 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
|
||||||
* <p>
|
* <p>
|
||||||
* Commands "stop" and "status" are currently supported.
|
* Commands "stop" and "status" are currently supported.
|
||||||
*/
|
*/
|
||||||
public class ShutdownMonitor extends Thread
|
public class ShutdownMonitor
|
||||||
{
|
{
|
||||||
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
|
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
|
||||||
static class Holder
|
static class Holder
|
||||||
|
@ -53,11 +53,165 @@ public class ShutdownMonitor extends Thread
|
||||||
return Holder.instance;
|
return Holder.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShutdownMonitorThread
|
||||||
|
*
|
||||||
|
* Thread for listening to STOP.PORT for command to stop Jetty.
|
||||||
|
* If ShowndownMonitor.exitVm is true, then Sytem.exit will also be
|
||||||
|
* called after the stop.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ShutdownMonitorThread extends Thread
|
||||||
|
{
|
||||||
|
|
||||||
|
public ShutdownMonitorThread ()
|
||||||
|
{
|
||||||
|
setDaemon(true);
|
||||||
|
setName("ShutdownMonitor");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
if (serverSocket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (serverSocket != null)
|
||||||
|
{
|
||||||
|
Socket socket = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket = serverSocket.accept();
|
||||||
|
|
||||||
|
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
||||||
|
String receivedKey = lin.readLine();
|
||||||
|
if (!key.equals(receivedKey))
|
||||||
|
{
|
||||||
|
System.err.println("Ignoring command with incorrect key");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream out = socket.getOutputStream();
|
||||||
|
|
||||||
|
String cmd = lin.readLine();
|
||||||
|
debug("command=%s",cmd);
|
||||||
|
if ("stop".equals(cmd))
|
||||||
|
{
|
||||||
|
// Graceful Shutdown
|
||||||
|
debug("Issuing graceful shutdown..");
|
||||||
|
ShutdownThread.getInstance().run();
|
||||||
|
|
||||||
|
// Reply to client
|
||||||
|
debug("Informing client that we are stopped.");
|
||||||
|
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
// Shutdown Monitor
|
||||||
|
debug("Shutting down monitor");
|
||||||
|
close(socket);
|
||||||
|
socket = null;
|
||||||
|
close(serverSocket);
|
||||||
|
serverSocket = null;
|
||||||
|
|
||||||
|
if (exitVm)
|
||||||
|
{
|
||||||
|
// Kill JVM
|
||||||
|
debug("Killing JVM");
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ("status".equals(cmd))
|
||||||
|
{
|
||||||
|
// Reply to client
|
||||||
|
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
|
||||||
|
out.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
debug(e);
|
||||||
|
System.err.println(e.toString());
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
close(socket);
|
||||||
|
socket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start()
|
||||||
|
{
|
||||||
|
if (isAlive())
|
||||||
|
{
|
||||||
|
System.err.printf("ShutdownMonitorThread already started");
|
||||||
|
return; // cannot start it again
|
||||||
|
}
|
||||||
|
|
||||||
|
startListenSocket();
|
||||||
|
|
||||||
|
if (serverSocket == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DEBUG)
|
||||||
|
System.err.println("Starting ShutdownMonitorThread");
|
||||||
|
super.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startListenSocket()
|
||||||
|
{
|
||||||
|
if (port < 0)
|
||||||
|
{
|
||||||
|
if (DEBUG)
|
||||||
|
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
|
||||||
|
if (port == 0)
|
||||||
|
{
|
||||||
|
// server assigned port in use
|
||||||
|
port = serverSocket.getLocalPort();
|
||||||
|
System.out.printf("STOP.PORT=%d%n",port);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key == null)
|
||||||
|
{
|
||||||
|
// create random key
|
||||||
|
key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
||||||
|
System.out.printf("STOP.KEY=%s%n",key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
debug(e);
|
||||||
|
System.err.println("Error binding monitor port " + port + ": " + e.toString());
|
||||||
|
serverSocket = null;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
// establish the port and key that are in use
|
||||||
|
debug("STOP.PORT=%d",port);
|
||||||
|
debug("STOP.KEY=%s",key);
|
||||||
|
debug("%s",serverSocket);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private boolean DEBUG;
|
private boolean DEBUG;
|
||||||
private int port;
|
private int port;
|
||||||
private String key;
|
private String key;
|
||||||
private boolean exitVm;
|
private boolean exitVm;
|
||||||
private ServerSocket serverSocket;
|
private ServerSocket serverSocket;
|
||||||
|
private ShutdownMonitorThread thread;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a ShutdownMonitor using configuration from the System properties.
|
* Create a ShutdownMonitor using configuration from the System properties.
|
||||||
|
@ -75,7 +229,7 @@ public class ShutdownMonitor extends Thread
|
||||||
|
|
||||||
// Use values passed thru via /jetty-start/
|
// Use values passed thru via /jetty-start/
|
||||||
this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
|
this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
|
||||||
this.key = props.getProperty("STOP.KEY","eclipse");
|
this.key = props.getProperty("STOP.KEY",null);
|
||||||
this.exitVm = true;
|
this.exitVm = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,77 +303,6 @@ public class ShutdownMonitor extends Thread
|
||||||
return exitVm;
|
return exitVm;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
if (serverSocket == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (serverSocket != null)
|
|
||||||
{
|
|
||||||
Socket socket = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket = serverSocket.accept();
|
|
||||||
|
|
||||||
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
|
|
||||||
String key = lin.readLine();
|
|
||||||
if (!this.key.equals(key))
|
|
||||||
{
|
|
||||||
System.err.println("Ignoring command with incorrect key");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
OutputStream out = socket.getOutputStream();
|
|
||||||
|
|
||||||
String cmd = lin.readLine();
|
|
||||||
debug("command=%s",cmd);
|
|
||||||
if ("stop".equals(cmd))
|
|
||||||
{
|
|
||||||
// Graceful Shutdown
|
|
||||||
debug("Issuing graceful shutdown..");
|
|
||||||
ShutdownThread.getInstance().run();
|
|
||||||
|
|
||||||
// Reply to client
|
|
||||||
debug("Informing client that we are stopped.");
|
|
||||||
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
|
|
||||||
out.flush();
|
|
||||||
|
|
||||||
// Shutdown Monitor
|
|
||||||
debug("Shutting down monitor");
|
|
||||||
close(socket);
|
|
||||||
socket = null;
|
|
||||||
close(serverSocket);
|
|
||||||
serverSocket = null;
|
|
||||||
|
|
||||||
if (exitVm)
|
|
||||||
{
|
|
||||||
// Kill JVM
|
|
||||||
debug("Killing JVM");
|
|
||||||
System.exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ("status".equals(cmd))
|
|
||||||
{
|
|
||||||
// Reply to client
|
|
||||||
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
|
|
||||||
out.flush();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
debug(e);
|
|
||||||
System.err.println(e.toString());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
close(socket);
|
|
||||||
socket = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDebug(boolean flag)
|
public void setDebug(boolean flag)
|
||||||
{
|
{
|
||||||
|
@ -228,90 +311,71 @@ public class ShutdownMonitor extends Thread
|
||||||
|
|
||||||
public void setExitVm(boolean exitVm)
|
public void setExitVm(boolean exitVm)
|
||||||
{
|
{
|
||||||
if (isAlive())
|
synchronized (this)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("ShutdownMonitor already started");
|
if (thread != null && thread.isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitorThread already started");
|
||||||
|
}
|
||||||
|
this.exitVm = exitVm;
|
||||||
}
|
}
|
||||||
this.exitVm = exitVm;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setKey(String key)
|
public void setKey(String key)
|
||||||
{
|
{
|
||||||
if (isAlive())
|
synchronized (this)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("ShutdownMonitor already started");
|
if (thread != null && thread.isAlive())
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("ShutdownMonitorThread already started");
|
||||||
|
}
|
||||||
|
this.key = key;
|
||||||
}
|
}
|
||||||
this.key = key;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPort(int port)
|
public void setPort(int port)
|
||||||
{
|
{
|
||||||
if (isAlive())
|
synchronized (this)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("ShutdownMonitor already started");
|
if (thread != null && thread.isAlive())
|
||||||
}
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void start()
|
|
||||||
{
|
|
||||||
if (isAlive())
|
|
||||||
{
|
|
||||||
System.err.printf("ShutdownMonitor already started");
|
|
||||||
return; // cannot start it again
|
|
||||||
}
|
|
||||||
startListenSocket();
|
|
||||||
if (serverSocket == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startListenSocket()
|
|
||||||
{
|
|
||||||
if (this.port < 0)
|
|
||||||
{
|
|
||||||
if (DEBUG)
|
|
||||||
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
setDaemon(true);
|
|
||||||
setName("ShutdownMonitor");
|
|
||||||
|
|
||||||
this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
|
|
||||||
if (this.port == 0)
|
|
||||||
{
|
{
|
||||||
// server assigned port in use
|
throw new IllegalStateException("ShutdownMonitorThread already started");
|
||||||
this.port = serverSocket.getLocalPort();
|
|
||||||
System.out.printf("STOP.PORT=%d%n",this.port);
|
|
||||||
}
|
}
|
||||||
|
this.port = port;
|
||||||
if (this.key == null)
|
|
||||||
{
|
|
||||||
// create random key
|
|
||||||
this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
|
|
||||||
System.out.printf("STOP.KEY=%s%n",this.key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
debug(e);
|
|
||||||
System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
// establish the port and key that are in use
|
|
||||||
debug("STOP.PORT=%d",this.port);
|
|
||||||
debug("STOP.KEY=%s",this.key);
|
|
||||||
debug("%s",serverSocket);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void start() throws Exception
|
||||||
|
{
|
||||||
|
ShutdownMonitorThread t = null;
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
if (thread != null && thread.isAlive())
|
||||||
|
{
|
||||||
|
System.err.printf("ShutdownMonitorThread already started");
|
||||||
|
return; // cannot start it again
|
||||||
|
}
|
||||||
|
|
||||||
|
thread = new ShutdownMonitorThread();
|
||||||
|
t = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t != null)
|
||||||
|
t.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected boolean isAlive ()
|
||||||
|
{
|
||||||
|
boolean result = false;
|
||||||
|
synchronized (this)
|
||||||
|
{
|
||||||
|
result = (thread != null && thread.isAlive());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
|
|
@ -294,17 +294,20 @@ public class JDBCSessionManager extends AbstractSessionManager
|
||||||
super.complete();
|
super.complete();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_dirty)
|
if (isValid())
|
||||||
{
|
{
|
||||||
//The session attributes have changed, write to the db, ensuring
|
if (_dirty)
|
||||||
//http passivation/activation listeners called
|
{
|
||||||
willPassivate();
|
//The session attributes have changed, write to the db, ensuring
|
||||||
updateSession(this);
|
//http passivation/activation listeners called
|
||||||
didActivate();
|
willPassivate();
|
||||||
}
|
updateSession(this);
|
||||||
else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L))
|
didActivate();
|
||||||
{
|
}
|
||||||
updateSessionAccessTime(this);
|
else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L))
|
||||||
|
{
|
||||||
|
updateSessionAccessTime(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.server;
|
package org.eclipse.jetty.server;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -36,7 +36,7 @@ import org.eclipse.jetty.continuation.Continuation;
|
||||||
import org.eclipse.jetty.continuation.ContinuationListener;
|
import org.eclipse.jetty.continuation.ContinuationListener;
|
||||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
import org.eclipse.jetty.toolchain.test.Stress;
|
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
@ -90,7 +90,7 @@ public class AsyncStressTest
|
||||||
@Test
|
@Test
|
||||||
public void testAsync() throws Throwable
|
public void testAsync() throws Throwable
|
||||||
{
|
{
|
||||||
if (Stress.isEnabled())
|
if (PropertyFlag.isEnabled("test.stress"))
|
||||||
{
|
{
|
||||||
doConnections(1600,240);
|
doConnections(1600,240);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2013 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.server;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.server.Request;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class HalfCloseRaceTest
|
||||||
|
{
|
||||||
|
@Test
|
||||||
|
public void testHalfCloseRace() throws Exception
|
||||||
|
{
|
||||||
|
Server server = new Server();
|
||||||
|
SelectChannelConnector connector = new SelectChannelConnector();
|
||||||
|
connector.setPort(0);
|
||||||
|
connector.setMaxIdleTime(500);
|
||||||
|
server.addConnector(connector);
|
||||||
|
TestHandler handler = new TestHandler();
|
||||||
|
server.setHandler(handler);
|
||||||
|
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
Socket client = new Socket("localhost",connector.getLocalPort());
|
||||||
|
|
||||||
|
int in = client.getInputStream().read();
|
||||||
|
assertEquals(-1,in);
|
||||||
|
|
||||||
|
client.getOutputStream().write("GET / HTTP/1.0\r\n\r\n".getBytes());
|
||||||
|
|
||||||
|
Thread.sleep(200);
|
||||||
|
assertEquals(0,handler.getHandled());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestHandler extends AbstractHandler
|
||||||
|
{
|
||||||
|
transient int handled;
|
||||||
|
|
||||||
|
public TestHandler()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||||
|
{
|
||||||
|
baseRequest.setHandled(true);
|
||||||
|
handled++;
|
||||||
|
response.setContentType("text/html;charset=utf-8");
|
||||||
|
response.setStatus(HttpServletResponse.SC_OK);
|
||||||
|
response.getWriter().println("<h1>Test</h1>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHandled()
|
||||||
|
{
|
||||||
|
return handled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
import org.eclipse.jetty.toolchain.test.Stress;
|
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ import org.junit.AfterClass;
|
||||||
public class HttpServerTestFixture
|
public class HttpServerTestFixture
|
||||||
{ // Useful constants
|
{ // Useful constants
|
||||||
protected static final long PAUSE=10L;
|
protected static final long PAUSE=10L;
|
||||||
protected static final int LOOPS=Stress.isEnabled()?250:50;
|
protected static final int LOOPS=PropertyFlag.isEnabled("test.stress")?250:50;
|
||||||
protected static final String HOST="localhost";
|
protected static final String HOST="localhost";
|
||||||
|
|
||||||
protected static Server _server;
|
protected static Server _server;
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2013 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.server;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.LineNumberReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.Socket;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ShutdownMonitorTest
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ShutdownMonitorTest
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testShutdown ()
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
//test port and key assignment
|
||||||
|
ShutdownMonitor.getInstance().setPort(0);
|
||||||
|
ShutdownMonitor.getInstance().setExitVm(false);
|
||||||
|
ShutdownMonitor.getInstance().start();
|
||||||
|
String key = ShutdownMonitor.getInstance().getKey();
|
||||||
|
int port = ShutdownMonitor.getInstance().getPort();
|
||||||
|
|
||||||
|
//try starting a 2nd time (should be ignored)
|
||||||
|
ShutdownMonitor.getInstance().start();
|
||||||
|
|
||||||
|
|
||||||
|
stop(port,key,true);
|
||||||
|
assertTrue(!ShutdownMonitor.getInstance().isAlive());
|
||||||
|
|
||||||
|
//should be able to change port and key because it is stopped
|
||||||
|
ShutdownMonitor.getInstance().setPort(0);
|
||||||
|
ShutdownMonitor.getInstance().setKey("foo");
|
||||||
|
ShutdownMonitor.getInstance().start();
|
||||||
|
|
||||||
|
key = ShutdownMonitor.getInstance().getKey();
|
||||||
|
port = ShutdownMonitor.getInstance().getPort();
|
||||||
|
assertTrue(ShutdownMonitor.getInstance().isAlive());
|
||||||
|
|
||||||
|
stop(port,key,true);
|
||||||
|
assertTrue(!ShutdownMonitor.getInstance().isAlive());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void stop (int port, String key, boolean check)
|
||||||
|
throws Exception
|
||||||
|
{
|
||||||
|
Socket s = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//send stop command
|
||||||
|
s = new Socket(InetAddress.getByName("127.0.0.1"),port);
|
||||||
|
|
||||||
|
OutputStream out = s.getOutputStream();
|
||||||
|
out.write((key + "\r\nstop\r\n").getBytes());
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
if (check)
|
||||||
|
{
|
||||||
|
//wait a little
|
||||||
|
Thread.currentThread().sleep(600);
|
||||||
|
|
||||||
|
//check for stop confirmation
|
||||||
|
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
|
||||||
|
String response;
|
||||||
|
if ((response = lin.readLine()) != null)
|
||||||
|
{
|
||||||
|
assertEquals("Stopped", response);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new IllegalStateException("No stop confirmation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (s != null) s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -36,7 +36,7 @@ import javax.servlet.http.HttpServletResponse;
|
||||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||||
import org.eclipse.jetty.toolchain.test.OS;
|
import org.eclipse.jetty.toolchain.test.OS;
|
||||||
import org.eclipse.jetty.toolchain.test.Stress;
|
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
@ -126,10 +126,10 @@ public class StressTest
|
||||||
public void testNonPersistent() throws Throwable
|
public void testNonPersistent() throws Throwable
|
||||||
{
|
{
|
||||||
// TODO needs to be further investigated
|
// TODO needs to be further investigated
|
||||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
|
||||||
|
|
||||||
doThreads(10,10,false);
|
doThreads(10,10,false);
|
||||||
if (Stress.isEnabled())
|
if (PropertyFlag.isEnabled("test.stress"))
|
||||||
{
|
{
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
doThreads(200,10,false);
|
doThreads(200,10,false);
|
||||||
|
@ -142,10 +142,10 @@ public class StressTest
|
||||||
public void testPersistent() throws Throwable
|
public void testPersistent() throws Throwable
|
||||||
{
|
{
|
||||||
// TODO needs to be further investigated
|
// TODO needs to be further investigated
|
||||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
|
||||||
|
|
||||||
doThreads(20,10,true);
|
doThreads(20,10,true);
|
||||||
if (Stress.isEnabled())
|
if (PropertyFlag.isEnabled("test.stress"))
|
||||||
{
|
{
|
||||||
Thread.sleep(1000);
|
Thread.sleep(1000);
|
||||||
doThreads(200,10,true);
|
doThreads(200,10,true);
|
||||||
|
|
|
@ -454,7 +454,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
||||||
if (resource!=null && resource.exists() && !resource.isDirectory())
|
if (resource!=null && resource.exists() && !resource.isDirectory())
|
||||||
{
|
{
|
||||||
// Tell caches that response may vary by accept-encoding
|
// Tell caches that response may vary by accept-encoding
|
||||||
response.setHeader(HttpHeaders.VARY,HttpHeaders.ACCEPT_ENCODING);
|
response.addHeader(HttpHeaders.VARY,HttpHeaders.ACCEPT_ENCODING);
|
||||||
|
|
||||||
// Does the client accept gzip?
|
// Does the client accept gzip?
|
||||||
String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING);
|
String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING);
|
||||||
|
|
|
@ -24,6 +24,7 @@ import javax.servlet.GenericServlet;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Dispatcher;
|
import org.eclipse.jetty.server.Dispatcher;
|
||||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||||
|
@ -96,7 +97,11 @@ public class JspPropertyGroupServlet extends GenericServlet
|
||||||
@Override
|
@Override
|
||||||
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
|
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
Request request=(req instanceof Request)?(Request)req:AbstractHttpConnection.getCurrentConnection().getRequest();
|
HttpServletRequest request = null;
|
||||||
|
if (req instanceof HttpServletRequest)
|
||||||
|
request = (HttpServletRequest)req;
|
||||||
|
else
|
||||||
|
throw new ServletException("Request not HttpServletRequest");
|
||||||
|
|
||||||
String servletPath=null;
|
String servletPath=null;
|
||||||
String pathInfo=null;
|
String pathInfo=null;
|
||||||
|
|
|
@ -340,8 +340,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
||||||
if (o==null)
|
if (o==null)
|
||||||
return;
|
return;
|
||||||
Servlet servlet = ((Servlet)o);
|
Servlet servlet = ((Servlet)o);
|
||||||
servlet.destroy();
|
|
||||||
getServletHandler().destroyServlet(servlet);
|
getServletHandler().destroyServlet(servlet);
|
||||||
|
servlet.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
|
|
|
@ -48,11 +48,6 @@
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
|
||||||
<groupId>junit</groupId>
|
|
||||||
<artifactId>junit</artifactId>
|
|
||||||
<scope>test</scope>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
<artifactId>jetty-test-helper</artifactId>
|
<artifactId>jetty-test-helper</artifactId>
|
||||||
|
|
|
@ -125,8 +125,11 @@ public class DoSFilter implements Filter
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(DoSFilter.class);
|
private static final Logger LOG = Log.getLogger(DoSFilter.class);
|
||||||
|
|
||||||
private static final Pattern IP_PATTERN = Pattern.compile("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})");
|
private static final String IPv4_GROUP = "(\\d{1,3})";
|
||||||
private static final Pattern CIDR_PATTERN = Pattern.compile(IP_PATTERN + "/(\\d{1,2})");
|
private static final Pattern IPv4_PATTERN = Pattern.compile(IPv4_GROUP+"\\."+IPv4_GROUP+"\\."+IPv4_GROUP+"\\."+IPv4_GROUP);
|
||||||
|
private static final String IPv6_GROUP = "(\\p{XDigit}{1,4})";
|
||||||
|
private static final Pattern IPv6_PATTERN = Pattern.compile(IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP);
|
||||||
|
private static final Pattern CIDR_PATTERN = Pattern.compile("([^/]+)/(\\d+)");
|
||||||
|
|
||||||
private static final String __TRACKER = "DoSFilter.Tracker";
|
private static final String __TRACKER = "DoSFilter.Tracker";
|
||||||
private static final String __THROTTLED = "DoSFilter.Throttled";
|
private static final String __THROTTLED = "DoSFilter.Throttled";
|
||||||
|
@ -618,31 +621,94 @@ public class DoSFilter implements Filter
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean subnetMatch(String subnetAddress, String candidate)
|
protected boolean subnetMatch(String subnetAddress, String address)
|
||||||
{
|
{
|
||||||
Matcher matcher = CIDR_PATTERN.matcher(subnetAddress);
|
Matcher cidrMatcher = CIDR_PATTERN.matcher(subnetAddress);
|
||||||
int subnet = intFromAddress(matcher);
|
if (!cidrMatcher.matches())
|
||||||
int prefix = Integer.parseInt(matcher.group(5));
|
return false;
|
||||||
// Sets the most significant prefix bits to 1
|
|
||||||
// If prefix == 8 => 11111111_00000000_00000000_00000000
|
String subnet = cidrMatcher.group(1);
|
||||||
int mask = ~((1 << (32 - prefix)) - 1);
|
int prefix;
|
||||||
int ip = intFromAddress(IP_PATTERN.matcher(candidate));
|
try
|
||||||
return (ip & mask) == (subnet & mask);
|
{
|
||||||
|
prefix = Integer.parseInt(cidrMatcher.group(2));
|
||||||
|
}
|
||||||
|
catch (NumberFormatException x)
|
||||||
|
{
|
||||||
|
LOG.info("Ignoring malformed CIDR address {}", subnetAddress);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] subnetBytes = addressToBytes(subnet);
|
||||||
|
if (subnetBytes == null)
|
||||||
|
{
|
||||||
|
LOG.info("Ignoring malformed CIDR address {}", subnetAddress);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
byte[] addressBytes = addressToBytes(address);
|
||||||
|
if (addressBytes == null)
|
||||||
|
{
|
||||||
|
LOG.info("Ignoring malformed remote address {}", address);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Comparing IPv4 with IPv6 ?
|
||||||
|
int length = subnetBytes.length;
|
||||||
|
if (length != addressBytes.length)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
byte[] mask = prefixToBytes(prefix, length);
|
||||||
|
|
||||||
|
for (int i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
if ((subnetBytes[i] & mask[i]) != (addressBytes[i] & mask[i]))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int intFromAddress(Matcher matcher)
|
private byte[] addressToBytes(String address)
|
||||||
{
|
{
|
||||||
int result = 0;
|
Matcher ipv4Matcher = IPv4_PATTERN.matcher(address);
|
||||||
if (matcher.matches())
|
if (ipv4Matcher.matches())
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 4; ++i)
|
byte[] result = new byte[4];
|
||||||
{
|
for (int i = 0; i < result.length; ++i)
|
||||||
int b = Integer.parseInt(matcher.group(i + 1));
|
result[i] = Integer.valueOf(ipv4Matcher.group(i + 1)).byteValue();
|
||||||
result |= b << 8 * (3 - i);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException();
|
else
|
||||||
|
{
|
||||||
|
Matcher ipv6Matcher = IPv6_PATTERN.matcher(address);
|
||||||
|
if (ipv6Matcher.matches())
|
||||||
|
{
|
||||||
|
byte[] result = new byte[16];
|
||||||
|
for (int i = 0; i < result.length; i += 2)
|
||||||
|
{
|
||||||
|
int word = Integer.valueOf(ipv6Matcher.group(i / 2 + 1), 16);
|
||||||
|
result[i] = (byte)((word & 0xFF00) >>> 8);
|
||||||
|
result[i + 1] = (byte)(word & 0xFF);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] prefixToBytes(int prefix, int length)
|
||||||
|
{
|
||||||
|
byte[] result = new byte[length];
|
||||||
|
int index = 0;
|
||||||
|
while (prefix / 8 > 0)
|
||||||
|
{
|
||||||
|
result[index] = -1;
|
||||||
|
prefix -= 8;
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
// Sets the _prefix_ most significant bits to 1
|
||||||
|
result[index] = (byte)~((1 << (8 - prefix)) - 1);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void destroy()
|
public void destroy()
|
||||||
|
@ -947,14 +1013,7 @@ public class DoSFilter implements Filter
|
||||||
private boolean addWhitelistAddress(List<String> list, String address)
|
private boolean addWhitelistAddress(List<String> list, String address)
|
||||||
{
|
{
|
||||||
address = address.trim();
|
address = address.trim();
|
||||||
if (address.length() > 0)
|
return address.length() > 0 && list.add(address);
|
||||||
{
|
|
||||||
if (CIDR_PATTERN.matcher(address).matches() || IP_PATTERN.matcher(address).matches())
|
|
||||||
return list.add(address);
|
|
||||||
else
|
|
||||||
LOG.warn("Ignoring malformed whitelist IP address {}", address);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean removeWhitelistAddress(String address)
|
public boolean removeWhitelistAddress(String address)
|
||||||
|
|
|
@ -84,15 +84,6 @@ public class IncludableGzipFilter extends GzipFilter
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setHeader(String name, String value)
|
|
||||||
{
|
|
||||||
super.setHeader(name, value);
|
|
||||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
|
||||||
if (!response.containsHeader(name))
|
|
||||||
response.setHeader("org.eclipse.jetty.server.include." + name, value);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -111,15 +102,6 @@ public class IncludableGzipFilter extends GzipFilter
|
||||||
{
|
{
|
||||||
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setHeader(String name, String value)
|
|
||||||
{
|
|
||||||
super.setHeader(name, value);
|
|
||||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
|
||||||
if (!response.containsHeader(name))
|
|
||||||
response.setHeader("org.eclipse.jetty.server.include." + name, value);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -138,15 +120,6 @@ public class IncludableGzipFilter extends GzipFilter
|
||||||
{
|
{
|
||||||
return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel, _deflateNoWrap));
|
return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel, _deflateNoWrap));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void setHeader(String name, String value)
|
|
||||||
{
|
|
||||||
super.setHeader(name, value);
|
|
||||||
HttpServletResponse response = (HttpServletResponse)getResponse();
|
|
||||||
if (!response.containsHeader(name))
|
|
||||||
response.setHeader("org.eclipse.jetty.server.include." + name, value);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -176,6 +149,16 @@ public class IncludableGzipFilter extends GzipFilter
|
||||||
if (!response.containsHeader(name))
|
if (!response.containsHeader(name))
|
||||||
response.setHeader("org.eclipse.jetty.server.include."+name,value);
|
response.setHeader("org.eclipse.jetty.server.include."+name,value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addHeader(String name, String value)
|
||||||
|
{
|
||||||
|
super.addHeader(name, value);
|
||||||
|
HttpServletResponse response = (HttpServletResponse)getResponse();
|
||||||
|
if (!response.containsHeader(name))
|
||||||
|
setHeader(name,value);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
|
protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
|
||||||
{
|
{
|
||||||
|
|
|
@ -79,12 +79,17 @@ public class DoSFilterTest extends AbstractDoSFilterTest
|
||||||
List<String> whitelist = new ArrayList<String>();
|
List<String> whitelist = new ArrayList<String>();
|
||||||
whitelist.add("192.168.0.1");
|
whitelist.add("192.168.0.1");
|
||||||
whitelist.add("10.0.0.0/8");
|
whitelist.add("10.0.0.0/8");
|
||||||
|
whitelist.add("4d8:0:a:1234:ABc:1F:b18:17");
|
||||||
|
whitelist.add("4d8:0:a:1234:ABc:1F:0:0/96");
|
||||||
Assert.assertTrue(filter.checkWhitelist(whitelist, "192.168.0.1"));
|
Assert.assertTrue(filter.checkWhitelist(whitelist, "192.168.0.1"));
|
||||||
Assert.assertFalse(filter.checkWhitelist(whitelist, "192.168.0.2"));
|
Assert.assertFalse(filter.checkWhitelist(whitelist, "192.168.0.2"));
|
||||||
Assert.assertFalse(filter.checkWhitelist(whitelist, "11.12.13.14"));
|
Assert.assertFalse(filter.checkWhitelist(whitelist, "11.12.13.14"));
|
||||||
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.11.12.13"));
|
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.11.12.13"));
|
||||||
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.0.0.0"));
|
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.0.0.0"));
|
||||||
Assert.assertFalse(filter.checkWhitelist(whitelist, "0.0.0.0"));
|
Assert.assertFalse(filter.checkWhitelist(whitelist, "0.0.0.0"));
|
||||||
|
Assert.assertTrue(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1F:b18:17"));
|
||||||
|
Assert.assertTrue(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1F:b18:0"));
|
||||||
|
Assert.assertFalse(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1D:0:0"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean hitRateTracker(DoSFilter doSFilter, int sleep) throws InterruptedException
|
private boolean hitRateTracker(DoSFilter doSFilter, int sleep) throws InterruptedException
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
<name>Jetty :: SPDY :: Parent</name>
|
<name>Jetty :: SPDY :: Parent</name>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<npn.version>1.1.0.v20120525</npn.version>
|
<npn.version>1.1.5.v20130313</npn.version>
|
||||||
|
<npn.api.version>1.1.0.v20120525</npn.api.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.npn</groupId>
|
<groupId>org.eclipse.jetty.npn</groupId>
|
||||||
<artifactId>npn-api</artifactId>
|
<artifactId>npn-api</artifactId>
|
||||||
<version>1.0.0.v20120402</version>
|
<version>${npn.api.version}</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -58,7 +58,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.npn</groupId>
|
<groupId>org.eclipse.jetty.npn</groupId>
|
||||||
<artifactId>npn-api</artifactId>
|
<artifactId>npn-api</artifactId>
|
||||||
<version>${npn.version}</version>
|
<version>${npn.api.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -578,8 +578,14 @@ public class Scanner extends AbstractLifeCycle
|
||||||
if (f.isDirectory() && (depth<_scanDepth || _scanDepth==-1 || _scanDirs.contains(f)))
|
if (f.isDirectory() && (depth<_scanDepth || _scanDepth==-1 || _scanDirs.contains(f)))
|
||||||
{
|
{
|
||||||
File[] files = f.listFiles();
|
File[] files = f.listFiles();
|
||||||
for (int i=0;i<files.length;i++)
|
if (files != null)
|
||||||
scanFile(files[i], scanInfoMap,depth+1);
|
{
|
||||||
|
for (int i=0;i<files.length;i++)
|
||||||
|
scanFile(files[i], scanInfoMap,depth+1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
LOG.warn("Error listing files in directory {}", f);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995-2013 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.util.component;
|
||||||
|
|
||||||
|
import java.io.FileWriter;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/** A LifeCycle Listener that writes state changes to a file.
|
||||||
|
* <p>This can be used with the jetty.sh script to wait for successful startup.
|
||||||
|
*/
|
||||||
|
public class FileNoticeLifeCycleListener implements LifeCycle.Listener
|
||||||
|
{
|
||||||
|
Logger LOG = Log.getLogger(FileNoticeLifeCycleListener.class);
|
||||||
|
|
||||||
|
private final String _filename;
|
||||||
|
|
||||||
|
public FileNoticeLifeCycleListener(String filename)
|
||||||
|
{
|
||||||
|
_filename=filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writeState(String action, LifeCycle lifecycle)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
FileWriter out = new FileWriter(_filename,true);
|
||||||
|
out.append(action).append(" ").append(lifecycle.toString()).append("\n");
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
LOG.warn(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lifeCycleStarting(LifeCycle event)
|
||||||
|
{
|
||||||
|
writeState("STARTING",event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lifeCycleStarted(LifeCycle event)
|
||||||
|
{
|
||||||
|
writeState("STARTED",event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lifeCycleFailure(LifeCycle event, Throwable cause)
|
||||||
|
{
|
||||||
|
writeState("FAILED",event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lifeCycleStopping(LifeCycle event)
|
||||||
|
{
|
||||||
|
writeState("STOPPING",event);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void lifeCycleStopped(LifeCycle event)
|
||||||
|
{
|
||||||
|
writeState("STOPPED",event);
|
||||||
|
}
|
||||||
|
}
|
|
@ -217,8 +217,7 @@ public abstract class Resource implements ResourceFactory
|
||||||
{
|
{
|
||||||
URL url=null;
|
URL url=null;
|
||||||
// Try to format as a URL?
|
// Try to format as a URL?
|
||||||
ClassLoader
|
ClassLoader loader=Thread.currentThread().getContextClassLoader();
|
||||||
loader=Thread.currentThread().getContextClassLoader();
|
|
||||||
if (loader!=null)
|
if (loader!=null)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -250,7 +249,7 @@ public abstract class Resource implements ResourceFactory
|
||||||
{
|
{
|
||||||
url=ClassLoader.getSystemResource(resource);
|
url=ClassLoader.getSystemResource(resource);
|
||||||
if (url==null && resource.startsWith("/"))
|
if (url==null && resource.startsWith("/"))
|
||||||
url=loader.getResource(resource.substring(1));
|
url=ClassLoader.getSystemResource(resource.substring(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url==null)
|
if (url==null)
|
||||||
|
|
4
pom.xml
4
pom.xml
|
@ -237,7 +237,7 @@
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
<artifactId>jetty-version-maven-plugin</artifactId>
|
<artifactId>jetty-version-maven-plugin</artifactId>
|
||||||
<version>1.0.9</version>
|
<version>1.0.10</version>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
@ -508,7 +508,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
<artifactId>jetty-test-helper</artifactId>
|
<artifactId>jetty-test-helper</artifactId>
|
||||||
<version>1.6.1</version>
|
<version>2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.slf4j</groupId>
|
<groupId>org.slf4j</groupId>
|
||||||
|
|
Loading…
Reference in New Issue