Merge branch 'jetty-7' into release-7

This commit is contained in:
Jesse McConnell 2013-05-06 17:29:21 -05:00
commit 67f55ec8e5
45 changed files with 1317 additions and 650 deletions

4
.travis.yml Normal file
View File

@ -0,0 +1,4 @@
language: java
jdk:
- openjdk7
- oraclejdk7

View File

@ -25,6 +25,7 @@ import org.eclipse.jetty.deploy.providers.ContextProvider;
import org.eclipse.jetty.deploy.providers.WebAppProvider; import org.eclipse.jetty.deploy.providers.WebAppProvider;
import org.eclipse.jetty.jmx.MBeanContainer; import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.HashLoginService; import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.AsyncNCSARequestLog;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.NCSARequestLog; import org.eclipse.jetty.server.NCSARequestLog;
@ -154,13 +155,13 @@ public class LikeJettyXml
login.setConfig(jetty_home + "/etc/realm.properties"); login.setConfig(jetty_home + "/etc/realm.properties");
server.addBean(login); server.addBean(login);
NCSARequestLog requestLog = new NCSARequestLog(jetty_home + "/logs/jetty-yyyy_mm_dd.log"); NCSARequestLog requestLog = new AsyncNCSARequestLog();
requestLog.setFilename(jetty_home + "/logs/jetty-yyyy_mm_dd.log");
requestLog.setExtended(false); requestLog.setExtended(false);
requestLogHandler.setRequestLog(requestLog); requestLogHandler.setRequestLog(requestLog);
server.setStopAtShutdown(true); server.setStopAtShutdown(true);
server.setSendServerVersion(true); server.setSendServerVersion(true);
server.start(); server.start();

View File

@ -18,12 +18,8 @@
package org.eclipse.jetty.client; package org.eclipse.jetty.client;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import static org.junit.Assert.assertNotNull; import static org.junit.matchers.JUnitMatchers.*;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.matchers.JUnitMatchers.containsString;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -46,7 +42,7 @@ import org.eclipse.jetty.io.Connection;
import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.EofException;
import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.io.nio.DirectNIOBuffer;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.toolchain.test.Stress; import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -115,7 +111,7 @@ public class HttpExchangeTest
sender(10,false); sender(10,false);
sender(10,true); sender(10,true);
if (Stress.isEnabled()) if (PropertyFlag.isEnabled("test.stress"))
{ {
sender(100,false); sender(100,false);
sender(100,true); sender(100,true);

View File

@ -1633,9 +1633,6 @@ public class SslBytesServerTest extends SslBytesTest
Assert.assertThat(sslFlushes.get(), lessThan(20)); Assert.assertThat(sslFlushes.get(), lessThan(20));
Assert.assertThat(httpParses.get(), lessThan(50)); Assert.assertThat(httpParses.get(), lessThan(50));
//System.err.println(((Dumpable)server.getConnectors()[0]).dump());
Assert.assertThat(((Dumpable)server.getConnectors()[0]).dump(),containsString("SCEP@"));
completeClose(client); completeClose(client);
TimeUnit.MILLISECONDS.sleep(200); TimeUnit.MILLISECONDS.sleep(200);
@ -1772,7 +1769,14 @@ public class SslBytesServerTest extends SslBytesTest
proxy.flushToServer(record); proxy.flushToServer(record);
// Close Alert // Close Alert
record = proxy.readFromServer(); try
{
record = proxy.readFromServer();
}
catch (IOException e)
{
e.printStackTrace();
}
proxy.flushToClient(record); proxy.flushToClient(record);
} }

View File

@ -110,6 +110,24 @@ running()
kill -0 "$PID" 2>/dev/null kill -0 "$PID" 2>/dev/null
} }
started()
{
# wait for 60s to see "STARTED" in PID file, needs jetty-started.xml as argument
for T in 1 2 3 4 5 6 7 9 10 11 12 13 14 15
do
sleep 4
[ -z "$(grep STARTED $1 2>/dev/null)" ] || return 0
[ -z "$(grep STOPPED $1 2>/dev/null)" ] || return 1
[ -z "$(grep FAILED $1 2>/dev/null)" ] || return 1
local PID=$(cat "$2" 2>/dev/null) || return 1
kill -0 "$PID" 2>/dev/null || return 1
echo -n ". "
done
return 1;
}
readConfig() readConfig()
{ {
(( DEBUG )) && echo "Reading $1.." (( DEBUG )) && echo "Reading $1.."
@ -137,7 +155,13 @@ shift
################################################## ##################################################
# Read any configuration files # Read any configuration files
################################################## ##################################################
for CONFIG in /etc/default/jetty{,7} $HOME/.jettyrc; do ETC=/etc
if [ $UID != 0 ]
then
ETC=$HOME/etc
fi
for CONFIG in $ETC/default/jetty{,7} $HOME/.jettyrc; do
if [ -f "$CONFIG" ] ; then if [ -f "$CONFIG" ] ; then
readConfig "$CONFIG" readConfig "$CONFIG"
fi fi
@ -262,9 +286,9 @@ fi
################################################## ##################################################
if [ -z "$JETTY_CONF" ] if [ -z "$JETTY_CONF" ]
then then
if [ -f /etc/jetty.conf ] if [ -f $ETC/jetty.conf ]
then then
JETTY_CONF=/etc/jetty.conf JETTY_CONF=$ETC/jetty.conf
elif [ -f "$JETTY_HOME/etc/jetty.conf" ] elif [ -f "$JETTY_HOME/etc/jetty.conf" ]
then then
JETTY_CONF=$JETTY_HOME/etc/jetty.conf JETTY_CONF=$JETTY_HOME/etc/jetty.conf
@ -312,13 +336,20 @@ then
fi fi
##################################################### #####################################################
# Find a PID for the pid file # Find a pid and state file
##################################################### #####################################################
if [ -z "$JETTY_PID" ] if [ -z "$JETTY_PID" ]
then then
JETTY_PID="$JETTY_RUN/jetty.pid" JETTY_PID="$JETTY_RUN/jetty.pid"
fi fi
if [ -z "$JETTY_STATE" ]
then
JETTY_STATE=$JETTY_HOME/jetty.state
fi
JAVA_OPTIONS+=("-Djetty.state=$JETTY_STATE")
rm -f $JETTY_STATE
################################################## ##################################################
# Setup JAVA if unset # Setup JAVA if unset
################################################## ##################################################
@ -407,23 +438,15 @@ case "$ACTION" in
exit exit
fi fi
if type start-stop-daemon > /dev/null 2>&1 if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1
then then
unset CH_USER unset CH_USER
if [ -n "$JETTY_USER" ] if [ -n "$JETTY_USER" ]
then then
CH_USER="-c$JETTY_USER" CH_USER="-c$JETTY_USER"
fi fi
if start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
then start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
sleep 1
if running "$JETTY_PID"
then
echo "OK"
else
echo "FAILED"
fi
fi
else else
@ -454,14 +477,25 @@ case "$ACTION" in
echo $! > "$JETTY_PID" echo $! > "$JETTY_PID"
fi fi
echo "STARTED Jetty `date`" fi
if expr "${CONFIGS[*]}" : '.*etc/jetty-started.xml.*' >/dev/null
then
if started "$JETTY_STATE" "$JETTY_PID"
then
echo "OK `date`"
else
echo "FAILED `date`"
fi
else
echo "ok `date`"
fi fi
;; ;;
stop) stop)
echo -n "Stopping Jetty: " echo -n "Stopping Jetty: "
if type start-stop-daemon > /dev/null 2>&1; then if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1; then
start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP
TIMEOUT=30 TIMEOUT=30

View File

@ -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>

View File

@ -6,8 +6,7 @@
# created by that script. # created by that script.
# #
# Each line in this file becomes an arguement to start.jar # Each line in this file becomes an arguement to start.jar
# unless this file contains an --ini option, then these # in addition to those found in the start.ini file
# arguments will be in addition to those found in the
# start.ini file
# ======================================================= # =======================================================
--pre=etc/jetty-logging.xml etc/jetty-logging.xml
etc/jetty-started.xml

