diff --git a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java index 33fa9b493a2..879c9e540fe 100644 --- a/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java +++ b/jetty-websocket/javax-websocket-client-impl/src/test/java/org/eclipse/jetty/websocket/jsr356/JsrSessionTest.java @@ -33,7 +33,6 @@ import javax.websocket.MessageHandler; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.websocket.api.FrameCallback; import org.eclipse.jetty.websocket.api.WebSocketPolicy; -import org.eclipse.jetty.websocket.common.FrameCallbackAdapter; import org.eclipse.jetty.websocket.common.frames.BinaryFrame; import org.eclipse.jetty.websocket.common.frames.ContinuationFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; @@ -128,7 +127,7 @@ public class JsrSessionTest session.open(); - FrameCallback callback = new FrameCallbackAdapter(); + FrameCallback callback = new FrameCallback.Adapter(); session.incomingFrame(new TextFrame().setPayload("G'day").setFin(true), callback); session.incomingFrame(new TextFrame().setPayload("Hello World").setFin(true), callback); @@ -159,7 +158,7 @@ public class JsrSessionTest session.open(); - FrameCallback callback = new FrameCallbackAdapter(); + FrameCallback callback = new FrameCallback.Adapter(); session.incomingFrame(new BinaryFrame().setPayload("G'day").setFin(false), callback); session.incomingFrame(new ContinuationFrame().setPayload(" World").setFin(true), callback); diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java index 3acac0adc42..6a00b706012 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/Parser.java @@ -566,6 +566,7 @@ public class Parser int bytesAvailable = buffer.remaining(); int windowBytes = Math.min(bytesAvailable, bytesExpected); int limit = buffer.limit(); + assert(buffer.position() + windowBytes < buffer.capacity()); buffer.limit(buffer.position() + windowBytes); ByteBuffer window = buffer.slice(); buffer.limit(limit); diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java index 4d285637372..d5ee381c988 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/WebSocketSession.java @@ -20,6 +20,8 @@ package org.eclipse.jetty.websocket.common; import java.io.IOException; import java.net.InetSocketAddress; +import java.net.SocketException; +import java.net.SocketTimeoutException; import java.net.URI; import java.nio.ByteBuffer; import java.util.HashMap; @@ -30,6 +32,7 @@ import java.util.Objects; import java.util.ServiceLoader; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicReference; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.Connection; @@ -99,7 +102,8 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem private UpgradeRequest upgradeRequest; private UpgradeResponse upgradeResponse; private CompletableFuture openFuture; - + private AtomicReference pendingError = new AtomicReference<>(); + public WebSocketSession(WebSocketContainerScope containerScope, URI requestURI, Object endpoint, LogicalConnection connection) { Objects.requireNonNull(containerScope, "Container Scope cannot be null"); @@ -181,6 +185,14 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem super.doStart(); connection.setMaxIdleTimeout(this.policy.getIdleTimeout()); + + Throwable fastFail; + synchronized (pendingError) + { + fastFail = pendingError.get(); + } + if(fastFail != null) + onError(fastFail); } @Override @@ -519,6 +531,16 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem @Override public void onError(Throwable t) { + synchronized (pendingError) + { + if (!endpointFunctions.isStarted()) + { + // this is a *really* fast fail, before the Session has even started. + pendingError.compareAndSet(null, t); + return; + } + } + Throwable cause = getInvokedCause(t); if (openFuture != null && !openFuture.isDone()) @@ -531,10 +553,18 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Rem { close(StatusCode.BAD_PAYLOAD, cause.getMessage()); } + else if (cause instanceof SocketTimeoutException) + { + close(StatusCode.SHUTDOWN, cause.getMessage()); + } else if (cause instanceof IOException) { close(StatusCode.PROTOCOL, cause.getMessage()); } + else if (cause instanceof SocketException) + { + close(StatusCode.SHUTDOWN, cause.getMessage()); + } else if (cause instanceof CloseException) { CloseException ce = (CloseException) cause; diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java index 26168132808..fb7497e43cb 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/io/AbstractWebSocketConnection.java @@ -594,15 +594,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp return true; } - try - { - notifyError(new SocketTimeoutException("Timeout on Read")); - } - finally - { - // This is an Abnormal Close condition - close(StatusCode.SHUTDOWN,"Idle Timeout"); - } + notifyError(new SocketTimeoutException("Timeout on Read")); return false; } diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/FrameCallbackAdapter.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/FrameCallbackAdapter.java deleted file mode 100644 index ce280b8dfda..00000000000 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/FrameCallbackAdapter.java +++ /dev/null @@ -1,25 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -// - -package org.eclipse.jetty.websocket.common; - -import org.eclipse.jetty.websocket.api.FrameCallback; - -public class FrameCallbackAdapter extends FrameCallback.Adapter -{ -} diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java index ca5915eb526..6c5d96d8a3e 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionTool.java @@ -26,12 +26,12 @@ import java.util.Collections; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.util.TypeUtil; +import org.eclipse.jetty.websocket.api.FrameCallback; import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.extensions.Extension; import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory; import org.eclipse.jetty.websocket.api.extensions.Frame; -import org.eclipse.jetty.websocket.common.FrameCallbackAdapter; import org.eclipse.jetty.websocket.common.Parser; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.frames.TextFrame; @@ -62,7 +62,7 @@ public class ExtensionTool this.capture = new IncomingFramesCapture(); this.parser = new UnitParser(policy, frame -> { - ext.incomingFrame(frame, new FrameCallbackAdapter()); + ext.incomingFrame(frame, new FrameCallback.Adapter()); return true; }); } diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java index 85dc98efc45..859d1e68911 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/FragmentExtensionTest.java @@ -29,10 +29,10 @@ import java.util.List; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.websocket.api.BatchMode; +import org.eclipse.jetty.websocket.api.FrameCallback; import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; import org.eclipse.jetty.websocket.api.extensions.Frame; -import org.eclipse.jetty.websocket.common.FrameCallbackAdapter; import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.extensions.fragment.FragmentExtension; @@ -78,7 +78,7 @@ public class FragmentExtensionTest for (String q : quote) { Frame frame = new TextFrame().setPayload(q); - ext.incomingFrame(frame, new FrameCallbackAdapter()); + ext.incomingFrame(frame, new FrameCallback.Adapter()); } int len = quote.size(); @@ -122,7 +122,7 @@ public class FragmentExtensionTest String payload = "Are you there?"; Frame ping = new PingFrame().setPayload(payload); - ext.incomingFrame(ping, new FrameCallbackAdapter()); + ext.incomingFrame(ping, new FrameCallback.Adapter()); capture.assertFrameCount(1); capture.assertHasFrame(OpCode.PING, 1); diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java index 649d79c10b0..fcaf6fc140c 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/IdentityExtensionTest.java @@ -26,9 +26,9 @@ import java.nio.charset.StandardCharsets; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.websocket.api.BatchMode; +import org.eclipse.jetty.websocket.api.FrameCallback; import org.eclipse.jetty.websocket.api.extensions.Extension; import org.eclipse.jetty.websocket.api.extensions.Frame; -import org.eclipse.jetty.websocket.common.FrameCallbackAdapter; import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.extensions.identity.IdentityExtension; @@ -53,7 +53,7 @@ public class IdentityExtensionTest ext.setNextIncomingFrames(capture); Frame frame = new TextFrame().setPayload("hello"); - ext.incomingFrame(frame, new FrameCallbackAdapter()); + ext.incomingFrame(frame, new FrameCallback.Adapter()); capture.assertFrameCount(1); capture.assertHasFrame(OpCode.TEXT, 1); diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java index 14c49cde585..edef61f25a8 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/compress/PerMessageDeflateExtensionTest.java @@ -19,7 +19,7 @@ package org.eclipse.jetty.websocket.common.extensions.compress; import static org.hamcrest.Matchers.is; -import static org.junit.Assert.*; +import static org.junit.Assert.assertThat; import java.io.IOException; import java.nio.ByteBuffer; @@ -30,10 +30,10 @@ import java.util.List; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.websocket.api.BatchMode; +import org.eclipse.jetty.websocket.api.FrameCallback; import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig; import org.eclipse.jetty.websocket.api.extensions.Frame; -import org.eclipse.jetty.websocket.common.FrameCallbackAdapter; import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.WebSocketFrame; import org.eclipse.jetty.websocket.common.extensions.AbstractExtensionTest; @@ -246,7 +246,7 @@ public class PerMessageDeflateExtensionTest extends AbstractExtensionTest String payload = "Are you there?"; Frame ping = new PingFrame().setPayload(payload); - ext.incomingFrame(ping, new FrameCallbackAdapter()); + ext.incomingFrame(ping, new FrameCallback.Adapter()); capture.assertFrameCount(1); capture.assertHasFrame(OpCode.PING, 1); @@ -292,7 +292,7 @@ public class PerMessageDeflateExtensionTest extends AbstractExtensionTest { TextFrame frame = new TextFrame().setPayload(q); frame.setRsv1(false); // indication to extension that frame is not compressed (ie: a normal frame) - ext.incomingFrame(frame, new FrameCallbackAdapter()); + ext.incomingFrame(frame, new FrameCallback.Adapter()); } int len = quote.size(); diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java index 75566ea0bd4..ffe15458476 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadClient.java @@ -619,7 +619,7 @@ public class BlockheadClient implements OutgoingFrames, ConnectionStateListener, @Override public boolean onFrame(Frame frame) { - // TODO: do something with frame? + extensionStack.incomingFrame(frame, new FrameCallback.Adapter()); return true; } diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServerConnection.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServerConnection.java index de7ea9c4c99..bc455392f77 100644 --- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServerConnection.java +++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/test/BlockheadServerConnection.java @@ -56,7 +56,6 @@ import org.eclipse.jetty.websocket.api.extensions.IncomingFrames; import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames; import org.eclipse.jetty.websocket.common.AcceptHash; import org.eclipse.jetty.websocket.common.CloseInfo; -import org.eclipse.jetty.websocket.common.FrameCallbackAdapter; import org.eclipse.jetty.websocket.common.Generator; import org.eclipse.jetty.websocket.common.OpCode; import org.eclipse.jetty.websocket.common.Parser; @@ -103,7 +102,7 @@ public class BlockheadServerConnection implements IncomingFrames, OutgoingFrames this.bufferPool = new MappedByteBufferPool(BUFFER_SIZE); this.parser = new Parser(policy,bufferPool, frame -> { - extensionStack.incomingFrame(frame, new FrameCallbackAdapter()); + extensionStack.incomingFrame(frame, new FrameCallback.Adapter()); return true; }); this.parseCount = new AtomicInteger(0); @@ -458,7 +457,10 @@ public class BlockheadServerConnection implements IncomingFrames, OutgoingFrames readBytes += len; LOG.debug("Read {} bytes",len); BufferUtil.flipToFlush(buf,0); - parser.parse(buf); + while(buf.hasRemaining()) + { + parser.parse(buf); + } } try diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java index 57ddc79da46..739a0e5e92b 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/IdentityExtensionTest.java @@ -51,7 +51,7 @@ public class IdentityExtensionTest server.stop(); } - @Test + @Test(timeout = 10000) public void testIdentityExtension() throws Exception { BlockheadClient client = new BlockheadClient(server.getServerUri()); diff --git a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/RFCSocket.java b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/RFCSocket.java index 91029ceeb3a..18d12cff743 100644 --- a/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/RFCSocket.java +++ b/jetty-websocket/websocket-server/src/test/java/org/eclipse/jetty/websocket/server/helper/RFCSocket.java @@ -27,6 +27,7 @@ import org.eclipse.jetty.websocket.api.BatchMode; import org.eclipse.jetty.websocket.api.RemoteEndpoint; import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect; +import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError; import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage; import org.eclipse.jetty.websocket.api.annotations.WebSocket; @@ -60,7 +61,7 @@ public class RFCSocket public void onText(String message) throws IOException { LOG.debug("onText({})",message); - // Test the RFC 6455 close code 1011 that should close + // Test the RFC 6455 close code 1011 that should close. // trigger a WebSocket server terminated close. if (message.equals("CRASH")) { @@ -73,4 +74,10 @@ public class RFCSocket if (remote.getBatchMode() == BatchMode.ON) remote.flush(); } + + @OnWebSocketError + public void onError(Throwable cause) + { + LOG.warn("onError()", cause); + } }