Skip to content

Commit 20950de

Browse files
ValentinZakharovdevflow.devflow-routing-intake
andauthored
Fix JDBC URL parsing crash when no port specified (#11550)
Fix StringIndexOutOfBoundsException in DB2/AS400 JDBC URL parsing when no port is specified Simplify test comments Parse query-string params and fix instance name for DB2/AS400 URLs without port Rewrite DB2 test using @TableTest and collapse into single method Add regression tests for DB2/AS400 URL parsing with port and without params Co-authored-by: devflow.devflow-routing-intake <devflow.devflow-routing-intake@kubernetes.us1.ddbuild.io>
1 parent cb71f86 commit 20950de

2 files changed

Lines changed: 52 additions & 4 deletions

File tree

dd-java-agent/agent-bootstrap/src/main/java/datadog/trace/bootstrap/instrumentation/jdbc/JDBCConnectionUrlParser.java

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,26 @@ DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) {
8181
final String urlPart1;
8282
final String urlPart2;
8383
final int paramLoc;
84+
char paramSeparator = ';';
8485

8586
if (type.equals("db2") || type.equals("as400")) {
8687
if (jdbcUrl.contains("=")) {
8788
paramLoc = jdbcUrl.lastIndexOf(':');
88-
urlPart1 = jdbcUrl.substring(0, paramLoc);
89-
urlPart2 = jdbcUrl.substring(paramLoc + 1);
90-
89+
if (paramLoc > hostIndex + 2) {
90+
urlPart1 = jdbcUrl.substring(0, paramLoc);
91+
urlPart2 = jdbcUrl.substring(paramLoc + 1);
92+
} else {
93+
// No ':' past '://': fall back to '?' query-string params
94+
final int queryLoc = jdbcUrl.indexOf('?');
95+
if (queryLoc >= 0) {
96+
urlPart1 = jdbcUrl.substring(0, queryLoc);
97+
urlPart2 = jdbcUrl.substring(queryLoc + 1);
98+
paramSeparator = '&';
99+
} else {
100+
urlPart1 = jdbcUrl;
101+
urlPart2 = null;
102+
}
103+
}
91104
} else {
92105
urlPart1 = jdbcUrl;
93106
urlPart2 = null;
@@ -99,7 +112,7 @@ DBInfo.Builder doParse(final String jdbcUrl, final DBInfo.Builder builder) {
99112
}
100113

101114
if (urlPart2 != null) {
102-
final Map<String, String> props = splitQuery(urlPart2, ';');
115+
final Map<String, String> props = splitQuery(urlPart2, paramSeparator);
103116
populateStandardProperties(builder, props);
104117
if (props.containsKey("servername")) {
105118
serverName = props.get("servername");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package datadog.trace.bootstrap.instrumentation.jdbc;
2+
3+
import static datadog.trace.bootstrap.instrumentation.jdbc.JDBCConnectionUrlParser.extractDBInfo;
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
6+
import org.tabletest.junit.TableTest;
7+
8+
/**
9+
* Tests for DB2/AS400 JDBC URL parsing when the URL contains '=' but no explicit port.
10+
*
11+
* <p>Without a port, {@code lastIndexOf(':')} returns the scheme colon, making {@code urlPart1} too
12+
* short for the subsequent {@code substring()} call and causing a {@code
13+
* StringIndexOutOfBoundsException}.
14+
*/
15+
class JDBCConnectionUrlParserDB2Test {
16+
17+
@TableTest({
18+
"scenario | url | type | host | instance | user | db ",
19+
"DB2 with user param, no port | jdbc:db2://db2.host/mydb?user=db2user | db2 | db2.host | mydb | db2user | mydb ",
20+
"AS400 with user param, no port | jdbc:as400://ashost/asdb?user=asuser | as400 | ashost | asdb | asuser | asdb ",
21+
"DB2 with multiple params, no port | jdbc:db2://db2.host/mydb?user=db2user&connectionTimeout=30 | db2 | db2.host | mydb | db2user | mydb ",
22+
"DB2 with databasename param, no port | jdbc:db2://db2.host/mydb?user=db2user&databasename=otherdb | db2 | db2.host | mydb | db2user | otherdb",
23+
"DB2 with port and colon params | jdbc:db2://db2.host:50000/mydb:user=db2user | db2 | db2.host | mydb | db2user | mydb ",
24+
"DB2 no params | jdbc:db2://db2.host/mydb | db2 | db2.host | mydb | | mydb "
25+
})
26+
void db2UrlWithEqualsAndNoPortShouldParseCorrectly(
27+
String url, String type, String host, String instance, String user, String db) {
28+
DBInfo info = extractDBInfo(url, null);
29+
assertEquals(type, info.getType());
30+
assertEquals(host, info.getHost());
31+
assertEquals(instance, info.getInstance());
32+
assertEquals(user, info.getUser());
33+
assertEquals(db, info.getDb());
34+
}
35+
}

0 commit comments

Comments
 (0)