You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by kk...@apache.org on 2014/04/08 14:55:54 UTC

svn commit: r1585713 - in /tomcat/trunk: java/org/apache/tomcat/util/file/ java/org/apache/tomcat/util/scan/ webapps/docs/

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-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org