This is an automated email from the ASF dual-hosted git repository.
cziegeler pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-api.git
The following commit(s) were added to refs/heads/master by this push:
new 923c461 SLING-13065 : SlingUriBuilder parse results in
java.lang.StringIndexOutOfBoundsException (#78)
923c461 is described below
commit 923c461a48888b565185f94c0a355497d760f552
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Mon Jun 1 07:03:58 2026 +0200
SLING-13065 : SlingUriBuilder parse results in
java.lang.StringIndexOutOfBoundsException (#78)
* SLING-13065 : SlingUriBuilder parse results in
java.lang.StringIndexOutOfBoundsException
Co-authored-by: Copilot <[email protected]>
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI
<[email protected]>
---------
Co-authored-by: Copilot <[email protected]>
Co-authored-by: Copilot Autofix powered by AI
<[email protected]>
---
.../org/apache/sling/api/uri/SlingUriBuilder.java | 7 +++
.../apache/sling/api/uri/SlingUriRebaseTest.java | 61 ++++++++++++++++++++++
2 files changed, 68 insertions(+)
diff --git a/src/main/java/org/apache/sling/api/uri/SlingUriBuilder.java
b/src/main/java/org/apache/sling/api/uri/SlingUriBuilder.java
index 582b925..ac48dd1 100644
--- a/src/main/java/org/apache/sling/api/uri/SlingUriBuilder.java
+++ b/src/main/java/org/apache/sling/api/uri/SlingUriBuilder.java
@@ -447,6 +447,13 @@ public class SlingUriBuilder {
suffix = null;
if (availableResourcePath.length() == path.length()) {
resourcePath = availableResourcePath;
+ } else if (availableResourcePath.length() + 1 == path.length()
+ && path.charAt(availableResourcePath.length()) == '/') {
+ // The path has a trailing slash that is not part of the resource
path (e.g.
+ // /apidocs/sling12/ with resource at /apidocs/sling12).
setPathWithDefinedResourcePosition
+ // assumes a dot separator at the given position; a trailing slash
must be handled here
+ // to avoid StringIndexOutOfBoundsException.
+ resourcePath = availableResourcePath;
} else {
setPathWithDefinedResourcePosition(path,
availableResourcePath.length());
}
diff --git a/src/test/java/org/apache/sling/api/uri/SlingUriRebaseTest.java
b/src/test/java/org/apache/sling/api/uri/SlingUriRebaseTest.java
index 0c985f1..1a053c7 100644
--- a/src/test/java/org/apache/sling/api/uri/SlingUriRebaseTest.java
+++ b/src/test/java/org/apache/sling/api/uri/SlingUriRebaseTest.java
@@ -18,6 +18,7 @@
*/
package org.apache.sling.api.uri;
+import java.net.URI;
import java.net.URISyntaxException;
import org.apache.sling.api.resource.Resource;
@@ -29,6 +30,8 @@ import org.mockito.junit.MockitoJUnitRunner;
import static org.apache.sling.api.uri.SlingUriTest.testUri;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.Silent.class)
@@ -310,4 +313,62 @@ public class SlingUriRebaseTest {
String testPath = "/path/to/page.html";
SlingUriBuilder.parse(testPath, null).rebaseResourcePath().build();
}
+
+ @Test
+ public void testRebaseResourcePathWithTrailingSlashResourceExists() {
+ // path with trailing slash, resource exists at path without trailing
slash
+ when(resolver.getResource("/apidocs/sling12")).thenReturn(resource);
+ SlingUri slingUri = SlingUriBuilder.parse("/apidocs/sling12/",
resolver).build();
+ assertNotNull(slingUri);
+ assertEquals("/apidocs/sling12", slingUri.getResourcePath());
+ assertNull(slingUri.getSelectorString());
+ assertNull(slingUri.getExtension());
+ assertNull(slingUri.getSuffix());
+ }
+
+ @Test
+ public void testRebaseResourcePathWithTrailingSlashNoResourceExists() {
+ // path with trailing slash, no resource exists: should not throw
StringIndexOutOfBoundsException
+ when(resolver.getResource("/apidocs/sling12")).thenReturn(null);
+ SlingUri slingUri = SlingUriBuilder.parse("/apidocs/sling12/",
resolver).build();
+ assertNotNull(slingUri);
+ }
+
+ @Test
+ public void testRebaseFullUriWithTrailingSlash() throws URISyntaxException
{
+ // full external URI with trailing slash path - the original bug
report scenario
+ // No StringIndexOutOfBoundsException should be thrown
+ SlingUri slingUri =
SlingUriBuilder.parse("https://sling.apache.org/apidocs/sling12/", resolver)
+ .build();
+ assertNotNull(slingUri);
+ assertEquals("https", slingUri.getScheme());
+ assertEquals("sling.apache.org", slingUri.getHost());
+ }
+
+ @Test
+ public void testRebaseCreateFromUriWithTrailingSlash() throws
URISyntaxException {
+ // createFrom(URI, resolver) with trailing slash path - the original
bug report scenario
+ // No StringIndexOutOfBoundsException should be thrown
+ URI input = new URI("https://sling.apache.org/apidocs/sling12/");
+ SlingUri slingUri = SlingUriBuilder.createFrom(input,
resolver).build();
+ assertNotNull(slingUri);
+ assertEquals("https", slingUri.getScheme());
+ assertEquals("sling.apache.org", slingUri.getHost());
+ }
+
+ @Test
+ public void testRebaseResourcePathWithSlashSuffix() {
+ // For /content/page.html/suffix, the iterator strips the suffix then
the .html extension,
+ // landing at /content/page; then setPathWithDefinedResourcePosition
splits at '.' giving
+ // extension=html, suffix=/suffix.
+
when(resolver.getResource("/content/page.html/suffix")).thenReturn(null);
+ when(resolver.getResource("/content/page")).thenReturn(resource);
+ SlingUri slingUri =
+ SlingUriBuilder.parse("/content/page.html/suffix",
resolver).build();
+ assertNotNull(slingUri);
+ assertEquals("/content/page", slingUri.getResourcePath());
+ assertEquals(null, slingUri.getSelectorString());
+ assertEquals("html", slingUri.getExtension());
+ assertEquals("/suffix", slingUri.getSuffix());
+ }
}