Java servlet url模式匹配实现中出错

Java servlet url模式匹配实现中出错,java,servlets,pattern-matching,url-pattern,Java,Servlets,Pattern Matching,Url Pattern,我正在按照Servlet规范实现Servlet URL模式匹配。我的配对方法: public static boolean match(String pattern, String str, boolean isCaseSensitive) { char[] patArr = pattern.toCharArray(); char[] strArr = str.toCharArray(); int patIdxStart = 0;

我正在按照Servlet规范实现Servlet URL模式匹配。我的配对方法:

public static boolean match(String pattern, String str, boolean isCaseSensitive) {
        char[] patArr = pattern.toCharArray();
        char[] strArr = str.toCharArray();
        int patIdxStart = 0;
        int patIdxEnd = patArr.length - 1;
        int strIdxStart = 0;
        int strIdxEnd = strArr.length - 1;

        boolean containsStar = false;
        for (int i = 0; i < patArr.length; i++) {
            if (patArr[i] != '*') {
                continue;
            }
            containsStar = true;
            break;
        }

        if (!containsStar) {
            if (patIdxEnd != strIdxEnd) {
                return false;
            }
            for (int i = 0; i <= patIdxEnd; i++) {
                char ch = patArr[i];
                if (ch == '?')
                    continue;
                if ((isCaseSensitive) && (ch != strArr[i])) {
                    return false;
                }
                if ((!isCaseSensitive)
                        && (Character.toUpperCase(ch) != Character
                                .toUpperCase(strArr[i]))) {
                    return false;
                }
            }

            return true;
        }

        if (patIdxEnd == 0) {
            return true;
        }

        char ch;
        while (((ch = patArr[patIdxStart]) != '*')
                && (strIdxStart <= strIdxEnd)) {
            if (ch != '?') {
                if ((isCaseSensitive) && (ch != strArr[strIdxStart])) {
                    return false;
                }
                if ((!isCaseSensitive)
                        && (Character.toUpperCase(ch) != Character
                                .toUpperCase(strArr[strIdxStart]))) {
                    return false;
                }
            }
            patIdxStart++;
            strIdxStart++;
        }

        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++) {
                if (patArr[i] != '*') {
                    return false;
                }
            }
            return true;
        }

        while (((ch = patArr[patIdxEnd]) != '*') && (strIdxStart <= strIdxEnd)) {
            if (ch != '?') {
                if ((isCaseSensitive) && (ch != strArr[strIdxEnd])) {
                    return false;
                }
                if ((!isCaseSensitive)
                        && (Character.toUpperCase(ch) != Character
                                .toUpperCase(strArr[strIdxEnd]))) {
                    return false;
                }
            }
            patIdxEnd--;
            strIdxEnd--;
        }

        if (strIdxStart > strIdxEnd) {
            for (int i = patIdxStart; i <= patIdxEnd; i++) {
                if (patArr[i] != '*') {
                    return false;
                }
            }
            return true;
        }

        while ((patIdxStart != patIdxEnd) && (strIdxStart <= strIdxEnd)) {
            int patIdxTmp = -1;
            for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
                if (patArr[i] != '*') {
                    continue;
                }
                patIdxTmp = i;
                break;
            }

            if (patIdxTmp == patIdxStart + 1) {
                patIdxStart++;
                continue;
            }

            int patLength = patIdxTmp - patIdxStart - 1;
            int strLength = strIdxEnd - strIdxStart + 1;
            int foundIdx = -1;
            for (int i = 0; i <= strLength - patLength; i++) {
                int j = 0;
                while (true)
                    if (j < patLength) {
                        ch = patArr[(patIdxStart + j + 1)];
                        if (ch != '?') {
                            if ((isCaseSensitive)
                                    && (ch != strArr[(strIdxStart + i + j)])) {
                                break;
                            }
                            if ((!isCaseSensitive)
                                    && (Character.toUpperCase(ch) != Character
                                            .toUpperCase(strArr[(strIdxStart
                                                    + i + j)])))
                                break;
                        } else {
                            j++;
                            continue;
                        }

                    } else {
                        foundIdx = strIdxStart + i;
                        break;
                    }
            }

            if (foundIdx == -1) {
                return false;
            }

            patIdxStart = patIdxTmp;
            strIdxStart = foundIdx + patLength;
        }

        for (int i = patIdxStart; i <= patIdxEnd; i++) {
            if (patArr[i] != '*') {
                return false;
            }
        }
        return true;
    }
