Merge branch 'master' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project

This commit is contained in:
Jesse McConnell 2011-12-21 14:12:46 -06:00
commit e96f828dcf
8 changed files with 201 additions and 88 deletions

View File

@ -14,6 +14,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
@ -54,6 +55,8 @@ public class SslBytesServerTest extends SslBytesTest
private final AtomicInteger sslHandles = new AtomicInteger(); private final AtomicInteger sslHandles = new AtomicInteger();
private final AtomicInteger sslFlushes = new AtomicInteger(); private final AtomicInteger sslFlushes = new AtomicInteger();
private final AtomicInteger httpParses = new AtomicInteger(); private final AtomicInteger httpParses = new AtomicInteger();
private final AtomicReference<EndPoint> serverEndPoint = new AtomicReference<EndPoint>();
private final int idleTimeout = 2000;
private ExecutorService threadPool; private ExecutorService threadPool;
private Server server; private Server server;
private SSLContext sslContext; private SSLContext sslContext;
@ -70,6 +73,7 @@ public class SslBytesServerTest extends SslBytesTest
@Override @Override
protected SslConnection newSslConnection(AsyncEndPoint endPoint, SSLEngine engine) protected SslConnection newSslConnection(AsyncEndPoint endPoint, SSLEngine engine)
{ {
serverEndPoint.set(endPoint);
return new SslConnection(engine, endPoint) return new SslConnection(engine, endPoint)
{ {
@Override @Override
@ -116,7 +120,7 @@ public class SslBytesServerTest extends SslBytesTest
}; };
} }
}; };
connector.setMaxIdleTime(5000); connector.setMaxIdleTime(idleTimeout);
// connector.setPort(5870); // connector.setPort(5870);
connector.setPort(0); connector.setPort(0);
@ -1237,9 +1241,8 @@ public class SslBytesServerTest extends SslBytesTest
closeClient(client); closeClient(client);
} }
@Ignore
@Test @Test
public void testServerCloseClientDoesNotClose() throws Exception public void testServerShutdownOutputClientDoesNotCloseServerCloses() throws Exception
{ {
final SSLSocket client = newClient(); final SSLSocket client = newClient();
final OutputStream clientOutput = client.getOutputStream(); final OutputStream clientOutput = client.getOutputStream();
@ -1261,7 +1264,6 @@ public class SslBytesServerTest extends SslBytesTest
"\r\n" + "\r\n" +
content).getBytes("UTF-8")); content).getBytes("UTF-8"));
clientOutput.flush(); clientOutput.flush();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8")); BufferedReader reader = new BufferedReader(new InputStreamReader(client.getInputStream(), "UTF-8"));
String line = reader.readLine(); String line = reader.readLine();
@ -1272,17 +1274,25 @@ public class SslBytesServerTest extends SslBytesTest
if (line.trim().length() == 0) if (line.trim().length() == 0)
break; break;
} }
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
// Check client is at EOF
Assert.assertEquals(-1,client.getInputStream().read());
// Client should close the socket, but let's hold it open.
// Check that we did not spin // Check that we did not spin
TimeUnit.MILLISECONDS.sleep(100);
Assert.assertThat(sslHandles.get(), lessThan(20)); Assert.assertThat(sslHandles.get(), lessThan(20));
Assert.assertThat(sslFlushes.get(), lessThan(20));
Assert.assertThat(httpParses.get(), lessThan(50)); Assert.assertThat(httpParses.get(), lessThan(50));
// TODO: instead of sleeping, we should expect the connection being closed by the idle timeout // The server has shutdown the output since the client sent a Connection: close
// TODO: mechanism; unfortunately this now is not working, and this test fails because the idle // but the client does not close, so the server must idle timeout the endPoint.
// TODO: timeout will not trigger.
TimeUnit.SECONDS.sleep(100);
closeClient(client); TimeUnit.MILLISECONDS.sleep(idleTimeout + idleTimeout/2);
Assert.assertFalse(serverEndPoint.get().isOpen());
} }
private void assumeJavaVersionSupportsTLSRenegotiations() private void assumeJavaVersionSupportsTLSRenegotiations()

View File

