410537 - Exceptions during @OnWebSocketConnect not reported to @OnWebSocketError

+ Fixed EventDriver behavior with regards to unhandled throwables during
  calls to the various onMethod() calls
+ Adding testcase to verify intended behavior
This commit is contained in:
Joakim Erdfelt 2013-06-12 11:05:01 -07:00
parent 9d89bc564e
commit a535381b53
3 changed files with 112 additions and 31 deletions

View File

@ -163,7 +163,14 @@ public abstract class EventDriver implements IncomingFrames
{
LOG.debug("openSession({})",session);
this.session = session;
this.onConnect();
try
{
this.onConnect();
}
catch (Throwable t)
{
unhandled(t);
}
}
protected void terminateConnection(int statusCode, String rawreason)
@ -177,6 +184,7 @@ public abstract class EventDriver implements IncomingFrames
private void unhandled(Throwable t)
{
LOG.warn("Unhandled Error (closing connection)",t);
onError(t);
// Unhandled Error, close the connection.
switch (policy.getBehavior())

View File

@ -237,17 +237,15 @@ public class ServletWebSocketRequest extends UpgradeRequest
{
if (protocol == null)
{
return new String[]
{ null };
return new String[] {};
}
protocol = protocol.trim();
if ((protocol == null) || (protocol.length() == 0))
{
return new String[]
{ null };
return new String[] {};
}
String[] passed = protocol.split("\\s*,\\s*");
String[] protocols = new String[passed.length + 1];
String[] protocols = new String[passed.length];
System.arraycopy(passed,0,protocols,0,passed.length);
return protocols;
}

View File

@ -28,6 +28,7 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.log.StacklessLogging;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
@ -36,6 +37,7 @@ import org.eclipse.jetty.websocket.api.WebSocketAdapter;
import org.eclipse.jetty.websocket.common.CloseInfo;
import org.eclipse.jetty.websocket.common.OpCode;
import org.eclipse.jetty.websocket.common.WebSocketFrame;
import org.eclipse.jetty.websocket.common.events.EventDriver;
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
import org.eclipse.jetty.websocket.server.helper.RFCSocket;
@ -52,28 +54,7 @@ import org.junit.Test;
*/
public class WebSocketCloseTest
{
@SuppressWarnings("serial")
public static class CloseServlet extends WebSocketServlet implements WebSocketCreator
{
@Override
public void configure(WebSocketServletFactory factory)
{
factory.setCreator(this);
}
@Override
public Object createWebSocket(UpgradeRequest req, UpgradeResponse resp)
{
if (req.hasSubProtocol("fastclose"))
{
fastcloseSocket = new FastCloseSocket();
return fastcloseSocket;
}
return new RFCSocket();
}
}
public static class FastCloseSocket extends WebSocketAdapter
static class AbstractCloseSocket extends WebSocketAdapter
{
public CountDownLatch closeLatch = new CountDownLatch(1);
public String closeReason = null;
@ -89,6 +70,48 @@ public class WebSocketCloseTest
closeLatch.countDown();
}
@Override
public void onWebSocketError(Throwable cause)
{
errors.add(cause);
}
}
@SuppressWarnings("serial")
public static class CloseServlet extends WebSocketServlet implements WebSocketCreator
{
@Override
public void configure(WebSocketServletFactory factory)
{
factory.setCreator(this);
}
@Override
public Object createWebSocket(UpgradeRequest req, UpgradeResponse resp)
{
if (req.hasSubProtocol("fastclose"))
{
closeSocket = new FastCloseSocket();
return closeSocket;
}
if (req.hasSubProtocol("fastfail"))
{
closeSocket = new FastFailSocket();
return closeSocket;
}
return new RFCSocket();
}
}
/**
* On Connect, close socket
*/
public static class FastCloseSocket extends AbstractCloseSocket
{
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastCloseSocket.class);
@Override
public void onWebSocketConnect(Session sess)
{
@ -102,6 +125,21 @@ public class WebSocketCloseTest
e.printStackTrace(System.err);
}
}
}
/**
* On Connect, throw unhandled exception
*/
public static class FastFailSocket extends AbstractCloseSocket
{
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.FastFailSocket.class);
@Override
public void onWebSocketConnect(Session sess)
{
LOG.debug("onWebSocketConnect({})",sess);
throw new RuntimeException("Intentional FastFail");
}
@Override
public void onWebSocketError(Throwable cause)
@ -111,8 +149,9 @@ public class WebSocketCloseTest
}
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.class);
private static SimpleServletServer server;
private static FastCloseSocket fastcloseSocket;
private static AbstractCloseSocket closeSocket;
@BeforeClass
public static void startServer() throws Exception
@ -150,8 +189,44 @@ public class WebSocketCloseTest
client.write(close.asFrame()); // respond with close
Assert.assertThat("Fast Close Latch",fastcloseSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
Assert.assertThat("Fast Close.statusCode",fastcloseSocket.closeStatusCode,is(StatusCode.NORMAL));
Assert.assertThat("Fast Close Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
Assert.assertThat("Fast Close.statusCode",closeSocket.closeStatusCode,is(StatusCode.NORMAL));
}
finally
{
client.close();
}
}
/**
* Test fast fail (bug #410537)
*/
@Test
public void testFastFail() throws Exception
{
BlockheadClient client = new BlockheadClient(server.getServerUri());
client.setProtocols("fastfail");
client.setTimeout(TimeUnit.SECONDS,1);
try
{
try (StacklessLogging scope = new StacklessLogging(EventDriver.class))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
IncomingFramesCapture capture = client.readFrames(1,TimeUnit.SECONDS,1);
WebSocketFrame frame = capture.getFrames().poll();
Assert.assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.CLOSE));
CloseInfo close = new CloseInfo(frame);
Assert.assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.SERVER_ERROR));
client.write(close.asFrame()); // respond with close
Assert.assertThat("Fast Fail Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
Assert.assertThat("Fast Fail.statusCode",closeSocket.closeStatusCode,is(StatusCode.SERVER_ERROR));
Assert.assertThat("Fast Fail.errors",closeSocket.errors.size(),is(1));
}
}
finally
{