Commit 8d3d28f5 added test cases for URLs which should be ssh.

Add more tests testing all the combinations:
 -IPv4 or IPv6
 -path starting with "/" or with "/~"
 -with and without the ssh:// scheme

Add tests for ssh:// with port number.

When a git repository "foo:bar" exist, git clone will call
absolute_path() and git_connect() will be called with
something like "/home/user/projects/foo:bar"

Tighten the test and use "foo:bar" instead of "./foo:bar",
refactor clear_ssh() and expect_ssh() into test_clone_url().

"git clone foo/bar:baz" should not be ssh:
  Make the rule
  "if there is a slash before the first colon, it is not ssh"
  more strict by using the same is_local() in both connect.c
  and transport.c. Add a test case.

Bug fixes for corner cases:
- Handle clone of [::1]:/~repo correctly (2e7766655):
  Git should call "ssh ::1 ~repo", not ssh ::1 /~repo
  This was caused by looking at (host != url), which never
  worked for host names with literal IPv6 adresses, embedded by []
  Support for the [] URLs was introduced in 356bece0a.

- Do not tamper local URLs starting with '[' which have a ']'

Signed-off-by: Torsten Bögershausen <tbo...@web.de>
---
(This does apply on pu, not on master.
 I'm almost sure there are more corner cases, but the
 most important things should be covered)

 connect.c        | 47 +++++++++++++++++----------
 connect.h        |  1 +
 t/t5601-clone.sh | 96 +++++++++++++++++++++++++++++++++++++++++++-------------
 transport.c      |  8 -----
 4 files changed, 106 insertions(+), 46 deletions(-)

