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

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

commit 0aba5167ec5c1babb12b204299aa7467ba1bf0e7
Author: opencode <[email protected]>
AuthorDate: Tue Oct 27 00:01:40 2026 +0100

    Preserve non-ASCII characters in jdbc-pool connection properties
    
    PoolProperties.getProperties(String,Properties) fed the configuration
    string to Properties.load(InputStream) through getBytes(). The stream
    loader decodes ISO-8859-1 while getBytes() encodes with the platform
    default charset, which is UTF-8 on every supported JVM; each non-ASCII
    character in `connectionProperties` therefore reached the driver
    corrupted ("café" arrived as "café"). The property is ordinary
    driver configuration (it is handed to java.sql.Driver#connect) and the
    corruption depended on the platform default charset, so the same
    config file behaved differently on different JVMs.
    
    Parse through a StringReader instead: Properties.load(Reader) carries
    the exact characters, so no charset conversion takes place at all. The
    parsing semantics are otherwise identical - the JDK routes both load
    overloads through the same parser, and a differential corpus (comments,
    #/=/[:] separators, CRLF line terminators, backslash continuations,
    unicode escapes and malformed escapes) confirms old and new agree on
    every input that previously parsed correctly, differing only where the
    old output was provably corrupt. Both reachable paths are fixed by the
    single change: the programmatic/JMX setter and the JNDI factory
    (DataSourceFactory) delegate to this method.
    
    Add a regression test that pins the round trip of a non-ASCII value
    through both paths. The test is written with unicode escapes to keep
    the source 7-bit for the ISO-8859-1 Ant build.
---
 .../apache/tomcat/jdbc/pool/PoolProperties.java    |  9 +++++++--
 .../tomcat/jdbc/pool/TestPoolProperties.java       | 22 ++++++++++++++++++++++
 2 files changed, 29 insertions(+), 2 deletions(-)

diff --git 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
index 66e1c91c83..afb0bd4527 100644
--- 
a/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
+++ 
b/modules/jdbc-pool/src/main/java/org/apache/tomcat/jdbc/pool/PoolProperties.java
@@ -16,9 +16,9 @@
  */
 package org.apache.tomcat.jdbc.pool;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.Serializable;
+import java.io.StringReader;
 import java.lang.reflect.Method;
 import java.util.HashMap;
 import java.util.Locale;
@@ -1136,7 +1136,12 @@ public class PoolProperties implements 
PoolConfiguration, Cloneable, Serializabl
         }
         if (propText != null) {
             try {
-                props.load(new ByteArrayInputStream(propText.replace(';', 
'\n').getBytes()));
+                // Load through a Reader: Properties.load(InputStream) decodes 
as
+                // ISO-8859-1 while encoding the string to bytes uses the 
platform
+                // charset, silently corrupting any non-ASCII value on a
+                // UTF-8-default JVM. A Reader carries the exact characters, 
so no
+                // charset conversion takes place at all.
+                props.load(new StringReader(propText.replace(';', '\n')));
             }catch (IOException ioe) {
                 throw new RuntimeException(ioe);
             }
diff --git 
a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolProperties.java
 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolProperties.java
index 22706bb387..c487d15ecd 100644
--- 
a/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolProperties.java
+++ 
b/modules/jdbc-pool/src/test/java/org/apache/tomcat/jdbc/pool/TestPoolProperties.java
@@ -137,6 +137,28 @@ class TestPoolProperties {
                 "an unconfigured attribute must leave the driver properties 
empty");
     }
 
+    @Test
+    void nonAsciiValuesInConnectionPropertiesSurviveParsing() {
+        // The escaped e-acute and a-ring below are multi-byte under the UTF-8
+        // default charset every supported JVM ships with, while
+        // Properties.load(InputStream) decodes as ISO-8859-1; parsing must
+        // hand the driver exactly the characters the configuration named,
+        // whatever the platform default charset is. Unicode escapes keep
+        // this source file 7-bit for the ISO-8859-1 Ant build.
+        PoolProperties properties = new PoolProperties();
+        
properties.setConnectionProperties("clientInfo=caf\u00e9;clientLocale=de_DE");
+
+        Assertions.assertEquals("caf\u00e9", 
properties.getDbProperties().getProperty("clientInfo"),
+                "a non-ASCII value must reach the driver properties 
uncorrupted");
+        Assertions.assertEquals("de_DE", 
properties.getDbProperties().getProperty("clientLocale"),
+                "the pairs around it must still parse");
+
+        // the static helper the JNDI factory routes through
+        Properties parsed = PoolProperties.getProperties("foo=b\u00e5r", null);
+        Assertions.assertEquals("b\u00e5r", parsed.getProperty("foo"),
+                "a non-ASCII value must survive the factory path as well");
+    }
+
     @Test
     void toStringMasksThePasswordButStillShowsTheConfiguration() {
         PoolProperties properties = new PoolProperties();


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

Reply via email to