You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2023/06/26 09:44:14 UTC

[tomcat] branch 8.5.x updated (9f55c9711c -> b2d404875d)

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

markt pushed a change to branch 8.5.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git


    from 9f55c9711c Simplify reading of request body for x-www-form-urlencoded processing
     new 04472f0d4b Add control of byte decoding errors to ByteChunk and StringCache
     new 03b5190810 Use the previous decode call in the old default for now
     new c3b02a10c2 Align with 9.0.x onwards
     new ee8af21fe1 Use correctly named method
     new b2d404875d Use consistent naming for i18n keys

The 5 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../http11/filters/SavedRequestInputFilter.java    |   2 +-
 java/org/apache/tomcat/util/buf/AbstractChunk.java |   3 +
 java/org/apache/tomcat/util/buf/B2CConverter.java  |   4 +-
 java/org/apache/tomcat/util/buf/ByteChunk.java     | 102 +++++++++++++++++++--
 java/org/apache/tomcat/util/buf/C2BConverter.java  |   4 +-
 java/org/apache/tomcat/util/buf/CharChunk.java     |  21 ++++-
 .../apache/tomcat/util/buf/LocalStrings.properties |   3 +-
 java/org/apache/tomcat/util/buf/StringCache.java   |  66 +++++++++++--
 java/org/apache/tomcat/util/buf/UDecoder.java      |   2 +-
 test/org/apache/jasper/compiler/TestGenerator.java |   3 +-
 .../apache/tomcat/util/buf/TestStringCache.java    | 100 ++++++++++++++++++++
 11 files changed, 281 insertions(+), 29 deletions(-)
 create mode 100644 test/org/apache/tomcat/util/buf/TestStringCache.java


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 03/05: Align with 9.0.x onwards

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit c3b02a10c2a984553647b2fea38f2b7364a86933
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Jun 26 10:39:02 2023 +0100

    Align with 9.0.x onwards
---
 java/org/apache/tomcat/util/buf/AbstractChunk.java |  3 ++
 java/org/apache/tomcat/util/buf/ByteChunk.java     | 48 +++++++++++++++++++---
 java/org/apache/tomcat/util/buf/CharChunk.java     | 21 +++++++++-
 3 files changed, 65 insertions(+), 7 deletions(-)

diff --git a/java/org/apache/tomcat/util/buf/AbstractChunk.java b/java/org/apache/tomcat/util/buf/AbstractChunk.java
index 7bd7001181..3e06362f5f 100644
--- a/java/org/apache/tomcat/util/buf/AbstractChunk.java
+++ b/java/org/apache/tomcat/util/buf/AbstractChunk.java
@@ -18,12 +18,15 @@ package org.apache.tomcat.util.buf;
 
 import java.io.Serializable;
 
