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

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


The following commit(s) were added to refs/heads/10.1.x by this push:
     new d505277094 Close NIO2 connections gracefully
d505277094 is described below

commit d505277094cfcf088a551cdd9608e95e81bdad75
Author: Mark Thomas <[email protected]>
AuthorDate: Sat Nov 7 22:18:43 2026 +0000

    Close NIO2 connections gracefully
    
    On Windows, closing an NIO2 connection with a read pending aborted the
    connection so the client saw a reset rather than the end of the stream.
    Shut down output before closing the channel.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 java/org/apache/tomcat/util/net/Nio2Channel.java   | 24 +++++++++++++++++++++-
 .../apache/tomcat/util/net/SecureNio2Channel.java  |  2 +-
 webapps/docs/changelog.xml                         |  6 ++++++
 3 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/Nio2Channel.java 
b/java/org/apache/tomcat/util/net/Nio2Channel.java
index 94d4fa2a4e..75f8d57587 100644
--- a/java/org/apache/tomcat/util/net/Nio2Channel.java
+++ b/java/org/apache/tomcat/util/net/Nio2Channel.java
@@ -22,6 +22,7 @@ import java.nio.channels.AsynchronousByteChannel;
 import java.nio.channels.AsynchronousSocketChannel;
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.CompletionHandler;
+import java.nio.channels.NotYetConnectedException;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -77,7 +78,28 @@ public class Nio2Channel implements AsynchronousByteChannel {
      */
     @Override
     public void close() throws IOException {
-        sc.close();
+        closeChannel();
+    }
+
+
+    /**
+     * Close the underlying channel, sending a FIN to the client before the 
channel is closed. On some platforms
+     * (Windows) closing an asynchronous channel with a read pending aborts 
the connection (the client sees a reset
+     * rather than the end of the stream) and any data not yet read by the 
client may be lost. Shutting down output first
+     * ensures that the client sees a graceful close.
+     *
+     * @throws IOException If an I/O error occurs
+     */
+    protected void closeChannel() throws IOException {
+        try {
+            if (sc.isOpen()) {
+                sc.shutdownOutput();
+            }
+        } catch (IOException | NotYetConnectedException ignore) {
+            // Ignore. The channel is about to be closed and the graceful 
close is on a best efforts basis.
+        } finally {
+            sc.close();
+        }
     }
 
 
diff --git a/java/org/apache/tomcat/util/net/SecureNio2Channel.java 
b/java/org/apache/tomcat/util/net/SecureNio2Channel.java
index 3a04470018..b39567c5f6 100644
--- a/java/org/apache/tomcat/util/net/SecureNio2Channel.java
+++ b/java/org/apache/tomcat/util/net/SecureNio2Channel.java
@@ -720,7 +720,7 @@ public class SecureNio2Channel extends Nio2Channel {
         } finally {
             if (force || closed) {
                 closed = true;
-                sc.close();
+                closeChannel();
             }
         }
     }
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index be23a83b3c..5473421bf7 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -583,6 +583,12 @@
         When validating HTTP/2 frames, make sure more serious errors take
         priority over less serious errors. (markt)
       </fix>
+      <fix>
+        Ensure that NIO2 connections are closed gracefully. On Windows, closing
+        an NIO2 connection with a read pending previously aborted the
+        connection, so the client saw a connection reset rather than the end of
+        the stream and could lose response data it had not yet read. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">


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

Reply via email to