Merge remote-tracking branch 'origin/master' into servlet-3.1-api

This commit is contained in:
Jan Bartel 2013-05-03 16:59:39 +10:00
commit 0d181d9a75
37 changed files with 820 additions and 633 deletions

View File

@ -115,21 +115,12 @@ public class TestSecurityAnnotationConversions
introspector.registerHandler(annotationHandler);
//set up the expected outcomes:
//set up the expected outcomes - no constraints at all as per Servlet Spec 3.1 pg 129
//1 ConstraintMapping per ServletMapping pathSpec
Constraint expectedConstraint = new Constraint();
expectedConstraint.setAuthenticate(false);
expectedConstraint.setDataConstraint(Constraint.DC_NONE);
ConstraintMapping[] expectedMappings = new ConstraintMapping[2];
expectedMappings[0] = new ConstraintMapping();
expectedMappings[0].setConstraint(expectedConstraint);
expectedMappings[0].setPathSpec("/foo/*");
expectedMappings[1] = new ConstraintMapping();
expectedMappings[1].setConstraint(expectedConstraint);
expectedMappings[1].setPathSpec("*.foo");
ConstraintMapping[] expectedMappings = new ConstraintMapping[]{};
introspector.introspect(PermitServlet.class);
compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings());

View File

@ -374,10 +374,9 @@ public class HttpReceiver implements HttpParser.ResponseHandler<ByteBuffer>
}
@Override
public boolean earlyEOF()
public void earlyEOF()
{
failAndClose(new EOFException());
return false;
}
private void failAndClose(Throwable failure)

View File

@ -1,21 +0,0 @@
#===========================================================
# Configure JVM arguments.
#-----------------------------------------------------------
--exec
-Xmx2000m
-Xmn512m
-XX:+UseConcMarkSweepGC
-XX:ParallelCMSThreads=2
-XX:+CMSClassUnloadingEnabled
-XX:+UseCMSCompactAtFullCollection
-XX:CMSInitiatingOccupancyFraction=80
# -verbose:gc
# -XX:+PrintGCDateStamps
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails
# -XX:+PrintTenuringDistribution
# -XX:+PrintCommandLineFlags
# -XX:+DisableExplicitGC
# -Dorg.apache.jasper.compiler.disablejsr199=true

View File

@ -1,16 +0,0 @@
#===========================================================
# Default Server Options
# Use the core server jars with websocket on the classpath
# Add the contents of the resources directory to the classpath
# Add jars discovered in lib/ext to the classpath
# Include the core jetty configuration file
#-----------------------------------------------------------
OPTIONS=Server,websocket,resources,ext
threads.min=10
threads.max=200
threads.timeout=60000
#jetty.host=myhost.com
jetty.dump.start=false
jetty.dump.stop=false
etc/jetty.xml

View File

@ -1,10 +0,0 @@
#===========================================================
# JMX Management
# To enable remote JMX access uncomment jmxremote and
# enable --exec
#-----------------------------------------------------------
OPTIONS=jmx
# jetty.jmxrmihost=localhost
# jetty.jmxrmiport=1099
# -Dcom.sun.management.jmxremote
etc/jetty-jmx.xml

View File

@ -1,5 +0,0 @@
#===========================================================
# Java Server Pages
#-----------------------------------------------------------
OPTIONS=jsp

View File

@ -1,7 +0,0 @@
#===========================================================
# Server logging.
# The following configuration will redirect stderr and stdout
# to file which is rolled over daily.
#-----------------------------------------------------------
jetty.log.retain=90
etc/jetty-logging.xml

View File

@ -1,13 +0,0 @@
#===========================================================
# Enable SetUID
# The default user and group is 'jetty' and if you are
# starting as root you must change the run privledged to true
#-----------------------------------------------------------
OPTIONS=setuid
jetty.startServerAsPrivileged=false
jetty.username=jetty
jetty.groupname=jetty
jetty.umask=002
etc/jetty-setuid.xml

View File

@ -1,12 +0,0 @@
#===========================================================
# NPN Next Protocol Negotiation
#
# The SPDY and HTTP/2.0 connectors require NPN. The jar for
# NPN cannot be downloaded from eclipse. So the --download
# option is used to install the NPN jar if it does not already
# exist
#
#-----------------------------------------------------------
--exec
--download=http://repo1.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar:lib/npn/npn-boot-1.1.5.v20130313.jar
-Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar

View File

@ -1,12 +0,0 @@
#===========================================================
# SSL Context
# For use by HTTPS and SPDY
#-----------------------------------------------------------
jetty.keystore=etc/keystore
jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
jetty.truststore=etc/keystore
jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
jetty.secure.port=8443
etc/jetty-ssl.xml

View File

@ -1,6 +0,0 @@
#===========================================================
# HTTP Connector
#-----------------------------------------------------------
jetty.port=8080
http.timeout=30000
etc/jetty-http.xml

View File

@ -1,6 +0,0 @@
#===========================================================
# HTTPS Connector
# Must be used with 200-ssl.ini
#-----------------------------------------------------------
jetty.https.port=8443
etc/jetty-https.xml

View File

@ -1,9 +0,0 @@
#===========================================================
# SPDY Connector
# Must be used with 200-ssl.ini and 200-npn.ini
#-----------------------------------------------------------
OPTIONS=spdy
jetty.spdy.port=8443
etc/jetty-spdy.xml

View File

@ -1,8 +0,0 @@
#===========================================================
# Annotations JNDI JAAS processing
#-----------------------------------------------------------
OPTIONS=plus
etc/jetty-plus.xml
OPTIONS=annotations
etc/jetty-annotations.xml

View File

@ -1,9 +0,0 @@
#===========================================================
# Request logger
# Will add a handler to log all HTTP requests to a standard
# request log format file.
#-----------------------------------------------------------
requestlog.retain=90
requestlog.append=true
requestlog.extended=true
etc/jetty-requestlog.xml

View File

@ -1 +0,0 @@
etc/jetty-debug.xml

View File

@ -1 +0,0 @@
etc/jetty-ipaccess.xml

View File

@ -1,11 +0,0 @@
#===========================================================
#-----------------------------------------------------------
lowresources.period=1050
lowresources.lowResourcesIdleTimeout=200
lowresources.monitorThreads=true
lowresources.maxConnections=0
lowresources.maxMemory=0
lowresources.maxLowResourcesTime=5000
etc/jetty-lowresources.xml

View File

@ -1,4 +0,0 @@
#===========================================================
#-----------------------------------------------------------
etc/jetty-stats.xml

View File

@ -1,4 +0,0 @@
#===========================================================
# Webapplication Deployer
#-----------------------------------------------------------
etc/jetty-deploy.xml

View File

