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/"); }