diff options
3 files changed, 106 insertions, 25 deletions
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java index d217937d47..5461df4188 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/events/EventDriver.java @@ -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()) diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java index e274c963ee..66140c8073 100644 --- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java +++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/ServletWebSocketRequest.java @@ -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; } diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java index 00c001bcd2..aafdea8946 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/WebSocketCloseTest.java @@ -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,6 +54,30 @@ import org.junit.Test; */ public class WebSocketCloseTest { + static class AbstractCloseSocket extends WebSocketAdapter + { + public CountDownLatch closeLatch = new CountDownLatch(1); + public String closeReason = null; + public int closeStatusCode = -1; + public List<Throwable> errors = new ArrayList<>(); + + @Override + public void onWebSocketClose(int statusCode, String reason) + { + LOG.debug("onWebSocketClose({}, {})",statusCode,reason); + this.closeStatusCode = statusCode; + this.closeReason = reason; + closeLatch.countDown(); + } + + @Override + public void onWebSocketError(Throwable cause) + { + errors.add(cause); + } + + } + @SuppressWarnings("serial") public static class CloseServlet extends WebSocketServlet implements WebSocketCreator { @@ -66,28 +92,25 @@ public class WebSocketCloseTest { if (req.hasSubProtocol("fastclose")) { - fastcloseSocket = new FastCloseSocket(); - return fastcloseSocket; + closeSocket = new FastCloseSocket(); + return closeSocket; + } + + if (req.hasSubProtocol("fastfail")) + { + closeSocket = new FastFailSocket(); + return closeSocket; } return new RFCSocket(); } } - public static class FastCloseSocket extends WebSocketAdapter + /** + * On Connect, close socket + */ + public static class FastCloseSocket extends AbstractCloseSocket { - public CountDownLatch closeLatch = new CountDownLatch(1); - public String closeReason = null; - public int closeStatusCode = -1; - public List<Throwable> errors = new ArrayList<>(); - - @Override - public void onWebSocketClose(int statusCode, String reason) - { - LOG.debug("onWebSocketClose({}, {})",statusCode,reason); - this.closeStatusCode = statusCode; - this.closeReason = reason; - closeLatch.countDown(); - } + 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 { |