@ -24,8 +24,187 @@
#
#===========================================================
#===========================================================
# Configure JVM arguments.
# If JVM args are uncommented here then --exec is needed
# to start a new JVM from start.jar with the extra args
#-----------------------------------------------------------
# --exec
# -Xmx2000m
# -Xmn512m
# -XX:+UseConcMarkSweepGC
# -XX:ParallelCMSThreads=2
# -XX:+CMSClassUnloadingEnabled
# -XX:+UseCMSCompactAtFullCollection
# -XX:CMSInitiatingOccupancyFraction=80
# -verbose:gc
# -XX:+PrintGCDateStamps
# -XX:+PrintGCTimeStamps
# -XX:+PrintGCDetails
# -XX:+PrintTenuringDistribution
# -XX:+PrintCommandLineFlags
# -XX:+DisableExplicitGC
# -Dorg.apache.jasper.compiler.disablejsr199=true
#===========================================================
# Default Server Options
# Use the core server jars with websocket on the classpath
# Add the contents of the resources directory to the classpath
# Add jars discovered in lib/ext to the classpath
# Include the core jetty configuration file
#-----------------------------------------------------------
OPTIONS=Server,websocket,resources,ext
threads.min=10
threads.max=200
threads.timeout=60000
#jetty.host=myhost.com
jetty.dump.start=false
jetty.dump.stop=false
etc/jetty.xml
#===========================================================
# JMX Management
# To enable remote JMX access uncomment jmxremote and
# enable --exec
#-----------------------------------------------------------
OPTIONS=jmx
# jetty.jmxrmihost=localhost
# jetty.jmxrmiport=1099
# -Dcom.sun.management.jmxremote
etc/jetty-jmx.xml
#===========================================================
# Java Server Pages
#-----------------------------------------------------------
OPTIONS=jsp
#===========================================================
# Server logging.
# The following configuration will redirect stderr and stdout
# to file which is rolled over daily.
#-----------------------------------------------------------
# jetty.log.retain=90
# etc/jetty-logging.xml
#===========================================================
# Enable SetUID
# The default user and group is 'jetty' and if you are
# starting as root you must change the run privledged to true
#-----------------------------------------------------------
# OPTIONS=setuid
# jetty.startServerAsPrivileged=false
# jetty.username=jetty
# jetty.groupname=jetty
# jetty.umask=002
# etc/jetty-setuid.xml
#===========================================================
# HTTP Connector
#-----------------------------------------------------------
jetty.port=8080
http.timeout=30000
etc/jetty-http.xml
#===========================================================
# SSL Context
# Create the keystore and trust store for use by
# HTTPS and SPDY
#-----------------------------------------------------------
# jetty.keystore=etc/keystore
# jetty.keystore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
# jetty.keymanager.password=OBF:1u2u1wml1z7s1z7a1wnl1u2g
# jetty.truststore=etc/keystore
# jetty.truststore.password=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
# jetty.secure.port=8443
# etc/jetty-ssl.xml
#===========================================================
# HTTPS Connector
# Must be used with 200-ssl.ini
#-----------------------------------------------------------
# jetty.https.port=8443
# etc/jetty-https.xml
#===========================================================
# NPN Next Protocol Negotiation
#
# The SPDY and HTTP/2.0 connectors require NPN. The jar for
# NPN cannot be downloaded from eclipse. So the --download
# option is used to install the NPN jar if it does not already
# exist
#
#-----------------------------------------------------------
# --exec
# --download=http://repo1.maven.org/maven2/org/mortbay/jetty/npn/npn-boot/1.1.5.v20130313/npn-boot-1.1.5.v20130313.jar:lib/npn/npn-boot-1.1.5.v20130313.jar
# -Xbootclasspath/p:lib/npn/npn-boot-1.1.5.v20130313.jar
#===========================================================
# SPDY Connector
# Requires SSL Context and NPN from above
#-----------------------------------------------------------
# OPTIONS=spdy
# jetty.spdy.port=8443
# etc/jetty-spdy.xml
#===========================================================
# Webapplication Deployer
#-----------------------------------------------------------
etc/jetty-deploy.xml
#===========================================================
# Annotations JNDI JAAS processing
#-----------------------------------------------------------
# OPTIONS=plus
# etc/jetty-plus.xml
# OPTIONS=annotations
# etc/jetty-annotations.xml
#===========================================================
# Request logger
# Will add a handler to log all HTTP requests to a standard
# request log format file.
#-----------------------------------------------------------
# requestlog.retain=90
# requestlog.append=true
# requestlog.extended=true
# etc/jetty-requestlog.xml
#===========================================================
# Other server features
#-----------------------------------------------------------
# etc/jetty-debug.xml
# etc/jetty-ipaccess.xml
# etc/jetty-stats.xml
#===========================================================
# Low resource managment
#-----------------------------------------------------------
# lowresources.period=1050
# lowresources.lowResourcesIdleTimeout=200
# lowresources.monitorThreads=true
# lowresources.maxConnections=0
# lowresources.maxMemory=0
# lowresources.maxLowResourcesTime=5000
# etc/jetty-lowresources.xml
#===========================================================
# The start.d directory contains the active start.ini fragments
start.d/
# More start.ini fragments are in files named start.d/*.ini.disabled
# They may be enabled by moving, linking or copying to *.ini files.

View File

