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

commit 774d8547834ad1e3309030d6a7d3470af269ae72
Author: Mark Thomas <[email protected]>
AuthorDate: Tue Jun 2 21:15:55 2026 +0100

    Follow-up to EOF handling fixes
---
 java/org/apache/tomcat/util/buf/B2CConverter.java | 93 +++++++++++++++--------
 java/org/apache/tomcat/util/buf/ByteChunk.java    |  7 ++
 2 files changed, 68 insertions(+), 32 deletions(-)

diff --git a/java/org/apache/tomcat/util/buf/B2CConverter.java 
b/java/org/apache/tomcat/util/buf/B2CConverter.java
index e40f020606..ce3c761bef 100644
--- a/java/org/apache/tomcat/util/buf/B2CConverter.java
+++ b/java/org/apache/tomcat/util/buf/B2CConverter.java
@@ -24,6 +24,7 @@ import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
 import java.nio.charset.CoderResult;
 import java.nio.charset.CodingErrorAction;
+import java.nio.charset.MalformedInputException;
 import java.util.Locale;
 
 import org.apache.juli.logging.Log;
@@ -150,31 +151,42 @@ public class B2CConverter {
         CoderResult result;
         // Parse leftover if any are present
         if (leftovers.position() > 0) {
-            int pos = cb.position();
-            // Loop until one char is decoded or there is a decoder error
             do {
+                // Previous call may have triggered overflow in cb so try 
conversion first
+                leftovers.flip();
+                result = decoder.decode(leftovers, cb, false);
+                if (result.isOverflow()) {
+                    leftovers.position(leftovers.limit());
+                    leftovers.limit(leftovers.array().length);
+                    return;
+                } else if (result.isError()) {
+                    result.throwException();
+                } else if (leftovers.remaining() == 0) {
+                    // leftovers have been converted
+                    leftovers.clear();
+                    bb.position(bc.getStart());
+                    break;
+                } else {
+                    // leftovers is incomplete
+                    leftovers.position(leftovers.limit());
+                    leftovers.limit(leftovers.array().length);
+                }
+                // Try
                 int b = bc.subtract();
                 if (b < 0) {
-                    leftovers.flip();
-                    result = decoder.decode(leftovers, cb, endOfInput);
-                    break;
+                    if (endOfInput) {
+                        throw new 
MalformedInputException(leftovers.position());
+                    }
+                    // Underflow - need more bytes to complete the leftover 
character
+                    return;
                 }
                 leftovers.put((byte) b);
-                leftovers.flip();
-                result = decoder.decode(leftovers, cb, endOfInput);
-                leftovers.position(leftovers.limit());
-                leftovers.limit(leftovers.array().length);
-            } while (result.isUnderflow() && (cb.position() == pos));
-            if (result.isError() || result.isMalformed()) {
-                result.throwException();
-            }
-            bb.position(bc.getStart());
-            leftovers.position(0);
+            } while (true);
         }
         // Do the decoding and get the results into the byte chunk and the char
         // chunk
         result = decoder.decode(bb, cb, endOfInput);
-        if (result.isError() || result.isMalformed()) {
+        if (result.isError()) {
             result.throwException();
         } else if (result.isOverflow()) {
             // Propagate current positions to the byte chunk and char chunk, if
@@ -225,33 +237,50 @@ public class B2CConverter {
         CoderResult result;
         // Parse leftover if any are present
         if (leftovers.position() > 0) {
-            int pos = cb.position();
-            // Loop until one char is decoded or there is a decoder error
             do {
+                // Previous call may have triggered overflow in cb so try 
conversion first
+                leftovers.flip();
+                result = decoder.decode(leftovers, cb, false);
+                if (result.isOverflow()) {
+                    leftovers.position(leftovers.limit());
+                    leftovers.limit(leftovers.array().length);
+                    return;
+                } else if (result.isError()) {
+                    result.throwException();
+                } else if (leftovers.remaining() == 0) {
+                    // leftovers have been converted
+                    leftovers.clear();
+                    bb.limit(bc.limit());
+                    bb.position(bc.position());
+                    break;
+                } else {
+                    // leftovers is incomplete
+                    leftovers.position(leftovers.limit());
+                    leftovers.limit(leftovers.array().length);
+                }
+                // Try
                 if (bc.remaining() == 0) {
                     int n = ic.realReadBytes();
+                    if (ic.getByteBuffer() != bc) {
+                        // realReadBytes changed the ByteBuffer used by the 
caller
+                        bc = ic.getByteBuffer();
+                        bb = ByteBuffer.wrap(bc.array(), bc.arrayOffset() + 
bc.position(), bc.remaining());
+                    }
                     if (n < 0) {
-                        leftovers.flip();
-                        result = decoder.decode(leftovers, cb, endOfInput);
-                        break;
+                        if (endOfInput) {
+                            throw new 
MalformedInputException(leftovers.position());
+                        }
+                        // Underflow - need more bytes to complete the 
leftover character
+                        return;
                     }
                 }
                 leftovers.put(bc.get());
-                leftovers.flip();
-                result = decoder.decode(leftovers, cb, endOfInput);
-                leftovers.position(leftovers.limit());
-                leftovers.limit(leftovers.array().length);
-            } while (result.isUnderflow() && (cb.position() == pos));
-            if (result.isError() || result.isMalformed()) {
-                result.throwException();
-            }
-            bb.position(bc.position());
-            leftovers.position(0);
+            } while (true);
         }
         // Do the decoding and get the results into the byte chunk and the char
         // chunk
         result = decoder.decode(bb, cb, endOfInput);
-        if (result.isError() || result.isMalformed()) {
+        if (result.isError()) {
             result.throwException();
         } else if (result.isOverflow()) {
             // Propagate current positions to the byte chunk and char chunk, if
diff --git a/java/org/apache/tomcat/util/buf/ByteChunk.java 
b/java/org/apache/tomcat/util/buf/ByteChunk.java
index 3897a1755e..012ae264e7 100644
--- a/java/org/apache/tomcat/util/buf/ByteChunk.java
+++ b/java/org/apache/tomcat/util/buf/ByteChunk.java
@@ -68,6 +68,13 @@ public final class ByteChunk extends AbstractChunk {
          * @throws IOException If an I/O error occurs during reading
          */
         int realReadBytes() throws IOException;
+
+        /**
+         * Obtain the ByteBuffer this channel is targeting.
+         *
+         * @return the ByteBuffer this channel is targeting
+         */
+        ByteBuffer getByteBuffer();
     }
 
     /**


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

Reply via email to