@ -257,15 +257,6 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
getSelectSet().scheduleTimeout(task,timeoutMs); getSelectSet().scheduleTimeout(task,timeoutMs);
} }
/* ------------------------------------------------------------ */
@Override
public boolean isOutputShutdown()
{
setCheckForIdle(true);
return super.isOutputShutdown();
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public void setCheckForIdle(boolean check) public void setCheckForIdle(boolean check)
{ {
@ -289,10 +280,11 @@ public class SelectChannelEndPoint extends ChannelEndPoint implements AsyncEndPo
public void checkIdleTimestamp(long now) public void checkIdleTimestamp(long now)
{ {
long idleTimestamp=_idleTimestamp; long idleTimestamp=_idleTimestamp;
if (idleTimestamp!=0 && _maxIdleTime>0) if (idleTimestamp!=0 && _maxIdleTime>0)
{ {
long idleForMs=now-idleTimestamp; long idleForMs=now-idleTimestamp;
if (idleForMs>_maxIdleTime) if (idleForMs>_maxIdleTime)
{ {
onIdleExpired(idleForMs); onIdleExpired(idleForMs);

View File

@ -249,7 +249,10 @@ public class SslConnection extends AbstractConnection implements AsyncConnection
try try
{ {
LOG.debug("onIdleExpired {}ms on {}",idleForMs,this); LOG.debug("onIdleExpired {}ms on {}",idleForMs,this);
_sslEndPoint.shutdownOutput(); if (_endp.isOutputShutdown())
_sslEndPoint.close();
else
_sslEndPoint.shutdownOutput();
} }
catch (IOException e) catch (IOException e)
{ {

View File

@ -54,6 +54,10 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async
try try
{ {
setCurrentConnection(this); setCurrentConnection(this);
// don't check for idle while dispatched (unless blocking IO is done).
_asyncEndp.setCheckForIdle(false);
// While progress and the connection has not changed // While progress and the connection has not changed
while (progress && connection==this) while (progress && connection==this)
@ -133,10 +137,16 @@ public class AsyncHttpConnection extends AbstractHttpConnection implements Async
finally finally
{ {
setCurrentConnection(null); setCurrentConnection(null);
// If we are not suspended
if (!_request.isAsyncStarted()) if (!_request.isAsyncStarted())
{ {
// return buffers
_parser.returnBuffers(); _parser.returnBuffers();
_generator.returnBuffers(); _generator.returnBuffers();
// resuming checking for idle
_asyncEndp.setCheckForIdle(true);
} }
// Safety net to catch spinning // Safety net to catch spinning

View File

@ -30,7 +30,6 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.RequestDispatcher; import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet; import javax.servlet.Servlet;
import javax.servlet.ServletContext; import javax.servlet.ServletContext;
@ -70,13 +69,13 @@ import org.eclipse.jetty.util.resource.Resource;
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* ContextHandler. * ContextHandler.
* *
* This handler wraps a call to handle by setting the context and servlet path, plus setting the context classloader. * This handler wraps a call to handle by setting the context and servlet path, plus setting the context classloader.
* *
* <p> * <p>
* If the context init parameter "org.eclipse.jetty.server.context.ManagedAttributes" is set to a comma separated list of names, then they are treated as * If the context init parameter "org.eclipse.jetty.server.context.ManagedAttributes" is set to a comma separated list of names, then they are treated as
* context attribute names, which if set as attributes are passed to the servers Container so that they may be managed with JMX. * context attribute names, which if set as attributes are passed to the servers Container so that they may be managed with JMX.
* *
* @org.apache.xbean.XBean description="Creates a basic HTTP context" * @org.apache.xbean.XBean description="Creates a basic HTTP context"
*/ */
public class ContextHandler extends ScopedHandler implements Attributes, Server.Graceful public class ContextHandler extends ScopedHandler implements Attributes, Server.Graceful
@ -95,7 +94,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Get the current ServletContext implementation. * Get the current ServletContext implementation.
* *
* @return ServletContext implementation * @return ServletContext implementation
*/ */
public static Context getCurrentContext() public static Context getCurrentContext()
@ -244,7 +243,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
* Set the virtual hosts for the context. Only requests that have a matching host header or fully qualified URL will be passed to that context with a * Set the virtual hosts for the context. Only requests that have a matching host header or fully qualified URL will be passed to that context with a
* virtual host name. A context with no virtual host names or a null virtual host name is available to all requests that are not served by a context with a * virtual host name. A context with no virtual host names or a null virtual host name is available to all requests that are not served by a context with a
* matching virtual host name. * matching virtual host name.
* *
* @param vhosts * @param vhosts
* Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be * Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be
* String representation of IP addresses. Host names may start with '*.' to wildcard one level of names. * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
@ -265,7 +264,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** Either set virtual hosts or add to an existing set of virtual hosts. /** Either set virtual hosts or add to an existing set of virtual hosts.
* *
* @param virtualHosts * @param virtualHosts
* Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be * Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be
* String representation of IP addresses. Host names may start with '*.' to wildcard one level of names. * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
@ -287,7 +286,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
{ {
currentVirtualHosts = new ArrayList<String>(); currentVirtualHosts = new ArrayList<String>();
} }
for (int i = 0; i < virtualHosts.length; i++) for (int i = 0; i < virtualHosts.length; i++)
{ {
String normVhost = normalizeHostname(virtualHosts[i]); String normVhost = normalizeHostname(virtualHosts[i]);
@ -303,7 +302,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Removes an array of virtual host entries, if this removes all entries the _vhosts will be set to null * Removes an array of virtual host entries, if this removes all entries the _vhosts will be set to null
* *
* @param virtualHosts * @param virtualHosts
* Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be * Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be
* String representation of IP addresses. Host names may start with '*.' to wildcard one level of names. * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
@ -321,7 +320,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
else else
{ {
List<String> existingVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts)); List<String> existingVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
for (int i = 0; i < virtualHosts.length; i++) for (int i = 0; i < virtualHosts.length; i++)
{ {
String toRemoveVirtualHost = normalizeHostname(virtualHosts[i]); String toRemoveVirtualHost = normalizeHostname(virtualHosts[i]);
@ -330,7 +329,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
existingVirtualHosts.remove(toRemoveVirtualHost); existingVirtualHosts.remove(toRemoveVirtualHost);
} }
} }
if (existingVirtualHosts.isEmpty()) if (existingVirtualHosts.isEmpty())
{ {
_vhosts = null; // if we ended up removing them all, just null out _vhosts _vhosts = null; // if we ended up removing them all, just null out _vhosts
@ -341,13 +340,13 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
} }
} }
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Get the virtual hosts for the context. Only requests that have a matching host header or fully qualified URL will be passed to that context with a * Get the virtual hosts for the context. Only requests that have a matching host header or fully qualified URL will be passed to that context with a
* virtual host name. A context with no virtual host names or a null virtual host name is available to all requests that are not served by a context with a * virtual host name. A context with no virtual host names or a null virtual host name is available to all requests that are not served by a context with a
* matching virtual host name. * matching virtual host name.
* *
* @return Array of virtual hosts that this context responds to. A null host name or empty array means any hostname is acceptable. Host names may be String * @return Array of virtual hosts that this context responds to. A null host name or empty array means any hostname is acceptable. Host names may be String
* representation of IP addresses. Host names may start with '*.' to wildcard one level of names. * representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
*/ */
@ -371,9 +370,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Set the names of accepted connectors. * Set the names of accepted connectors.
* *
* Names are either "host:port" or a specific configured name for a connector. * Names are either "host:port" or a specific configured name for a connector.
* *
* @param connectors * @param connectors
* If non null, an array of connector names that this context will accept a request from. * If non null, an array of connector names that this context will accept a request from.
*/ */
@ -425,7 +424,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Make best effort to extract a file classpath from the context classloader * Make best effort to extract a file classpath from the context classloader
* *
* @return Returns the classLoader. * @return Returns the classLoader.
*/ */
public String getClassPath() public String getClassPath()
@ -521,7 +520,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Set the context event listeners. * Set the context event listeners.
* *
* @param eventListeners * @param eventListeners
* the event listeners * the event listeners
* @see ServletContextListener * @see ServletContextListener
@ -559,7 +558,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Add a context event listeners. * Add a context event listeners.
* *
* @see ServletContextListener * @see ServletContextListener
* @see ServletContextAttributeListener * @see ServletContextAttributeListener
* @see ServletRequestListener * @see ServletRequestListener
@ -586,7 +585,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/** /**
* Set shutdown status. This field allows for graceful shutdown of a context. A started context may be put into non accepting state so that existing * Set shutdown status. This field allows for graceful shutdown of a context. A started context may be put into non accepting state so that existing
* requests can complete, but no new requests are accepted. * requests can complete, but no new requests are accepted.
* *
* @param shutdown * @param shutdown
* true if this context is (not?) accepting new requests * true if this context is (not?) accepting new requests
*/ */
@ -694,7 +693,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/** /**
* Extensible startContext. this method is called from {@link ContextHandler#doStart()} instead of a call to super.doStart(). This allows derived classes to * Extensible startContext. this method is called from {@link ContextHandler#doStart()} instead of a call to super.doStart(). This allows derived classes to
* insert additional handling (Eg configuration) before the call to super.doStart by this method will start contained handlers. * insert additional handling (Eg configuration) before the call to super.doStart by this method will start contained handlers.
* *
* @see org.eclipse.jetty.server.handler.ContextHandler.Context * @see org.eclipse.jetty.server.handler.ContextHandler.Context
*/ */
protected void startContext() throws Exception protected void startContext() throws Exception
@ -1116,7 +1115,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* /*
* Set a context attribute. Attributes set via this API cannot be overriden by the ServletContext.setAttribute API. Their lifecycle spans the stop/start of * Set a context attribute. Attributes set via this API cannot be overriden by the ServletContext.setAttribute API. Their lifecycle spans the stop/start of
* a context. No attribute listener events are triggered by this API. * a context. No attribute listener events are triggered by this API.
* *
* @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object) * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
*/ */
public void setAttribute(String name, Object value) public void setAttribute(String name, Object value)
@ -1381,14 +1380,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();
String p = getClass().getPackage().getName(); Package pkg = getClass().getPackage();
if (p != null && p.length() > 0) if (pkg != null)
{ {
String[] ss = p.split("\\."); String p = pkg.getName();
for (String s : ss) if (p != null && p.length() > 0)
b.append(s.charAt(0)).append('.'); {
String[] ss = p.split("\\.");
for (String s : ss)
b.append(s.charAt(0)).append('.');
}
} }
b.append(getClass().getSimpleName()); b.append(getClass().getSimpleName());
b.append('{').append(getContextPath()).append(',').append(getBaseResource()); b.append('{').append(getContextPath()).append(',').append(getBaseResource());
@ -1431,7 +1433,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/** /**
* Get the character encoding for a locale. The full locale name is first looked up in the map of encodings. If no encoding is found, then the locale * Get the character encoding for a locale. The full locale name is first looked up in the map of encodings. If no encoding is found, then the locale
* language is looked up. * language is looked up.
* *
* @param locale * @param locale
* a <code>Locale</code> value * a <code>Locale</code> value
* @return a <code>String</code> representing the character encoding for the locale or null if none found. * @return a <code>String</code> representing the character encoding for the locale or null if none found.
@ -1495,7 +1497,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* Convert a URL or path to a Resource. The default implementation is a wrapper for {@link Resource#newResource(String)}. * Convert a URL or path to a Resource. The default implementation is a wrapper for {@link Resource#newResource(String)}.
* *
* @param urlOrPath * @param urlOrPath
* The URL or path to convert * The URL or path to convert
* @return The Resource for the URL/path * @return The Resource for the URL/path
@ -1557,8 +1559,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server.
* <p> * <p>
* A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}. * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}.
* </p> * </p>
* *
* *
*/ */
public class Context implements ServletContext public class Context implements ServletContext
{ {

View File

@ -122,7 +122,6 @@ public class SelectChannelConnector extends AbstractNIOConnector
public void customize(EndPoint endpoint, Request request) throws IOException public void customize(EndPoint endpoint, Request request) throws IOException
{ {
AsyncEndPoint aEndp = ((AsyncEndPoint)endpoint); AsyncEndPoint aEndp = ((AsyncEndPoint)endpoint);
aEndp.setCheckForIdle(false);
request.setTimeStamp(System.currentTimeMillis()); request.setTimeStamp(System.currentTimeMillis());
endpoint.setMaxIdleTime(_maxIdleTime); endpoint.setMaxIdleTime(_maxIdleTime);
super.customize(endpoint, request); super.customize(endpoint, request);

View File

@ -13,44 +13,45 @@
package org.eclipse.jetty.server; package org.eclipse.jetty.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import junit.framework.Assert;
import org.eclipse.jetty.server.handler.AbstractHandler; import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.matchers.JUnitMatchers.containsString;
public abstract class ConnectorTimeoutTest extends HttpServerTestFixture public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
{ {
protected static final int MAX_IDLE_TIME=250; protected static final int MAX_IDLE_TIME=250;
static static
{ {
System.setProperty("org.eclipse.jetty.io.nio.IDLE_TICK","100"); System.setProperty("org.eclipse.jetty.io.nio.IDLE_TICK","100");
} }
@Test @Test
public void testMaxIdleWithRequest10() throws Exception public void testMaxIdleWithRequest10() throws Exception
{ {
configureServer(new HelloWorldHandler()); configureServer(new HelloWorldHandler());
Socket client=newSocket(HOST,_connector.getLocalPort()); Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000); client.setSoTimeout(10000);
assertFalse(client.isClosed()); assertFalse(client.isClosed());
OutputStream os=client.getOutputStream(); OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream(); InputStream is=client.getInputStream();
@ -63,7 +64,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
IO.toString(is); IO.toString(is);
Thread.sleep(300); Thread.sleep(300);
assertEquals(-1, is.read()); assertEquals(-1, is.read());
@ -73,13 +74,13 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
@Test @Test
public void testMaxIdleWithRequest11() throws Exception public void testMaxIdleWithRequest11() throws Exception
{ {
configureServer(new EchoHandler()); configureServer(new EchoHandler());
Socket client=newSocket(HOST,_connector.getLocalPort()); Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000); client.setSoTimeout(10000);
assertFalse(client.isClosed()); assertFalse(client.isClosed());
OutputStream os=client.getOutputStream(); OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream(); InputStream is=client.getInputStream();
@ -96,24 +97,119 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
IO.toString(is); IO.toString(is);
Thread.sleep(300); Thread.sleep(300);
assertEquals(-1, is.read()); assertEquals(-1, is.read());
Assert.assertTrue(System.currentTimeMillis()-start>200); Assert.assertTrue(System.currentTimeMillis()-start>200);
Assert.assertTrue(System.currentTimeMillis()-start<5000); Assert.assertTrue(System.currentTimeMillis()-start<5000);
} }
@Test
public void testMaxIdleWithRequest10NoClientClose() throws Exception
{
configureServer(new HelloWorldHandler());
Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000);
assertFalse(client.isClosed());
OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream();
os.write((
"GET / HTTP/1.0\r\n"+
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
"connection: close\r\n"+
"\r\n").getBytes("utf-8"));
os.flush();
String result=IO.toString(is);
Assert.assertThat("OK",result,containsString("200 OK"));
assertEquals(-1, is.read());
TimeUnit.MILLISECONDS.sleep(MAX_IDLE_TIME);
// further writes will get broken pipe or similar
try
{
for (int i=0;i<100;i++)
{
os.write((
"GET / HTTP/1.0\r\n"+
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
"connection: keep-alive\r\n"+
"\r\n").getBytes("utf-8"));
os.flush();
}
Assert.fail("half close should have timed out");
}
catch(SocketException e)
{
// expected
}
}
@Test
public void testMaxIdleWithRequest11NoClientClose() throws Exception
{
configureServer(new EchoHandler());
Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000);
assertFalse(client.isClosed());
OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream();
String content="Wibble";
byte[] contentB=content.getBytes("utf-8");
os.write((
"POST /echo HTTP/1.1\r\n"+
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
"content-type: text/plain; charset=utf-8\r\n"+
"content-length: "+contentB.length+"\r\n"+
"connection: close\r\n"+
"\r\n").getBytes("utf-8"));
os.write(contentB);
os.flush();
IO.toString(is);
assertEquals(-1, is.read());
TimeUnit.MILLISECONDS.sleep(MAX_IDLE_TIME);
// further writes will get broken pipe or similar
try
{
for (int i=0;i<100;i++)
{
os.write((
"GET / HTTP/1.0\r\n"+
"host: "+HOST+":"+_connector.getLocalPort()+"\r\n"+
"connection: keep-alive\r\n"+
"\r\n").getBytes("utf-8"));
os.flush();
}
Assert.fail("half close should have timed out");
}
catch(SocketException e)
{
// expected
}
}
@Test @Test
public void testMaxIdleNoRequest() throws Exception public void testMaxIdleNoRequest() throws Exception
{ {
configureServer(new EchoHandler()); configureServer(new EchoHandler());
Socket client=newSocket(HOST,_connector.getLocalPort()); Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000); client.setSoTimeout(10000);
InputStream is=client.getInputStream(); InputStream is=client.getInputStream();
assertFalse(client.isClosed()); assertFalse(client.isClosed());
Thread.sleep(500); Thread.sleep(500);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
try try
@ -123,25 +219,25 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
} }
catch(SSLException e) catch(SSLException e)
{ {
} }
catch(Exception e) catch(Exception e)
{ {
e.printStackTrace(); e.printStackTrace();
} }
Assert.assertTrue(System.currentTimeMillis()-start<5000); Assert.assertTrue(System.currentTimeMillis()-start<5000);
} }
@Test @Test
public void testMaxIdleWithSlowRequest() throws Exception public void testMaxIdleWithSlowRequest() throws Exception
{ {
configureServer(new EchoHandler()); configureServer(new EchoHandler());
Socket client=newSocket(HOST,_connector.getLocalPort()); Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000); client.setSoTimeout(10000);
assertFalse(client.isClosed()); assertFalse(client.isClosed());
OutputStream os=client.getOutputStream(); OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream(); InputStream is=client.getInputStream();
@ -163,7 +259,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
os.write(contentB); os.write(contentB);
os.flush(); os.flush();
} }
String in = IO.toString(is); String in = IO.toString(is);
int offset=0; int offset=0;
for (int i =0;i<20;i++) for (int i =0;i<20;i++)
@ -175,13 +271,13 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
@Test @Test
public void testMaxIdleWithSlowResponse() throws Exception public void testMaxIdleWithSlowResponse() throws Exception
{ {
configureServer(new SlowResponseHandler()); configureServer(new SlowResponseHandler());
Socket client=newSocket(HOST,_connector.getLocalPort()); Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000); client.setSoTimeout(10000);
assertFalse(client.isClosed()); assertFalse(client.isClosed());
OutputStream os=client.getOutputStream(); OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream(); InputStream is=client.getInputStream();
@ -192,7 +288,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"Connection: close\r\n"+ "Connection: close\r\n"+
"\r\n").getBytes("utf-8")); "\r\n").getBytes("utf-8"));
os.flush(); os.flush();
String in = IO.toString(is); String in = IO.toString(is);
int offset=0; int offset=0;
for (int i =0;i<20;i++) for (int i =0;i<20;i++)
@ -204,13 +300,13 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
@Test @Test
public void testMaxIdleWithWait() throws Exception public void testMaxIdleWithWait() throws Exception
{ {
configureServer(new WaitHandler()); configureServer(new WaitHandler());
Socket client=newSocket(HOST,_connector.getLocalPort()); Socket client=newSocket(HOST,_connector.getLocalPort());
client.setSoTimeout(10000); client.setSoTimeout(10000);
assertFalse(client.isClosed()); assertFalse(client.isClosed());
OutputStream os=client.getOutputStream(); OutputStream os=client.getOutputStream();
InputStream is=client.getInputStream(); InputStream is=client.getInputStream();
@ -221,12 +317,12 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
"Connection: close\r\n"+ "Connection: close\r\n"+
"\r\n").getBytes("utf-8")); "\r\n").getBytes("utf-8"));
os.flush(); os.flush();
String in = IO.toString(is); String in = IO.toString(is);
int offset=in.indexOf("Hello World"); int offset=in.indexOf("Hello World");
Assert.assertTrue(offset>0); Assert.assertTrue(offset>0);
} }
protected static class SlowResponseHandler extends AbstractHandler protected static class SlowResponseHandler extends AbstractHandler
{ {
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
@ -234,7 +330,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
baseRequest.setHandled(true); baseRequest.setHandled(true);
response.setStatus(200); response.setStatus(200);
OutputStream out = response.getOutputStream(); OutputStream out = response.getOutputStream();
for (int i=0;i<20;i++) for (int i=0;i<20;i++)
{ {
out.write("Hello World\r\n".getBytes()); out.write("Hello World\r\n".getBytes());
@ -244,7 +340,7 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
out.close(); out.close();
} }
} }
protected static class WaitHandler extends AbstractHandler protected static class WaitHandler extends AbstractHandler
{ {
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException

View File

@ -15,8 +15,6 @@
*******************************************************************************/ *******************************************************************************/
package org.eclipse.jetty.websocket; package org.eclipse.jetty.websocket;
import static org.hamcrest.Matchers.*;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -46,6 +44,9 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
public class WebSocketClientTest public class WebSocketClientTest
{ {
private WebSocketClientFactory _factory = new WebSocketClientFactory(); private WebSocketClientFactory _factory = new WebSocketClientFactory();
@ -717,7 +718,7 @@ public class WebSocketClientTest
Assert.assertThat("URI (" + uri + ").host", addr.getHostName(), is("localhost")); Assert.assertThat("URI (" + uri + ").host", addr.getHostName(), is("localhost"));
Assert.assertThat("URI (" + uri + ").port", addr.getPort(), is(80)); Assert.assertThat("URI (" + uri + ").port", addr.getPort(), is(80));
} }
@Test @Test
public void testURIWithDefaultWSSPort() throws Exception public void testURIWithDefaultWSSPort() throws Exception
{ {