@ -217,6 +217,11 @@ public class HttpParser
badMessage(buffer,400,"Bad EOL");
return -1;
}
/*
if (ch>HttpTokens.SPACE)
System.err.println("Next "+(char)ch);
else
System.err.println("Next ["+ch+"]");*/
return ch;
}
@ -260,6 +265,12 @@ public class HttpParser
return -1;
}
/*
if (ch>HttpTokens.SPACE)
System.err.println("Next "+(char)ch);
else
System.err.println("Next ["+ch+"]");
*/
return ch;
}
@ -575,7 +586,7 @@ public class HttpParser
}
// Should we try to cache header fields?
if (_version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
if (_connectionFields==null && _version.getVersion()>=HttpVersion.HTTP_1_1.getVersion())
{
int header_cache = _handler.getHeaderCacheSize();
if (header_cache>0)
@ -868,7 +879,7 @@ public class HttpParser
}
else
{
if (buffer.remaining()>6)
if (buffer.hasRemaining())
{
// Try a look ahead for the known header name and value.
HttpField field=_connectionFields==null?null:_connectionFields.getBest(buffer,-1,buffer.remaining());
@ -883,14 +894,12 @@ public class HttpParser
if (v==null)
{
// Header only
int pos=buffer.position()+n.length()+1;
byte b=buffer.get(pos);
_header=field.getHeader();
_headerString=n;
setState(State.HEADER_VALUE);
_string.setLength(0);
_length=0;
buffer.position(pos);
buffer.position(buffer.position()+n.length()+1);
break;
}
else
@ -949,8 +958,6 @@ public class HttpParser
{
_headerString=takeLengthString();
_header=HttpHeader.CACHE.get(_headerString);
if (_header!=null)
System.err.println(_header);
}
setState(State.HEADER_VALUE);
break;
@ -1144,16 +1151,14 @@ public class HttpParser
case CLOSED:
if (BufferUtil.hasContent(buffer))
{
int len=buffer.remaining();
_headerBytes+=len;
// Just ignore data when closed
_headerBytes+=buffer.remaining();
BufferUtil.clear(buffer);
if (_headerBytes>_maxHeaderBytes)
{
Thread.sleep(100);
String chars = BufferUtil.toDetailString(buffer);
BufferUtil.clear(buffer);
throw new IllegalStateException(String.format("%s %d/%d>%d data when CLOSED:%s",this,len,_headerBytes,_maxHeaderBytes,chars));
// Don't want to waste time reading data of a closed request
throw new IllegalStateException("too much data after closed");
}
BufferUtil.clear(buffer);
}
return false;
default: break;
@ -1318,7 +1323,6 @@ public class HttpParser
}
catch(Exception e)
{
e.printStackTrace();
BufferUtil.clear(buffer);
if (isClosed())
{
@ -1467,8 +1471,18 @@ public class HttpParser
*/
public boolean parsedHeader(HttpField field);
public boolean earlyEOF();
/* ------------------------------------------------------------ */
/** Called to signal that an EOF was received unexpectedly
* during the parsing of a HTTP message
* @return True if the parser should return to its caller
*/
public void earlyEOF();
/* ------------------------------------------------------------ */
/** Called to signal that a bad HTTP message has been received.
* @param status The bad status to send
* @param reason The textual reason for badness
*/
public void badMessage(int status, String reason);
/* ------------------------------------------------------------ */
@ -1505,5 +1519,9 @@ public class HttpParser
public abstract boolean startResponse(HttpVersion version, int status, String reason);
}
public Trie<HttpField> getFieldCache()
{
return _connectionFields;
}
}

View File

@ -138,9 +138,8 @@ public class HttpTester
}
@Override
public boolean earlyEOF()
public void earlyEOF()
{
return true;
}
@Override

View File

@ -51,9 +51,8 @@ public class HttpGeneratorServerTest
}
@Override
public boolean earlyEOF()
public void earlyEOF()
{
return true;
}
@Override

View File

@ -23,6 +23,8 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.jetty.http.HttpParser.State;
import org.eclipse.jetty.util.BufferUtil;
@ -261,6 +263,8 @@ public class HttpParserTest
assertEquals(9, _h);
}
@Test
public void testHeaderParseLF() throws Exception
{
@ -332,7 +336,7 @@ public class HttpParserTest
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
HttpParser parser= new HttpParser(handler);
System.err.println(BufferUtil.toDetailString(buffer));
// System.err.println(BufferUtil.toDetailString(buffer));
buffer.position(2);
buffer.limit(2+i);
@ -989,6 +993,28 @@ public class HttpParserTest
assertEquals(8888,_port);
}
@Test
public void testCachedField() throws Exception
{
ByteBuffer buffer= BufferUtil.toBuffer(
"GET / HTTP/1.1\r\n"+
"Host: www.smh.com.au\r\n"+
"\r\n");
HttpParser.RequestHandler<ByteBuffer> handler = new Handler();
HttpParser parser= new HttpParser(handler);
parseAll(parser,buffer);
assertEquals("www.smh.com.au",parser.getFieldCache().get("Host: www.smh.com.au").getValue());
HttpField field=_fields.get(0);
//System.err.println(parser.getFieldCache());
buffer.position(0);
parseAll(parser,buffer);
assertTrue(field==_fields.get(0));
}
@Before
public void init()
{
@ -1011,6 +1037,7 @@ public class HttpParserTest
private String _methodOrVersion;
private String _uriOrStatus;
private String _versionOrReason;
private List<HttpField> _fields=new ArrayList<>();
private String[] _hdr;
private String[] _val;
private int _h;
@ -1038,6 +1065,7 @@ public class HttpParserTest
@Override
public boolean startRequest(HttpMethod httpMethod, String method, ByteBuffer uri, HttpVersion version)
{
_fields.clear();
request=true;
_h= -1;
_hdr= new String[10];
@ -1055,6 +1083,7 @@ public class HttpParserTest
@Override
public boolean parsedHeader(HttpField field)
{
_fields.add(field);
//System.err.println("header "+name+": "+value);
_hdr[++_h]= field.getName();
_val[_h]= field.getValue();
@ -1102,6 +1131,7 @@ public class HttpParserTest
@Override
public boolean startResponse(HttpVersion version, int status, String reason)
{
_fields.clear();
request=false;
_methodOrVersion = version.asString();
_uriOrStatus = Integer.toString(status);
@ -1117,9 +1147,8 @@ public class HttpParserTest
}
@Override
public boolean earlyEOF()
public void earlyEOF()
{
return true;
}
@Override

View File

@ -238,115 +238,104 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
Thread.currentThread().setName(threadName + " - " + _uri);
}
// Loop here to handle async request redispatches.
// The loop is controlled by the call to async.unhandle in the
// finally block below. Unhandle will return false only if an async dispatch has
// already happened when unhandle is called.
HttpChannelState.Next next = _state.handling();
try
while (next==Next.CONTINUE && getServer().isRunning())
{
while (next==Next.CONTINUE && getServer().isRunning())
try
{
try
{
_request.setHandled(false);
_response.getHttpOutput().reopen();
_request.setHandled(false);
_response.getHttpOutput().reopen();
if (_state.isInitial())
if (_state.isInitial())
{
_request.setTimeStamp(System.currentTimeMillis());
_request.setDispatcherType(DispatcherType.REQUEST);
for (HttpConfiguration.Customizer customizer : _configuration.getCustomizers())
customizer.customize(getConnector(),_configuration,_request);
getServer().handle(this);
}
else
{
if (_request.getHttpChannelState().isExpired())
{
_request.setTimeStamp(System.currentTimeMillis());
_request.setDispatcherType(DispatcherType.REQUEST);
for (HttpConfiguration.Customizer customizer : _configuration.getCustomizers())
customizer.customize(getConnector(),_configuration,_request);
getServer().handle(this);
_request.setDispatcherType(DispatcherType.ERROR);
_request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
_request.setAttribute(RequestDispatcher.ERROR_MESSAGE,"Async Timeout");
_request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,_request.getRequestURI());
_response.setStatusWithReason(500,"Async Timeout");
}
else
{
if (_request.getHttpChannelState().isExpired())
{
_request.setDispatcherType(DispatcherType.ERROR);
_request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE,new Integer(500));
_request.setAttribute(RequestDispatcher.ERROR_MESSAGE,"Async Timeout");
_request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI,_request.getRequestURI());
_response.setStatusWithReason(500,"Async Timeout");
}
else
_request.setDispatcherType(DispatcherType.ASYNC);
getServer().handleAsync(this);
}
}
catch (Error e)
{
if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
LOG.ignore(e);
else
throw e;
}
catch (Exception e)
{
if (e instanceof EofException)
LOG.debug(e);
else
LOG.warn(String.valueOf(_uri), e);
_state.error(e);
_request.setHandled(true);
handleException(e);
}
finally
{
next = _state.unhandle();
_request.setDispatcherType(DispatcherType.ASYNC);
getServer().handleAsync(this);
}
}
if (next==Next.WAIT)
return false;
}
finally
{
if (threadName != null && LOG.isDebugEnabled())
Thread.currentThread().setName(threadName);
setCurrentHttpChannel(null);
if (next==Next.COMPLETE)
catch (Error e)
{
try
{
_state.completed();
if (!_response.isCommitted() && !_request.isHandled())
_response.sendError(404);
// Complete generating the response
_response.complete();
}
catch(EofException e)
{
if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
LOG.ignore(e);
else
throw e;
}
catch (Exception e)
{
if (e instanceof EofException)
LOG.debug(e);
}
catch(Exception e)
{
LOG.warn(e);
}
finally
{
next=Next.RECYCLE;
}
}
if (next==Next.RECYCLE)
{
else
LOG.warn(String.valueOf(_uri), e);
_state.error(e);
_request.setHandled(true);
_transport.completed();
handleException(e);
}
finally
{
next = _state.unhandle();
}
LOG.debug("{} handle exit", this);
}
return true;
if (threadName != null && LOG.isDebugEnabled())
Thread.currentThread().setName(threadName);
setCurrentHttpChannel(null);
if (next==Next.COMPLETE)
{
try
{
_state.completed();
if (!_response.isCommitted() && !_request.isHandled())
_response.sendError(404);
// Complete generating the response
_response.complete();
}
catch(EofException e)
{
LOG.debug(e);
}
catch(Exception e)
{
LOG.warn(e);
}
finally
{
next=Next.RECYCLE;
}
}
if (next==Next.RECYCLE)
{
_request.setHandled(true);
_transport.completed();
}
LOG.debug("{} handle exit", this);
return next!=Next.WAIT;
}
/**
@ -577,10 +566,9 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
}
@Override
public boolean earlyEOF()
public void earlyEOF()
{
_request.getHttpInput().earlyEOF();
return false;
}
@Override

View File

@ -288,16 +288,7 @@ public class HttpChannelState
_initial=false;
_state=State.ASYNCWAIT;
scheduleTimeout();
if (_state==State.ASYNCWAIT)
return Next.WAIT;
else if (_state==State.COMPLETECALLED)
{
_state=State.COMPLETING;
return Next.COMPLETE;
}
_initial=false;
_state=State.REDISPATCHED;
return Next.CONTINUE;
return Next.WAIT;
case REDISPATCHING:
_initial=false;

View File

@ -277,7 +277,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
{
LOG.debug(e);
}
catch (IOException e)
catch (Exception e)
{
if (_parser.isIdle())
LOG.debug(e);
@ -285,11 +285,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
LOG.warn(this.toString(), e);
close();
}
catch (Exception e)
{
LOG.warn(this.toString(), e);
close();
}
finally
{
setCurrentConnection(null);
@ -561,6 +556,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
if (getEndPoint().isInputShutdown())
{
_parser.shutdownInput();
shutdown();
return;
}
@ -620,7 +616,6 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
*/
}
@Override
protected void onAllContentConsumed()
{
@ -630,6 +625,12 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http
*/
releaseRequestBuffer();
}
@Override
public String toString()
{
return super.toString()+"{"+HttpConnection.this+","+getEndPoint()+","+_parser+"}";
}
}
private class HttpChannelOverHttp extends HttpChannel<ByteBuffer>

