This is an automated email from the ASF dual-hosted git repository.

andy pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/jena.git


The following commit(s) were added to refs/heads/main by this push:
     new c8a32ea1ed GH-3465: Preserve trailing slash
c8a32ea1ed is described below

commit c8a32ea1ed06fabd4fdc6ebf7d5ed65fafb1e7ab
Author: Andy Seaborne <a...@apache.org>
AuthorDate: Thu Sep 25 09:57:45 2025 +0100

    GH-3465: Preserve trailing slash
---
 .../src/main/java/org/apache/jena/rfc3986/AlgResolveIRI.java   |  9 +++++++--
 .../src/test/java/org/apache/jena/rfc3986/TestNormalize.java   |  4 ++++
 .../src/test/java/org/apache/jena/rfc3986/TestResolve.java     | 10 ++++++++++
 3 files changed, 21 insertions(+), 2 deletions(-)

diff --git 
a/jena-iri3986/src/main/java/org/apache/jena/rfc3986/AlgResolveIRI.java 
b/jena-iri3986/src/main/java/org/apache/jena/rfc3986/AlgResolveIRI.java
index d560f885cc..c4ee538166 100644
--- a/jena-iri3986/src/main/java/org/apache/jena/rfc3986/AlgResolveIRI.java
+++ b/jena-iri3986/src/main/java/org/apache/jena/rfc3986/AlgResolveIRI.java
@@ -198,12 +198,17 @@ public class AlgResolveIRI {
         }
 
         boolean initialSlash = segments[0].isEmpty();
+        // path has a trailing slash, special case is "/"
         boolean trailingSlash = false;
-        // Trailing slash if it isn't the initial "/" and it ends in "/" or 
"/." or "/.."
-        if ( N > 1 ) {
+        // Determine whether there is going to be a trailing slash.
+        // *  if it isn't the initial "/" and it ends in "/"
+        // *  there is "/." or "/.." which will be resolved below.
+        if ( N > (initialSlash ? 1 : 0) ) {
             if ( segments[N-1].equals(".") || segments[N-1].equals("..") )
+                // Not the initial slash, and the last segment is "." or ".."
                 trailingSlash = true;
             else if ( path.charAt(path.length()-1) == '/' )
+                // Not the initial slash, and the last character is "/"
                 trailingSlash = true;
         }
 
diff --git 
a/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestNormalize.java 
b/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestNormalize.java
index c0cd569f11..9abc379509 100644
--- a/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestNormalize.java
+++ b/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestNormalize.java
@@ -45,6 +45,10 @@ public class TestNormalize {
     @Test public void normalize_23() { testNormalize("http://host//..";, 
"http://host/";); }
     @Test public void normalize_24() { testNormalize("http://host/abc//..";, 
"http://host/abc/";); }
 
+    @Test public void normalize_25() { testNormalize("http://host/abc/";, 
"http://host/abc/";); }
+    @Test public void normalize_26() { testNormalize("http://host/abc";, 
"http://host/abc";); }
+    @Test public void normalize_27() { testNormalize("http://host/";, 
"http://host/";); }
+
     private void testNormalize(String input, String expected) {
         IRI3986 iri = RFC3986.create(input);
         IRI3986 iri2 = iri.normalize();
diff --git 
a/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestResolve.java 
b/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestResolve.java
index 1e3be41efe..87b1cfab3b 100644
--- a/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestResolve.java
+++ b/jena-iri3986/src/test/java/org/apache/jena/rfc3986/TestResolve.java
@@ -45,11 +45,21 @@ public class TestResolve {
     @Test public void resolve_abs_11() { 
testResolve("http://example/dir1/dir2/";, "//EX/OtherPath", 
"http://EX/OtherPath";); }
     @Test public void resolve_abs_12() { testResolve("http:", 
"//EX/OtherPath", "http://EX/OtherPath";); }
 
+    @Test public void resolve_abs_20() { testResolve("https://example/";, "//", 
"https://";); }
+    @Test public void resolve_abs_21() { testResolve("https://example/";, 
"//host", "https://host";); }
+    @Test public void resolve_abs_22() { testResolve("https://example/";, 
"//host/", "https://host/";); }
+    @Test public void resolve_abs_23() { testResolve("https://example/";, 
"//host/path", "https://host/path";); }
+
     @Test public void resolve_ref_1() { testResolve("http://example/dir/";, 
"A", "http://example/dir/A";); }
     @Test public void resolve_ref_2() { testResolve("http://example/dir";, "A", 
"http://example/A";); }
     @Test public void resolve_ref_3() { testResolve("http://example/dir";, 
"A/", "http://example/A/";); }
     @Test public void resolve_ref_4() { testResolve("http://example/dir/";, 
"A/", "http://example/dir/A/";); }
 
+    // Different scheme.
+    @Test public void resolve_ref_5() { testResolve("http://example/";, 
"https:subdir/", "https:subdir/"); }
+    @Test public void resolve_ref_6() { testResolve("http://example/";, 
"https:subdir", "https:subdir"); }
+    @Test public void resolve_ref_7() { testResolve("http://example/";, 
"urn:foo/", "urn:foo/"); }
+
     @Test public void resolve_dot_01() { 
testResolve("http://example/dir1/dir2/";, ".", "http://example/dir1/dir2/";); }
     @Test public void resolve_dot_02() { testResolve("http://example/";, ".", 
"http://example/";); }
     @Test public void resolve_dot_03() { 
testResolve("http://example/dir1/dir2/x";, ".", "http://example/dir1/dir2/";); }

Reply via email to