diff --git a/CHANGELOG.md b/CHANGELOG.md index b74bc0886e..770be8996f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## Unreleased + +### Fixes + +- Trim DSN string before parsing to avoid `URISyntaxException` caused by trailing whitespace ([#5113](https://github.com/getsentry/sentry-java/pull/5113)) + ## 8.33.0 ### Features diff --git a/sentry/src/main/java/io/sentry/Dsn.java b/sentry/src/main/java/io/sentry/Dsn.java index 836e2c5546..31e57c7f5a 100644 --- a/sentry/src/main/java/io/sentry/Dsn.java +++ b/sentry/src/main/java/io/sentry/Dsn.java @@ -50,8 +50,8 @@ URI getSentryUri() { Dsn(@Nullable String dsn) throws IllegalArgumentException { try { - Objects.requireNonNull(dsn, "The DSN is required."); - final URI uri = new URI(dsn).normalize(); + final String dsnString = Objects.requireNonNull(dsn, "The DSN is required.").trim(); + final URI uri = new URI(dsnString).normalize(); final String scheme = uri.getScheme(); if (!("http".equalsIgnoreCase(scheme) || "https".equalsIgnoreCase(scheme))) { throw new IllegalArgumentException("Invalid DSN scheme: " + scheme); diff --git a/sentry/src/main/java/io/sentry/SentryOptions.java b/sentry/src/main/java/io/sentry/SentryOptions.java index 14f4acf51f..298e37795b 100644 --- a/sentry/src/main/java/io/sentry/SentryOptions.java +++ b/sentry/src/main/java/io/sentry/SentryOptions.java @@ -749,7 +749,7 @@ Dsn retrieveParsedDsn() throws IllegalArgumentException { * @param dsn the DSN */ public void setDsn(final @Nullable String dsn) { - this.dsn = dsn; + this.dsn = dsn != null ? dsn.trim() : null; this.parsedDsn.resetValue(); dsnHash = StringUtils.calculateStringHash(this.dsn, logger); diff --git a/sentry/src/test/java/io/sentry/DsnTest.kt b/sentry/src/test/java/io/sentry/DsnTest.kt index eaa129c207..fee1cf50af 100644 --- a/sentry/src/test/java/io/sentry/DsnTest.kt +++ b/sentry/src/test/java/io/sentry/DsnTest.kt @@ -89,6 +89,12 @@ class DsnTest { assertEquals("http://host/api/id", dsn.sentryUri.toURL().toString()) } + @Test + fun `dsn parsed with leading and trailing whitespace`() { + val dsn = Dsn(" https://key@host/id ") + assertEquals("https://host/api/id", dsn.sentryUri.toURL().toString()) + } + @Test fun `non http protocols are not accepted`() { assertFailsWith { Dsn("ftp://publicKey:secretKey@host/path/id") } diff --git a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt index 6868b55c2b..80510db931 100644 --- a/sentry/src/test/java/io/sentry/SentryOptionsTest.kt +++ b/sentry/src/test/java/io/sentry/SentryOptionsTest.kt @@ -588,6 +588,24 @@ class SentryOptionsTest { assertFalse(cacheDirPathWithoutDsn.contains(hash.toString())) } + @Test + fun `when setting dsn with whitespace, it is trimmed and produces the same cache dir path`() { + val dsn = "http://key@localhost/proj" + val options1 = + SentryOptions().apply { + setDsn(dsn) + cacheDirPath = "${File.separator}test" + } + val options2 = + SentryOptions().apply { + setDsn(" $dsn ") + cacheDirPath = "${File.separator}test" + } + + assertEquals(dsn, options2.dsn) + assertEquals(options1.cacheDirPath, options2.cacheDirPath) + } + @Test fun `when options are initialized, idleTimeout is 3000`() { assertEquals(3000L, SentryOptions().idleTimeout)