View File

@ -97,32 +97,53 @@ public abstract class HttpInput<T> extends ServletInputStream
T item = null;
synchronized (lock())
{
while (item == null)
// Get the current head of the input Q
item = _inputQ.peekUnsafe();
// Skip empty items at the head of the queue
while (item != null && remaining(item) == 0)
{
_inputQ.pollUnsafe();
onContentConsumed(item);
LOG.debug("{} consumed {}", this, item);
item = _inputQ.peekUnsafe();
while (item != null && remaining(item) == 0)
// If that was the last item then notify
if (item==null)
onAllContentConsumed();
}
// If we have no item
if (item == null)
{
// Was it unexpectedly EOF'd?
if (isEarlyEOF())
throw new EofException();
// check for EOF
if (isShutdown())
{
_inputQ.pollUnsafe();
onContentConsumed(item);
LOG.debug("{} consumed {}", this, item);
item = _inputQ.peekUnsafe();
onEOF();
return -1;
}
if (item == null)
// OK then block for some more content
blockForContent();
// If still not content, we must be closed
item = _inputQ.peekUnsafe();
if (item==null)
{
onAllContentConsumed();
if (isEarlyEOF())
throw new EofException();
// blockForContent will only return with no
// content if it is closed.
if (!isShutdown())
LOG.warn("Unexpected !EOF ");
// check for EOF
if (isShutdown())
{
onEOF();
return -1;
}
blockForContent();
onEOF();
return -1;
}
}
}
@ -153,20 +174,34 @@ public abstract class HttpInput<T> extends ServletInputStream
}
}
/* ------------------------------------------------------------ */
/** Called by this HttpInput to signal new content has been queued
* @param item
*/
protected void onContentQueued(T item)
{
lock().notify();
}
/* ------------------------------------------------------------ */
/** Called by this HttpInput to signal all available content has been consumed
*/
protected void onAllContentConsumed()
{
}
/* ------------------------------------------------------------ */
/** Called by this HttpInput to signal it has reached EOF
*/
protected void onEOF()
{
}
public boolean content(T item)
/* ------------------------------------------------------------ */
/** Add some content to the input stream
* @param item
*/
public void content(T item)
{
synchronized (lock())
{
@ -177,19 +212,26 @@ public abstract class HttpInput<T> extends ServletInputStream
onContentQueued(item);
LOG.debug("{} queued {}", this, item);
}
return true;
}
/* ------------------------------------------------------------ */
/** This method should be called to signal to the HttpInput
* that an EOF has arrived before all the expected content.
* Typically this will result in an EOFException being thrown
* from a subsequent read rather than a -1 return.
*/
public void earlyEOF()
{
synchronized (lock())
{
_earlyEOF = true;
_inputEOF = true;
lock().notify();
LOG.debug("{} early EOF", this);
}
}
/* ------------------------------------------------------------ */
public boolean isEarlyEOF()
{
synchronized (lock())
@ -198,6 +240,7 @@ public abstract class HttpInput<T> extends ServletInputStream
}
}
/* ------------------------------------------------------------ */
public void shutdown()
{
synchronized (lock())
@ -208,6 +251,7 @@ public abstract class HttpInput<T> extends ServletInputStream
}
}
/* ------------------------------------------------------------ */
public boolean isShutdown()
{
synchronized (lock())
@ -216,13 +260,14 @@ public abstract class HttpInput<T> extends ServletInputStream
}
}
/* ------------------------------------------------------------ */
public void consumeAll()
{
synchronized (lock())
{
T item = _inputQ.peekUnsafe();
while (!isShutdown() && !isEarlyEOF())
{
T item = _inputQ.peekUnsafe();
while (item != null)
{
_inputQ.pollUnsafe();
@ -236,6 +281,9 @@ public abstract class HttpInput<T> extends ServletInputStream
try
{
blockForContent();
item = _inputQ.peekUnsafe();
if (item==null)
break;
}
catch (IOException e)
{

View File

@ -775,6 +775,8 @@ public class Response implements HttpServletResponse
break;
case STREAM:
getOutputStream().close();
break;
default:
}
return true;
}
@ -954,6 +956,7 @@ public class Response implements HttpServletResponse
case TE:
_fields.put(HttpHeader.CONNECTION, HttpHeaderValue.TE.toString());
break;
default:
}
}
}
@ -993,6 +996,8 @@ public class Response implements HttpServletResponse
case STREAM:
case WRITER:
_out.reset();
break;
default:
}
_out.resetBuffer();
@ -1051,7 +1056,7 @@ public class Response implements HttpServletResponse
return _reason;
}
public void complete() throws IOException
public void complete()
{
_out.close();
}

