From: Christian Halstrick Date: Wed, 6 Oct 2010 15:29:25 +0000 (+0200) Subject: Refactored URI parsing to detect wrong URIs X-Git-Tag: v0.10.1~173 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=refs%2Fchanges%2F90%2F1690%2F5;p=jgit.git Refactored URI parsing to detect wrong URIs There where quite some bugs regarding wrong URI parsing. In order to solve them the parsing has to be refactored. We now have specialized regexps for 'scheme://host/...', scp URIs and local file names. Now we can detect problems while parsing 'git://host:/abc' which was previously not possible. Bug: 315571 Bug: 292897 Bug: 307017 Bug: 323571 Bug: 317388 Change-Id: If72576576ebb6b9d9dc8b7e51ddd87c9909e8b62 Signed-off-by: Christian Halstrick Signed-off-by: Matthias Sohn --- diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java index 88651b75e6..6a53810d07 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java @@ -447,4 +447,10 @@ public class URIishTest extends TestCase { assertEquals("secret@pass", u.getPass()); assertEquals(u, new URIish(str)); } + + public void testMissingPort() throws URISyntaxException { + final String incorrectSshUrl = "ssh://some-host:/path/to/repository.git"; + URIish u = new URIish(incorrectSshUrl); + assertFalse(TransportGitSsh.canHandle(u)); + } } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java index 3c044fe675..82f80c547e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/URIish.java @@ -78,10 +78,10 @@ public class URIish implements Serializable { private static final String OPT_USER_PWD_P = "(?:([^/:@]+)(?::([^/]+))?@)?"; /** - * Part of a pattern which matches the optional host part of URIs. Defines - * one capturing group containing the host name. + * Part of a pattern which matches the host part of URIs. Defines one + * capturing group containing the host name. */ - private static final String OPT_HOST_P = "(?:([^/]+?))?"; + private static final String HOST_P = "([^/:]+)"; /** * Part of a pattern which matches the optional port part of URIs. Defines @@ -89,6 +89,12 @@ public class URIish implements Serializable { */ private static final String OPT_PORT_P = "(?::(\\d+))?"; + /** + * Part of a pattern which matches the ~username part (e.g. /~root in + * git://host.xyz/~root/a.git) of URIs. Defines no capturing group. + */ + private static final String USER_HOME_P = "(?:/~(?:[^/]+))"; + /** * Part of a pattern which matches the optional drive letter in paths (e.g. * D: in file:///D:/a.txt). Defines no capturing group. @@ -99,7 +105,14 @@ public class URIish implements Serializable { * Part of a pattern which matches a relative path. Relative paths don't * start with slash or drive letters. Defines no capturing group. */ - private static final String OPT_RELATIVE_PATH_P = "(?:\\.\\.)?"; + private static final String RELATIVE_PATH_P = "(?:(?:[^/]+/)*[^/]+/?)"; + + /** + * Part of a pattern which matches a relative or absolute path. Defines no + * capturing group. + */ + private static final String PATH_P = "(" + OPT_DRIVE_LETTER_P + "/?" + + RELATIVE_PATH_P + ")"; private static final long serialVersionUID = 1L; @@ -108,24 +121,37 @@ public class URIish implements Serializable { * scheme "://" user_password? hostname? portnumber? path */ private static final Pattern FULL_URI = Pattern.compile("^" // - + "(?:" // + SCHEME_P // + + "(?:" // start a group containing hostname and all options only + // availabe when a hostname is there + OPT_USER_PWD_P // - + OPT_HOST_P // + + HOST_P // + OPT_PORT_P // - + ")?" // - + "(" + OPT_DRIVE_LETTER_P + OPT_RELATIVE_PATH_P + "/.+" // - + ")$"); // /anything + + "(" // open a catpuring group the the user-home-dir part + + (USER_HOME_P + "?") // + + "/)" // + + ")?" // close the optional group containing hostname + + "(.+)?" // + + "$"); + + /** + * A pattern matching the reference to a local file. This may be an absolute + * path (maybe even containing windows drive-letters) or a relative path. + */ + private static final Pattern LOCAL_FILE = Pattern.compile("^" // + + "(/?" + PATH_P + ")" // + + "$"); /** * A pattern matching SCP URI's of the form user@host:path/to/repo.git */ private static final Pattern SCP_URI = Pattern.compile("^" // - + "(?:([^@]+?)@)?" // - + "([^:]+?)" // - + ":" // - + "(.+)" // - + "$"); // + + OPT_USER_PWD_P // + + HOST_P // + + ":(" // + + ("(?:" + USER_HOME_P + "/)?") // + + RELATIVE_PATH_P // + + ")$"); private String scheme; @@ -155,27 +181,49 @@ public class URIish implements Serializable { host = matcher.group(4); if (matcher.group(5) != null) port = Integer.parseInt(matcher.group(5)); - path = matcher.group(6); - if (path.length() >= 3 - && path.charAt(0) == '/' - && path.charAt(2) == ':' - && (path.charAt(1) >= 'A' && path.charAt(1) <= 'Z' - || path.charAt(1) >= 'a' && path.charAt(1) <= 'z')) - path = path.substring(1); - else if (scheme != null && path.length() >= 2 - && path.charAt(0) == '/' && path.charAt(1) == '~') - path = path.substring(1); + path = cleanLeadingSlashes( + n2e(matcher.group(6)) + n2e(matcher.group(7)), scheme); } else { matcher = SCP_URI.matcher(s); if (matcher.matches()) { user = matcher.group(1); - host = matcher.group(2); - path = matcher.group(3); - } else - throw new URISyntaxException(s, JGitText.get().cannotParseGitURIish); + pass = matcher.group(2); + host = matcher.group(3); + path = matcher.group(4); + } else { + matcher = LOCAL_FILE.matcher(s); + if (matcher.matches()) { + path = matcher.group(1); + } else + throw new URISyntaxException(s, + JGitText.get().cannotParseGitURIish); + } } } + private String n2e(String s) { + if (s == null) + return ""; + else + return s; + } + + // takes care to cut of a leading slash if a windows drive letter or a + // user-home-dir specifications are + private String cleanLeadingSlashes(String p, String s) { + if (p.length() >= 3 + && p.charAt(0) == '/' + && p.charAt(2) == ':' + && (p.charAt(1) >= 'A' && p.charAt(1) <= 'Z' || p.charAt(1) >= 'a' + && p.charAt(1) <= 'z')) + return p.substring(1); + else if (s != null && p.length() >= 2 && p.charAt(0) == '/' + && p.charAt(1) == '~') + return p.substring(1); + else + return p; + } + /** * Construct a URIish from a standard URL. *