Author: kkolinko Date: Tue Apr 8 12:55:54 2014 New Revision: 1585713 URL: http://svn.apache.org/r1585713 Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56365 Simplify file name matching code in StandardJarScanFilter.
Removed: tomcat/trunk/java/org/apache/tomcat/util/file/Constants.java tomcat/trunk/java/org/apache/tomcat/util/file/LocalStrings.properties Modified: tomcat/trunk/java/org/apache/tomcat/util/file/Matcher.java tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanFilter.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/tomcat/util/file/Matcher.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/file/Matcher.java?rev=1585713&r1=1585712&r2=1585713&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/file/Matcher.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/file/Matcher.java Tue Apr 8 12:55:54 2014 @@ -18,14 +18,8 @@ package org.apache.tomcat.util.file; -import java.io.File; -import java.util.Locale; import java.util.Set; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.res.StringManager; - /** * <p>This is a utility class to match file globs. * The class has been derived from @@ -36,44 +30,23 @@ import org.apache.tomcat.util.res.String public final class Matcher { /** - * The pattern that matches an arbitrary number of directories. - */ - public static final String DEEP_TREE_MATCH = "**"; - - private static final String OS_NAME = - System.getProperty("os.name").toLowerCase(Locale.ENGLISH); - private static final String PATH_SEP = - System.getProperty("path.separator"); - private static final boolean ON_NETWARE = isNetware(); - private static final boolean ON_DOS = isDos(); - - /** - * The string resources for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - private static final Log log = LogFactory.getLog(Matcher.class); - - /** - * Tests whether or not a given path matches any pattern in the given set. + * Tests whether or not a given file name matches any file name pattern in + * the given set. The match is performed case-sensitively. * - * If you need to call this method multiple times with the same - * pattern you should rather pre parse the pattern using tokenizePathAsArray. - * - * @see #tokenizePathAsArray + * @see #match(String, String, boolean) * * @param patternSet The pattern set to match against. Must not be * <code>null</code>. - * @param str The path to match, as a String. Must not be - * <code>null</code>. - * - * @return <code>true</code> if any pattern in the set matches against the string, - * or <code>false</code> otherwise. - */ - public static boolean matchPath(Set<String[]> patternSet, String str) { - for (String[] patternTokens: patternSet) { - if (matchPath(patternTokens, tokenizePathAsArray(str), true)) { + * @param str The file name to match, as a String. Must not be + * <code>null</code>. It must be just a file name, without + * a path. + * + * @return <code>true</code> if any pattern in the set matches against the + * file name, or <code>false</code> otherwise. + */ + public static boolean matchName(Set<String> patternSet, String fileName) { + for (String pattern: patternSet) { + if (match(pattern, fileName, true)) { return true; } } @@ -81,177 +54,6 @@ public final class Matcher { } /** - * Tests whether or not a given path matches a given pattern. - * - * If you need to call this method multiple times with the same - * pattern you should rather pre parse the pattern using tokenizePathAsArray. - * - * @see #tokenizePathAsArray - * - * @param pattern The pattern to match against. Must not be - * <code>null</code>. - * @param str The path to match, as a String. Must not be - * <code>null</code>. - * - * @return <code>true</code> if the pattern matches against the string, - * or <code>false</code> otherwise. - */ - public static boolean matchPath(String pattern, String str) { - String[] patDirs = tokenizePathAsArray(pattern); - return matchPath(patDirs, tokenizePathAsArray(str), true); - } - - /** - * Tests whether or not a given path matches a given pattern. - * - * If you need to call this method multiple times with the same - * pattern you should rather pre parse the pattern using tokenizePathAsArray. - * - * @see #tokenizePathAsArray - * - * @param pattern The pattern to match against. Must not be - * <code>null</code>. - * @param str The path to match, as a String. Must not be - * <code>null</code>. - * @param isCaseSensitive Whether or not matching should be performed - * case sensitively. - * - * @return <code>true</code> if the pattern matches against the string, - * or <code>false</code> otherwise. - */ - public static boolean matchPath(String pattern, String str, - boolean isCaseSensitive) { - String[] patDirs = tokenizePathAsArray(pattern); - return matchPath(patDirs, tokenizePathAsArray(str), isCaseSensitive); - } - - /** - * Core implementation of matchPath using an already tokenized pattern. - */ - public static boolean matchPath(String[] tokenizedPattern, String[] strDirs, - boolean isCaseSensitive) { - int patIdxStart = 0; - int patIdxEnd = tokenizedPattern.length - 1; - int strIdxStart = 0; - int strIdxEnd = strDirs.length - 1; - - // up to first '**' - while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { - String patDir = tokenizedPattern[patIdxStart]; - if (patDir.equals(DEEP_TREE_MATCH)) { - break; - } - if (!match(patDir, strDirs[strIdxStart], isCaseSensitive)) { - return false; - } - patIdxStart++; - strIdxStart++; - } - if (strIdxStart > strIdxEnd) { - // String is exhausted - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { - return false; - } - } - return true; - } else { - if (patIdxStart > patIdxEnd) { - // String not exhausted, but pattern is. Failure. - return false; - } - } - - // up to last '**' - while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { - String patDir = tokenizedPattern[patIdxEnd]; - if (patDir.equals(DEEP_TREE_MATCH)) { - break; - } - if (!match(patDir, strDirs[strIdxEnd], isCaseSensitive)) { - return false; - } - patIdxEnd--; - strIdxEnd--; - } - if (strIdxStart > strIdxEnd) { - // String is exhausted - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { - return false; - } - } - return true; - } - - while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { - int patIdxTmp = -1; - for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { - if (tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { - patIdxTmp = i; - break; - } - } - if (patIdxTmp == patIdxStart + 1) { - // '**/**' situation, so skip one - patIdxStart++; - continue; - } - // Find the pattern between padIdxStart & padIdxTmp in str between - // strIdxStart & strIdxEnd - int patLength = (patIdxTmp - patIdxStart - 1); - int strLength = (strIdxEnd - strIdxStart + 1); - int foundIdx = -1; - strLoop: - for (int i = 0; i <= strLength - patLength; i++) { - for (int j = 0; j < patLength; j++) { - String subPat = tokenizedPattern[patIdxStart + j + 1]; - String subStr = strDirs[strIdxStart + i + j]; - if (!match(subPat, subStr, isCaseSensitive)) { - continue strLoop; - } - } - - foundIdx = strIdxStart + i; - break; - } - - if (foundIdx == -1) { - return false; - } - - patIdxStart = patIdxTmp; - strIdxStart = foundIdx + patLength; - } - - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!tokenizedPattern[i].equals(DEEP_TREE_MATCH)) { - return false; - } - } - - return true; - } - - /** - * Tests whether or not a string matches against a pattern. - * The pattern may contain two special characters:<br> - * '*' means zero or more characters<br> - * '?' means one and only one character - * - * @param pattern The pattern to match against. - * Must not be <code>null</code>. - * @param str The string which must be matched against the pattern. - * Must not be <code>null</code>. - * - * @return <code>true</code> if the string matches against the pattern, - * or <code>false</code> otherwise. - */ - public static boolean match(String pattern, String str) { - return match(pattern, str, true); - } - - /** * Tests whether or not a string matches against a pattern. * The pattern may contain two special characters:<br> * '*' means zero or more characters<br> @@ -411,156 +213,4 @@ public final class Matcher { : Character.toUpperCase(ch) != Character.toUpperCase(other); } - /** - * Breaks a path up into a array of path elements, tokenizing on - * <code>File.separator</code>. - * - * @param path Path to tokenize. Must not be <code>null</code>. - * - * @return a String array of path elements from the tokenized path - */ - public static String[] tokenizePathAsArray(String path) { - if (log.isTraceEnabled()) { - log.trace(sm.getString("matcher.tokenize", path)); - } - String root = null; - if (isAbsolutePath(path)) { - String[] s = dissect(path); - root = s[0]; - path = s[1]; - } - char sep = File.separatorChar; - int start = 0; - int len = path.length(); - int count = 0; - for (int pos = 0; pos < len; pos++) { - if (path.charAt(pos) == sep) { - if (pos != start) { - count++; - } - start = pos + 1; - } - } - if (len != start) { - count++; - } - String[] l = new String[count + ((root == null) ? 0 : 1)]; - - if (root != null) { - l[0] = root; - count = 1; - } else { - count = 0; - } - start = 0; - for (int pos = 0; pos < len; pos++) { - if (path.charAt(pos) == sep) { - if (pos != start) { - String tok = path.substring(start, pos); - l[count++] = tok; - } - start = pos + 1; - } - } - if (len != start) { - String tok = path.substring(start); - l[count/*++*/] = tok; - } - return l; - } - - /** - * Dissect the specified absolute path. - * @param path the path to dissect (must be absolute). - * @return String[] {root, remaining path}. - * @throws java.lang.NullPointerException if path is null. - */ - private static String[] dissect(String path) { - char sep = File.separatorChar; - path = path.replace('/', sep).replace('\\', sep); - - String root = null; - int colon = path.indexOf(':'); - if (colon > 0 && (ON_DOS || ON_NETWARE)) { - - int next = colon + 1; - root = path.substring(0, next); - char[] ca = path.toCharArray(); - root += sep; - //remove the initial separator; the root has it. - next = (ca[next] == sep) ? next + 1 : next; - - StringBuilder sbPath = new StringBuilder(); - // Eliminate consecutive slashes after the drive spec: - for (int i = next; i < ca.length; i++) { - if (ca[i] != sep || ca[i - 1] != sep) { - sbPath.append(ca[i]); - } - } - path = sbPath.toString(); - } else if (path.length() > 1 && path.charAt(1) == sep) { - // UNC drive - int nextsep = path.indexOf(sep, 2); - nextsep = path.indexOf(sep, nextsep + 1); - root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path; - path = path.substring(root.length()); - } else { - root = File.separator; - path = path.substring(1); - } - return new String[] {root, path}; - } - - /** - * Verifies that the specified filename represents an absolute path. - * Differs from new java.io.File("filename").isAbsolute() in that a path - * beginning with a double file separator--signifying a Windows UNC--must - * at minimum match "\\a\b" to be considered an absolute path. - * @param filename the filename to be checked. - * @return true if the filename represents an absolute path. - * @throws java.lang.NullPointerException if filename is null. - */ - private static boolean isAbsolutePath(String filename) { - int len = filename.length(); - if (len == 0) { - return false; - } - char sep = File.separatorChar; - filename = filename.replace('/', sep).replace('\\', sep); - char c = filename.charAt(0); - if (!(ON_DOS || ON_NETWARE)) { - return (c == sep); - } - if (c == sep) { - // CheckStyle:MagicNumber OFF - if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) { - return false; - } - // CheckStyle:MagicNumber ON - int nextsep = filename.indexOf(sep, 2); - return nextsep > 2 && nextsep + 1 < len; - } - int colon = filename.indexOf(':'); - return (Character.isLetter(c) && colon == 1 - && filename.length() > 2 && filename.charAt(2) == sep) - || (ON_NETWARE && colon > 0); - } - - /** - * Determines if our OS is Netware. - * - * @return true if we run on Netware - */ - private static boolean isNetware() { - return OS_NAME.indexOf("netware") > -1; - } - - /** - * Determines if our OS is DOS. - * - * @return true if we run on DOS - */ - private static boolean isDos() { - return PATH_SEP.equals(";") && !isNetware(); - } } Modified: tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanFilter.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanFilter.java?rev=1585713&r1=1585712&r2=1585713&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanFilter.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanFilter.java Tue Apr 8 12:55:54 2014 @@ -34,19 +34,19 @@ public class StandardJarScanFilter imple private String defaultSkip; private String defaultScan; - private Set<String[]> defaultSkipSet = new HashSet<>(); - private Set<String[]> defaultScanSet = new HashSet<>(); + private Set<String> defaultSkipSet = new HashSet<>(); + private Set<String> defaultScanSet = new HashSet<>(); private String tldSkip; private String tldScan; - private Set<String[]> tldSkipSet = new HashSet<>(); - private Set<String[]> tldScanSet = new HashSet<>(); + private Set<String> tldSkipSet = new HashSet<>(); + private Set<String> tldScanSet = new HashSet<>(); private boolean defaultTldScan = true; private String pluggabilitySkip; private String pluggabilityScan; - private Set<String[]> pluggabilitySkipSet = new HashSet<>(); - private Set<String[]> pluggabilityScanSet = new HashSet<>(); + private Set<String> pluggabilitySkipSet = new HashSet<>(); + private Set<String> pluggabilityScanSet = new HashSet<>(); private boolean defaultPluggabilityScan = true; /** @@ -186,8 +186,8 @@ public class StandardJarScanFilter imple @Override public boolean check(JarScanType jarScanType, String jarName) { boolean defaultScan; - Set<String[]> toSkip = new HashSet<>(); - Set<String[]> toScan = new HashSet<>(); + Set<String> toSkip = new HashSet<>(); + Set<String> toScan = new HashSet<>(); Lock readLock = configurationLock.readLock(); readLock.lock(); @@ -217,8 +217,8 @@ public class StandardJarScanFilter imple } if (defaultScan) { - if (Matcher.matchPath(toSkip, jarName)) { - if (Matcher.matchPath(toScan, jarName)) { + if (Matcher.matchName(toSkip, jarName)) { + if (Matcher.matchName(toScan, jarName)) { return true; } else { return false; @@ -226,8 +226,8 @@ public class StandardJarScanFilter imple } return true; } else { - if (Matcher.matchPath(toScan, jarName)) { - if (Matcher.matchPath(toSkip, jarName)) { + if (Matcher.matchName(toScan, jarName)) { + if (Matcher.matchName(toSkip, jarName)) { return false; } else { return true; @@ -237,13 +237,15 @@ public class StandardJarScanFilter imple } } - private void populateSetFromAttribute(String attribute, Set<String[]> set) { + private void populateSetFromAttribute(String attribute, Set<String> set) { set.clear(); if (attribute != null) { StringTokenizer tokenizer = new StringTokenizer(attribute, ","); while (tokenizer.hasMoreElements()) { String token = tokenizer.nextToken().trim(); - set.add(Matcher.tokenizePathAsArray(token)); + if (token.length() > 0) { + set.add(token); + } } } } Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1585713&r1=1585712&r2=1585713&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Tue Apr 8 12:55:54 2014 @@ -79,6 +79,10 @@ <code>session.invalidate()</code> from the session destroyed event for that session. (markt) </fix> + <scode> + <bug>56365</bug>: Simplify filename pattern matching code in + <scode>StandardJarScanner</scode>. (kkolinko) + </scode> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org