Author: markt Date: Fri Feb 17 14:24:33 2017 New Revision: 1783408 URL: http://svn.apache.org/viewvc?rev=1783408&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=60728 Make the separator Tomcat uses in the Tomcat specific war:file:... URL protocol customizable via a system property. The separator is equivalent to the use of the '!' character in jar:file:... URLs. The default separator of '*' remains unchanged.
Added: tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil24.java tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil26.java tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil2A.java tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil40.java tomcat/trunk/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java - copied, changed from r1783407, tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil.java Removed: tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil.java Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java tomcat/trunk/java/org/apache/catalina/webresources/WarResource.java tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/systemprops.xml Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java?rev=1783408&r1=1783407&r2=1783408&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarWarResource.java Fri Feb 17 14:24:33 2017 @@ -24,6 +24,7 @@ import java.util.jar.JarInputStream; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.buf.UriUtil; /** * Represents a single resource (file or directory) that is located within a @@ -38,8 +39,9 @@ public class JarWarResource extends Abst public JarWarResource(AbstractArchiveResourceSet archiveResourceSet, String webAppPath, String baseUrl, JarEntry jarEntry, String archivePath) { - super(archiveResourceSet, webAppPath, "jar:war:" + baseUrl + "*/" + archivePath + "!/", - jarEntry, "war:" + baseUrl + "*/" + archivePath); + super(archiveResourceSet, webAppPath, + "jar:war:" + baseUrl + UriUtil.getWarSeparator() + archivePath + "!/", + jarEntry, "war:" + baseUrl + UriUtil.getWarSeparator() + archivePath); this.archivePath = archivePath; } Modified: tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java?rev=1783408&r1=1783407&r2=1783408&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/StandardRoot.java Fri Feb 17 14:24:33 2017 @@ -44,6 +44,7 @@ import org.apache.catalina.WebResourceSe import org.apache.catalina.util.LifecycleMBeanBase; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.buf.UriUtil; import org.apache.tomcat.util.http.RequestUtil; import org.apache.tomcat.util.res.StringManager; @@ -806,7 +807,7 @@ public class StandardRoot extends Lifecy if ("jar".equals(url.getProtocol())) { endOfFileUrl = jarUrl.indexOf("!/"); } else { - endOfFileUrl = jarUrl.indexOf("*/"); + endOfFileUrl = jarUrl.indexOf(UriUtil.getWarSeparator()); } String fileUrl = jarUrl.substring(4, endOfFileUrl); try { Modified: tomcat/trunk/java/org/apache/catalina/webresources/WarResource.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/WarResource.java?rev=1783408&r1=1783407&r2=1783408&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/WarResource.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/WarResource.java Fri Feb 17 14:24:33 2017 @@ -20,6 +20,7 @@ import java.util.jar.JarEntry; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.util.buf.UriUtil; /** * Represents a single resource (file or directory) that is located within a @@ -32,7 +33,8 @@ public class WarResource extends Abstrac public WarResource(AbstractArchiveResourceSet archiveResourceSet, String webAppPath, String baseUrl, JarEntry jarEntry) { - super(archiveResourceSet, webAppPath, "war:" + baseUrl + "*/", jarEntry, baseUrl); + super(archiveResourceSet, webAppPath, "war:" + baseUrl + UriUtil.getWarSeparator(), + jarEntry, baseUrl); } Modified: tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java?rev=1783408&r1=1783407&r2=1783408&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java Fri Feb 17 14:24:33 2017 @@ -26,9 +26,42 @@ import java.util.regex.Pattern; */ public final class UriUtil { - private static Pattern PATTERN_EXCLAMATION_MARK = Pattern.compile("!/"); - private static Pattern PATTERN_CARET = Pattern.compile("\\^/"); - private static Pattern PATTERN_ASTERISK = Pattern.compile("\\*/"); + private static final char[] HEX = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + + private static final Pattern PATTERN_EXCLAMATION_MARK = Pattern.compile("!/"); + private static final Pattern PATTERN_CARET = Pattern.compile("\\^/"); + private static final Pattern PATTERN_ASTERISK = Pattern.compile("\\*/"); + private static final Pattern PATTERN_CUSTOM; + private static final String REPLACE_CUSTOM; + + private static final String WAR_SEPARATOR; + + static { + String custom = System.getProperty("org.apache.tomcat.util.buf.UriUtil.WAR_SEPARATOR"); + if (custom == null) { + WAR_SEPARATOR = "*/"; + PATTERN_CUSTOM = null; + REPLACE_CUSTOM = null; + } else { + WAR_SEPARATOR = custom + "/"; + PATTERN_CUSTOM = Pattern.compile(Pattern.quote(WAR_SEPARATOR)); + StringBuffer sb = new StringBuffer(custom.length() * 3); + // Deliberately use the platform's default encoding + byte[] ba = custom.getBytes(); + for (int j = 0; j < ba.length; j++) { + // Converting each byte in the buffer + byte toEncode = ba[j]; + sb.append('%'); + int low = toEncode & 0x0f; + int high = (toEncode & 0xf0) >> 4; + sb.append(HEX[high]); + sb.append(HEX[low]); + } + REPLACE_CUSTOM = sb.toString(); + } + } + private UriUtil() { // Utility class. Hide default constructor @@ -126,7 +159,11 @@ public final class UriUtil { String tmp = PATTERN_EXCLAMATION_MARK.matcher(input).replaceAll("%21/"); // Tomcat's custom jar:war: URL handling treats */ and ^/ as special tmp = PATTERN_CARET.matcher(tmp).replaceAll("%5e/"); - return PATTERN_ASTERISK.matcher(tmp).replaceAll("%2a/"); + tmp = PATTERN_ASTERISK.matcher(tmp).replaceAll("%2a/"); + if (PATTERN_CUSTOM != null) { + tmp = PATTERN_CUSTOM.matcher(tmp).replaceAll(REPLACE_CUSTOM); + } + return tmp; } @@ -145,10 +182,17 @@ public final class UriUtil { String file = warUrl.getFile(); if (file.contains("*/")) { file = file.replaceFirst("\\*/", "!/"); - } else { + } else if (file.contains("^/")) { file = file.replaceFirst("\\^/", "!/"); + } else if (PATTERN_CUSTOM != null) { + file = file.replaceFirst(PATTERN_CUSTOM.pattern(), "!/"); } return new URL("jar", warUrl.getHost(), warUrl.getPort(), file); } + + + public static String getWarSeparator() { + return WAR_SEPARATOR; + } } Modified: tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java?rev=1783408&r1=1783407&r2=1783408&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/scan/JarFactory.java Fri Feb 17 14:24:33 2017 @@ -19,6 +19,7 @@ package org.apache.tomcat.util.scan; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.util.regex.Matcher; import org.apache.tomcat.Jar; import org.apache.tomcat.util.buf.UriUtil; @@ -61,7 +62,8 @@ public class JarFactory { // Assume this is pointing to a JAR file within a WAR. Java doesn't // support jar:jar:file:... so switch to Tomcat's war:file:... baseExternal = baseExternal.replaceFirst("^jar:", "war:"); - baseExternal = baseExternal.replaceFirst("!/", "*/"); + baseExternal = baseExternal.replaceFirst("!/", + Matcher.quoteReplacement(UriUtil.getWarSeparator())); } return new URL("jar:" + baseExternal + "!/" + entryName); Added: tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil24.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil24.java?rev=1783408&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil24.java (added) +++ tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil24.java Fri Feb 17 14:24:33 2017 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.buf; + +public class TestUriUtil24 extends TesterUriUtilBase { + + public TestUriUtil24() { + super("$"); + } +} Added: tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil26.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil26.java?rev=1783408&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil26.java (added) +++ tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil26.java Fri Feb 17 14:24:33 2017 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.buf; + +public class TestUriUtil26 extends TesterUriUtilBase { + + public TestUriUtil26() { + super("&"); + } +} Added: tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil2A.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil2A.java?rev=1783408&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil2A.java (added) +++ tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil2A.java Fri Feb 17 14:24:33 2017 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.buf; + +public class TestUriUtil2A extends TesterUriUtilBase { + + public TestUriUtil2A() { + super("*"); + } +} Added: tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil40.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil40.java?rev=1783408&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil40.java (added) +++ tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil40.java Fri Feb 17 14:24:33 2017 @@ -0,0 +1,24 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.buf; + +public class TestUriUtil40 extends TesterUriUtilBase { + + public TestUriUtil40() { + super("@"); + } +} Copied: tomcat/trunk/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java (from r1783407, tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil.java) URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java?p2=tomcat/trunk/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java&p1=tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil.java&r1=1783407&r2=1783408&rev=1783408&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/tomcat/util/buf/TestUriUtil.java (original) +++ tomcat/trunk/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java Fri Feb 17 14:24:33 2017 @@ -23,7 +23,18 @@ import java.net.URL; import org.junit.Assert; import org.junit.Test; -public class TestUriUtil { +import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory; + +public abstract class TesterUriUtilBase { + + private final String separator; + + protected TesterUriUtilBase(String separator) { + this.separator = separator; + TomcatURLStreamHandlerFactory.register(); + System.setProperty("org.apache.tomcat.util.buf.UriUtil.WAR_SEPARATOR", separator); + } + @Test public void testBuildJarUrl01() throws MalformedURLException { @@ -61,6 +72,44 @@ public class TestUriUtil { } + @Test + public void testBuildJarUrl04() throws MalformedURLException { + File jarFile = new File("/patha/pathb" + separator + "/pathc"); + String result = UriUtil.buildJarUrl(jarFile).toString(); + + int index = result.indexOf("!/"); + Assert.assertEquals(result, result.length() - 2, index); + + index = result.indexOf(separator + "/"); + Assert.assertEquals(result, -1, index); + } + + + @Test + public void testWarToJar01() throws MalformedURLException { + doTestWarToJar("^"); + } + + + @Test + public void testWarToJar02() throws MalformedURLException { + doTestWarToJar("*"); + } + + + @Test + public void testWarToJar03() throws MalformedURLException { + doTestWarToJar(separator); + } + + + private void doTestWarToJar(String separator) throws MalformedURLException { + URL warUrl = new URL("war:file:/external/path" + separator + "/internal/path"); + URL jarUrl = UriUtil.warToJar(warUrl); + Assert.assertEquals("jar:file:/external/path!/internal/path", jarUrl.toString()); + } + + // @Test /* Uncomment to test performance for different implementations. */ public void performanceTestBuildJarUrl() throws MalformedURLException { File jarFile = new File("/patha/pathb^/pathc"); Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1783408&r1=1783407&r2=1783408&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Fri Feb 17 14:24:33 2017 @@ -119,6 +119,13 @@ <strong>Context</strong> when generating paths for dispatches triggered by <code>AsyncContext.dispatch()</code>. (markt) </fix> + <fix> + <bug>60728</bug>: Make the separator Tomcat uses in the Tomcat specific + <code>war:file:...</code> URL protocol customizable via a system + property. The separator is equivalent to the use of the <code>!</code> + character in <code>jar:file:...</code> URLs. The default separator of + <code>*</code> remains unchanged. (markt) + </fix> </changelog> </subsection> <subsection name="Coyote"> Modified: tomcat/trunk/webapps/docs/config/systemprops.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/systemprops.xml?rev=1783408&r1=1783407&r2=1783408&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/systemprops.xml (original) +++ tomcat/trunk/webapps/docs/config/systemprops.xml Fri Feb 17 14:24:33 2017 @@ -606,6 +606,13 @@ <p>If not specified, the default value of <code>200</code> will be used.</p> </property> + <property name="org.apache.tomcat.util.buf.UriUtil.WAR_SEPARATOR"> + <p>The character to use to separate the WAR file and WAR content parts of + a WAR URL using the custom WAR scheme provided by Tomcat. This is + equivalent to how <code>!</code> is used in JAR URLs.</p> + <p>If not specified, the default value of <code>*</code> will be used.</p> + </property> + <property name="tomcat.util.buf.StringCache.maxStringSize"> <p>The maximum length of String that will be cached.</p> <p>If not specified, the default value of <code>128</code> will be used.</p> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org