测试用例永远运行,不能停止。我有两个问题:

  • 模式
    “*.a*”
    与Servlet URL模式匹配规范有效吗
  • 如何修复此错误以打破无限循环
  • 我修复了它,在while(true)循环中添加以下行以中断循环:

    [...]
    while(true) {
         if (ch != '?') {
              if(...) {
                 //...
                 break;
              }
    
              if(...) {
                 //...
                 break;
              }
              j++;  // Add this line to avoid infinite loop
         }
    }
    

    下面是我的JavaServlet规范3.1(2013年4月),它将请求映射到Servlet实现

    /**
     * Java Servlet Specification 3.1 (April 2013)
     * Mapping Requests to Servlets (Chapter 12) implementation.
     *
     * This class is thread safe.
     */
    public class ServletMappingMatcher {
        private final String[] patterns;
        private final String[] welcomePages;
    
        public ServletMappingMatcher(String... patterns) {
            this(patterns, new String[0]);
        }
    
        public ServletMappingMatcher(String[] patterns, String[] welcomePages) {
            this.patterns = patterns;
            this.welcomePages = welcomePages;
        }
    
        public String getPatternForPath(String path) {
            for (String pattern : patterns) {
                if (matches(pattern, path)) {
                    return pattern;
                }
            }
    
            return null;
        }
    
        private boolean matches(String pattern, String path) {
            if (isPathMapping(pattern)) {
                return pathMatches(pattern, path);
            } else if (isExtensionPattern(pattern)) {
                return extensionMatches(pattern, path);
            } else if (isApplicationContextRoot(pattern)) {
                return matchesApplicationContextRoot(path);
            } else if (isDefaultServlet(pattern)) {
                return matchesDefaultServlet(path);
            }
    
            return strictlyMatches(pattern, path);
        }
    
        private boolean isPathMapping(String pattern) {
            return pattern.startsWith("/") && pattern.endsWith("/*");
        }
    
        private boolean isExtensionPattern(String pattern) {
            return pattern.startsWith("*.");
        }
    
        private boolean isApplicationContextRoot(String pattern) {
            return pattern.isEmpty();
        }
    
        private boolean isDefaultServlet(String pattern) {
            return pattern.equals("/");
        }
    
        private boolean pathMatches(String pattern, String path) {
            return path.startsWith(pattern.substring(0, pattern.length() - 1)) ||
                    path.equals(pattern.substring(0, pattern.length() - 2));
        }
    
        private boolean extensionMatches(String pattern, String path) {
            return path.endsWith(pattern.substring(1));
        }
    
        private boolean matchesApplicationContextRoot(String path) {
            return path.equals("/");
        }
    
        private boolean strictlyMatches(String pattern, String path) {
            return path.equals(pattern);
        }
    
        private boolean matchesDefaultServlet(String path) {
            if (path.endsWith("/")) {
                return true;
            }
    
            for (String welcomePage : welcomePages) {
                if (path.endsWith("/" + welcomePage)) {
                    return true;
                }
            }
    
            return false;
        }
    }
    
    和JUnit测试:

    import org.junit.Assert;
    import org.junit.Test;
    
    public class ServletMappingMatcherTest {
        @Test
        public void testsFromSpec() {
            final String servlet1Pattern = "/foo/bar/*";
            final String servlet2Pattern = "/baz/*";
            final String servlet3Pattern = "/catalog";
            final String servlet4Pattern = "*.bop";
            final String defaultServlet = "/";
    
            final String[] patterns = {servlet1Pattern, servlet2Pattern, servlet3Pattern, servlet4Pattern, defaultServlet};
            final String[] welcomePages = {"index.html"};
    
            final ServletMappingMatcher matcher = new ServletMappingMatcher(patterns, welcomePages);
    
            Assert.assertEquals(servlet1Pattern, matcher.getPatternForPath("/foo/bar/index.html"));
            Assert.assertEquals(servlet1Pattern, matcher.getPatternForPath("/foo/bar/index.bop"));
            Assert.assertEquals(servlet2Pattern, matcher.getPatternForPath("/baz"));
            Assert.assertEquals(servlet2Pattern, matcher.getPatternForPath("/baz/index.html"));
            Assert.assertEquals(servlet3Pattern, matcher.getPatternForPath("/catalog"));
            Assert.assertEquals(defaultServlet, matcher.getPatternForPath("/catalog/index.html"));
            Assert.assertEquals(servlet4Pattern, matcher.getPatternForPath("/catalog/rececar.bop"));
            Assert.assertEquals(servlet4Pattern, matcher.getPatternForPath("/index.bop"));
        }
    }
    
    import org.junit.Assert;
    import org.junit.Test;
    
    public class ServletMappingMatcherTest {
        @Test
        public void testsFromSpec() {
            final String servlet1Pattern = "/foo/bar/*";
            final String servlet2Pattern = "/baz/*";
            final String servlet3Pattern = "/catalog";
            final String servlet4Pattern = "*.bop";
            final String defaultServlet = "/";
    
            final String[] patterns = {servlet1Pattern, servlet2Pattern, servlet3Pattern, servlet4Pattern, defaultServlet};
            final String[] welcomePages = {"index.html"};
    
            final ServletMappingMatcher matcher = new ServletMappingMatcher(patterns, welcomePages);
    
            Assert.assertEquals(servlet1Pattern, matcher.getPatternForPath("/foo/bar/index.html"));
            Assert.assertEquals(servlet1Pattern, matcher.getPatternForPath("/foo/bar/index.bop"));
            Assert.assertEquals(servlet2Pattern, matcher.getPatternForPath("/baz"));
            Assert.assertEquals(servlet2Pattern, matcher.getPatternForPath("/baz/index.html"));
            Assert.assertEquals(servlet3Pattern, matcher.getPatternForPath("/catalog"));
            Assert.assertEquals(defaultServlet, matcher.getPatternForPath("/catalog/index.html"));
            Assert.assertEquals(servlet4Pattern, matcher.getPatternForPath("/catalog/rececar.bop"));
            Assert.assertEquals(servlet4Pattern, matcher.getPatternForPath("/index.bop"));
        }
    }