From ad10552c7d1d15c718610171a3a5cd82f1720616 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Thu, 8 Oct 2026 15:21:20 -0400 Subject: [PATCH 1/2] Fix DB2 JDBC URL parsing failure when :// is only in a property value A DB2/AS400 URL without // after the type (e.g. jdbc:as400:host;keystore=file:///x) whose only :// sits inside a ';' property value made MODIFIED_URL_LIKE take the '://' as the host delimiter while cutting urlPart1 at the earlier ';', so urlPart1.substring(hostIndex + 3) threw StringIndexOutOfBoundsException. Return the builder unchanged in that case, which is the same DBInfo the exception fallback produced, minus the exception. Co-Authored-By: Claude Opus 5.5 --- .../jdbc/JDBCConnectionUrlParser.java | 4 ++++ .../jdbc/JDBCConnectionUrlParserDB2Test.java | 22 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java index a908e0766d2..e464f6804fe 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -116,6 +116,10 @@ DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { } } else { paramLoc = jdbcUrl.indexOf(';'); + if (paramLoc >= 0 && paramLoc < hostIndex) { + // the "://" is inside a property value (e.g. db2:mydb;x=file://...), so no host part + return builder; + } urlPart1 = paramLoc >= 0 ? jdbcUrl.substring(0, paramLoc) : jdbcUrl; urlPart2 = paramLoc >= 0 ? jdbcUrl.substring(paramLoc + 1) : null; } diff --git a/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java index 091c1e2b02f..97da1ed88e4 100644 --- a/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java +++ b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java @@ -1,7 +1,9 @@ package datadog.trace.bootstrap.instrumentation.jdbc; +import static datadog.trace.bootstrap.instrumentation.jdbc.JDBCConnectionUrlParser.DB2; import static datadog.trace.bootstrap.instrumentation.jdbc.JDBCConnectionUrlParser.extractDBInfo; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; import org.tabletest.junit.TableTest; @@ -32,4 +34,24 @@ void db2UrlWithEqualsAndNoPortShouldParseCorrectly( assertEquals(user, info.getUser()); assertEquals(db, info.getDb()); } + + /** + * A URL without "//" after the type, whose only "://" is inside a ';' property value, used to + * throw a {@code StringIndexOutOfBoundsException}. Calls {@code DB2.doParse} directly since + * {@code extractDBInfo} swallows parse exceptions. + */ + @TableTest({ + "scenario | url | type ", + "DB2 with URL in property value | db2:mydb;x=http://y | db2 ", + "AS400 with file URL in property | as400:host;ssltruststore=file://x | as400", + "AS400 with several properties | as400:host;libraries=a;secure=true;keystore=file:///x | as400", + "Empty type suffix with property | db2:;a=b://h | db2 " + }) + void schemeSeparatorOnlyInPropertyValueShouldNotThrow(String url, String type) { + DBInfo info = DB2.doParse(url, DBInfo.DEFAULT.toBuilder().type(type)).build(); + assertEquals(type, info.getType()); + assertNull(info.getHost()); + assertEquals(50000, info.getPort()); + assertNull(info.getInstance()); + } } From 07713f9a9e13612cf48df89b8fe436608e4e7059 Mon Sep 17 00:00:00 2001 From: Douglas Q Hawkins Date: Fri, 9 Oct 2026 09:53:56 -0400 Subject: [PATCH 2/2] Keep DB2/AS400 URL properties when :// is only in a property value The early return skipped splitQuery/populateStandardProperties, so properties such as user or schema were lost. The old parser applied them before throwing and parse() returned that builder from its catch block, so populate them before returning. Co-Authored-By: Claude Opus 5.5 --- .../jdbc/JDBCConnectionUrlParser.java | 4 +++- .../jdbc/JDBCConnectionUrlParserDB2Test.java | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java index e464f6804fe..b4c01027609 100644 --- a/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java +++ b/dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java @@ -117,7 +117,9 @@ DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) { } else { paramLoc = jdbcUrl.indexOf(';'); if (paramLoc >= 0 && paramLoc < hostIndex) { - // the "://" is inside a property value (e.g. db2:mydb;x=file://...), so no host part + // the "://" is inside a property value (e.g. db2:mydb;x=file://...), so there is no host + // part to parse, but the properties (user, schema, ...) still apply + populateStandardProperties(builder, splitQuery(jdbcUrl.substring(paramLoc + 1), ';')); return builder; } urlPart1 = paramLoc >= 0 ? jdbcUrl.substring(0, paramLoc) : jdbcUrl; diff --git a/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java index 97da1ed88e4..9a222676336 100644 --- a/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java +++ b/dd-java-agent/agent-bootstrap/src/test/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParserDB2Test.java @@ -54,4 +54,22 @@ void schemeSeparatorOnlyInPropertyValueShouldNotThrow(String url, String type) { assertEquals(50000, info.getPort()); assertNull(info.getInstance()); } + + /** + * The same URLs keep their recognized properties. The old parser applied them before throwing, + * and {@code parse} returned that builder from its catch block, so they were recorded then too. + */ + @TableTest({ + "scenario | url | type | user | schema", + "AS400 user before file URL | as400:host;user=alice;ssltruststore=file://x | as400 | alice | ", + "DB2 schema before http URL | db2:mydb;schema=s1;x=http://y | db2 | | s1 ", + "AS400 user after file URL | as400:host;keystore=file:///k;user=bob | as400 | bob | " + }) + void schemeSeparatorOnlyInPropertyValueKeepsProperties( + String url, String type, String user, String schema) { + DBInfo info = DB2.doParse(url, DBInfo.DEFAULT.toBuilder().type(type)).build(); + assertEquals(type, info.getType()); + assertEquals(user, info.getUser()); + assertEquals(schema, info.getSchema()); + } }