View File

@ -350,10 +350,14 @@ public class HttpParser implements Parser
ch=_buffer.get(); ch=_buffer.get();
if (_eol == HttpTokens.CARRIAGE_RETURN && ch == HttpTokens.LINE_FEED) if (_eol == HttpTokens.CARRIAGE_RETURN)
{ {
_eol=HttpTokens.LINE_FEED; if (ch == HttpTokens.LINE_FEED)
continue; {
_eol=HttpTokens.LINE_FEED;
continue;
}
throw new HttpException(HttpStatus.BAD_REQUEST_400);
} }
_eol=0; _eol=0;

View File

@ -234,7 +234,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
setHeader("Content-Encoding", _encoding); setHeader("Content-Encoding", _encoding);
if (_response.containsHeader("Content-Encoding")) if (_response.containsHeader("Content-Encoding"))
{ {
setHeader("Vary",_vary); addHeader("Vary",_vary);
_out=_compressedOutputStream=createStream(); _out=_compressedOutputStream=createStream();
if (_out!=null) if (_out!=null)
{ {
@ -269,7 +269,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
if (_out == null || _bOut != null) if (_out == null || _bOut != null)
{ {
if (sendVary) if (sendVary)
setHeader("Vary",_vary); addHeader("Vary",_vary);
if (_wrapper.getETag()!=null) if (_wrapper.getETag()!=null)
setHeader("ETag",_wrapper.getETag()); setHeader("ETag",_wrapper.getETag());
@ -341,6 +341,11 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
} }
protected void addHeader(String name,String value)
{
_response.addHeader(name, value);
}
protected void setHeader(String name,String value) protected void setHeader(String name,String value)
{ {
_response.setHeader(name, value); _response.setHeader(name, value);

View File

@ -23,6 +23,8 @@ import static org.junit.Assert.assertTrue;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import junit.framework.Assert;
import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.io.SimpleBuffers; import org.eclipse.jetty.io.SimpleBuffers;
@ -179,6 +181,88 @@ public class HttpParserTest
assertEquals(5, h); assertEquals(5, h);
} }
@Test
public void testHeaderParseLF() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
"GET / HTTP/1.0\012"
+ "Host: localhost\012"
+ "Header1: value1\012"
+ "Header2 : value 2a \012"
+ " value 2b \012"
+ "Header3: \012"
+ "Header4 \012"
+ " value4\012"
+ "Server5: notServer\012"
+ "\012");
ByteArrayBuffer buffer= new ByteArrayBuffer(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
parser.parse();
assertEquals("GET", f0);
assertEquals("/", f1);
assertEquals("HTTP/1.0", f2);
assertEquals("Host", hdr[0]);
assertEquals("localhost", val[0]);
assertEquals("Header1", hdr[1]);
assertEquals("value1", val[1]);
assertEquals("Header2", hdr[2]);
assertEquals("value 2a value 2b", val[2]);
assertEquals("Header3", hdr[3]);
assertEquals("", val[3]);
assertEquals("Header4", hdr[4]);
assertEquals("value4", val[4]);
assertEquals("Server5", hdr[5]);
assertEquals("notServer", val[5]);
assertEquals(5, h);
}
@Test
public void testHeaderParseCR() throws Exception
{
StringEndPoint io=new StringEndPoint();
io.setInput(
"GET / HTTP/1.0\015"
+ "Host: localhost\015"
+ "Header1: value1\015"
+ "\015");
ByteArrayBuffer buffer= new ByteArrayBuffer(4096);
SimpleBuffers buffers=new SimpleBuffers(buffer,null);
Handler handler = new Handler();
HttpParser parser= new HttpParser(buffers,io, handler);
try
{
parser.parse();
Assert.fail();
}
catch(HttpException e)
{
assertEquals(400,e._status);
}
io.setInput(
"GET / HTTP/1.0\r\n"
+ "Host: localhost\r\r\n"
+ "Header1: value1\r\n"
+ "\r\n");
parser= new HttpParser(buffers,io, handler);
try
{
parser.parse();
Assert.fail();
}
catch(HttpException e)
{
assertEquals(400,e._status);
}
}
@Test @Test
public void testChunkParse() throws Exception public void testChunkParse() throws Exception
{ {

View File

@ -63,11 +63,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
*/ */
private volatile AsyncConnection _connection; private volatile AsyncConnection _connection;
/** true if a thread has been dispatched to handle this endpoint */ private static final int STATE_NEEDS_DISPATCH=-1;
private boolean _dispatched = false; private static final int STATE_UNDISPATCHED=0;
private static final int STATE_DISPATCHED=1;
/** true if a non IO dispatch (eg async resume) is outstanding */ private static final int STATE_ASYNC=2;
private boolean _asyncDispatch = false; private int _state;
private boolean _onIdle;
/** true if the last write operation succeed and wrote all offered bytes */ /** true if the last write operation succeed and wrote all offered bytes */
private volatile boolean _writable = true; private volatile boolean _writable = true;
@ -83,6 +85,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
private boolean _open; private boolean _open;
private volatile long _idleTimestamp; private volatile long _idleTimestamp;
private volatile boolean _checkIdle;
private boolean _ishut; private boolean _ishut;
@ -94,8 +97,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
_manager = selectSet.getManager(); _manager = selectSet.getManager();
_selectSet = selectSet; _selectSet = selectSet;
_dispatched = false; _state=STATE_UNDISPATCHED;
_asyncDispatch = false; _onIdle=false;
_open=true; _open=true;
_key = key; _key = key;
@ -169,7 +172,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
// we are not interested in further selecting // we are not interested in further selecting
_key.interestOps(0); _key.interestOps(0);
if (!_dispatched) if (_state<STATE_DISPATCHED)
updateKey(); updateKey();
return; return;
} }
@ -184,13 +187,13 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
} }
// If dispatched, then deregister interest // If dispatched, then deregister interest
if (_dispatched) if (_state>=STATE_DISPATCHED)
_key.interestOps(0); _key.interestOps(0);
else else
{ {
// other wise do the dispatch // other wise do the dispatch
dispatch(); dispatch();
if (_dispatched && !_selectSet.getManager().isDeferringInterestedOps0()) if (_state>=STATE_DISPATCHED && !_selectSet.getManager().isDeferringInterestedOps0())
{ {
_key.interestOps(0); _key.interestOps(0);
} }
@ -203,10 +206,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{ {
synchronized(this) synchronized(this)
{ {
if (_dispatched) switch(_state)
_asyncDispatch=true; {
else case STATE_NEEDS_DISPATCH:
dispatch(); case STATE_UNDISPATCHED:
dispatch();
break;
case STATE_DISPATCHED:
case STATE_ASYNC:
_state=STATE_ASYNC;
break;
}
} }
} }
@ -215,15 +226,20 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{ {
synchronized(this) synchronized(this)
{ {
if (!_dispatched) if (_state<=STATE_UNDISPATCHED)
{ {
_dispatched = true; if (_onIdle)
boolean dispatched = _manager.dispatch(_handler); _state = STATE_NEEDS_DISPATCH;
if(!dispatched) else
{ {
_dispatched = false; _state = STATE_DISPATCHED;
LOG.warn("Dispatched Failed! "+this+" to "+_manager); boolean dispatched = _manager.dispatch(_handler);
updateKey(); if(!dispatched)
{
_state = STATE_NEEDS_DISPATCH;
LOG.warn("Dispatched Failed! "+this+" to "+_manager);
updateKey();
}
} }
} }
} }
@ -240,15 +256,18 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{ {
synchronized (this) synchronized (this)
{ {
if (_asyncDispatch) switch(_state)
{ {
_asyncDispatch=false; case STATE_ASYNC:
return false; _state=STATE_DISPATCHED;
return false;
default:
_state=STATE_UNDISPATCHED;
updateKey();
return true;
} }
_dispatched = false;
updateKey();
} }
return true;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -266,30 +285,33 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public void setCheckForIdle(boolean check) public void setCheckForIdle(boolean check)
{ {
_idleTimestamp=check?System.currentTimeMillis():0; if (check)
{
_idleTimestamp=System.currentTimeMillis();
_checkIdle=true;
}
else
_checkIdle=false;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public boolean isCheckForIdle() public boolean isCheckForIdle()
{ {
return _idleTimestamp!=0; return _checkIdle;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
protected void notIdle() protected void notIdle()
{ {
if (_idleTimestamp!=0) _idleTimestamp=System.currentTimeMillis();
_idleTimestamp=System.currentTimeMillis();
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public void checkIdleTimestamp(long now) public void checkIdleTimestamp(long now)
{ {
long idleTimestamp=_idleTimestamp; if (isCheckForIdle() && _maxIdleTime>0)
if (idleTimestamp!=0 && _maxIdleTime>0)
{ {
final long idleForMs=now-idleTimestamp; final long idleForMs=now-_idleTimestamp;
if (idleForMs>_maxIdleTime) if (idleForMs>_maxIdleTime)
{ {
@ -316,7 +338,25 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public void onIdleExpired(long idleForMs) public void onIdleExpired(long idleForMs)
{ {
_connection.onIdleExpired(idleForMs); try
{
synchronized (this)
{
_onIdle=true;
}
if (_maxIdleTime>0 && (System.currentTimeMillis()-_idleTimestamp)>_maxIdleTime)
_connection.onIdleExpired(idleForMs);
}
finally
{
synchronized (this)
{
_onIdle=false;
if (_state==STATE_NEEDS_DISPATCH)
dispatch();
}
}
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
@ -341,7 +381,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
synchronized (this) synchronized (this)
{ {
_writable=false; _writable=false;
if (!_dispatched) if (_state<STATE_DISPATCHED)
updateKey(); updateKey();
} }
} }
@ -367,7 +407,7 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
synchronized (this) synchronized (this)
{ {
_writable=false; _writable=false;
if (!_dispatched) if (_state<STATE_DISPATCHED)
updateKey(); updateKey();
} }
} }
@ -514,8 +554,8 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
int current_ops=-1; int current_ops=-1;
if (getChannel().isOpen()) if (getChannel().isOpen())
{ {
boolean read_interest = _readBlocked || (!_dispatched && !_connection.isSuspended()); boolean read_interest = _readBlocked || (_state<STATE_DISPATCHED && !_connection.isSuspended());
boolean write_interest= _writeBlocked || (!_dispatched && !_writable); boolean write_interest= _writeBlocked || (_state<STATE_DISPATCHED && !_writable);
_interestOps = _interestOps =
((!_socket.isInputShutdown() && read_interest ) ? SelectionKey.OP_READ : 0) ((!_socket.isInputShutdown() && read_interest ) ? SelectionKey.OP_READ : 0)
@ -764,11 +804,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
{ {
keyString += "-"; keyString += "-";
} }
return String.format("SCEP@%x{l(%s)<->r(%s),d=%b,open=%b,ishut=%b,oshut=%b,rb=%b,wb=%b,w=%b,i=%d%s}-{%s}", return String.format("SCEP@%x{l(%s)<->r(%s),s=%d,open=%b,ishut=%b,oshut=%b,rb=%b,wb=%b,w=%b,i=%d%s}-{%s}",
hashCode(), hashCode(),
_socket.getRemoteSocketAddress(), _socket.getRemoteSocketAddress(),
_socket.getLocalSocketAddress(), _socket.getLocalSocketAddress(),
_dispatched, _state,
isOpen(), isOpen(),
isInputShutdown(), isInputShutdown(),
isOutputShutdown(), isOutputShutdown(),

View File

@ -24,15 +24,15 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.jetty.toolchain.test.Stress; import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.junit.Test; import org.junit.Test;
public class ThreadLocalBuffersTest public class ThreadLocalBuffersTest
{ {
private Buffers httpBuffers; private Buffers httpBuffers;
private List<Thread> threadList = new ArrayList<Thread>(); private List<Thread> threadList = new ArrayList<Thread>();
private int numThreads = Stress.isEnabled()?100:10; private int numThreads = PropertyFlag.isEnabled("test.stress")?100:10;
private int runTestLength = Stress.isEnabled()?5000:1000; private int runTestLength = PropertyFlag.isEnabled("test.stress")?5000:1000;
private boolean runTest = false; private boolean runTest = false;
private AtomicLong buffersRetrieved; private AtomicLong buffersRetrieved;

View File

@ -143,7 +143,7 @@ public class MongoSessionManager extends NoSqlSessionManager
} }
else else
{ {
version = new Long(((Long)version).intValue() + 1); version = new Long(((Number)version).longValue() + 1);
update.put("$inc",__version_1); update.put("$inc",__version_1);
} }

View File

@ -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>

View File

@ -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()
* {
* &#64;Override
* public boolean supports()
* {
* return true;
* }
*
* &#64;Override
* public void unsupported()
* {
* }
*
* &#64;Override
* public String selectProtocol(List&lt;String&gt; protocols)
* {
* return protocols.get(0);
* }
* });
* </pre>
* <p>Server side typical usage:</p>
* <pre>
* SSLSocket sslSocket = ...;
* NextProtoNego.put(sslSocket, new NextProtoNego.ServerProvider()
* {
* &#64;Override
* public void unsupported()
* {
* }
*
* &#64;Override
* public List<String> protocols()
* {
* return Arrays.asList("http/1.1");
* }
*
* &#64;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);
}
}

View File

@ -29,6 +29,7 @@ import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import org.eclipse.jetty.http.HttpSchemes;
import org.eclipse.jetty.http.PathMap; import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.AbstractHttpConnection;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
@ -365,7 +366,11 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
return true; return true;
if (connector.getIntegralPort() > 0) if (connector.getIntegralPort() > 0)
{ {
String url = connector.getIntegralScheme() + "://" + request.getServerName() + ":" + connector.getIntegralPort() + request.getRequestURI(); String scheme=connector.getIntegralScheme();
int port=connector.getIntegralPort();
String url = (HttpSchemes.HTTPS.equalsIgnoreCase(scheme) && port==443)
? "https://"+request.getServerName()+request.getRequestURI()
: scheme + "://" + request.getServerName() + ":" + port + request.getRequestURI();
if (request.getQueryString() != null) if (request.getQueryString() != null)
url += "?" + request.getQueryString(); url += "?" + request.getQueryString();
response.setContentLength(0); response.setContentLength(0);
@ -384,11 +389,13 @@ public class ConstraintSecurityHandler extends SecurityHandler implements Constr
if (connector.getConfidentialPort() > 0) if (connector.getConfidentialPort() > 0)
{ {
String url = connector.getConfidentialScheme() + "://" + request.getServerName() + ":" + connector.getConfidentialPort() String scheme=connector.getConfidentialScheme();
+ request.getRequestURI(); int port=connector.getConfidentialPort();
String url = (HttpSchemes.HTTPS.equalsIgnoreCase(scheme) && port==443)
? "https://"+request.getServerName()+request.getRequestURI()
: scheme + "://" + request.getServerName() + ":" + port + request.getRequestURI();
if (request.getQueryString() != null) if (request.getQueryString() != null)
url += "?" + request.getQueryString(); url += "?" + request.getQueryString();
response.setContentLength(0); response.setContentLength(0);
response.sendRedirect(url); response.sendRedirect(url);
} }

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.security.authentication;
import java.io.IOException; import java.io.IOException;
import java.security.MessageDigest; import java.security.MessageDigest;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.BitSet;
import java.util.Queue; import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
@ -60,17 +61,32 @@ public class DigestAuthenticator extends LoginAuthenticator
private static final Logger LOG = Log.getLogger(DigestAuthenticator.class); private static final Logger LOG = Log.getLogger(DigestAuthenticator.class);
SecureRandom _random = new SecureRandom(); SecureRandom _random = new SecureRandom();
private long _maxNonceAgeMs = 60*1000; private long _maxNonceAgeMs = 60*1000;
private ConcurrentMap<String, Nonce> _nonceCount = new ConcurrentHashMap<String, Nonce>(); private int _maxNC=1024;
private ConcurrentMap<String, Nonce> _nonceMap = new ConcurrentHashMap<String, Nonce>();
private Queue<Nonce> _nonceQueue = new ConcurrentLinkedQueue<Nonce>(); private Queue<Nonce> _nonceQueue = new ConcurrentLinkedQueue<Nonce>();
private static class Nonce private static class Nonce
{ {
final String _nonce; final String _nonce;
final long _ts; final long _ts;
AtomicInteger _nc=new AtomicInteger(); final BitSet _seen;
public Nonce(String nonce, long ts)
public Nonce(String nonce, long ts, int size)
{ {
_nonce=nonce; _nonce=nonce;
_ts=ts; _ts=ts;
_seen = new BitSet(size);
}
public boolean seen(int count)
{
synchronized (this)
{
if (count>=_seen.size())
return true;
boolean s=_seen.get(count);
_seen.set(count);
return s;
}
} }
} }
@ -92,19 +108,35 @@ public class DigestAuthenticator extends LoginAuthenticator
String mna=configuration.getInitParameter("maxNonceAge"); String mna=configuration.getInitParameter("maxNonceAge");
if (mna!=null) if (mna!=null)
{ {
synchronized (this) _maxNonceAgeMs=Long.valueOf(mna);
{
_maxNonceAgeMs=Long.valueOf(mna);
}
} }
} }
/* ------------------------------------------------------------ */
public int getMaxNonceCount()
{
return _maxNC;
}
/* ------------------------------------------------------------ */
public void setMaxNonceCount(int maxNC)
{
_maxNC = maxNC;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public synchronized void setMaxNonceAge(long maxNonceAgeInMillis) public void setMaxNonceAge(long maxNonceAgeInMillis)
{ {
_maxNonceAgeMs = maxNonceAgeInMillis; _maxNonceAgeMs = maxNonceAgeInMillis;
} }
/* ------------------------------------------------------------ */
public long getMaxNonceAge()
{
return _maxNonceAgeMs;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public String getAuthMethod() public String getAuthMethod()
{ {
@ -233,9 +265,9 @@ public class DigestAuthenticator extends LoginAuthenticator
byte[] nounce = new byte[24]; byte[] nounce = new byte[24];
_random.nextBytes(nounce); _random.nextBytes(nounce);
nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp()); nonce = new Nonce(new String(B64Code.encode(nounce)),request.getTimeStamp(),_maxNC);
} }
while (_nonceCount.putIfAbsent(nonce._nonce,nonce)!=null); while (_nonceMap.putIfAbsent(nonce._nonce,nonce)!=null);
_nonceQueue.add(nonce); _nonceQueue.add(nonce);
return nonce._nonce; return nonce._nonce;
@ -250,36 +282,27 @@ public class DigestAuthenticator extends LoginAuthenticator
private int checkNonce(Digest digest, Request request) private int checkNonce(Digest digest, Request request)
{ {
// firstly let's expire old nonces // firstly let's expire old nonces
long expired; long expired = request.getTimeStamp()-_maxNonceAgeMs;
synchronized (this)
{
expired = request.getTimeStamp()-_maxNonceAgeMs;
}
Nonce nonce=_nonceQueue.peek(); Nonce nonce=_nonceQueue.peek();
while (nonce!=null && nonce._ts<expired) while (nonce!=null && nonce._ts<expired)
{ {
_nonceQueue.remove(nonce); _nonceQueue.remove(nonce);
_nonceCount.remove(nonce._nonce); _nonceMap.remove(nonce._nonce);
nonce=_nonceQueue.peek(); nonce=_nonceQueue.peek();
} }
// Now check the requested nonce
try try
{ {
nonce = _nonceCount.get(digest.nonce); nonce = _nonceMap.get(digest.nonce);
if (nonce==null) if (nonce==null)
return 0; return 0;
long count = Long.parseLong(digest.nc,16); long count = Long.parseLong(digest.nc,16);
if (count>Integer.MAX_VALUE) if (count>=_maxNC)
return 0; return 0;
int old=nonce._nc.get(); if (nonce.seen((int)count))
while (!nonce._nc.compareAndSet(old,(int)count))
old=nonce._nc.get();
if (count<=old)
return -1; return -1;
return 1; return 1;
} }
catch (Exception e) catch (Exception e)
@ -378,6 +401,7 @@ public class DigestAuthenticator extends LoginAuthenticator
return false; return false;
} }
@Override
public String toString() public String toString()
{ {
return username + "," + response; return username + "," + response;

View File

@ -22,17 +22,21 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.io.IOException; import java.io.IOException;
import java.security.MessageDigest;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.security.authentication.BasicAuthenticator; import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.security.authentication.DigestAuthenticator;
import org.eclipse.jetty.security.authentication.FormAuthenticator; import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.LocalConnector;
@ -44,7 +48,10 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.session.SessionHandler; import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.util.B64Code; import org.eclipse.jetty.util.B64Code;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.security.Constraint; import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.util.security.Credential;
import org.eclipse.jetty.util.security.Password; import org.eclipse.jetty.util.security.Password;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
@ -138,7 +145,14 @@ public class ConstraintTest
mapping5.setPathSpec("/forbid/post"); mapping5.setPathSpec("/forbid/post");
mapping5.setConstraint(constraint5); mapping5.setConstraint(constraint5);
mapping5.setMethod("POST"); mapping5.setMethod("POST");
Constraint constraint6 = new Constraint();
constraint6.setAuthenticate(false);
constraint6.setName("data constraint");
constraint6.setDataConstraint(2);
ConstraintMapping mapping6 = new ConstraintMapping();
mapping6.setPathSpec("/data/*");
mapping6.setConstraint(constraint6);
Set<String> knownRoles=new HashSet<String>(); Set<String> knownRoles=new HashSet<String>();
knownRoles.add("user"); knownRoles.add("user");
@ -146,7 +160,7 @@ public class ConstraintTest
_security.setConstraintMappings(Arrays.asList(new ConstraintMapping[] _security.setConstraintMappings(Arrays.asList(new ConstraintMapping[]
{ {
mapping0, mapping1, mapping2, mapping3, mapping4, mapping5 mapping0, mapping1, mapping2, mapping3, mapping4, mapping5,mapping6
}), knownRoles); }), knownRoles);
} }
@ -215,7 +229,6 @@ public class ConstraintTest
"\r\n"); "\r\n");
assertTrue(response.startsWith("HTTP/1.1 200 OK")); assertTrue(response.startsWith("HTTP/1.1 200 OK"));
// test admin // test admin
response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n"); response = _connector.getResponses("GET /ctx/admin/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized")); assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
@ -243,6 +256,127 @@ public class ConstraintTest
assertTrue(response.startsWith("HTTP/1.1 200 OK")); assertTrue(response.startsWith("HTTP/1.1 200 OK"));
} }
private static String CNONCE="1234567890";
private String digest(String nonce, String username,String password,String uri,String nc) throws Exception
{
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] ha1;
// calc A1 digest
md.update(username.getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update("TestRealm".getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update(password.getBytes(StringUtil.__ISO_8859_1));
ha1 = md.digest();
// calc A2 digest
md.reset();
md.update("GET".getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update(uri.getBytes(StringUtil.__ISO_8859_1));
byte[] ha2 = md.digest();
// calc digest
// request-digest = <"> < KD ( H(A1), unq(nonce-value) ":"
// nc-value ":" unq(cnonce-value) ":" unq(qop-value) ":" H(A2) )
// <">
// request-digest = <"> < KD ( H(A1), unq(nonce-value) ":" H(A2)
// ) > <">
md.update(TypeUtil.toString(ha1, 16).getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update(nonce.getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update(nc.getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update(CNONCE.getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update("auth".getBytes(StringUtil.__ISO_8859_1));
md.update((byte) ':');
md.update(TypeUtil.toString(ha2, 16).getBytes(StringUtil.__ISO_8859_1));
byte[] digest = md.digest();
// check digest
return TypeUtil.toString(digest, 16);
}
@Test
public void testDigest() throws Exception
{
_security.setAuthenticator(new DigestAuthenticator());
_security.setStrict(false);
_server.start();
String response;
response = _connector.getResponses("GET /ctx/noauth/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
assertTrue(response.contains("WWW-Authenticate: Digest realm=\"TestRealm\""));
Pattern nonceP = Pattern.compile("nonce=\"([^\"]*)\",");
Matcher matcher = nonceP.matcher(response);
assertTrue(matcher.find());
String nonce=matcher.group(1);
//wrong password
String digest= digest(nonce,"user","WRONG","/ctx/auth/info","1");
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
"nc=1, "+
"nonce=\""+nonce+"\", "+
"response=\""+digest+"\"\r\n"+
"\r\n");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
// right password
digest= digest(nonce,"user","password","/ctx/auth/info","2");
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
"nc=2, "+
"nonce=\""+nonce+"\", "+
"response=\""+digest+"\"\r\n"+
"\r\n");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
// once only
digest= digest(nonce,"user","password","/ctx/auth/info","2");
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
"nc=2, "+
"nonce=\""+nonce+"\", "+
"response=\""+digest+"\"\r\n"+
"\r\n");
assertTrue(response.startsWith("HTTP/1.1 401 Unauthorized"));
// increasing
digest= digest(nonce,"user","password","/ctx/auth/info","4");
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
"nc=4, "+
"nonce=\""+nonce+"\", "+
"response=\""+digest+"\"\r\n"+
"\r\n");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
// out of order
digest= digest(nonce,"user","password","/ctx/auth/info","3");
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n" +
"Authorization: Digest username=\"user\", qop=auth, cnonce=\"1234567890\", uri=\"/ctx/auth/info\", realm=\"TestRealm\", "+
"nc=3, "+
"nonce=\""+nonce+"\", "+
"response=\""+digest+"\"\r\n"+
"\r\n");
assertTrue(response.startsWith("HTTP/1.1 200 OK"));
}
@Test @Test
public void testFormDispatch() throws Exception public void testFormDispatch() throws Exception
{ {
@ -668,9 +802,9 @@ public class ConstraintTest
response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n"); response = _connector.getResponses("GET /ctx/forbid/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 403 Forbidden")); assertTrue(response.startsWith("HTTP/1.1 403 Forbidden"));
response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\n\r\n"); response = _connector.getResponses("GET /ctx/auth/info HTTP/1.0\r\nHost:wibble.com:8888\r\n\r\n");
assertTrue(response.indexOf(" 302 Found") > 0); assertTrue(response.indexOf(" 302 Found") > 0);
assertTrue(response.indexOf("/ctx/testLoginPage") > 0); assertTrue(response.indexOf("http://wibble.com:8888/ctx/testLoginPage") > 0);
String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx")); String session = response.substring(response.indexOf("JSESSIONID=") + 11, response.indexOf(";Path=/ctx"));
@ -766,6 +900,48 @@ public class ConstraintTest
assertTrue(response.startsWith("HTTP/1.1 200 OK")); assertTrue(response.startsWith("HTTP/1.1 200 OK"));
} }
@Test
public void testDataRedirection() throws Exception
{
_security.setAuthenticator(new BasicAuthenticator());
_server.start();
String response;
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 403"));
_connector.setConfidentialPort(8443);
_connector.setConfidentialScheme("https");
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
assertTrue(response.indexOf("Location") > 0);
assertTrue(response.indexOf(":8443/ctx/data/info") > 0);
_connector.setConfidentialPort(443);
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
assertTrue(response.indexOf("Location") > 0);
assertTrue(response.indexOf(":443/ctx/data/info") < 0);
_connector.setConfidentialPort(8443);
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\nHost: wobble.com\r\n\r\n");
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
assertTrue(response.indexOf("Location") > 0);
assertTrue(response.indexOf("https://wobble.com:8443/ctx/data/info") > 0);
_connector.setConfidentialPort(443);
response = _connector.getResponses("GET /ctx/data/info HTTP/1.0\r\nHost: wobble.com\r\n\r\n");
System.err.println(response);
assertTrue(response.startsWith("HTTP/1.1 302 Found"));
assertTrue(response.indexOf("Location") > 0);
assertTrue(response.indexOf(":443") < 0);
assertTrue(response.indexOf("https://wobble.com/ctx/data/info") > 0);
}
@Test @Test
public void testRoleRef() throws Exception public void testRoleRef() throws Exception
{ {

View File

@ -15,6 +15,7 @@
<Arg> <Arg>
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler"> <New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
<Set name="requestLog"> <Set name="requestLog">
<!-- Use AsyncNCSARequestLog for improved request latency -->
<New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog"> <New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
<Set name="filename"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set> <Set name="filename"><Property name="jetty.logs" default="./logs"/>/yyyy_mm_dd.request.log</Set>
<Set name="filenameDateFormat">yyyy_MM_dd</Set> <Set name="filenameDateFormat">yyyy_MM_dd</Set>

View File

@ -860,6 +860,13 @@ public abstract class AbstractHttpConnection extends AbstractConnection
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
protected void headerComplete() throws IOException protected void headerComplete() throws IOException
{ {
// Handle idle race
if (_endp.isOutputShutdown())
{
_endp.close();
return;
}
_requests++; _requests++;
_generator.setVersion(_version); _generator.setVersion(_version);
switch (_version) switch (_version)

View File

@ -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;
}
}
}

View File

@ -53,6 +53,14 @@ import org.eclipse.jetty.util.log.Logger;
public class NCSARequestLog extends AbstractLifeCycle implements RequestLog public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
{ {
private static final Logger LOG = Log.getLogger(NCSARequestLog.class); private static final Logger LOG = Log.getLogger(NCSARequestLog.class);
private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
{
@Override
protected StringBuilder initialValue()
{
return new StringBuilder(256);
}
};
private String _filename; private String _filename;
private boolean _extended; private boolean _extended;
@ -461,7 +469,8 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
if (_fileOut == null) if (_fileOut == null)
return; return;
StringBuilder buf= new StringBuilder(256); StringBuilder buf= _buffers.get();
buf.setLength(0);
if (_logServer) if (_logServer)
{ {
@ -577,22 +586,29 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
} }
buf.append(StringUtil.__LINE_SEPARATOR); buf.append(StringUtil.__LINE_SEPARATOR);
String log = buf.toString(); String log = buf.toString();
synchronized(this) write(log);
{
if (_writer==null)
return;
_writer.write(log);
_writer.flush();
}
} }
catch (IOException e) catch (IOException e)
{ {
LOG.warn(e); LOG.warn(e);
} }
} }
/* ------------------------------------------------------------ */
protected void write(String log) throws IOException
{
synchronized(this)
{
if (_writer==null)
return;
_writer.write(log);
_writer.flush();
}
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Writes extended request and response information to the output stream. * Writes extended request and response information to the output stream.
@ -662,7 +678,10 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
else else
_ignorePathMap = null; _ignorePathMap = null;
_writer = new OutputStreamWriter(_out); synchronized(this)
{
_writer = new OutputStreamWriter(_out);
}
super.doStart(); super.doStart();
} }

View File

@ -78,6 +78,7 @@ public class ResourceCache
_mimeTypes=mimeTypes; _mimeTypes=mimeTypes;
_parent=parent; _parent=parent;
_etags=etags; _etags=etags;
_useFileMappedBuffer=useFileMappedBuffer;
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -261,10 +261,12 @@ public class Server extends HandlerWrapper implements Attributes
@Override @Override
protected void doStart() throws Exception protected void doStart() throws Exception
{ {
if (getStopAtShutdown()) { if (getStopAtShutdown())
ShutdownThread.register(this); {
ShutdownMonitor.getInstance().start(); // initialize ShutdownThread.register(this);
} }
ShutdownMonitor.getInstance().start(); // initialize
LOG.info("jetty-"+__version); LOG.info("jetty-"+__version);
HttpGenerator.setServerVersion(__version); HttpGenerator.setServerVersion(__version);

View File

@ -40,7 +40,7 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
* <p> * <p>
* Commands "stop" and "status" are currently supported. * Commands "stop" and "status" are currently supported.
*/ */
public class ShutdownMonitor extends Thread public class ShutdownMonitor
{ {
// Implementation of safe lazy init, using Initialization on Demand Holder technique. // Implementation of safe lazy init, using Initialization on Demand Holder technique.
static class Holder static class Holder
@ -53,11 +53,165 @@ public class ShutdownMonitor extends Thread
return Holder.instance; return Holder.instance;
} }
/**
* ShutdownMonitorThread
*
* Thread for listening to STOP.PORT for command to stop Jetty.
* If ShowndownMonitor.exitVm is true, then Sytem.exit will also be
* called after the stop.
*
*/
public class ShutdownMonitorThread extends Thread
{
public ShutdownMonitorThread ()
{
setDaemon(true);
setName("ShutdownMonitor");
}
@Override
public void run()
{
if (serverSocket == null)
{
return;
}
while (serverSocket != null)
{
Socket socket = null;
try
{
socket = serverSocket.accept();
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
String receivedKey = lin.readLine();
if (!key.equals(receivedKey))
{
System.err.println("Ignoring command with incorrect key");
continue;
}
OutputStream out = socket.getOutputStream();
String cmd = lin.readLine();
debug("command=%s",cmd);
if ("stop".equals(cmd))
{
// Graceful Shutdown
debug("Issuing graceful shutdown..");
ShutdownThread.getInstance().run();
// Reply to client
debug("Informing client that we are stopped.");
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
out.flush();
// Shutdown Monitor
debug("Shutting down monitor");
close(socket);
socket = null;
close(serverSocket);
serverSocket = null;
if (exitVm)
{
// Kill JVM
debug("Killing JVM");
System.exit(0);
}
}
else if ("status".equals(cmd))
{
// Reply to client
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
out.flush();
}
}
catch (Exception e)
{
debug(e);
System.err.println(e.toString());
}
finally
{
close(socket);
socket = null;
}
}
}
public void start()
{
if (isAlive())
{
System.err.printf("ShutdownMonitorThread already started");
return; // cannot start it again
}
startListenSocket();
if (serverSocket == null)
{
return;
}
if (DEBUG)
System.err.println("Starting ShutdownMonitorThread");
super.start();
}
private void startListenSocket()
{
if (port < 0)
{
if (DEBUG)
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
return;
}
try
{
serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
if (port == 0)
{
// server assigned port in use
port = serverSocket.getLocalPort();
System.out.printf("STOP.PORT=%d%n",port);
}
if (key == null)
{
// create random key
key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
System.out.printf("STOP.KEY=%s%n",key);
}
}
catch (Exception e)
{
debug(e);
System.err.println("Error binding monitor port " + port + ": " + e.toString());
serverSocket = null;
}
finally
{
// establish the port and key that are in use
debug("STOP.PORT=%d",port);
debug("STOP.KEY=%s",key);
debug("%s",serverSocket);
}
}
}
private boolean DEBUG; private boolean DEBUG;
private int port; private int port;
private String key; private String key;
private boolean exitVm; private boolean exitVm;
private ServerSocket serverSocket; private ServerSocket serverSocket;
private ShutdownMonitorThread thread;
/** /**
* Create a ShutdownMonitor using configuration from the System properties. * Create a ShutdownMonitor using configuration from the System properties.
@ -75,7 +229,7 @@ public class ShutdownMonitor extends Thread
// Use values passed thru via /jetty-start/ // Use values passed thru via /jetty-start/
this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1")); this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
this.key = props.getProperty("STOP.KEY","eclipse"); this.key = props.getProperty("STOP.KEY",null);
this.exitVm = true; this.exitVm = true;
} }
@ -149,77 +303,6 @@ public class ShutdownMonitor extends Thread
return exitVm; return exitVm;
} }
@Override
public void run()
{
if (serverSocket == null)
{
return;
}
while (serverSocket != null)
{
Socket socket = null;
try
{
socket = serverSocket.accept();
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
String key = lin.readLine();
if (!this.key.equals(key))
{
System.err.println("Ignoring command with incorrect key");
continue;
}
OutputStream out = socket.getOutputStream();
String cmd = lin.readLine();
debug("command=%s",cmd);
if ("stop".equals(cmd))
{
// Graceful Shutdown
debug("Issuing graceful shutdown..");
ShutdownThread.getInstance().run();
// Reply to client
debug("Informing client that we are stopped.");
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
out.flush();
// Shutdown Monitor
debug("Shutting down monitor");
close(socket);
socket = null;
close(serverSocket);
serverSocket = null;
if (exitVm)
{
// Kill JVM
debug("Killing JVM");
System.exit(0);
}
}
else if ("status".equals(cmd))
{
// Reply to client
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
out.flush();
}
}
catch (Exception e)
{
debug(e);
System.err.println(e.toString());
}
finally
{
close(socket);
socket = null;
}
}
}
public void setDebug(boolean flag) public void setDebug(boolean flag)
{ {
@ -228,90 +311,71 @@ public class ShutdownMonitor extends Thread
public void setExitVm(boolean exitVm) public void setExitVm(boolean exitVm)
{ {
if (isAlive()) synchronized (this)
{ {
throw new IllegalStateException("ShutdownMonitor already started"); if (thread != null && thread.isAlive())
{
throw new IllegalStateException("ShutdownMonitorThread already started");
}
this.exitVm = exitVm;
} }
this.exitVm = exitVm;
} }
public void setKey(String key) public void setKey(String key)
{ {
if (isAlive()) synchronized (this)
{ {
throw new IllegalStateException("ShutdownMonitor already started"); if (thread != null && thread.isAlive())
{
throw new IllegalStateException("ShutdownMonitorThread already started");
}
this.key = key;
} }
this.key = key;
} }
public void setPort(int port) public void setPort(int port)
{ {
if (isAlive()) synchronized (this)
{ {
throw new IllegalStateException("ShutdownMonitor already started"); if (thread != null && thread.isAlive())
}
this.port = port;
}
public void start()
{
if (isAlive())
{
System.err.printf("ShutdownMonitor already started");
return; // cannot start it again
}
startListenSocket();
if (serverSocket == null)
{
return;
}
super.start();
}
private void startListenSocket()
{
if (this.port < 0)
{
if (DEBUG)
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
return;
}
try
{
setDaemon(true);
setName("ShutdownMonitor");
this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
if (this.port == 0)
{ {
// server assigned port in use throw new IllegalStateException("ShutdownMonitorThread already started");
this.port = serverSocket.getLocalPort();
System.out.printf("STOP.PORT=%d%n",this.port);
} }
this.port = port;
if (this.key == null)
{
// create random key
this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
System.out.printf("STOP.KEY=%s%n",this.key);
}
}
catch (Exception e)
{
debug(e);
System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
}
finally
{
// establish the port and key that are in use
debug("STOP.PORT=%d",this.port);
debug("STOP.KEY=%s",this.key);
debug("%s",serverSocket);
} }
} }
protected void start() throws Exception
{
ShutdownMonitorThread t = null;
synchronized (this)
{
if (thread != null && thread.isAlive())
{
System.err.printf("ShutdownMonitorThread already started");
return; // cannot start it again
}
thread = new ShutdownMonitorThread();
t = thread;
}
if (t != null)
t.start();
}
protected boolean isAlive ()
{
boolean result = false;
synchronized (this)
{
result = (thread != null && thread.isAlive());
}
return result;
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -294,17 +294,20 @@ public class JDBCSessionManager extends AbstractSessionManager
super.complete(); super.complete();
try try
{ {
if (_dirty) if (isValid())
{ {
//The session attributes have changed, write to the db, ensuring if (_dirty)
//http passivation/activation listeners called {
willPassivate(); //The session attributes have changed, write to the db, ensuring
updateSession(this); //http passivation/activation listeners called
didActivate(); willPassivate();
} updateSession(this);
else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L)) didActivate();
{ }
updateSessionAccessTime(this); else if ((getAccessed() - _lastSaved) >= (getSaveInterval() * 1000L))
{
updateSessionAccessTime(this);
}
} }
} }
catch (Exception e) catch (Exception e)

View File

@ -18,7 +18,7 @@
package org.eclipse.jetty.server; package org.eclipse.jetty.server;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.*;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -36,7 +36,7 @@ import org.eclipse.jetty.continuation.Continuation;
import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationListener;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.toolchain.test.Stress; import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -90,7 +90,7 @@ public class AsyncStressTest
@Test @Test
public void testAsync() throws Throwable public void testAsync() throws Throwable
{ {
if (Stress.isEnabled()) if (PropertyFlag.isEnabled("test.stress"))
{ {
doConnections(1600,240); doConnections(1600,240);
} }

View File

@ -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;
}
}
}

View File

@ -36,7 +36,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.toolchain.test.Stress; import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.junit.AfterClass; import org.junit.AfterClass;
@ -44,7 +44,7 @@ import org.junit.AfterClass;
public class HttpServerTestFixture public class HttpServerTestFixture
{ // Useful constants { // Useful constants
protected static final long PAUSE=10L; protected static final long PAUSE=10L;
protected static final int LOOPS=Stress.isEnabled()?250:50; protected static final int LOOPS=PropertyFlag.isEnabled("test.stress")?250:50;
protected static final String HOST="localhost"; protected static final String HOST="localhost";
protected static Server _server; protected static Server _server;

View File

@ -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();
}
}
}

View File

@ -36,7 +36,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.toolchain.test.Stress; import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.eclipse.jetty.util.BlockingArrayQueue; import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -126,10 +126,10 @@ public class StressTest
public void testNonPersistent() throws Throwable public void testNonPersistent() throws Throwable
{ {
// TODO needs to be further investigated // TODO needs to be further investigated
assumeTrue(!OS.IS_OSX || Stress.isEnabled()); assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
doThreads(10,10,false); doThreads(10,10,false);
if (Stress.isEnabled()) if (PropertyFlag.isEnabled("test.stress"))
{ {
Thread.sleep(1000); Thread.sleep(1000);
doThreads(200,10,false); doThreads(200,10,false);
@ -142,10 +142,10 @@ public class StressTest
public void testPersistent() throws Throwable public void testPersistent() throws Throwable
{ {
// TODO needs to be further investigated // TODO needs to be further investigated
assumeTrue(!OS.IS_OSX || Stress.isEnabled()); assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
doThreads(20,10,true); doThreads(20,10,true);
if (Stress.isEnabled()) if (PropertyFlag.isEnabled("test.stress"))
{ {
Thread.sleep(1000); Thread.sleep(1000);
doThreads(200,10,true); doThreads(200,10,true);

View File

@ -454,7 +454,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory
if (resource!=null && resource.exists() && !resource.isDirectory()) if (resource!=null && resource.exists() && !resource.isDirectory())
{ {
// Tell caches that response may vary by accept-encoding // Tell caches that response may vary by accept-encoding
response.setHeader(HttpHeaders.VARY,HttpHeaders.ACCEPT_ENCODING); response.addHeader(HttpHeaders.VARY,HttpHeaders.ACCEPT_ENCODING);
// Does the client accept gzip? // Does the client accept gzip?
String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING); String accept=request.getHeader(HttpHeaders.ACCEPT_ENCODING);

View File

@ -24,6 +24,7 @@ import javax.servlet.GenericServlet;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Dispatcher; import org.eclipse.jetty.server.Dispatcher;
import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.AbstractHttpConnection;
@ -96,7 +97,11 @@ public class JspPropertyGroupServlet extends GenericServlet
@Override @Override
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException
{ {
Request request=(req instanceof Request)?(Request)req:AbstractHttpConnection.getCurrentConnection().getRequest(); HttpServletRequest request = null;
if (req instanceof HttpServletRequest)
request = (HttpServletRequest)req;
else
throw new ServletException("Request not HttpServletRequest");
String servletPath=null; String servletPath=null;
String pathInfo=null; String pathInfo=null;

View File

@ -340,8 +340,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
if (o==null) if (o==null)
return; return;
Servlet servlet = ((Servlet)o); Servlet servlet = ((Servlet)o);
servlet.destroy();
getServletHandler().destroyServlet(servlet); getServletHandler().destroyServlet(servlet);
servlet.destroy();
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */

View File

@ -48,11 +48,6 @@
</plugins> </plugins>
</build> </build>
<dependencies> <dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId> <artifactId>jetty-test-helper</artifactId>

View File

@ -125,8 +125,11 @@ public class DoSFilter implements Filter
{ {
private static final Logger LOG = Log.getLogger(DoSFilter.class); private static final Logger LOG = Log.getLogger(DoSFilter.class);
private static final Pattern IP_PATTERN = Pattern.compile("(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"); private static final String IPv4_GROUP = "(\\d{1,3})";
private static final Pattern CIDR_PATTERN = Pattern.compile(IP_PATTERN + "/(\\d{1,2})"); private static final Pattern IPv4_PATTERN = Pattern.compile(IPv4_GROUP+"\\."+IPv4_GROUP+"\\."+IPv4_GROUP+"\\."+IPv4_GROUP);
private static final String IPv6_GROUP = "(\\p{XDigit}{1,4})";
private static final Pattern IPv6_PATTERN = Pattern.compile(IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP+":"+IPv6_GROUP);
private static final Pattern CIDR_PATTERN = Pattern.compile("([^/]+)/(\\d+)");
private static final String __TRACKER = "DoSFilter.Tracker"; private static final String __TRACKER = "DoSFilter.Tracker";
private static final String __THROTTLED = "DoSFilter.Throttled"; private static final String __THROTTLED = "DoSFilter.Throttled";
@ -618,31 +621,94 @@ public class DoSFilter implements Filter
return false; return false;
} }
protected boolean subnetMatch(String subnetAddress, String candidate) protected boolean subnetMatch(String subnetAddress, String address)
{ {
Matcher matcher = CIDR_PATTERN.matcher(subnetAddress); Matcher cidrMatcher = CIDR_PATTERN.matcher(subnetAddress);
int subnet = intFromAddress(matcher); if (!cidrMatcher.matches())
int prefix = Integer.parseInt(matcher.group(5)); return false;
// Sets the most significant prefix bits to 1
// If prefix == 8 => 11111111_00000000_00000000_00000000 String subnet = cidrMatcher.group(1);
int mask = ~((1 << (32 - prefix)) - 1); int prefix;
int ip = intFromAddress(IP_PATTERN.matcher(candidate)); try
return (ip & mask) == (subnet & mask); {
prefix = Integer.parseInt(cidrMatcher.group(2));
}
catch (NumberFormatException x)
{
LOG.info("Ignoring malformed CIDR address {}", subnetAddress);
return false;
}
byte[] subnetBytes = addressToBytes(subnet);
if (subnetBytes == null)
{
LOG.info("Ignoring malformed CIDR address {}", subnetAddress);
return false;
}
byte[] addressBytes = addressToBytes(address);
if (addressBytes == null)
{
LOG.info("Ignoring malformed remote address {}", address);
return false;
}
// Comparing IPv4 with IPv6 ?
int length = subnetBytes.length;
if (length != addressBytes.length)
return false;
byte[] mask = prefixToBytes(prefix, length);
for (int i = 0; i < length; ++i)
{
if ((subnetBytes[i] & mask[i]) != (addressBytes[i] & mask[i]))
return false;
}
return true;
} }
private int intFromAddress(Matcher matcher) private byte[] addressToBytes(String address)
{ {
int result = 0; Matcher ipv4Matcher = IPv4_PATTERN.matcher(address);
if (matcher.matches()) if (ipv4Matcher.matches())
{ {
for (int i = 0; i < 4; ++i) byte[] result = new byte[4];
{ for (int i = 0; i < result.length; ++i)
int b = Integer.parseInt(matcher.group(i + 1)); result[i] = Integer.valueOf(ipv4Matcher.group(i + 1)).byteValue();
result |= b << 8 * (3 - i);
}
return result; return result;
} }
throw new IllegalStateException(); else
{
Matcher ipv6Matcher = IPv6_PATTERN.matcher(address);
if (ipv6Matcher.matches())
{
byte[] result = new byte[16];
for (int i = 0; i < result.length; i += 2)
{
int word = Integer.valueOf(ipv6Matcher.group(i / 2 + 1), 16);
result[i] = (byte)((word & 0xFF00) >>> 8);
result[i + 1] = (byte)(word & 0xFF);
}
return result;
}
}
return null;
}
private byte[] prefixToBytes(int prefix, int length)
{
byte[] result = new byte[length];
int index = 0;
while (prefix / 8 > 0)
{
result[index] = -1;
prefix -= 8;
++index;
}
// Sets the _prefix_ most significant bits to 1
result[index] = (byte)~((1 << (8 - prefix)) - 1);
return result;
} }
public void destroy() public void destroy()
@ -947,14 +1013,7 @@ public class DoSFilter implements Filter
private boolean addWhitelistAddress(List<String> list, String address) private boolean addWhitelistAddress(List<String> list, String address)
{ {
address = address.trim(); address = address.trim();
if (address.length() > 0) return address.length() > 0 && list.add(address);
{
if (CIDR_PATTERN.matcher(address).matches() || IP_PATTERN.matcher(address).matches())
return list.add(address);
else
LOG.warn("Ignoring malformed whitelist IP address {}", address);
}
return false;
} }
public boolean removeWhitelistAddress(String address) public boolean removeWhitelistAddress(String address)

View File

@ -84,15 +84,6 @@ public class IncludableGzipFilter extends GzipFilter
{ {
return null; return null;
} }
@Override
protected void setHeader(String name, String value)
{
super.setHeader(name, value);
HttpServletResponse response = (HttpServletResponse)getResponse();
if (!response.containsHeader(name))
response.setHeader("org.eclipse.jetty.server.include." + name, value);
}
}; };
} }
}; };
@ -111,15 +102,6 @@ public class IncludableGzipFilter extends GzipFilter
{ {
return new GZIPOutputStream(_response.getOutputStream(),_bufferSize); return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
} }
@Override
protected void setHeader(String name, String value)
{
super.setHeader(name, value);
HttpServletResponse response = (HttpServletResponse)getResponse();
if (!response.containsHeader(name))
response.setHeader("org.eclipse.jetty.server.include." + name, value);
}
}; };
} }
}; };
@ -138,15 +120,6 @@ public class IncludableGzipFilter extends GzipFilter
{ {
return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel, _deflateNoWrap)); return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel, _deflateNoWrap));
} }
@Override
protected void setHeader(String name, String value)
{
super.setHeader(name, value);
HttpServletResponse response = (HttpServletResponse)getResponse();
if (!response.containsHeader(name))
response.setHeader("org.eclipse.jetty.server.include." + name, value);
}
}; };
} }
}; };
@ -176,6 +149,16 @@ public class IncludableGzipFilter extends GzipFilter
if (!response.containsHeader(name)) if (!response.containsHeader(name))
response.setHeader("org.eclipse.jetty.server.include."+name,value); response.setHeader("org.eclipse.jetty.server.include."+name,value);
} }
@Override
public void addHeader(String name, String value)
{
super.addHeader(name, value);
HttpServletResponse response = (HttpServletResponse)getResponse();
if (!response.containsHeader(name))
setHeader(name,value);
}
@Override @Override
protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
{ {

View File

@ -79,12 +79,17 @@ public class DoSFilterTest extends AbstractDoSFilterTest
List<String> whitelist = new ArrayList<String>(); List<String> whitelist = new ArrayList<String>();
whitelist.add("192.168.0.1"); whitelist.add("192.168.0.1");
whitelist.add("10.0.0.0/8"); whitelist.add("10.0.0.0/8");
whitelist.add("4d8:0:a:1234:ABc:1F:b18:17");
whitelist.add("4d8:0:a:1234:ABc:1F:0:0/96");
Assert.assertTrue(filter.checkWhitelist(whitelist, "192.168.0.1")); Assert.assertTrue(filter.checkWhitelist(whitelist, "192.168.0.1"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "192.168.0.2")); Assert.assertFalse(filter.checkWhitelist(whitelist, "192.168.0.2"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "11.12.13.14")); Assert.assertFalse(filter.checkWhitelist(whitelist, "11.12.13.14"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.11.12.13")); Assert.assertTrue(filter.checkWhitelist(whitelist, "10.11.12.13"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "10.0.0.0")); Assert.assertTrue(filter.checkWhitelist(whitelist, "10.0.0.0"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "0.0.0.0")); Assert.assertFalse(filter.checkWhitelist(whitelist, "0.0.0.0"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1F:b18:17"));
Assert.assertTrue(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1F:b18:0"));
Assert.assertFalse(filter.checkWhitelist(whitelist, "4d8:0:a:1234:ABc:1D:0:0"));
} }
private boolean hitRateTracker(DoSFilter doSFilter, int sleep) throws InterruptedException private boolean hitRateTracker(DoSFilter doSFilter, int sleep) throws InterruptedException

View File

@ -13,7 +13,8 @@
<name>Jetty :: SPDY :: Parent</name> <name>Jetty :: SPDY :: Parent</name>
<properties> <properties>
<npn.version>1.1.0.v20120525</npn.version> <npn.version>1.1.5.v20130313</npn.version>
<npn.api.version>1.1.0.v20120525</npn.api.version>
</properties> </properties>
<modules> <modules>

View File

@ -57,7 +57,7 @@
<dependency> <dependency>
<groupId>org.eclipse.jetty.npn</groupId> <groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId> <artifactId>npn-api</artifactId>
<version>1.0.0.v20120402</version> <version>${npn.api.version}</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -58,7 +58,7 @@
<dependency> <dependency>
<groupId>org.eclipse.jetty.npn</groupId> <groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId> <artifactId>npn-api</artifactId>
<version>${npn.version}</version> <version>${npn.api.version}</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -578,8 +578,14 @@ public class Scanner extends AbstractLifeCycle
if (f.isDirectory() && (depth<_scanDepth || _scanDepth==-1 || _scanDirs.contains(f))) if (f.isDirectory() && (depth<_scanDepth || _scanDepth==-1 || _scanDirs.contains(f)))
{ {
File[] files = f.listFiles(); File[] files = f.listFiles();
for (int i=0;i<files.length;i++) if (files != null)
scanFile(files[i], scanInfoMap,depth+1); {
for (int i=0;i<files.length;i++)
scanFile(files[i], scanInfoMap,depth+1);
}
else
LOG.warn("Error listing files in directory {}", f);
} }
} }
catch (IOException e) catch (IOException e)