diff --git a/connect.c b/connect.c
index 06e88b0..903063e 100644
--- a/connect.c
+++ b/connect.c
@@ -231,6 +231,7 @@ int server_supports(const char *feature)
 }
 
 enum protocol {
+       PROTO_LOCAL_OR_SSH = 0,
        PROTO_LOCAL = 1,
        PROTO_SSH,
        PROTO_GIT
@@ -547,6 +548,15 @@ static char *get_port(char *host)
 
 static struct child_process no_fork;
 
+int is_local(const char *url)
+{
+       const char *colon = strchr(url, ':');
+       const char *slash = strchr(url, '/');
+       return !colon || (slash && slash < colon) ||
+               has_dos_drive_prefix(url);
+}
+
+
 /*
  * This returns a dummy child_process if the transport protocol does not
  * need fork(2), or a struct child_process object if it does.  Once done,
@@ -564,9 +574,9 @@ struct child_process *git_connect(int fd[2], const char 
*url_orig,
        char *url;
        char *host, *path;
        char *end;
-       int c;
+       int seperator;
        struct child_process *conn = &no_fork;
-       enum protocol protocol = PROTO_LOCAL;
+       enum protocol protocol = PROTO_LOCAL_OR_SSH;
        int free_path = 0;
        char *port = NULL;
        const char **arg;
@@ -587,20 +597,23 @@ struct child_process *git_connect(int fd[2], const char 
*url_orig,
                *host = '\0';
                protocol = get_protocol(url);
                host += 3;
-               c = '/';
+               seperator = '/';
        } else {
                host = url;
-               c = ':';
+               seperator = ':';
+               if (is_local(url))
+                       protocol = PROTO_LOCAL;
        }
 
        /*
         * Don't do destructive transforms with git:// as that
         * protocol code does '[]' unwrapping of its own.
+        * Don't change local URLs
         */
        if (host[0] == '[') {
                end = strchr(host + 1, ']');
                if (end) {
-                       if (protocol != PROTO_GIT) {
+                       if (protocol != PROTO_GIT && protocol != PROTO_LOCAL) {
                                *end = 0;
                                host++;
                        }
@@ -610,17 +623,17 @@ struct child_process *git_connect(int fd[2], const char 
*url_orig,
        } else
                end = host;
 
-       path = strchr(end, c);
-       if (path && !has_dos_drive_prefix(end)) {
-               if (c == ':') {
-                       if (host != url || path < strchrnul(host, '/')) {
-                               protocol = PROTO_SSH;
-                               *path++ = '\0';
-                       } else /* '/' in the host part, assume local path */
-                               path = end;
+       path = strchr(end, seperator);
+       if (seperator == ':') {
+               if (path && protocol == PROTO_LOCAL_OR_SSH) {
+                       /* We have a ':' */
+                       protocol = PROTO_SSH;
+                       *path++ = '\0';
+               } else {/* assume local path */
+                       protocol = PROTO_LOCAL;
+                       path = end;
                }
-       } else
-               path = end;
+       }
 
        if (!path || !*path)
                die("No path specified. See 'man git-pull' for valid url 
syntax");
@@ -629,7 +642,7 @@ struct child_process *git_connect(int fd[2], const char 
*url_orig,
         * null-terminate hostname and point path to ~ for URL's like this:
         *    ssh://host.xz/~user/repo
         */
-       if (protocol != PROTO_LOCAL && host != url) {
+       if (protocol != PROTO_LOCAL && seperator == '/') {
                char *ptr = path;
                if (path[1] == '~')
                        path++;
@@ -644,7 +657,7 @@ struct child_process *git_connect(int fd[2], const char 
*url_orig,
        /*
         * Add support for ssh port: ssh://host.xy:<port>/...
         */
-       if (protocol == PROTO_SSH && host != url)
+       if (protocol == PROTO_SSH && seperator == '/')
                port = get_port(end);
 
        if (protocol == PROTO_GIT) {
diff --git a/connect.h b/connect.h
index 64fb7db..fb2de9b 100644
--- a/connect.h
+++ b/connect.h
@@ -5,6 +5,7 @@
 extern struct child_process *git_connect(int fd[2], const char *url, const 
char *prog, int flags);
 extern int finish_connect(struct child_process *conn);
 extern int git_connection_is_socket(struct child_process *conn);
+extern int is_local(const char *url);
 extern int server_supports(const char *feature);
 extern int parse_feature_request(const char *features, const char *feature);
 extern const char *server_feature_value(const char *feature, int *len_ret);
diff --git a/t/t5601-clone.sh b/t/t5601-clone.sh
index 1d1c875..69af007 100755
--- a/t/t5601-clone.sh
+++ b/t/t5601-clone.sh
@@ -294,39 +294,93 @@ test_expect_success 'setup ssh wrapper' '
        export TRASH_DIRECTORY
 '
 
-clear_ssh () {
-       >"$TRASH_DIRECTORY/ssh-output"
-}
-
-expect_ssh () {
+i6501=0
+# $1 url
+# $2 none|host
+# $3 path
+test_clone_url () {
+       i6501=$(($i6501 + 1))
+       >"$TRASH_DIRECTORY/ssh-output" &&
+       test_might_fail git clone "$1" tmp$i6501 &&
        {
-               case "$1" in
+               case "$2" in
                none)
                        ;;
                *)
-                       echo "ssh: $1 git-upload-pack '$2'"
+                       echo "ssh: $2 git-upload-pack '$3'"
                esac
        } >"$TRASH_DIRECTORY/ssh-expect" &&
-       (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output)
+       (cd "$TRASH_DIRECTORY" && test_cmp ssh-expect ssh-output) && {
+               rm -rf ssh-expect ssh-output
+       }
 }
 
-test_expect_success 'cloning myhost:src uses ssh' '
-       clear_ssh &&
-       git clone myhost:src ssh-clone &&
-       expect_ssh myhost src
-'
-
+# url looks ssh like, and is on disc: should be local
 test_expect_success NOT_MINGW,NOT_CYGWIN 'clone local path foo:bar' '
-       clear_ssh &&
        cp -R src "foo:bar" &&
-       git clone "./foo:bar" foobar &&
-       expect_ssh none
+       test_clone_url "foo:bar" none &&
+       ( cd tmp$i6501 && git log)
+'
+#ip v4
+for repo in rep rep/home/project /~proj 123
+do
+       test_expect_success "cloning host:$repo" '
+               test_clone_url host:$repo host $repo
+       '
+done
+
+#ipv6
+for repo in rep rep/home/project /~proj 123
+do
+       test_expect_success "cloning [::1]:$repo" '
+               test_clone_url [::1]:$repo ::1 $repo
+       '
+done
+
+# Corner cases
+for url in [foo]bar/baz:qux [foo/bar]:baz foo/bar:baz
+do
+       test_expect_success "cloning $url is not ssh" '
+                       test_clone_url $url none
+       '
+done
+
+#with ssh:// scheme
+test_expect_success 'ssh://host.xz/home/user/repo' '
+       test_clone_url "ssh://host.xz/home/user/repo" host.xz "/home/user/repo"
+'
+
+# from home directory
+test_expect_success 'ssh://host.xz/~repo' '
+       test_clone_url "ssh://host.xz/~repo" host.xz "~repo"
+'
+# with port number
+test_expect_success 'ssh://host.xz:22/home/user/repo' '
+       test_clone_url "ssh://host.xz:22/home/user/repo" "-p 22 host.xz" 
"/home/user/repo"
 '
 
-test_expect_success 'bracketed hostnames are still ssh' '
-       clear_ssh &&
-       git clone "[myhost:123]:src" ssh-bracket-clone &&
-       expect_ssh myhost:123 src
+# from home directory with port number
+test_expect_success 'ssh://host.xz:22/~repo' '
+       test_clone_url "ssh://host.xz:22/~repo" "-p 22 host.xz" "~repo"
+'
+
+#IPv6
+test_expect_success 'ssh://[::1]/home/user/repo' '
+       test_clone_url "ssh://[::1]/home/user/repo" "::1" "/home/user/repo"
+'
+
+#IPv6 from home directory
+test_expect_success 'ssh://[::1]/~repo' '
+       test_clone_url "ssh://[::1]/~repo" "::1" "~repo"
+'
+
+#IPv6 with port number
+test_expect_success 'ssh://[::1]:22/home/user/repo' '
+       test_clone_url "ssh://[::1]:22/home/user/repo" "-p 22 ::1" 
"/home/user/repo"
+'
+#IPv6 from home directory with port number
+test_expect_success 'ssh://[::1]:22/~repo' '
+       test_clone_url "ssh://[::1]:22/~repo" "-p 22 ::1" "~repo"
 '
 
 test_expect_success 'clone from a repository with two identical branches' '
diff --git a/transport.c b/transport.c
index 7202b77..a09ba95 100644
--- a/transport.c
+++ b/transport.c
@@ -885,14 +885,6 @@ void transport_take_over(struct transport *transport,
        transport->cannot_reuse = 1;
 }
 
-static int is_local(const char *url)
-{
-       const char *colon = strchr(url, ':');
-       const char *slash = strchr(url, '/');
-       return !colon || (slash && slash < colon) ||
-               has_dos_drive_prefix(url);
-}
-
 static int is_file(const char *url)
 {
        struct stat buf;
-- 
1.8.4.457.g424cb08

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to