View File

@ -18,26 +18,38 @@
package org.eclipse.jetty.server;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Arrays;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Exchanger;
import java.util.concurrent.TimeUnit;
import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.StringUtil;
import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
@ -46,116 +58,129 @@ public class AsyncRequestReadTest
{
private static Server server;
private static ServerConnector connector;
private final static Exchanger<Long> __total=new Exchanger<Long>();
private final static BlockingQueue<Long> __total=new BlockingArrayQueue<>();
@BeforeClass
public static void startServer() throws Exception
@Before
public void startServer() throws Exception
{
server = new Server();
connector = new ServerConnector(server);
connector.setIdleTimeout(10000);
server.addConnector(connector);
server.setHandler(new EmptyHandler());
server.start();
}
@AfterClass
public static void stopServer() throws Exception
@After
public void stopServer() throws Exception
{
server.stop();
server.join();
}
@Test
public void test() throws Exception
public void testPipelined() throws Exception
{
final Socket socket = new Socket("localhost",connector.getLocalPort());
server.setHandler(new AsyncStreamHandler());
server.start();
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
{
socket.setSoTimeout(1000);
byte[] content = new byte[32*4096];
Arrays.fill(content, (byte)120);
byte[] content = new byte[16*4096];
Arrays.fill(content, (byte)120);
OutputStream out = socket.getOutputStream();
String header=
"POST / HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"\r\n";
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
out.write(h);
out.write(content);
header=
"POST / HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"Connection: close\r\n"+
"\r\n";
h=header.getBytes(StringUtil.__ISO_8859_1);
out.write(h);
out.write(content);
out.flush();
OutputStream out = socket.getOutputStream();
String header=
"POST / HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"Connection: close\r\n"+
"\r\n";
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
InputStream in = socket.getInputStream();
String response = IO.toString(in);
assertTrue(response.indexOf("200 OK")>0);
out.write(h);
out.flush();
out.write(content,0,4*4096);
Thread.sleep(100);
out.write(content,8192,4*4096);
Thread.sleep(100);
out.write(content,8*4096,content.length-8*4096);
out.flush();
InputStream in = socket.getInputStream();
String response = IO.toString(in);
assertTrue(response.indexOf("200 OK")>0);
long total=__total.exchange(0L,30,TimeUnit.SECONDS);
assertEquals(content.length, total);
long total=__total.poll(5,TimeUnit.SECONDS);
assertEquals(content.length, total);
total=__total.poll(5,TimeUnit.SECONDS);
assertEquals(content.length, total);
}
}
@Test
@Ignore
public void tests() throws Exception
public void testAsyncReadsWithDelays() throws Exception
{
runTest(64,4,4,20);
runTest(256,16,16,50);
runTest(256,1,128,10);
runTest(128*1024,1,64,10);
runTest(256*1024,5321,10,100);
runTest(512*1024,32*1024,10,10);
server.setHandler(new AsyncStreamHandler());
server.start();
asyncReadTest(64,4,4,20);
asyncReadTest(256,16,16,50);
asyncReadTest(256,1,128,10);
asyncReadTest(128*1024,1,64,10);
asyncReadTest(256*1024,5321,10,100);
asyncReadTest(512*1024,32*1024,10,10);
}
public void runTest(int contentSize, int chunkSize, int chunks, int delayMS) throws Exception
public void asyncReadTest(int contentSize, int chunkSize, int chunks, int delayMS) throws Exception
{
String tst=contentSize+","+chunkSize+","+chunks+","+delayMS;
//System.err.println(tst);
final Socket socket = new Socket("localhost",connector.getLocalPort());
byte[] content = new byte[contentSize];
Arrays.fill(content, (byte)120);
OutputStream out = socket.getOutputStream();
out.write("POST / HTTP/1.1\r\n".getBytes());
out.write("Host: localhost\r\n".getBytes());
out.write(("Content-Length: "+content.length+"\r\n").getBytes());
out.write("Content-Type: bytes\r\n".getBytes());
out.write("Connection: close\r\n".getBytes());
out.write("\r\n".getBytes());
out.flush();
int offset=0;
for (int i=0;i<chunks;i++)
try(final Socket socket = new Socket("localhost",connector.getLocalPort()))
{
out.write(content,offset,chunkSize);
offset+=chunkSize;
Thread.sleep(delayMS);
byte[] content = new byte[contentSize];
Arrays.fill(content, (byte)120);
OutputStream out = socket.getOutputStream();
out.write("POST / HTTP/1.1\r\n".getBytes());
out.write("Host: localhost\r\n".getBytes());
out.write(("Content-Length: "+content.length+"\r\n").getBytes());
out.write("Content-Type: bytes\r\n".getBytes());
out.write("Connection: close\r\n".getBytes());
out.write("\r\n".getBytes());
out.flush();
int offset=0;
for (int i=0;i<chunks;i++)
{
out.write(content,offset,chunkSize);
offset+=chunkSize;
Thread.sleep(delayMS);
}
out.write(content,offset,content.length-offset);
out.flush();
InputStream in = socket.getInputStream();
String response = IO.toString(in);
assertTrue(tst,response.indexOf("200 OK")>0);
long total=__total.poll(30,TimeUnit.SECONDS);
assertEquals(tst,content.length, total);
}
out.write(content,offset,content.length-offset);
out.flush();
InputStream in = socket.getInputStream();
String response = IO.toString(in);
assertTrue(tst,response.indexOf("200 OK")>0);
long total=__total.exchange(0L,30,TimeUnit.SECONDS);
assertEquals(tst,content.length, total);
}
private static class EmptyHandler extends AbstractHandler
private static class AsyncStreamHandler extends AbstractHandler
{
@Override
public void handle(String path, final Request request, HttpServletRequest httpRequest, final HttpServletResponse httpResponse) throws IOException, ServletException
@ -164,6 +189,7 @@ public class AsyncRequestReadTest
request.setHandled(true);
final AsyncContext async = request.startAsync();
// System.err.println("handle "+request.getContentLength());
new Thread()
{
@ -171,9 +197,10 @@ public class AsyncRequestReadTest
public void run()
{
long total=0;
try
try(InputStream in = request.getInputStream();)
{
InputStream in = request.getInputStream();
// System.err.println("reading...");
byte[] b = new byte[4*4096];
int read;
while((read =in.read(b))>=0)
@ -188,17 +215,156 @@ public class AsyncRequestReadTest
{
httpResponse.setStatus(200);
async.complete();
try
{
__total.exchange(total);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
// System.err.println("read "+total);
__total.offer(total);
}
}
}.start();
}
}
@Test
public void testPartialRead() throws Exception
{
server.setHandler(new PartialReaderHandler());
server.start();
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
{
socket.setSoTimeout(1000);
byte[] content = new byte[32*4096];
Arrays.fill(content, (byte)88);
OutputStream out = socket.getOutputStream();
String header=
"POST /?read=10 HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"\r\n";
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
out.write(h);
out.write(content);
header= "POST /?read=10 HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"Connection: close\r\n"+
"\r\n";
h=header.getBytes(StringUtil.__ISO_8859_1);
out.write(h);
out.write(content);
out.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
assertThat(in.readLine(),containsString("Content-Length:"));
assertThat(in.readLine(),containsString("Server:"));
in.readLine();
assertThat(in.readLine(),containsString("XXXXXXX"));
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
assertThat(in.readLine(),containsString("Connection: close"));
assertThat(in.readLine(),containsString("Server:"));
in.readLine();
assertThat(in.readLine(),containsString("XXXXXXX"));
}
}
@Test
public void testPartialReadThenShutdown() throws Exception
{
server.setHandler(new PartialReaderHandler());
server.start();
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
{
socket.setSoTimeout(10000);
byte[] content = new byte[32*4096];
Arrays.fill(content, (byte)88);
OutputStream out = socket.getOutputStream();
String header=
"POST /?read=10 HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"\r\n";
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
out.write(h);
out.write(content,0,4096);
out.flush();
socket.shutdownOutput();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
assertThat(in.readLine(),containsString("Content-Length:"));
assertThat(in.readLine(),containsString("Server:"));
in.readLine();
assertThat(in.readLine(),containsString("XXXXXXX"));
}
}
@Test
public void testPartialReadThenClose() throws Exception
{
server.setHandler(new PartialReaderHandler());
server.start();
try (final Socket socket = new Socket("localhost",connector.getLocalPort()))
{
socket.setSoTimeout(1000);
byte[] content = new byte[32*4096];
Arrays.fill(content, (byte)88);
OutputStream out = socket.getOutputStream();
String header=
"POST /?read=10 HTTP/1.1\r\n"+
"Host: localhost\r\n"+
"Content-Length: "+content.length+"\r\n"+
"Content-Type: bytes\r\n"+
"\r\n";
byte[] h=header.getBytes(StringUtil.__ISO_8859_1);
out.write(h);
out.write(content,0,4096);
out.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
assertThat(in.readLine(),containsString("HTTP/1.1 200 OK"));
assertThat(in.readLine(),containsString("Content-Length:"));
assertThat(in.readLine(),containsString("Server:"));
in.readLine();
assertThat(in.readLine(),containsString("XXXXXXX"));
socket.close();
}
}
private static class PartialReaderHandler extends AbstractHandler
{
@Override
public void handle(String path, final Request request, HttpServletRequest httpRequest, final HttpServletResponse httpResponse) throws IOException, ServletException
{
httpResponse.setStatus(200);
request.setHandled(true);
BufferedReader in = request.getReader();
PrintWriter out =httpResponse.getWriter();
int read=Integer.valueOf(request.getParameter("read"));
// System.err.println("read="+read);
for (int i=read;i-->0;)
{
int c=in.read();
if (c<0)
break;
out.write(c);
}
out.println();
}
}
}

View File

@ -18,19 +18,11 @@
package org.eclipse.jetty.server.handler;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
@ -46,6 +38,12 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
public class StatisticsHandlerTest
{
private Server _server;
@ -60,7 +58,7 @@ public class StatisticsHandlerTest
_server = new Server();
_connector = new LocalConnector(_server);
_statistics=new ConnectorStatistics();
_statistics = new ConnectorStatistics();
_connector.addBean(_statistics);
_server.addConnector(_connector);
@ -105,8 +103,8 @@ public class StatisticsHandlerTest
_server.start();
String request = "GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
"Host: localhost\r\n" +
"\r\n";
_connector.executeRequest(request);
barrier[0].await();
@ -174,8 +172,8 @@ public class StatisticsHandlerTest
assertEquals(2, _statsHandler.getResponses2xx());
_latchHandler.reset(2);
barrier[0]=new CyclicBarrier(3);
barrier[1]=new CyclicBarrier(3);
barrier[0] = new CyclicBarrier(3);
barrier[1] = new CyclicBarrier(3);
_connector.executeRequest(request);
_connector.executeRequest(request);
@ -208,37 +206,33 @@ public class StatisticsHandlerTest
assertEquals(0, _statsHandler.getAsyncDispatches());
assertEquals(0, _statsHandler.getExpires());
assertEquals(4, _statsHandler.getResponses2xx());
}
@Test
public void testSuspendResume() throws Exception
{
final long dispatchTime = 10;
final long requestTime = 50;
final AtomicReference<AsyncContext> asyncHolder = new AtomicReference<>();
final CyclicBarrier barrier[] = { new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
final CyclicBarrier barrier[] = {new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
_statsHandler.setHandler(new AbstractHandler()
{
@Override
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
{
request.setHandled(true);
try
{
barrier[0].await();
Thread.sleep(10);
Thread.sleep(dispatchTime);
if (asyncHolder.get() == null)
{
asyncHolder.set(request.startAsync());
}
}
catch (Exception x)
{
Thread.currentThread().interrupt();
throw (IOException)new IOException().initCause(x);
throw new ServletException(x);
}
finally
{
@ -246,50 +240,41 @@ public class StatisticsHandlerTest
{
barrier[1].await();
}
catch (Exception x)
catch (Exception ignored)
{
x.printStackTrace();
Thread.currentThread().interrupt();
fail();
}
}
}
});
_server.start();
String request = "GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
"Host: localhost\r\n" +
"\r\n";
_connector.executeRequest(request);
barrier[0].await();
assertEquals(1, _statistics.getConnectionsOpen());
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(1, _statsHandler.getDispatchedActive());
barrier[1].await();
assertTrue(_latchHandler.await());
assertNotNull(asyncHolder.get());
assertTrue(asyncHolder.get()!=null);
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(0, _statsHandler.getDispatchedActive());
Thread.sleep(10);
_latchHandler.reset();
barrier[0].reset();
barrier[1].reset();
Thread.sleep(50);
Thread.sleep(requestTime);
asyncHolder.get().addListener(new AsyncListener()
{
@ -297,30 +282,34 @@ public class StatisticsHandlerTest
public void onTimeout(AsyncEvent event) throws IOException
{
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
@Override
public void onError(AsyncEvent event) throws IOException
{
}
@Override
public void onComplete(AsyncEvent event) throws IOException
{
try { barrier[2].await(); } catch(Exception e) {}
try
{
barrier[2].await();
}
catch (Exception ignored)
{
}
}
});
asyncHolder.get().dispatch();
barrier[0].await(); // entered app handler
assertEquals(1, _statistics.getConnectionsOpen());
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(2, _statsHandler.getDispatched());
@ -335,50 +324,49 @@ public class StatisticsHandlerTest
assertEquals(2, _statsHandler.getDispatched());
assertEquals(0, _statsHandler.getDispatchedActive());
assertEquals(1, _statsHandler.getAsyncRequests());
assertEquals(1, _statsHandler.getAsyncDispatches());
assertEquals(0, _statsHandler.getExpires());
assertEquals(1, _statsHandler.getResponses2xx());
assertThat(_statsHandler.getRequestTimeTotal(), greaterThanOrEqualTo(requestTime * 3 / 4));
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMax());
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMean(), 0.01);
assertThat(_statsHandler.getRequestTimeTotal(),greaterThanOrEqualTo(50L));
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax());
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01);
assertTrue(_statsHandler.getDispatchedTimeTotal()>=20);
assertTrue(_statsHandler.getDispatchedTimeMean()+10<=_statsHandler.getDispatchedTimeTotal());
assertTrue(_statsHandler.getDispatchedTimeMax()+10<=_statsHandler.getDispatchedTimeTotal());
assertThat(_statsHandler.getDispatchedTimeTotal(), greaterThanOrEqualTo(dispatchTime * 2 * 3 / 4));
assertTrue(_statsHandler.getDispatchedTimeMean() + dispatchTime <= _statsHandler.getDispatchedTimeTotal());
assertTrue(_statsHandler.getDispatchedTimeMax() + dispatchTime <= _statsHandler.getDispatchedTimeTotal());
}
@Test
public void testSuspendExpire() throws Exception
{
final long dispatchTime = 10;
final long timeout = 100;
final AtomicReference<AsyncContext> asyncHolder = new AtomicReference<>();
final CyclicBarrier barrier[] = { new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
final CyclicBarrier barrier[] = {new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
_statsHandler.setHandler(new AbstractHandler()
{
@Override
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
{
request.setHandled(true);
try
{
barrier[0].await();
Thread.sleep(10);
Thread.sleep(dispatchTime);
if (asyncHolder.get() == null)
{
AsyncContext async=request.startAsync();
async.setTimeout(100);
AsyncContext async = request.startAsync();
asyncHolder.set(async);
async.setTimeout(timeout);
}
}
catch (Exception x)
{
Thread.currentThread().interrupt();
throw (IOException)new IOException().initCause(x);
throw new ServletException(x);
}
finally
{
@ -386,28 +374,22 @@ public class StatisticsHandlerTest
{
barrier[1].await();
}
catch (Exception x)
catch (Exception ignored)
{
x.printStackTrace();
Thread.currentThread().interrupt();
fail();
}
}
}
});
_server.start();
String request = "GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
"Host: localhost\r\n" +
"\r\n";
_connector.executeRequest(request);
barrier[0].await();
assertEquals(1, _statistics.getConnectionsOpen());
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
@ -423,31 +405,35 @@ public class StatisticsHandlerTest
{
event.getAsyncContext().complete();
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
@Override
public void onError(AsyncEvent event) throws IOException
{
}
@Override
public void onComplete(AsyncEvent event) throws IOException
{
try { barrier[2].await(); } catch(Exception e) {}
try
{
barrier[2].await();
}
catch (Exception ignored)
{
}
}
});
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(0, _statsHandler.getDispatchedActive());
barrier[2].await();
assertEquals(1, _statsHandler.getRequests());
@ -460,67 +446,40 @@ public class StatisticsHandlerTest
assertEquals(1, _statsHandler.getExpires());
assertEquals(1, _statsHandler.getResponses2xx());
assertTrue(_statsHandler.getRequestTimeTotal() >= (timeout + dispatchTime) * 3 / 4);
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMax());
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMean(), 0.01);
assertTrue(_statsHandler.getRequestTimeTotal()>=30);
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax());
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01);
assertThat(_statsHandler.getDispatchedTimeTotal(),greaterThanOrEqualTo(10L));
assertThat(_statsHandler.getDispatchedTimeTotal(), greaterThanOrEqualTo(dispatchTime * 3 / 4));
}
@Test
public void testSuspendComplete() throws Exception
{
final long dispatchTime = 10;
final AtomicReference<AsyncContext> asyncHolder = new AtomicReference<>();
final CyclicBarrier barrier[] = { new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
final CyclicBarrier barrier[] = {new CyclicBarrier(2), new CyclicBarrier(2), new CyclicBarrier(2)};
_statsHandler.setHandler(new AbstractHandler()
{
@Override
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
{
request.setHandled(true);
try
{
barrier[0].await();
Thread.sleep(10);
Thread.sleep(dispatchTime);
if (asyncHolder.get() == null)
{
AsyncContext async=request.startAsync();
async.setTimeout(1000);
AsyncContext async = request.startAsync();
asyncHolder.set(async);
asyncHolder.get().addListener(new AsyncListener()
{
@Override
public void onTimeout(AsyncEvent event) throws IOException
{
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
@Override
public void onError(AsyncEvent event) throws IOException
{
}
@Override
public void onComplete(AsyncEvent event) throws IOException
{
try { barrier[2].await(); } catch(Exception e) {}
}
});
}
}
catch (Exception x)
{
Thread.currentThread().interrupt();
throw (IOException)new IOException().initCause(x);
throw new ServletException(x);
}
finally
{
@ -528,11 +487,8 @@ public class StatisticsHandlerTest
{
barrier[1].await();
}
catch (Exception x)
catch (Exception ignored)
{
x.printStackTrace();
Thread.currentThread().interrupt();
fail();
}
}
@ -541,21 +497,18 @@ public class StatisticsHandlerTest
_server.start();
String request = "GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
"Host: localhost\r\n" +
"\r\n";
_connector.executeRequest(request);
barrier[0].await();
assertEquals(1, _statistics.getConnectionsOpen());
assertEquals(1, _statsHandler.getRequests());
assertEquals(1, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(1, _statsHandler.getDispatchedActive());
barrier[1].await();
assertTrue(_latchHandler.await());
assertNotNull(asyncHolder.get());
@ -565,7 +518,37 @@ public class StatisticsHandlerTest
assertEquals(1, _statsHandler.getDispatched());
assertEquals(0, _statsHandler.getDispatchedActive());
Thread.sleep(10);
asyncHolder.get().addListener(new AsyncListener()
{
@Override
public void onTimeout(AsyncEvent event) throws IOException
{
}
@Override
public void onStartAsync(AsyncEvent event) throws IOException
{
}
@Override
public void onError(AsyncEvent event) throws IOException
{
}
@Override
public void onComplete(AsyncEvent event) throws IOException
{
try
{
barrier[2].await();
}
catch (Exception ignored)
{
}
}
});
long requestTime = 20;
Thread.sleep(requestTime);
asyncHolder.get().complete();
barrier[2].await();
@ -579,17 +562,16 @@ public class StatisticsHandlerTest
assertEquals(0, _statsHandler.getExpires());
assertEquals(1, _statsHandler.getResponses2xx());
assertTrue(_statsHandler.getRequestTimeTotal()>=20);
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMax());
assertEquals(_statsHandler.getRequestTimeTotal(),_statsHandler.getRequestTimeMean(), 0.01);
assertTrue(_statsHandler.getRequestTimeTotal() >= (dispatchTime + requestTime) * 3 / 4);
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMax());
assertEquals(_statsHandler.getRequestTimeTotal(), _statsHandler.getRequestTimeMean(), 0.01);
assertTrue(_statsHandler.getDispatchedTimeTotal()>=10);
assertTrue(_statsHandler.getDispatchedTimeTotal()<_statsHandler.getRequestTimeTotal());
assertEquals(_statsHandler.getDispatchedTimeTotal(),_statsHandler.getDispatchedTimeMax());
assertEquals(_statsHandler.getDispatchedTimeTotal(),_statsHandler.getDispatchedTimeMean(), 0.01);
assertTrue(_statsHandler.getDispatchedTimeTotal() >= dispatchTime * 3 / 4);
assertTrue(_statsHandler.getDispatchedTimeTotal() < _statsHandler.getRequestTimeTotal());
assertEquals(_statsHandler.getDispatchedTimeTotal(), _statsHandler.getDispatchedTimeMax());
assertEquals(_statsHandler.getDispatchedTimeTotal(), _statsHandler.getDispatchedTimeMean(), 0.01);
}
/**
* This handler is external to the statistics handler and it is used to ensure that statistics handler's
* handle() is fully executed before asserting its values in the tests, to avoid race conditions with the
@ -602,7 +584,7 @@ public class StatisticsHandlerTest
@Override
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException
{
final CountDownLatch latch=_latch;
final CountDownLatch latch = _latch;
try
{
super.handle(path, request, httpRequest, httpResponse);
@ -615,12 +597,12 @@ public class StatisticsHandlerTest
private void reset()
{
_latch=new CountDownLatch(1);
_latch = new CountDownLatch(1);
}
private void reset(int count)
{
_latch=new CountDownLatch(count);
_latch = new CountDownLatch(count);
}
private boolean await() throws InterruptedException

View File

@ -385,8 +385,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();
}
/* ------------------------------------------------------------ */

View File

@ -158,10 +158,9 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
}
@Override
public boolean earlyEOF()
public void earlyEOF()
{
// TODO
return false;
}
@Override

View File

@ -332,10 +332,9 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
if (dataInfo.isClose())
{
currentStreamId.compareAndSet(currentStreamId.get(), currentStreamId.get() + 2);
allPushDataReceivedLatch.countDown();
dataReceivedOrder.add(stream.getId());
allPushDataReceivedLatch.countDown();
}
LOG.info(stream.getId() + ":" + dataInfo);
}
};

View File

@ -39,6 +39,7 @@ import java.net.ConnectException;
import java.net.InetAddress;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@ -328,92 +329,24 @@ public class Main
if (file.exists())
return;
String[] parse = split[1].split("/",4);
String host=parse[2];
String uri="/"+split[1].substring(3+host.length());
URL url = new URL(split[0].substring(11)+":"+split[1]);
try (Socket socket = new Socket(host,80))
System.err.println("DOWNLOAD: "+url+" to "+location);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
byte[] buf=new byte[8192];
try (InputStream in = url.openStream(); OutputStream out = new FileOutputStream(file);)
{
String request="GET "+uri+" HTTP/1.0\r\n"+
"Host: "+host+"\r\n"+
"User-Agent: jetty-start.jar\r\n"+
"\r\n";
socket.getOutputStream().write(request.getBytes("ISO-8859-1"));
socket.getOutputStream().flush();
InputStream in = socket.getInputStream();
int state=0;
loop: while (state>=0)
while(true)
{
char c = (char)in.read();
int len = in.read(buf);
switch (state)
{
case 0:
c=Character.toLowerCase(c);
if (c==' ')
state=1;
else if (c!='h' && c!='t' && c!='p' && c!='/' && c!='.' && !Character.isDigit(c))
break loop;
break;
case 1:
if (c==' ')
state=2;
else if (c!='2' && c!='0')
break loop;
break;
case 2:
if (c=='\r')
state=3;
else if (c=='\n')
state=4;
break;
case 3:
if (c=='\n')
state=4;
else if (c=='\r')
state=-1;
break;
case 4:
if (c=='\r')
state=5;
else if (c=='\n')
state=-1;
else
state=2;
break;
case 5:
if (c=='\n')
state=-1;
else
state=2;
break;
}
}
if (state>=0)
throw new IOException("Bad HTTP response: "+state);
System.err.println("DOWNLOAD: "+uri+" from "+host+" to "+location);
if (!file.getParentFile().exists())
file.getParentFile().mkdirs();
byte[] buf=new byte[8192];
try (OutputStream out = new FileOutputStream(file))
{
while(!socket.isInputShutdown())
{
int len = in.read(buf);
if (len>0)
out.write(buf,0,len);
if (len<0)
break;
}
if (len>0)
out.write(buf,0,len);
if (len<0)
break;
}
}
}

View File

@ -131,8 +131,6 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
_tree[row]=c;
_tree[last]=(char)t;
last=row+EQ;
t=0;
break;
}
int row=ROW_SIZE*t;
@ -419,4 +417,22 @@ public class ArrayTernaryTrie<V> extends AbstractTrie<V>
{
return _rows+1==_key.length;
}
public void dump()
{
for (int r=0;r<=_rows;r++)
{
char c=_tree[r*ROW_SIZE+0];
System.err.printf("%4d [%s,%d,%d,%d] %s:%s%n",
r,
(c<' '||c>127)?(""+(int)c):"'"+c+"'",
(int)_tree[r*ROW_SIZE+LO],
(int)_tree[r*ROW_SIZE+EQ],
(int)_tree[r*ROW_SIZE+HI],
_key[r],
_value[r]);
}
}
}