From 8a8bc4e45ba185b215d4988895b76bda5fb12aa0 Mon Sep 17 00:00:00 2001 From: Lachlan Roberts Date: Fri, 29 Jul 2022 16:45:46 +1000 Subject: [PATCH] Issue #8353 - do not attempt to send pong frame after output closed Signed-off-by: Lachlan Roberts --- .../common/JavaxWebSocketFrameHandler.java | 57 ++++++++------- .../common/JettyWebSocketFrameHandler.java | 73 ++++++++++--------- 2 files changed, 71 insertions(+), 59 deletions(-) diff --git a/jetty-websocket/websocket-javax-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java b/jetty-websocket/websocket-javax-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java index e93c08bd891..32b9a10a7b1 100644 --- a/jetty-websocket/websocket-javax-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java +++ b/jetty-websocket/websocket-javax-common/src/main/java/org/eclipse/jetty/websocket/javax/common/JavaxWebSocketFrameHandler.java @@ -13,31 +13,10 @@ package org.eclipse.jetty.websocket.javax.common; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodType; -import java.nio.ByteBuffer; -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.stream.Collectors; -import javax.websocket.ClientEndpointConfig; -import javax.websocket.CloseReason; -import javax.websocket.Decoder; -import javax.websocket.EndpointConfig; -import javax.websocket.MessageHandler; -import javax.websocket.PongMessage; -import javax.websocket.server.ServerEndpointConfig; - import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.thread.AutoLock; -import org.eclipse.jetty.websocket.core.CloseStatus; -import org.eclipse.jetty.websocket.core.CoreSession; -import org.eclipse.jetty.websocket.core.Frame; -import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.OpCode; +import org.eclipse.jetty.websocket.core.*; import org.eclipse.jetty.websocket.core.exception.ProtocolException; import org.eclipse.jetty.websocket.core.exception.WebSocketException; import org.eclipse.jetty.websocket.core.internal.messages.MessageSink; @@ -54,6 +33,18 @@ import org.eclipse.jetty.websocket.javax.common.messages.DecodedTextStreamMessag import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.websocket.*; +import javax.websocket.server.ServerEndpointConfig; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + public class JavaxWebSocketFrameHandler implements FrameHandler { private final AutoLock lock = new AutoLock(); @@ -596,10 +587,24 @@ public class JavaxWebSocketFrameHandler implements FrameHandler public void onPing(Frame frame, Callback callback) { - ByteBuffer payload = BufferUtil.copy(frame.getPayload()); - coreSession.sendFrame(new Frame(OpCode.PONG).setPayload(payload), Callback.NOOP, false); - callback.succeeded(); - coreSession.demand(1); + if (coreSession.isOutputOpen()) + { + ByteBuffer payload = BufferUtil.copy(frame.getPayload()); + coreSession.sendFrame(new Frame(OpCode.PONG).setPayload(payload), Callback.from(() -> + { + callback.succeeded(); + coreSession.demand(1); + }, t -> + { + callback.failed(t); + coreSession.demand(1); + }), false); + } + else + { + callback.succeeded(); + coreSession.demand(1); + } } public void onPong(Frame frame, Callback callback) diff --git a/jetty-websocket/websocket-jetty-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java b/jetty-websocket/websocket-jetty-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java index b0cd8ecd8e5..f8e636a325c 100644 --- a/jetty-websocket/websocket-jetty-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java +++ b/jetty-websocket/websocket-jetty-common/src/main/java/org/eclipse/jetty/websocket/common/JettyWebSocketFrameHandler.java @@ -13,39 +13,25 @@ package org.eclipse.jetty.websocket.common; +import org.eclipse.jetty.util.BufferUtil; +import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.thread.AutoLock; +import org.eclipse.jetty.websocket.api.*; +import org.eclipse.jetty.websocket.core.CloseStatus; +import org.eclipse.jetty.websocket.core.Frame; +import org.eclipse.jetty.websocket.core.*; +import org.eclipse.jetty.websocket.core.exception.*; +import org.eclipse.jetty.websocket.core.internal.messages.MessageSink; +import org.eclipse.jetty.websocket.core.internal.util.InvokerUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.lang.invoke.MethodHandle; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicBoolean; -import org.eclipse.jetty.util.BufferUtil; -import org.eclipse.jetty.util.Callback; -import org.eclipse.jetty.util.thread.AutoLock; -import org.eclipse.jetty.websocket.api.BatchMode; -import org.eclipse.jetty.websocket.api.UpgradeRequest; -import org.eclipse.jetty.websocket.api.UpgradeResponse; -import org.eclipse.jetty.websocket.api.WebSocketContainer; -import org.eclipse.jetty.websocket.api.WriteCallback; -import org.eclipse.jetty.websocket.core.CloseStatus; -import org.eclipse.jetty.websocket.core.Configuration; -import org.eclipse.jetty.websocket.core.CoreSession; -import org.eclipse.jetty.websocket.core.Frame; -import org.eclipse.jetty.websocket.core.FrameHandler; -import org.eclipse.jetty.websocket.core.OpCode; -import org.eclipse.jetty.websocket.core.exception.BadPayloadException; -import org.eclipse.jetty.websocket.core.exception.CloseException; -import org.eclipse.jetty.websocket.core.exception.InvalidSignatureException; -import org.eclipse.jetty.websocket.core.exception.MessageTooLargeException; -import org.eclipse.jetty.websocket.core.exception.ProtocolException; -import org.eclipse.jetty.websocket.core.exception.UpgradeException; -import org.eclipse.jetty.websocket.core.exception.WebSocketException; -import org.eclipse.jetty.websocket.core.exception.WebSocketTimeoutException; -import org.eclipse.jetty.websocket.core.internal.messages.MessageSink; -import org.eclipse.jetty.websocket.core.internal.util.InvokerUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - public class JettyWebSocketFrameHandler implements FrameHandler { private enum SuspendState @@ -365,16 +351,37 @@ public class JettyWebSocketFrameHandler implements FrameHandler { throw new WebSocketException(endpointInstance.getClass().getSimpleName() + " PING method error: " + cause.getMessage(), cause); } + + callback.succeeded(); + demand(); } else { - // Automatically respond - ByteBuffer payload = BufferUtil.copy(frame.getPayload()); - getSession().getRemote().sendPong(payload, WriteCallback.NOOP); - } + // Automatically respond if output is open. + if (coreSession.isOutputOpen()) + { + ByteBuffer payload = BufferUtil.copy(frame.getPayload()); + getSession().getRemote().sendPong(payload, new WriteCallback() + { + @Override + public void writeSuccess() { + callback.succeeded(); + demand(); + } - callback.succeeded(); - demand(); + @Override + public void writeFailed(Throwable x) { + callback.failed(x); + demand(); + } + }); + } + else + { + callback.succeeded(); + demand(); + } + } } private void onPongFrame(Frame frame, Callback callback)