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

rmaucher 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 9b530379ec Fix possible corruption with HTTP/2 and large uploads
9b530379ec is described below

commit 9b530379eca4bc4d0d33162884916af888d96951
Author: remm <[email protected]>
AuthorDate: Sun Sep 27 09:29:02 2026 +0200

    Fix possible corruption with HTTP/2 and large uploads
    
    PR#1073
    Submitted by Tim Burke.
---
 .../tomcat/util/net/SocketBufferHandler.java       | 14 +++++++---
 .../tomcat/util/net/TestSocketBufferHandler.java   | 30 ++++++++++++++++++++++
 webapps/docs/changelog.xml                         |  4 +++
 3 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/java/org/apache/tomcat/util/net/SocketBufferHandler.java 
b/java/org/apache/tomcat/util/net/SocketBufferHandler.java
index fc6888b532..be54610c42 100644
--- a/java/org/apache/tomcat/util/net/SocketBufferHandler.java
+++ b/java/org/apache/tomcat/util/net/SocketBufferHandler.java
@@ -148,8 +148,11 @@ public class SocketBufferHandler {
                 if ((readBuffer.position() + bytesReturned) > 
readBuffer.capacity()) {
                     throw new BufferOverflowException();
                 } else {
-                    // Move the bytes up to make space for the returned data
-                    for (int i = 0; i < readBuffer.position(); i++) {
+                    // Move the bytes up to make space for the returned data.
+                    // Copy backwards so that, when the source and destination
+                    // regions overlap, the source bytes are not overwritten
+                    // before they have been read.
+                    for (int i = readBuffer.position() - 1; i >= 0; i--) {
                         readBuffer.put(i + bytesReturned, readBuffer.get(i));
                     }
                     // Insert the bytes returned
@@ -166,10 +169,13 @@ public class SocketBufferHandler {
                     if ((readBuffer.capacity() - readBuffer.limit()) < 
shiftRequired) {
                         throw new BufferOverflowException();
                     }
-                    // Move the bytes up to make space for the returned data
+                    // Move the bytes up to make space for the returned data.
+                    // Copy backwards so that, when the source and destination
+                    // regions overlap, the source bytes are not overwritten
+                    // before they have been read.
                     int oldLimit = readBuffer.limit();
                     readBuffer.limit(oldLimit + shiftRequired);
-                    for (int i = readBuffer.position(); i < oldLimit; i++) {
+                    for (int i = oldLimit - 1; i >= readBuffer.position(); 
i--) {
                         readBuffer.put(i + shiftRequired, readBuffer.get(i));
                     }
                 } else {
diff --git a/test/org/apache/tomcat/util/net/TestSocketBufferHandler.java 
b/test/org/apache/tomcat/util/net/TestSocketBufferHandler.java
index 048c182a51..be891cb494 100644
--- a/test/org/apache/tomcat/util/net/TestSocketBufferHandler.java
+++ b/test/org/apache/tomcat/util/net/TestSocketBufferHandler.java
@@ -124,6 +124,36 @@ public class TestSocketBufferHandler {
     }
 
 
+    @Test
+    public void testReturnWhenWritableOverlap() {
+        SocketBufferHandler sbh = new SocketBufferHandler(16, 16, direct);
+
+        sbh.configureReadBufferForWrite();
+        sbh.getReadBuffer().put(getBytes("ABCDEFGH"));
+
+        sbh.unReadReadBuffer(ByteBuffer.wrap(getBytes("XY")));
+
+        validate(sbh, "XYABCDEFGH");
+    }
+
+
+    @Test
+    public void testReturnWhenReadableOverlap() {
+        SocketBufferHandler sbh = new SocketBufferHandler(16, 16, direct);
+
+        sbh.configureReadBufferForWrite();
+        sbh.getReadBuffer().put(getBytes("ABCDEFGH"));
+        sbh.configureReadBufferForRead();
+        for (int i = 0; i < 2; i++) {
+            sbh.getReadBuffer().get();
+        }
+
+        sbh.unReadReadBuffer(ByteBuffer.wrap(getBytes("123456")));
+
+        validate(sbh, "123456CDEFGH");
+    }
+
+
     private void validate(SocketBufferHandler sbh, String expected) {
         sbh.configureReadBufferForRead();
         for (byte b : getBytes(expected)) {
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3155b936a5..cd3ca7d51b 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -326,6 +326,10 @@
         header using the <code>altService</code> attribute of the
         <code>Connector</code> element. (remm)
       </update>
+      <fix>
+        <pr>1073</pr>: Fix possible corruption when using HTTP/2 and async IO
+        on uploads. Submitted by Tim Burke. (remm)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">


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

Reply via email to