+import org.apache.tomcat.util.res.StringManager;
+
 /**
  * Base class for the *Chunk implementation to reduce duplication.
  */
 public abstract class AbstractChunk implements Cloneable, Serializable {
 
     private static final long serialVersionUID = 1L;
+    protected static final StringManager sm = StringManager.getManager(AbstractChunk.class);
 
     /*
      * JVMs may limit the maximum array size to slightly less than Integer.MAX_VALUE. On markt's desktop the limit is
diff --git a/java/org/apache/tomcat/util/buf/ByteChunk.java b/java/org/apache/tomcat/util/buf/ByteChunk.java
index 58b6a57794..1002d2fe49 100644
--- a/java/org/apache/tomcat/util/buf/ByteChunk.java
+++ b/java/org/apache/tomcat/util/buf/ByteChunk.java
@@ -26,8 +26,6 @@ import java.nio.charset.Charset;
 import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
 
-import org.apache.tomcat.util.res.StringManager;
-
 /*
  * In a server it is very important to be able to operate on
  * the original byte[] without converting everything to chars.
@@ -114,8 +112,6 @@ public final class ByteChunk extends AbstractChunk {
 
     // --------------------
 
-    private static final StringManager sm = StringManager.getManager(ByteChunk.class);
-
     /**
      * Default encoding used to convert to strings. It should be UTF8, as most standards seem to converge, but the
      * servlet API requires 8859_1, and this object is used mostly for servlets.
@@ -387,15 +383,30 @@ public final class ByteChunk extends AbstractChunk {
 
     // -------------------- Removing data from the buffer --------------------
 
+    /*
+     * @deprecated Use {@link #subtract()}. This method will be removed in Tomcat 10
+     */
+    @Deprecated
     public int substract() throws IOException {
+        return subtract();
+    }
+
+    public int subtract() throws IOException {
         if (checkEof()) {
             return -1;
         }
         return buff[start++] & 0xFF;
     }
 
-
+    /*
+     * @deprecated Use {@link #subtractB()}. This method will be removed in Tomcat 10
+     */
+    @Deprecated
     public byte substractB() throws IOException {
+        return subtractB();
+    }
+
+    public byte subtractB() throws IOException {
         if (checkEof()) {
             return -1;
         }
@@ -403,7 +414,15 @@ public final class ByteChunk extends AbstractChunk {
     }
 
 
+    /*
+     * @deprecated Use {@link #subtract(byte[],int,int)}. This method will be removed in Tomcat 10
+     */
+    @Deprecated
     public int substract(byte dest[], int off, int len) throws IOException {
+        return subtract(dest, off, len);
+    }
+
+    public int subtract(byte dest[], int off, int len) throws IOException {
         if (checkEof()) {
             return -1;
         }
@@ -427,8 +446,27 @@ public final class ByteChunk extends AbstractChunk {
      * @return an integer specifying the actual number of bytes read, or -1 if the end of the stream is reached
      *
      * @throws IOException if an input or output exception has occurred
+     *
+     * @deprecated Use {@link #subtract(ByteBuffer)}. This method will be removed in Tomcat 10
      */
+    @Deprecated
     public int substract(ByteBuffer to) throws IOException {
+        return subtract(to);
+    }
+
+
+    /**
+     * Transfers bytes from the buffer to the specified ByteBuffer. After the operation the position of the ByteBuffer
+     * will be returned to the one before the operation, the limit will be the position incremented by the number of the
+     * transfered bytes.
+     *
+     * @param to the ByteBuffer into which bytes are to be written.
+     *
+     * @return an integer specifying the actual number of bytes read, or -1 if the end of the stream is reached
+     *
+     * @throws IOException if an input or output exception has occurred
+     */
+    public int subtract(ByteBuffer to) throws IOException {
         if (checkEof()) {
             return -1;
         }
diff --git a/java/org/apache/tomcat/util/buf/CharChunk.java b/java/org/apache/tomcat/util/buf/CharChunk.java
index 9b78408c24..a79e539440 100644
--- a/java/org/apache/tomcat/util/buf/CharChunk.java
+++ b/java/org/apache/tomcat/util/buf/CharChunk.java
@@ -289,7 +289,15 @@ public final class CharChunk extends AbstractChunk implements CharSequence {
 
     // -------------------- Removing data from the buffer --------------------
 
+    /*
+     * @deprecated Use {@link #subtract()}. This method will be removed in Tomcat 10
+     */
+    @Deprecated
     public int substract() throws IOException {
+        return subtract();
+    }
+
+    public int subtract() throws IOException {
         if (checkEof()) {
             return -1;
         }
@@ -297,7 +305,15 @@ public final class CharChunk extends AbstractChunk implements CharSequence {
     }
 
 
+    /*
+     * @deprecated Use {@link #subtract(char[],int,int)}. This method will be removed in Tomcat 10
+     */
+    @Deprecated
     public int substract(char dest[], int off, int len) throws IOException {
+        return subtract(dest, off, len);
+    }
+
+    public int subtract(char dest[], int off, int len) throws IOException {
         if (checkEof()) {
             return -1;
         }
@@ -334,7 +350,8 @@ public final class CharChunk extends AbstractChunk implements CharSequence {
     public void flushBuffer() throws IOException {
         // assert out!=null
         if (out == null) {
-            throw new IOException("Buffer overflow, no sink " + getLimit() + " " + buff.length);
+            throw new IOException(
+                    sm.getString("chunk.overflow", Integer.valueOf(getLimit()), Integer.valueOf(buff.length)));
         }
         out.realWriteChars(buff, start, end - start);
         end = start;
@@ -395,7 +412,7 @@ public final class CharChunk extends AbstractChunk implements CharSequence {
 
     @Override
     public String toString() {
-        if (null == buff) {
+        if (isNull()) {
             return null;
         } else if (end - start == 0) {
             return "";


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 04/05: Use correctly named method

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit ee8af21fe19b3c49086d30c3af4d36c61b7fb853
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Jun 26 10:41:03 2023 +0100

    Use correctly named method
---
 java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java | 2 +-
 java/org/apache/tomcat/util/buf/B2CConverter.java                  | 4 ++--
 java/org/apache/tomcat/util/buf/C2BConverter.java                  | 4 ++--
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java b/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java
index ecfb8d6c13..5a79f8b4af 100644
--- a/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java
+++ b/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java
@@ -78,7 +78,7 @@ public class SavedRequestInputFilter implements InputFilter {
 
         ByteBuffer byteBuffer = handler.getByteBuffer();
         byteBuffer.position(byteBuffer.limit()).limit(byteBuffer.capacity());
-        input.substract(byteBuffer);
+        input.subtract(byteBuffer);
 
         return byteBuffer.remaining();
     }
diff --git a/java/org/apache/tomcat/util/buf/B2CConverter.java b/java/org/apache/tomcat/util/buf/B2CConverter.java
index a7db2a3385..e623a20af4 100644
--- a/java/org/apache/tomcat/util/buf/B2CConverter.java
+++ b/java/org/apache/tomcat/util/buf/B2CConverter.java
@@ -158,7 +158,7 @@ public class B2CConverter {
             int pos = cb.position();
             // Loop until one char is decoded or there is a decoder error
             do {
-                leftovers.put(bc.substractB());
+                leftovers.put(bc.subtractB());
                 leftovers.flip();
                 result = decoder.decode(leftovers, cb, endOfInput);
                 leftovers.position(leftovers.limit());
@@ -188,7 +188,7 @@ public class B2CConverter {
             if (bc.getLength() > 0) {
                 leftovers.limit(leftovers.array().length);
                 leftovers.position(bc.getLength());
-                bc.substract(leftovers.array(), 0, bc.getLength());
+                bc.subtract(leftovers.array(), 0, bc.getLength());
             }
         }
     }
diff --git a/java/org/apache/tomcat/util/buf/C2BConverter.java b/java/org/apache/tomcat/util/buf/C2BConverter.java
index 8082c09300..5cff0f3a78 100644
--- a/java/org/apache/tomcat/util/buf/C2BConverter.java
+++ b/java/org/apache/tomcat/util/buf/C2BConverter.java
@@ -88,7 +88,7 @@ public final class C2BConverter {
             int pos = bb.position();
             // Loop until one char is encoded or there is a encoder error
             do {
-                leftovers.put((char) cc.substract());
+                leftovers.put((char) cc.subtract());
                 leftovers.flip();
                 result = encoder.encode(leftovers, bb, false);
                 leftovers.position(leftovers.limit());
@@ -117,7 +117,7 @@ public final class C2BConverter {
             if (cc.getLength() > 0) {
                 leftovers.limit(leftovers.array().length);
                 leftovers.position(cc.getLength());
-                cc.substract(leftovers.array(), 0, cc.getLength());
+                cc.subtract(leftovers.array(), 0, cc.getLength());
             }
         }
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 05/05: Use consistent naming for i18n keys

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit b2d404875d5dd14d8be323fc5eca2d57c0a47919
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Jun 26 10:43:40 2023 +0100

    Use consistent naming for i18n keys
---
 java/org/apache/tomcat/util/buf/LocalStrings.properties | 3 +--
 java/org/apache/tomcat/util/buf/UDecoder.java           | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/java/org/apache/tomcat/util/buf/LocalStrings.properties b/java/org/apache/tomcat/util/buf/LocalStrings.properties
index 523cd2dc1b..52e8efd906 100644
--- a/java/org/apache/tomcat/util/buf/LocalStrings.properties
+++ b/java/org/apache/tomcat/util/buf/LocalStrings.properties
@@ -32,7 +32,6 @@ messageBytes.illegalCharacter=The Unicode character [{0}] at code point [{1}] ca
 uDecoder.eof=End of file (EOF)
 uDecoder.noSlash=The encoded slash character is not allowed
 uDecoder.urlDecode.conversionError=Failed to decode [{0}] using character set [{1}]
+uDecoder.urlDecode.iae=It is practical to %nn decode a byte array since how the %nn is encoded will vary by character set
 uDecoder.urlDecode.missingDigit=Failed to decode [{0}] because the % character must be followed by two hexadecimal digits
 uDecoder.urlDecode.uee=Unable to URL decode the specified input since the encoding [{0}] is not supported.
-
-udecoder.urlDecode.iae=It is practical to %nn decode a byte array since how the %nn is encoded will vary by character set
diff --git a/java/org/apache/tomcat/util/buf/UDecoder.java b/java/org/apache/tomcat/util/buf/UDecoder.java
index bf738ed7f8..1c46a6f566 100644
--- a/java/org/apache/tomcat/util/buf/UDecoder.java
+++ b/java/org/apache/tomcat/util/buf/UDecoder.java
@@ -443,7 +443,7 @@ public final class UDecoder {
      */
     @Deprecated
     public static String URLDecode(byte[] bytes, String enc, boolean isQuery) {
-        throw new IllegalArgumentException(sm.getString("udecoder.urlDecode.iae"));
+        throw new IllegalArgumentException(sm.getString("uDecoder.urlDecode.iae"));
     }
 
 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 01/05: Add control of byte decoding errors to ByteChunk and StringCache

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 04472f0d4ba3796f5e07ba98c38c82d9154d8e7f
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Jun 14 12:25:21 2023 +0100

    Add control of byte decoding errors to ByteChunk and StringCache
---
 java/org/apache/tomcat/util/buf/ByteChunk.java     |  49 +++++++++-
 java/org/apache/tomcat/util/buf/StringCache.java   |  66 +++++++++++---
 test/org/apache/jasper/compiler/TestGenerator.java |   3 +-
 .../apache/tomcat/util/buf/TestStringCache.java    | 100 +++++++++++++++++++++
 4 files changed, 204 insertions(+), 14 deletions(-)

diff --git a/java/org/apache/tomcat/util/buf/ByteChunk.java b/java/org/apache/tomcat/util/buf/ByteChunk.java
index a1a65cfdbc..ef02a4f86b 100644
--- a/java/org/apache/tomcat/util/buf/ByteChunk.java
+++ b/java/org/apache/tomcat/util/buf/ByteChunk.java
@@ -21,7 +21,9 @@ import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
 import java.nio.charset.Charset;
+import java.nio.charset.CodingErrorAction;
 import java.nio.charset.StandardCharsets;
 
 import org.apache.tomcat.util.res.StringManager;
@@ -526,23 +528,64 @@ public final class ByteChunk extends AbstractChunk {
 
     @Override
     public String toString() {
-        if (null == buff) {
+        try {
+            return toString(CodingErrorAction.REPLACE, CodingErrorAction.REPLACE);
+        } catch (CharacterCodingException e) {
+            // Unreachable code. Use of REPLACE above means the exception will never be thrown.
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+    public String toString(CodingErrorAction malformedInputAction, CodingErrorAction unmappableCharacterAction)
+            throws CharacterCodingException {
+        if (isNull()) {
             return null;
         } else if (end - start == 0) {
             return "";
         }
-        return StringCache.toString(this);
+        return StringCache.toString(this, malformedInputAction, unmappableCharacterAction);
     }
 
 
+    /**
+     * Converts the current content of the byte buffer to a String using the configured character set.
+     *
+     * @return The result of converting the bytes to a String
+     *
+     * @deprecated Unused. This method will be removed in Tomcat 11 onwards.
+     */
+    @Deprecated
     public String toStringInternal() {
+        try {
+            return toStringInternal(CodingErrorAction.REPLACE, CodingErrorAction.REPLACE);
+        } catch (CharacterCodingException e) {
+            // Unreachable code. Use of REPLACE above means the exception will never be thrown.
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+    /**
+     * Converts the current content of the byte buffer to a String using the configured character set.
+     *
+     * @param malformedInputAction      Action to take if the input is malformed
+     * @param unmappableCharacterAction Action to take if a byte sequence can't be mapped to a character
+     *
+     * @return The result of converting the bytes to a String
+     *
+     * @throws CharacterCodingException If an error occurs during the conversion
+     */
+    public String toStringInternal(CodingErrorAction malformedInputAction, CodingErrorAction unmappableCharacterAction)
+            throws CharacterCodingException {
         if (charset == null) {
             charset = DEFAULT_CHARSET;
         }
         // new String(byte[], int, int, Charset) takes a defensive copy of the
         // entire byte array. This is expensive if only a small subset of the
         // bytes will be used. The code below is from Apache Harmony.
-        CharBuffer cb = charset.decode(ByteBuffer.wrap(buff, start, end - start));
+        CharBuffer cb = charset.newDecoder().onMalformedInput(malformedInputAction)
+                .onUnmappableCharacter(unmappableCharacterAction).decode(ByteBuffer.wrap(buff, start, end - start));
         return new String(cb.array(), cb.arrayOffset(), cb.length());
     }
 
diff --git a/java/org/apache/tomcat/util/buf/StringCache.java b/java/org/apache/tomcat/util/buf/StringCache.java
index 3ba1e6eebf..929ec58607 100644
--- a/java/org/apache/tomcat/util/buf/StringCache.java
+++ b/java/org/apache/tomcat/util/buf/StringCache.java
@@ -16,10 +16,13 @@
  */
 package org.apache.tomcat.util.buf;
 
+import java.nio.charset.CharacterCodingException;
 import java.nio.charset.Charset;
+import java.nio.charset.CodingErrorAction;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map.Entry;
+import java.util.Objects;
 import java.util.TreeMap;
 
 import org.apache.juli.logging.Log;
@@ -208,11 +211,22 @@ public class StringCache {
 
 
     public static String toString(ByteChunk bc) {
+        try {
+            return toString(bc, CodingErrorAction.REPLACE, CodingErrorAction.REPLACE);
+        } catch (CharacterCodingException e) {
+            // Unreachable code. Use of REPLACE above means the exception will never be thrown.
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+    public static String toString(ByteChunk bc, CodingErrorAction malformedInputAction,
+            CodingErrorAction unmappableCharacterAction) throws CharacterCodingException {
 
         // If the cache is null, then either caching is disabled, or we're
         // still training
         if (bcCache == null) {
-            String value = bc.toStringInternal();
+            String value = bc.toStringInternal(malformedInputAction, unmappableCharacterAction);
             if (byteEnabled && (value.length() < maxStringSize)) {
                 // If training, everything is synced
                 synchronized (bcStats) {
@@ -291,6 +305,8 @@ public class StringCache {
                             System.arraycopy(bc.getBuffer(), start, entry.name, 0, end - start);
                             // Set encoding
                             entry.charset = bc.getCharset();
+                            entry.malformedInputAction = malformedInputAction;
+                            entry.unmappableCharacterAction = unmappableCharacterAction;
                             // Initialize occurrence count to one
                             count = new int[1];
                             count[0] = 1;
@@ -306,9 +322,9 @@ public class StringCache {
         } else {
             accessCount++;
             // Find the corresponding String
-            String result = find(bc);
+            String result = find(bc, malformedInputAction, unmappableCharacterAction);
             if (result == null) {
-                return bc.toStringInternal();
+                return bc.toStringInternal(malformedInputAction, unmappableCharacterAction);
             }
             // Note: We don't care about safety for the stats
             hitCount++;
@@ -473,10 +489,31 @@ public class StringCache {
      * @param name The name to find
      *
      * @return the corresponding value
+     *
+     * @deprecated Unused. Will be removed in Tomcat 11.
+     *             Use {@link #find(ByteChunk, CodingErrorAction, CodingErrorAction)}
      */
+    @Deprecated
     protected static final String find(ByteChunk name) {
+        return find(name, CodingErrorAction.REPLACE, CodingErrorAction.REPLACE);
+    }
+
+
+    /**
+     * Find an entry given its name in the cache and return the associated String.
+     *
+     * @param name                      The name to find
+     * @param malformedInputAction      Action to take if an malformed input is encountered
+     * @param unmappableCharacterAction Action to take if an unmappable character is encountered
+     *
+     * @return the corresponding value
+     */
+    protected static final String find(ByteChunk name, CodingErrorAction malformedInputAction,
+        CodingErrorAction unmappableCharacterAction) {
         int pos = findClosest(name, bcCache, bcCache.length);
-        if ((pos < 0) || (compare(name, bcCache[pos].name) != 0) || !(name.getCharset().equals(bcCache[pos].charset))) {
+        if ((pos < 0) || (compare(name, bcCache[pos].name) != 0) || !(name.getCharset().equals(bcCache[pos].charset)) ||
+                !malformedInputAction.equals(bcCache[pos].malformedInputAction) ||
+                !unmappableCharacterAction.equals(bcCache[pos].unmappableCharacterAction)) {
             return null;
         } else {
             return bcCache[pos].value;
@@ -642,11 +679,12 @@ public class StringCache {
 
     // -------------------------------------------------- ByteEntry Inner Class
 
-
     private static class ByteEntry {
 
         private byte[] name = null;
         private Charset charset = null;
+        private CodingErrorAction malformedInputAction = null;
+        private CodingErrorAction unmappableCharacterAction = null;
         private String value = null;
 
         @Override
@@ -656,17 +694,25 @@ public class StringCache {
 
         @Override
         public int hashCode() {
-            return value.hashCode();
+            return Objects.hash(malformedInputAction, unmappableCharacterAction, value);
         }
 
         @Override
         public boolean equals(Object obj) {
-            if (obj instanceof ByteEntry) {
-                return value.equals(((ByteEntry) obj).value);
+            if (this == obj) {
+                return true;
             }
-            return false;
+            if (obj == null) {
+                return false;
+            }
+            if (getClass() != obj.getClass()) {
+                return false;
+            }
+            ByteEntry other = (ByteEntry) obj;
+            return Objects.equals(malformedInputAction, other.malformedInputAction) &&
+                    Objects.equals(unmappableCharacterAction, other.unmappableCharacterAction) &&
+                    Objects.equals(value, other.value);
         }
-
     }
 
 
diff --git a/test/org/apache/jasper/compiler/TestGenerator.java b/test/org/apache/jasper/compiler/TestGenerator.java
index 4e3a07b250..f776af6ea8 100644
--- a/test/org/apache/jasper/compiler/TestGenerator.java
+++ b/test/org/apache/jasper/compiler/TestGenerator.java
@@ -21,6 +21,7 @@ import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.beans.PropertyEditorSupport;
 import java.io.IOException;
+import java.nio.charset.CodingErrorAction;
 import java.util.Date;
 
 import javax.servlet.http.HttpServletResponse;
@@ -205,7 +206,7 @@ public class TestGenerator extends TomcatBaseTest {
         ByteChunk bc = new ByteChunk();
         int rc = getUrl("http://localhost:" + getPort() + "/test/bug5nnnn/bug56529.jsp", bc, null);
         Assert.assertEquals(HttpServletResponse.SC_OK, rc);
-        String response = bc.toStringInternal();
+        String response = bc.toStringInternal(CodingErrorAction.REPORT, CodingErrorAction.REPORT);
         Assert.assertTrue(response, response.contains("[1:attribute1: '', attribute2: '']"));
         Assert.assertTrue(response, response.contains("[2:attribute1: '', attribute2: '']"));
     }
diff --git a/test/org/apache/tomcat/util/buf/TestStringCache.java b/test/org/apache/tomcat/util/buf/TestStringCache.java
new file mode 100644
index 0000000000..2345d2de76
--- /dev/null
+++ b/test/org/apache/tomcat/util/buf/TestStringCache.java
@@ -0,0 +1,100 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.tomcat.util.buf;
+
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CodingErrorAction;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestStringCache {
+
+    private static final byte[] BYTES_VALID = new byte[] { 65, 66, 67, 68};
+    private static final byte[] BYTES_INVALID = new byte[] {65, 66, -1, 67, 68};
+
+    private static final ByteChunk INPUT_VALID = new ByteChunk();
+    private static final ByteChunk INPUT_INVALID = new ByteChunk();
+
+    private static final CodingErrorAction[] actions =
+            new CodingErrorAction[] { CodingErrorAction.IGNORE, CodingErrorAction.REPLACE, CodingErrorAction.REPORT };
+
+    static {
+        INPUT_VALID.setBytes(BYTES_VALID, 0, BYTES_VALID.length);
+        INPUT_VALID.setCharset(StandardCharsets.UTF_8);
+        INPUT_INVALID.setBytes(BYTES_INVALID, 0, BYTES_INVALID.length);
+        INPUT_INVALID.setCharset(StandardCharsets.UTF_8);
+    }
+
+
+    @Test
+    public void testCodingErrorLookup() {
+
+        System.setProperty("tomcat.util.buf.StringCache.byte.enabled", "true");
+
+        Assert.assertTrue(StringCache.byteEnabled);
+        StringCache sc = new StringCache();
+        sc.reset();
+
+        for (int i = 0; i < StringCache.trainThreshold * 2; i++) {
+            for (CodingErrorAction malformedInputAction : actions) {
+                try {
+                    // UTF-8 doesn't have any unmappable characters
+                    INPUT_VALID.toString(malformedInputAction, CodingErrorAction.IGNORE);
+                    INPUT_INVALID.toString(malformedInputAction, CodingErrorAction.IGNORE);
+                } catch (CharacterCodingException e) {
+                    // Ignore
+                }
+            }
+        }
+
+        Assert.assertNotNull(StringCache.bcCache);
+
+        // Check the valid input is cached correctly
+        for (CodingErrorAction malformedInputAction : actions) {
+            try {
+                Assert.assertEquals("ABCD", INPUT_VALID.toString(malformedInputAction, CodingErrorAction.IGNORE));
+            } catch (CharacterCodingException e) {
+                // Should not happen for valid input
+                Assert.fail();
+            }
+        }
+
+        // Check the valid input is cached correctly
+        try {
+            Assert.assertEquals("ABCD", INPUT_INVALID.toString(CodingErrorAction.IGNORE, CodingErrorAction.IGNORE));
+        } catch (CharacterCodingException e) {
+            // Should not happen for invalid input with IGNORE
+            Assert.fail();
+        }
+        try {
+            Assert.assertEquals("AB\ufffdCD", INPUT_INVALID.toString(CodingErrorAction.REPLACE, CodingErrorAction.IGNORE));
+        } catch (CharacterCodingException e) {
+            // Should not happen for invalid input with REPLACE
+            Assert.fail();
+        }
+        try {
+            Assert.assertEquals("ABCD", INPUT_INVALID.toString(CodingErrorAction.REPORT, CodingErrorAction.IGNORE));
+            // Should throw exception
+            Assert.fail();
+        } catch (CharacterCodingException e) {
+            // Ignore
+        }
+
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 02/05: Use the previous decode call in the old default for now

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 03b51908102e9fa42739e680f2b785b9b2b84f78
Author: remm <re...@apache.org>
AuthorDate: Fri Jun 23 09:43:40 2023 +0200

    Use the previous decode call in the old default for now
    
    Just in case it makes a performance difference (the JVM code is very
    different).
---
 java/org/apache/tomcat/util/buf/ByteChunk.java | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/java/org/apache/tomcat/util/buf/ByteChunk.java b/java/org/apache/tomcat/util/buf/ByteChunk.java
index ef02a4f86b..58b6a57794 100644
--- a/java/org/apache/tomcat/util/buf/ByteChunk.java
+++ b/java/org/apache/tomcat/util/buf/ByteChunk.java
@@ -584,8 +584,13 @@ public final class ByteChunk extends AbstractChunk {
         // new String(byte[], int, int, Charset) takes a defensive copy of the
         // entire byte array. This is expensive if only a small subset of the
         // bytes will be used. The code below is from Apache Harmony.
-        CharBuffer cb = charset.newDecoder().onMalformedInput(malformedInputAction)
-                .onUnmappableCharacter(unmappableCharacterAction).decode(ByteBuffer.wrap(buff, start, end - start));
+        CharBuffer cb;
+        if (malformedInputAction == CodingErrorAction.REPLACE && unmappableCharacterAction == CodingErrorAction.REPLACE) {
+            cb = charset.decode(ByteBuffer.wrap(buff, start, end - start));
+        } else {
+            cb = charset.newDecoder().onMalformedInput(malformedInputAction)
+                    .onUnmappableCharacter(unmappableCharacterAction).decode(ByteBuffer.wrap(buff, start, end - start));
+        }
         return new String(cb.array(), cb.arrayOffset(), cb.length());
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org