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]
