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
---
(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/~use