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.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.AsyncNCSARequestLog;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.NCSARequestLog;
|
||||
|
@ -154,13 +155,13 @@ public class LikeJettyXml
|
|||
login.setConfig(jetty_home + "/etc/realm.properties");
|
||||
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);
|
||||
requestLogHandler.setRequestLog(requestLog);
|
||||
|
||||
server.setStopAtShutdown(true);
|
||||
server.setSendServerVersion(true);
|
||||
|
||||
|
||||
server.start();
|
||||
|
||||
|
|
|
@ -18,12 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
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 static org.junit.Assert.*;
|
||||
import static org.junit.matchers.JUnitMatchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
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.nio.DirectNIOBuffer;
|
||||
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.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -115,7 +111,7 @@ public class HttpExchangeTest
|
|||
sender(10,false);
|
||||
sender(10,true);
|
||||
|
||||
if (Stress.isEnabled())
|
||||
if (PropertyFlag.isEnabled("test.stress"))
|
||||
{
|
||||
sender(100,false);
|
||||
sender(100,true);
|
||||
|
|
|
@ -1633,9 +1633,6 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
Assert.assertThat(sslFlushes.get(), lessThan(20));
|
||||
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);
|
||||
|
||||
TimeUnit.MILLISECONDS.sleep(200);
|
||||
|
@ -1772,7 +1769,14 @@ public class SslBytesServerTest extends SslBytesTest
|
|||
proxy.flushToServer(record);
|
||||
|
||||
// Close Alert
|
||||
record = proxy.readFromServer();
|
||||
try
|
||||
{
|
||||
record = proxy.readFromServer();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
proxy.flushToClient(record);
|
||||
|
||||
}
|
||||
|
|
|
@ -110,6 +110,24 @@ running()
|
|||
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()
|
||||
{
|
||||
(( DEBUG )) && echo "Reading $1.."
|
||||
|
@ -137,7 +155,13 @@ shift
|
|||
##################################################
|
||||
# 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
|
||||
readConfig "$CONFIG"
|
||||
fi
|
||||
|
@ -262,9 +286,9 @@ fi
|
|||
##################################################
|
||||
if [ -z "$JETTY_CONF" ]
|
||||
then
|
||||
if [ -f /etc/jetty.conf ]
|
||||
if [ -f $ETC/jetty.conf ]
|
||||
then
|
||||
JETTY_CONF=/etc/jetty.conf
|
||||
JETTY_CONF=$ETC/jetty.conf
|
||||
elif [ -f "$JETTY_HOME/etc/jetty.conf" ]
|
||||
then
|
||||
JETTY_CONF=$JETTY_HOME/etc/jetty.conf
|
||||
|
@ -312,13 +336,20 @@ then
|
|||
fi
|
||||
|
||||
#####################################################
|
||||
# Find a PID for the pid file
|
||||
# Find a pid and state file
|
||||
#####################################################
|
||||
if [ -z "$JETTY_PID" ]
|
||||
then
|
||||
JETTY_PID="$JETTY_RUN/jetty.pid"
|
||||
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
|
||||
##################################################
|
||||
|
@ -407,23 +438,15 @@ case "$ACTION" in
|
|||
exit
|
||||
fi
|
||||
|
||||
if type start-stop-daemon > /dev/null 2>&1
|
||||
if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1
|
||||
then
|
||||
unset CH_USER
|
||||
if [ -n "$JETTY_USER" ]
|
||||
then
|
||||
CH_USER="-c$JETTY_USER"
|
||||
fi
|
||||
if start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
|
||||
then
|
||||
sleep 1
|
||||
if running "$JETTY_PID"
|
||||
then
|
||||
echo "OK"
|
||||
else
|
||||
echo "FAILED"
|
||||
fi
|
||||
fi
|
||||
|
||||
start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
|
||||
|
||||
else
|
||||
|
||||
|
@ -454,14 +477,25 @@ case "$ACTION" in
|
|||
echo $! > "$JETTY_PID"
|
||||
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
|
||||
|
||||
;;
|
||||
|
||||
stop)
|
||||
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
|
||||
|
||||
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.
|
||||
#
|
||||
# Each line in this file becomes an arguement to start.jar
|
||||
# unless this file contains an --ini option, then these
|
||||
# arguments will be in addition to those found in the
|
||||
# start.ini file
|
||||
# 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();
|
||||
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED)
|
||||
if (_eol == HttpTokens.CARRIAGE_RETURN)
|
||||
{
|
||||
_eol=HttpTokens.LINE_FEED;
|
||||
continue;
|
||||
if (ch == HttpTokens.LINE_FEED)
|
||||
{
|
||||
_eol=HttpTokens.LINE_FEED;
|
||||
continue;
|
||||
}
|
||||
throw new HttpException(HttpStatus.BAD_REQUEST_400);
|
||||
}
|
||||
_eol=0;
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
setHeader("Content-Encoding", _encoding);
|
||||
if (_response.containsHeader("Content-Encoding"))
|
||||
{
|
||||
setHeader("Vary",_vary);
|
||||
addHeader("Vary",_vary);
|
||||
_out=_compressedOutputStream=createStream();
|
||||
if (_out!=null)
|
||||
{
|
||||
|
@ -269,7 +269,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
|
|||
if (_out == null || _bOut != null)
|
||||
{
|
||||
if (sendVary)
|
||||
setHeader("Vary",_vary);
|
||||
addHeader("Vary",_vary);
|
||||
if (_wrapper.getETag()!=null)
|
||||
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));
|
||||
}
|
||||
|
||||
protected void addHeader(String name,String value)
|
||||
{
|
||||
_response.addHeader(name, value);
|
||||
}
|
||||
|
||||
protected void setHeader(String name,String value)
|
||||
{
|
||||
_response.setHeader(name, value);
|
||||
|
|
|
@ -23,6 +23,8 @@ import static org.junit.Assert.assertTrue;
|
|||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.SimpleBuffers;
|
||||
|
@ -179,6 +181,88 @@ public class HttpParserTest
|
|||
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
|
||||
public void testChunkParse() throws Exception
|
||||
{
|
||||
|
|
|
@ -63,11 +63,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
*/
|
||||
private volatile AsyncConnection _connection;
|
||||
|
||||
/** true if a thread has been dispatched to handle this endpoint */
|
||||
private boolean _dispatched = false;
|
||||
|
||||
/** true if a non IO dispatch (eg async resume) is outstanding */
|
||||
private boolean _asyncDispatch = false;
|
||||
private static final int STATE_NEEDS_DISPATCH=-1;
|
||||
private static final int STATE_UNDISPATCHED=0;
|
||||
private static final int STATE_DISPATCHED=1;
|
||||
private static final int STATE_ASYNC=2;
|
||||
private int _state;
|
||||
|
||||
private boolean _onIdle;
|
||||
|
||||
/** true if the last write operation succeed and wrote all offered bytes */
|
||||
private volatile boolean _writable = true;
|
||||
|
@ -83,6 +85,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
private boolean _open;
|
||||
|
||||
private volatile long _idleTimestamp;
|
||||
private volatile boolean _checkIdle;
|
||||
|
||||
private boolean _ishut;
|
||||
|
||||
|
@ -94,8 +97,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
|
||||
_manager = selectSet.getManager();
|
||||
_selectSet = selectSet;
|
||||
_dispatched = false;
|
||||
_asyncDispatch = false;
|
||||
_state=STATE_UNDISPATCHED;
|
||||
_onIdle=false;
|
||||
_open=true;
|
||||
_key = key;
|
||||
|
||||
|
@ -169,7 +172,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
|
||||
// we are not interested in further selecting
|
||||
_key.interestOps(0);
|
||||
if (!_dispatched)
|
||||
if (_state<STATE_DISPATCHED)
|
||||
updateKey();
|
||||
return;
|
||||
}
|
||||
|
@ -184,13 +187,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
}
|
||||
|
||||
// If dispatched, then deregister interest
|
||||
if (_dispatched)
|
||||
if (_state>=STATE_DISPATCHED)
|
||||
_key.interestOps(0);
|
||||
else
|
||||
{
|
||||
// other wise do the dispatch
|
||||
dispatch();
|
||||
if (_dispatched && !_selectSet.getManager().isDeferringInterestedOps0())
|
||||
if (_state>=STATE_DISPATCHED && !_selectSet.getManager().isDeferringInterestedOps0())
|
||||
{
|
||||
_key.interestOps(0);
|
||||
}
|
||||
|
@ -203,10 +206,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
synchronized(this)
|
||||
{
|
||||
if (_dispatched)
|
||||
_asyncDispatch=true;
|
||||
else
|
||||
dispatch();
|
||||
switch(_state)
|
||||
{
|
||||
case STATE_NEEDS_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)
|
||||
{
|
||||
if (!_dispatched)
|
||||
if (_state<=STATE_UNDISPATCHED)
|
||||
{
|
||||
_dispatched = true;
|
||||
boolean dispatched = _manager.dispatch(_handler);
|
||||
if(!dispatched)
|
||||
if (_onIdle)
|
||||
_state = STATE_NEEDS_DISPATCH;
|
||||
else
|
||||
{
|
||||
_dispatched = false;
|
||||
LOG.warn("Dispatched Failed! "+this+" to "+_manager);
|
||||
updateKey();
|
||||
_state = STATE_DISPATCHED;
|
||||
boolean dispatched = _manager.dispatch(_handler);
|
||||
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)
|
||||
{
|
||||
if (_asyncDispatch)
|
||||
switch(_state)
|
||||
{
|
||||
_asyncDispatch=false;
|
||||
return false;
|
||||
case STATE_ASYNC:
|
||||
_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)
|
||||
{
|
||||
_idleTimestamp=check?System.currentTimeMillis():0;
|
||||
if (check)
|
||||
{
|
||||
_idleTimestamp=System.currentTimeMillis();
|
||||
_checkIdle=true;
|
||||
}
|
||||
else
|
||||
_checkIdle=false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isCheckForIdle()
|
||||
{
|
||||
return _idleTimestamp!=0;
|
||||
return _checkIdle;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void notIdle()
|
||||
{
|
||||
if (_idleTimestamp!=0)
|
||||
_idleTimestamp=System.currentTimeMillis();
|
||||
_idleTimestamp=System.currentTimeMillis();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void checkIdleTimestamp(long now)
|
||||
{
|
||||
long idleTimestamp=_idleTimestamp;
|
||||
|
||||
if (idleTimestamp!=0 && _maxIdleTime>0)
|
||||
if (isCheckForIdle() && _maxIdleTime>0)
|
||||
{
|
||||
final long idleForMs=now-idleTimestamp;
|
||||
final long idleForMs=now-_idleTimestamp;
|
||||
|
||||
if (idleForMs>_maxIdleTime)
|
||||
{
|
||||
|
@ -316,7 +338,25 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
/* ------------------------------------------------------------ */
|
||||
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)
|
||||
{
|
||||
_writable=false;
|
||||
if (!_dispatched)
|
||||
if (_state<STATE_DISPATCHED)
|
||||
updateKey();
|
||||
}
|
||||
}
|
||||
|
@ -367,7 +407,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
synchronized (this)
|
||||
{
|
||||
_writable=false;
|
||||
if (!_dispatched)
|
||||
if (_state<STATE_DISPATCHED)
|
||||
updateKey();
|
||||
}
|
||||
}
|
||||
|
@ -514,8 +554,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
int current_ops=-1;
|
||||
if (getChannel().isOpen())
|
||||
{
|
||||
boolean read_interest = _readBlocked || (!_dispatched && !_connection.isSuspended());
|
||||
boolean write_interest= _writeBlocked || (!_dispatched && !_writable);
|
||||
boolean read_interest = _readBlocked || (_state<STATE_DISPATCHED && !_connection.isSuspended());
|
||||
boolean write_interest= _writeBlocked || (_state<STATE_DISPATCHED && !_writable);
|
||||
|
||||
_interestOps =
|
||||
((!_socket.isInputShutdown() && read_interest ) ? SelectionKey.OP_READ : 0)
|
||||
|
@ -764,11 +804,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
|
|||
{
|
||||
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(),
|
||||
_socket.getRemoteSocketAddress(),
|
||||
_socket.getLocalSocketAddress(),
|
||||
_dispatched,
|
||||
_state,
|
||||
isOpen(),
|
||||
isInputShutdown(),
|
||||
isOutputShutdown(),
|
||||
|
|
|
@ -24,15 +24,15 @@ import java.util.ArrayList;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ThreadLocalBuffersTest
|
||||
{
|
||||
private Buffers httpBuffers;
|
||||
private List<Thread> threadList = new ArrayList<Thread>();
|
||||
private int numThreads = Stress.isEnabled()?100:10;
|
||||
private int runTestLength = Stress.isEnabled()?5000:1000;
|
||||
private int numThreads = PropertyFlag.isEnabled("test.stress")?100:10;
|
||||
private int runTestLength = PropertyFlag.isEnabled("test.stress")?5000:1000;
|
||||
private boolean runTest = false;
|
||||
private AtomicLong buffersRetrieved;
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ public class MongoSessionManager extends NoSqlSessionManager
|
|||
}
|
||||
else
|
||||
{
|
||||
version = new Long(((Long)version).intValue() + 1);
|
||||
version = new Long(((Number)version).longValue() + 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.CopyOnWriteArraySet;
|
||||
|
||||
import org.eclipse.jetty.http.HttpSchemes;
|
||||
import org.eclipse.jetty.http.PathMap;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
|
@ -365,7 +366,11 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
return true;
|
||||
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)
|
||||
url += "?" + request.getQueryString();
|
||||
response.setContentLength(0);
|
||||
|
@ -384,11 +389,13 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
|
|||
|
||||
if (connector.getConfidentialPort() > 0)
|
||||
{
|
||||
String url = connector.getConfidentialScheme() + "://" + request.getServerName() + ":" + connector.getConfidentialPort()
|
||||
+ request.getRequestURI();
|
||||
String scheme=connector.getConfidentialScheme();
|
||||
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)
|
||||
url += "?" + request.getQueryString();
|
||||
|
||||
response.setContentLength(0);
|
||||
response.sendRedirect(url);
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.security.authentication;
|
|||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.BitSet;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
@ -60,17 +61,32 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
|
||||
SecureRandom _random = new SecureRandom();
|
||||
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 static class Nonce
|
||||
{
|
||||
final String _nonce;
|
||||
final long _ts;
|
||||
AtomicInteger _nc=new AtomicInteger();
|
||||
public Nonce(String nonce, long ts)
|
||||
final BitSet _seen;
|
||||
|
||||
public Nonce(String nonce, long ts, int size)
|
||||
{
|
||||
_nonce=nonce;
|
||||
_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");
|
||||
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;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public long getMaxNonceAge()
|
||||
{
|
||||
return _maxNonceAgeMs;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getAuthMethod()
|
||||
{
|
||||
|
@ -233,9 +265,9 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
byte[] nounce = new byte[24];
|
||||
_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);
|
||||
|
||||
return nonce._nonce;
|
||||
|
@ -250,36 +282,27 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
private int checkNonce(Digest digest, Request request)
|
||||
{
|
||||
// firstly let's expire old nonces
|
||||
long expired;
|
||||
synchronized (this)
|
||||
{
|
||||
expired = request.getTimeStamp()-_maxNonceAgeMs;
|
||||
}
|
||||
|
||||
long expired = request.getTimeStamp()-_maxNonceAgeMs;
|
||||
Nonce nonce=_nonceQueue.peek();
|
||||
while (nonce!=null && nonce._ts<expired)
|
||||
{
|
||||
_nonceQueue.remove(nonce);
|
||||
_nonceCount.remove(nonce._nonce);
|
||||
_nonceMap.remove(nonce._nonce);
|
||||
nonce=_nonceQueue.peek();
|
||||
}
|
||||
|
||||
|
||||
// Now check the requested nonce
|
||||
try
|
||||
{
|
||||
nonce = _nonceCount.get(digest.nonce);
|
||||
nonce = _nonceMap.get(digest.nonce);
|
||||
if (nonce==null)
|
||||
return 0;
|
||||
|
||||
|
||||
long count = Long.parseLong(digest.nc,16);
|
||||
if (count>Integer.MAX_VALUE)
|
||||
if (count>=_maxNC)
|
||||
return 0;
|
||||
int old=nonce._nc.get();
|
||||
while (!nonce._nc.compareAndSet(old,(int)count))
|
||||
old=nonce._nc.get();
|
||||
if (count<=old)
|
||||
if (nonce.seen((int)count))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -378,6 +401,7 @@ public class DigestAuthenticator extends LoginAuthenticator
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return username + "," + response;
|
||||
|
|
|
@ -22,17 +22,21 @@ import static org.junit.Assert.assertFalse;
|
|||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
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.server.Connector;
|
||||
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.session.SessionHandler;
|
||||
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.Credential;
|
||||
import org.eclipse.jetty.util.security.Password;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
@ -138,7 +145,14 @@ public class ConstraintTest
|
|||
mapping5.setPathSpec("/forbid/post");
|
||||
mapping5.setConstraint(constraint5);
|
||||
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>();
|
||||
knownRoles.add("user");
|
||||
|
@ -146,7 +160,7 @@ public class ConstraintTest
|
|||
|
||||
_security.setConstraintMappings(Arrays.asList(new ConstraintMapping[]
|
||||
{
|
||||
mapping0, mapping1, mapping2, mapping3, mapping4, mapping5
|
||||
mapping0, mapping1, mapping2, mapping3, mapping4, mapping5,mapping6
|
||||
}), knownRoles);
|
||||
}
|
||||
|
||||
|
@ -215,7 +229,6 @@ public class ConstraintTest
|
|||
"\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
|
||||
|
||||
|
||||
// test admin
|
||||
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
|
||||
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
|
||||
|
@ -243,6 +256,127 @@ public class ConstraintTest
|
|||
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
|
||||
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");
|
||||
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("/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"));
|
||||
|
||||
|
@ -766,6 +900,48 @@ public class ConstraintTest
|
|||
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
|
||||
public void testRoleRef() throws Exception
|
||||
{
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
<Arg>
|
||||
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
|
||||
<Set name="requestLog">
|
||||
<!-- Use AsyncNCSARequestLog for improved request latency -->
|
||||
<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="filenameDateFormat">yyyy_MM_dd</Set>
|
||||
|
|
|
@ -860,6 +860,13 @@ public abstract class AbstractHttpConnection extends AbstractConnection
|
|||
/* ------------------------------------------------------------ */
|
||||
protected void headerComplete() throws IOException
|
||||
{
|
||||
// Handle idle race
|
||||
if (_endp.isOutputShutdown())
|
||||
{
|
||||
_endp.close();
|
||||
return;
|
||||
}
|
||||
|
||||
_requests++;
|
||||
_generator.setVersion(_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
|
||||
{
|
||||
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 boolean _extended;
|
||||
|
@ -461,7 +469,8 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
|||
if (_fileOut == null)
|
||||
return;
|
||||
|
||||
StringBuilder buf= new StringBuilder(256);
|
||||
StringBuilder buf= _buffers.get();
|
||||
buf.setLength(0);
|
||||
|
||||
if (_logServer)
|
||||
{
|
||||
|
@ -577,22 +586,29 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
|||
}
|
||||
|
||||
buf.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
String log = buf.toString();
|
||||
synchronized(this)
|
||||
{
|
||||
if (_writer==null)
|
||||
return;
|
||||
_writer.write(log);
|
||||
_writer.flush();
|
||||
}
|
||||
write(log);
|
||||
}
|
||||
catch (IOException 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.
|
||||
|
@ -662,7 +678,10 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
|
|||
else
|
||||
_ignorePathMap = null;
|
||||
|
||||
_writer = new OutputStreamWriter(_out);
|
||||
synchronized(this)
|
||||
{
|
||||
_writer = new OutputStreamWriter(_out);
|
||||
}
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
|
|
@ -78,6 +78,7 @@ public class ResourceCache
|
|||
_mimeTypes=mimeTypes;
|
||||
_parent=parent;
|
||||
_etags=etags;
|
||||
_useFileMappedBuffer=useFileMappedBuffer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -261,10 +261,12 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (getStopAtShutdown()) {
|
||||
ShutdownThread.register(this);
|
||||
ShutdownMonitor.getInstance().start(); // initialize
|
||||
if (getStopAtShutdown())
|
||||
{
|
||||
ShutdownThread.register(this);
|
||||
}
|
||||
|
||||
ShutdownMonitor.getInstance().start(); // initialize
|
||||
|
||||
LOG.info("jetty-"+__version);
|
||||
HttpGenerator.setServerVersion(__version);
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
|
|||
* <p>
|
||||
* 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.
|
||||
static class Holder
|
||||
|
@ -53,11 +53,165 @@ public class ShutdownMonitor extends Thread
|
|||
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 int port;
|
||||
private String key;
|
||||
private boolean exitVm;
|
||||
private ServerSocket serverSocket;
|
||||
private ShutdownMonitorThread thread;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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/
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -149,77 +303,6 @@ public class ShutdownMonitor extends Thread
|
|||
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)
|
||||
{
|
||||
|
@ -228,90 +311,71 @@ public class ShutdownMonitor extends Thread
|
|||
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (isAlive())
|
||||
synchronized (this)
|
||||
{
|
||||
throw new IllegalStateException("ShutdownMonitor already started");
|
||||
}
|
||||
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)
|
||||
if (thread != null && thread.isAlive())
|
||||
{
|
||||
// server assigned port in use
|
||||
this.port = serverSocket.getLocalPort();
|
||||
System.out.printf("STOP.PORT=%d%n",this.port);
|
||||
throw new IllegalStateException("ShutdownMonitorThread already started");
|
||||
}
|
||||
|
||||
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);
|
||||
this.port = port;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -294,17 +294,20 @@ public class JDBCSessionManager extends AbstractSessionManager
|
|||
super.complete();
|
||||
try
|
||||
{
|
||||
if (_dirty)
|
||||
if (isValid())
|
||||
{
|
||||
//The session attributes have changed, write to the db, ensuring
|
||||
//http passivation/activation listeners called
|
||||
willPassivate();
|
||||
updateSession(this);
|
||||
didActivate();
|
||||
}
|
||||
else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L))
|
||||
{
|
||||
updateSessionAccessTime(this);
|
||||
if (_dirty)
|
||||
{
|
||||
//The session attributes have changed, write to the db, ensuring
|
||||
//http passivation/activation listeners called
|
||||
willPassivate();
|
||||
updateSession(this);
|
||||
didActivate();
|
||||
}
|
||||
else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L))
|
||||
{
|
||||
updateSessionAccessTime(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.server;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -36,7 +36,7 @@ import org.eclipse.jetty.continuation.Continuation;
|
|||
import org.eclipse.jetty.continuation.ContinuationListener;
|
||||
import org.eclipse.jetty.server.handler.HandlerWrapper;
|
||||
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.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -90,7 +90,7 @@ public class AsyncStressTest
|
|||
@Test
|
||||
public void testAsync() throws Throwable
|
||||
{
|
||||
if (Stress.isEnabled())
|
||||
if (PropertyFlag.isEnabled("test.stress"))
|
||||
{
|
||||
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.HandlerWrapper;
|
||||
import org.eclipse.jetty.toolchain.test.Stress;
|
||||
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.AfterClass;
|
||||
|
||||
|
@ -44,7 +44,7 @@ import org.junit.AfterClass;
|
|||
public class HttpServerTestFixture
|
||||
{ // Useful constants
|
||||
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 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.nio.SelectChannelConnector;
|
||||
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.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -126,10 +126,10 @@ public class StressTest
|
|||
public void testNonPersistent() throws Throwable
|
||||
{
|
||||
// TODO needs to be further investigated
|
||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
|
||||
|
||||
doThreads(10,10,false);
|
||||
if (Stress.isEnabled())
|
||||
if (PropertyFlag.isEnabled("test.stress"))
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,10,false);
|
||||
|
@ -142,10 +142,10 @@ public class StressTest
|
|||
public void testPersistent() throws Throwable
|
||||
{
|
||||
// TODO needs to be further investigated
|
||||
assumeTrue(!OS.IS_OSX || Stress.isEnabled());
|
||||
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
|
||||
|
||||
doThreads(20,10,true);
|
||||
if (Stress.isEnabled())
|
||||
if (PropertyFlag.isEnabled("test.stress"))
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
doThreads(200,10,true);
|
||||
|
|
|
@ -454,7 +454,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
|
|||
if (resource!=null && resource.exists() && !resource.isDirectory())
|
||||
{
|
||||
// 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?
|
||||
String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING);
|
||||
|
|
|
@ -24,6 +24,7 @@ import javax.servlet.GenericServlet;
|
|||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.Dispatcher;
|
||||
import org.eclipse.jetty.server.AbstractHttpConnection;
|
||||
|
@ -96,7 +97,11 @@ public class JspPropertyGroupServlet extends GenericServlet
|
|||
@Override
|
||||
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 pathInfo=null;
|
||||
|
|
|
@ -340,8 +340,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
if (o==null)
|
||||
return;
|
||||
Servlet servlet = ((Servlet)o);
|
||||
servlet.destroy();
|
||||
getServletHandler().destroyServlet(servlet);
|
||||
servlet.destroy();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -48,11 +48,6 @@
|
|||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<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 Pattern IP_PATTERN = Pattern.compile("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})");
|
||||
private static final Pattern CIDR_PATTERN = Pattern.compile(IP_PATTERN + "/(\\d{1,2})");
|
||||
private static final String IPv4_GROUP = "(\\d{1,3})";
|
||||
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 __THROTTLED = "DoSFilter.Throttled";
|
||||
|
@ -618,31 +621,94 @@ public class DoSFilter implements Filter
|
|||
return false;
|
||||
}
|
||||
|
||||
protected boolean subnetMatch(String subnetAddress, String candidate)
|
||||
protected boolean subnetMatch(String subnetAddress, String address)
|
||||
{
|
||||
Matcher matcher = CIDR_PATTERN.matcher(subnetAddress);
|
||||
int subnet = intFromAddress(matcher);
|
||||
int prefix = Integer.parseInt(matcher.group(5));
|
||||
// Sets the most significant prefix bits to 1
|
||||
// If prefix == 8 => 11111111_00000000_00000000_00000000
|
||||
int mask = ~((1 << (32 - prefix)) - 1);
|
||||
int ip = intFromAddress(IP_PATTERN.matcher(candidate));
|
||||
return (ip & mask) == (subnet & mask);
|
||||
Matcher cidrMatcher = CIDR_PATTERN.matcher(subnetAddress);
|
||||
if (!cidrMatcher.matches())
|
||||
return false;
|
||||
|
||||
String subnet = cidrMatcher.group(1);
|
||||
int prefix;
|
||||
try
|
||||
{
|
||||
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;
|
||||
if (matcher.matches())
|
||||
Matcher ipv4Matcher = IPv4_PATTERN.matcher(address);
|
||||
if (ipv4Matcher.matches())
|
||||
{
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
int b = Integer.parseInt(matcher.group(i + 1));
|
||||
result |= b << 8 * (3 - i);
|
||||
}
|
||||
byte[] result = new byte[4];
|
||||
for (int i = 0; i < result.length; ++i)
|
||||
result[i] = Integer.valueOf(ipv4Matcher.group(i + 1)).byteValue();
|
||||
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()
|
||||
|
@ -947,14 +1013,7 @@ public class DoSFilter implements Filter
|
|||
private boolean addWhitelistAddress(List<String> list, String address)
|
||||
{
|
||||
address = address.trim();
|
||||
if (address.length() > 0)
|
||||
{
|
||||
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;
|
||||
return address.length() > 0 && list.add(address);
|
||||
}
|
||||
|
||||
public boolean removeWhitelistAddress(String address)
|
||||
|
|
|
@ -84,15 +84,6 @@ public class IncludableGzipFilter extends GzipFilter
|
|||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@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));
|
||||
}
|
||||
|
||||
@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))
|
||||
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
|
||||
protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
|
||||
{
|
||||
|
|
|
@ -79,12 +79,17 @@ public class DoSFilterTest extends AbstractDoSFilterTest
|
|||
List<String> whitelist = new ArrayList<String>();
|
||||
whitelist.add("192.168.0.1");
|
||||
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.assertFalse(filter.checkWhitelist(whitelist, "192.168.0.2"));
|
||||
Assert.assertFalse(filter.checkWhitelist(whitelist, "11.12.13.14"));
|
||||
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.11.12.13"));
|
||||
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.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
|
||||
|
|
|
@ -13,7 +13,8 @@
|
|||
<name>Jetty :: SPDY :: Parent</name>
|
||||
|
||||
<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>
|
||||
|
||||
<modules>
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
<artifactId>npn-api</artifactId>
|
||||
<version>1.0.0.v20120402</version>
|
||||
<version>${npn.api.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty.npn</groupId>
|
||||
<artifactId>npn-api</artifactId>
|
||||
<version>${npn.version}</version>
|
||||
<version>${npn.api.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -578,8 +578,14 @@ public class Scanner extends AbstractLifeCycle
|
|||
if (f.isDirectory() && (depth<_scanDepth || _scanDepth==-1 || _scanDirs.contains(f)))
|
||||
{
|
||||
File[] files = f.listFiles();
|
||||
for (int i=0;i<files.length;i++)
|
||||
scanFile(files[i], scanInfoMap,depth+1);
|
||||
if (files != null)
|
||||
{
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
// Try to format as a URL?
|
||||
ClassLoader
|
||||
loader=Thread.currentThread().getContextClassLoader();
|
||||
ClassLoader loader=Thread.currentThread().getContextClassLoader();
|
||||
if (loader!=null)
|
||||
{
|
||||
try
|
||||
|
@ -250,7 +249,7 @@ public abstract class Resource implements ResourceFactory
|
|||
{
|
||||
url=ClassLoader.getSystemResource(resource);
|
||||
if (url==null && resource.startsWith("/"))
|
||||
url=loader.getResource(resource.substring(1));
|
||||
url=ClassLoader.getSystemResource(resource.substring(1));
|
||||
}
|
||||
|
||||
if (url==null)
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -237,7 +237,7 @@
|
|||
<plugin>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-version-maven-plugin</artifactId>
|
||||
<version>1.0.9</version>
|
||||
<version>1.0.10</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
@ -508,7 +508,7 @@
|
|||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<version>1.6.1</version>
|
||||
<version>2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
Loading…
Reference in New Issue