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

rmaucher pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 37533f725ca0ad1ef56acf8d4044f68ae9e208a1
Author: opencode <[email protected]>
AuthorDate: Wed Oct 14 11:17:54 2026 +0200

    Preserve separator slash when escaping custom WAR separator in JAR URLs
    
    When a custom WAR separator is configured via the
    org.apache.tomcat.util.buf.UriUtil.WAR_SEPARATOR system property,
    PATTERN_CUSTOM matches the full separator (custom + "/") but
    REPLACE_CUSTOM percent-encoded only the custom part. The replaceAll in
    makeSafeForJarUrl therefore deleted the trailing '/' of the separator,
    silently rewriting any file path containing the separator sequence to a
    different, non-existent path and producing a broken jar:file: URL.
    
    Fix this by appending a literal '/' to REPLACE_CUSTOM so the escaped
    replacement keeps the separator's trailing slash, consistent with the
    default handling where "*/" is replaced with "%2a/". As a side
    effect, an empty custom separator now behaves as a no-op instead of
    stripping every '/' from the path.
    
    Add a regression test asserting the full expected JAR URL with the '@'
    separator, using the String overload of buildJarUrl so the expected
    value is independent of platform-specific File.toURI() behaviour.
---
 java/org/apache/tomcat/util/buf/UriUtil.java       |  6 +++++-
 test/org/apache/tomcat/util/buf/TestUriUtil40.java | 17 +++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/tomcat/util/buf/UriUtil.java 
b/java/org/apache/tomcat/util/buf/UriUtil.java
index 1c1938daf8..a2381cd3b9 100644
--- a/java/org/apache/tomcat/util/buf/UriUtil.java
+++ b/java/org/apache/tomcat/util/buf/UriUtil.java
@@ -48,7 +48,7 @@ public final class UriUtil {
         } else {
             WAR_SEPARATOR = custom + "/";
             PATTERN_CUSTOM = Pattern.compile(Pattern.quote(WAR_SEPARATOR));
-            StringBuilder sb = new StringBuilder(custom.length() * 3);
+            StringBuilder sb = new StringBuilder(custom.length() * 3 + 1);
             // Deliberately use the platform's default encoding
             byte[] ba = custom.getBytes();
             for (byte toEncode : ba) {
@@ -59,6 +59,10 @@ public final class UriUtil {
                 sb.append(HEX[high]);
                 sb.append(HEX[low]);
             }
+            // The pattern matches custom + "/" so the trailing '/' has to be
+            // preserved by the replacement. This is consistent with the
+            // default handling of "*/" which is replaced with "%2a/".
+            sb.append('/');
             REPLACE_CUSTOM = sb.toString();
         }
     }
diff --git a/test/org/apache/tomcat/util/buf/TestUriUtil40.java 
b/test/org/apache/tomcat/util/buf/TestUriUtil40.java
index 10dcaf7a03..297c6e23f1 100644
--- a/test/org/apache/tomcat/util/buf/TestUriUtil40.java
+++ b/test/org/apache/tomcat/util/buf/TestUriUtil40.java
@@ -16,9 +16,26 @@
  */
 package org.apache.tomcat.util.buf;
 
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
 public class TestUriUtil40 extends TesterUriUtilBase {
 
     public TestUriUtil40() {
         super("@");
     }
+
+    @Test
+    public void testBuildJarUrlPreservesSeparatorSlash() throws IOException {
+        // Use the String overload with a literal file: URL so the expected
+        // value does not depend on File.toURI() behaviour (which varies
+        // with platform)
+        String result = 
UriUtil.buildJarUrl("file:/patha/pathb@/pathc").toString();
+        // The custom separator must be escaped but the trailing '/' of the
+        // separator must be preserved, consistent with the default handling
+        // of "*/" being replaced with "%2a/"
+        Assert.assertEquals("jar:file:/patha/pathb%40/pathc!/", result);
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to