Merge remote-tracking branch 'origin/master' into servlet-3.1-api
This commit is contained in:
commit
0d181d9a75
|
@ -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());
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,5 +0,0 @@
|
|||
#===========================================================
|
||||
# Java Server Pages
|
||||
#-----------------------------------------------------------
|
||||
OPTIONS=jsp
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -1,6 +0,0 @@
|
|||
#===========================================================
|
||||
# HTTP Connector
|
||||
#-----------------------------------------------------------
|
||||
jetty.port=8080
|
||||
http.timeout=30000
|
||||
etc/jetty-http.xml
|
|
@ -1,6 +0,0 @@
|
|||
#===========================================================
|
||||
# HTTPS Connector
|
||||
# Must be used with 200-ssl.ini
|
||||
#-----------------------------------------------------------
|
||||
jetty.https.port=8443
|
||||
etc/jetty-https.xml
|
|
@ -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
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#===========================================================
|
||||
# Annotations JNDI JAAS processing
|
||||
#-----------------------------------------------------------
|
||||
OPTIONS=plus
|
||||
etc/jetty-plus.xml
|
||||
OPTIONS=annotations
|
||||
etc/jetty-annotations.xml
|
||||
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
etc/jetty-debug.xml
|
|
@ -1 +0,0 @@
|
|||
etc/jetty-ipaccess.xml
|
|
@ -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
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#===========================================================
|
||||
#-----------------------------------------------------------
|
||||
etc/jetty-stats.xml
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
#===========================================================
|
||||
# Webapplication Deployer
|
||||
#-----------------------------------------------------------
|
||||
etc/jetty-deploy.xml
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -138,9 +138,8 @@ public class HttpTester
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -51,9 +51,8 @@ public class HttpGeneratorServerTest
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -158,10 +158,9 @@ public class ProxyHTTPSPDYConnection extends HttpConnection implements HttpParse
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean earlyEOF()
|
||||
public void earlyEOF()
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue