This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new f69ab9e9a6 Follow-up to 06da787736
f69ab9e9a6 is described below

commit f69ab9e9a66f197af59e2a1096a6907a131c38ee
Author: Mark Thomas <[email protected]>
AuthorDate: Fri Aug 14 11:58:34 2026 +0100

    Follow-up to 06da787736
---
 java/org/apache/tomcat/websocket/WsFrameBase.java  |  9 ++--
 .../tomcat/websocket/WsRemoteEndpointImplBase.java |  3 +-
 test/org/apache/tomcat/websocket/TestWsFrame.java  | 63 +++++++++++++++-------
 webapps/docs/changelog.xml                         |  9 ++--
 4 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/java/org/apache/tomcat/websocket/WsFrameBase.java 
b/java/org/apache/tomcat/websocket/WsFrameBase.java
index a3d3633df6..4077c32ae8 100644
--- a/java/org/apache/tomcat/websocket/WsFrameBase.java
+++ b/java/org/apache/tomcat/websocket/WsFrameBase.java
@@ -16,6 +16,7 @@
  */
 package org.apache.tomcat.websocket;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
@@ -379,10 +380,12 @@ public abstract class WsFrameBase {
             if (wsSession.isOpen()) {
                 try {
                     wsSession.getBasicRemote().sendPong(controlBufferBinary);
-                } catch (IllegalStateException ise) {
-                    // The close process may have started after isOpen() was 
checked.
+                } catch (IllegalStateException | EOFException e) {
+                    // IllegalStateException - wsSession started to close 
while pong was being prepared
+                    // EOFException - wsSession closed while pong was being 
prepared
+                    // Either way, ignore the error
                     if (!wsSession.isClosing()) {
-                        throw ise;
+                        throw e;
                     }
                 }
             }
diff --git a/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java 
b/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
index 9d5f4d39c0..deb80519fd 100644
--- a/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
+++ b/java/org/apache/tomcat/websocket/WsRemoteEndpointImplBase.java
@@ -16,6 +16,7 @@
  */
 package org.apache.tomcat.websocket;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.Writer;
@@ -548,7 +549,7 @@ public abstract class WsRemoteEndpointImplBase implements 
RemoteEndpoint {
 
     void writeMessagePart(MessagePart mp) throws IOException {
         if (closed) {
-            throw new IOException(sm.getString("wsRemoteEndpoint.closed"));
+            throw new EOFException(sm.getString("wsRemoteEndpoint.closed"));
         }
 
         if (Constants.INTERNAL_OPCODE_FLUSH == mp.getOpCode()) {
diff --git a/test/org/apache/tomcat/websocket/TestWsFrame.java 
b/test/org/apache/tomcat/websocket/TestWsFrame.java
index 2096fbbf76..503d384728 100644
--- a/test/org/apache/tomcat/websocket/TestWsFrame.java
+++ b/test/org/apache/tomcat/websocket/TestWsFrame.java
@@ -16,17 +16,18 @@
  */
 package org.apache.tomcat.websocket;
 
+import java.io.EOFException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 
 import jakarta.websocket.RemoteEndpoint;
 
-import org.easymock.EasyMock;
 import org.junit.Assert;
 import org.junit.Test;
 
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.easymock.EasyMock;
 
 public class TestWsFrame {
 
@@ -69,39 +70,61 @@ public class TestWsFrame {
 
     @Test
     public void testAutomaticPongAfterCloseStarted() throws Exception {
-        WsSession wsSession = EasyMock.createNiceMock(WsSession.class);
-        RemoteEndpoint.Basic basicRemote = 
EasyMock.createMock(RemoteEndpoint.Basic.class);
-        EasyMock.expect(wsSession.isOpen()).andReturn(Boolean.TRUE);
-        EasyMock.expect(wsSession.getBasicRemote()).andReturn(basicRemote);
-        basicRemote.sendPong(EasyMock.anyObject(ByteBuffer.class));
-        EasyMock.expectLastCall().andThrow(new IllegalStateException());
-        EasyMock.expect(wsSession.isClosing()).andReturn(Boolean.TRUE);
-        EasyMock.replay(wsSession, basicRemote);
+        doTestAutomaticPongFailure(new IllegalStateException(), true, true);
+    }
 
-        TestFrame frame = new TestFrame(wsSession);
-        frame.processPing();
 
-        EasyMock.verify(wsSession, basicRemote);
+    @Test
+    public void testAutomaticPongISEWhileOpen() throws Exception {
+        doTestAutomaticPongFailure(new IllegalStateException(), false, false);
+    }
+
+
+    @Test
+    public void testAutomaticPongAfterCloseCompleted() throws Exception {
+        doTestAutomaticPongFailure(new EOFException(), true, true);
     }
 
 
     @Test
-    public void testAutomaticPongFailureWhileOpen() throws Exception {
+    public void testAutomaticPongEOFWhileOpen() throws Exception {
+        doTestAutomaticPongFailure(new EOFException(), false, false);
+    }
+
+
+    @Test
+    public void testAutomaticPongIOEAfterCloseStarted() throws Exception {
+        doTestAutomaticPongFailure(new IOException(), true, false);
+    }
+
+
+    @Test
+    public void testAutomaticPongIOEWhileOpen() throws Exception {
+        doTestAutomaticPongFailure(new IOException(), false, false);
+    }
+
+
+    private static void doTestAutomaticPongFailure(Exception failure, boolean 
closing, boolean swallowed)
+            throws Exception {
         WsSession wsSession = EasyMock.createNiceMock(WsSession.class);
         RemoteEndpoint.Basic basicRemote = 
EasyMock.createMock(RemoteEndpoint.Basic.class);
-        EasyMock.expect(wsSession.isOpen()).andReturn(Boolean.TRUE);
+        
EasyMock.expect(Boolean.valueOf(wsSession.isOpen())).andReturn(Boolean.TRUE);
         EasyMock.expect(wsSession.getBasicRemote()).andReturn(basicRemote);
         basicRemote.sendPong(EasyMock.anyObject(ByteBuffer.class));
-        EasyMock.expectLastCall().andThrow(new IllegalStateException());
-        EasyMock.expect(wsSession.isClosing()).andReturn(Boolean.FALSE);
+        EasyMock.expectLastCall().andThrow(failure);
+        
EasyMock.expect(Boolean.valueOf(wsSession.isClosing())).andStubReturn(Boolean.valueOf(closing));
         EasyMock.replay(wsSession, basicRemote);
 
         TestFrame frame = new TestFrame(wsSession);
-        try {
+        if (swallowed) {
             frame.processPing();
-            Assert.fail();
-        } catch (IllegalStateException expected) {
-            // Expected.
+        } else {
+            try {
+                frame.processPing();
+                Assert.fail();
+            } catch (Exception actual) {
+                Assert.assertSame(failure, actual);
+            }
         }
 
         EasyMock.verify(wsSession, basicRemote);
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index bb64015f0e..6d8e0727aa 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -336,10 +336,6 @@
   </subsection>
   <subsection name="WebSocket">
     <changelog>
-      <fix>
-        Fix an exception when an automatic Pong response races with the
-        closing of the WebSocket session. (moritzfl)
-      </fix>
       <update>
         Update Tomcat's WebSocket support to version 2.3 of the Jakarta
         WebSocket API. (markt)
@@ -367,6 +363,11 @@
         <code>Writer</code> and <code>OutputStream</code>. (markt)
       </fix>
       <!-- Entries for backport and removal before 12.0.0-M1 below this line 
-->
+      <fix>
+        Fix an exception when an automatic Pong response races with the
+        closing of the WebSocket session. Pull request <pr>1041</pr> provided 
by
+        moritzfl. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Web applications">


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to