View File

@ -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);
}
}

View File

@ -217,8 +217,7 @@ public abstract class Resource implements ResourceFactory
{ {
URL url=null; URL url=null;
// Try to format as a URL? // Try to format as a URL?
ClassLoader ClassLoader loader=Thread.currentThread().getContextClassLoader();
loader=Thread.currentThread().getContextClassLoader();
if (loader!=null) if (loader!=null)
{ {
try try
@ -250,7 +249,7 @@ public abstract class Resource implements ResourceFactory
{ {
url=ClassLoader.getSystemResource(resource); url=ClassLoader.getSystemResource(resource);
if (url==null && resource.startsWith("/")) if (url==null && resource.startsWith("/"))
url=loader.getResource(resource.substring(1)); url=ClassLoader.getSystemResource(resource.substring(1));
} }
if (url==null) if (url==null)

View File

@ -237,7 +237,7 @@
<plugin> <plugin>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-version-maven-plugin</artifactId> <artifactId>jetty-version-maven-plugin</artifactId>
<version>1.0.9</version> <version>1.0.10</version>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@ -508,7 +508,7 @@
<dependency> <dependency>
<groupId>org.eclipse.jetty.toolchain</groupId> <groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId> <artifactId>jetty-test-helper</artifactId>
<version>1.6.1</version> <version>2.0</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.slf4j</groupId> <groupId>org.slf4j</groupId>