public static Map<String, String> parseUriPattern(String pattern, String url) {
        int qpos = url.indexOf('?');
        if (qpos != -1) {
            url = url.substring(0, qpos);
        }
        List<String> leftList = StringUtils.split(pattern, '/', false);
        List<String> rightList = StringUtils.split(url, '/', false);
        int leftSize = leftList.size();
        int rightSize = rightList.size();
        if (rightSize != leftSize) {
            return null;
        }
        Map<String, String> map = new LinkedHashMap<>(leftSize);
        for (int i = 0; i < leftSize; i++) {
            String left = leftList.get(i);
            String right = rightList.get(i);
            if (left.equals(right)) {
                continue;
            }
            if (left.startsWith("{") && left.endsWith("}")) {
                left = left.substring(1, left.length() - 1);
                map.put(left, right);
            } else {
                return null; // match failed
            }
        }
        return map;
    }
@Test
    void testParseUriPathPatterns() {
        Map<String, String> map = HttpUtils.parseUriPattern("/cats/{id}", "/cats/1");
        match(map, "{ id: '1' }");
        map = HttpUtils.parseUriPattern("/cats/{id}/", "/cats/1"); // trailing slash
        match(map, "{ id: '1' }");
        map = HttpUtils.parseUriPattern("/cats/{id}", "/cats/1/"); // trailing slash
        match(map, "{ id: '1' }");
        map = HttpUtils.parseUriPattern("/cats/{id}", "/foo/bar");
        match(map, null);
        map = HttpUtils.parseUriPattern("/cats", "/cats/1"); // exact match
        match(map, null);
        map = HttpUtils.parseUriPattern("/{path}/{id}", "/cats/1");
        match(map, "{ path: 'cats', id: '1' }");
        map = HttpUtils.parseUriPattern("/cats/{id}/foo", "/cats/1/foo");
        match(map, "{ id: '1' }");
        map = HttpUtils.parseUriPattern("/api/{img}", "/api/billie.jpg");
        match(map, "{ img: 'billie.jpg' }");
        map = HttpUtils.parseUriPattern("/hello/{raw}", "/hello/�Ill~Formed@RequiredString!");
        match(map, "{ raw: '�Ill~Formed@RequiredString!' }");
    }