Commit b7809b84 by Edward Thomson

Merge pull request #3555 from cbargren/ssh-git-protocols

Support for ssh+git and git+ssh protocols
parents 534ca888 813d73f6
...@@ -99,7 +99,7 @@ do { \ ...@@ -99,7 +99,7 @@ do { \
FOR##_mark = NULL; \ FOR##_mark = NULL; \
} \ } \
} while (0) } while (0)
/* Run the data callback FOR and consume the current byte */ /* Run the data callback FOR and consume the current byte */
#define CALLBACK_DATA(FOR) \ #define CALLBACK_DATA(FOR) \
CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1) CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
...@@ -444,6 +444,9 @@ parse_url_char(enum state s, const char ch) ...@@ -444,6 +444,9 @@ parse_url_char(enum state s, const char ch)
return s_req_path; return s_req_path;
} }
/* The schema must start with an alpha character. After that, it may
* consist of digits, '+', '-' or '.', followed by a ':'.
*/
if (IS_ALPHA(ch)) { if (IS_ALPHA(ch)) {
return s_req_schema; return s_req_schema;
} }
...@@ -451,7 +454,7 @@ parse_url_char(enum state s, const char ch) ...@@ -451,7 +454,7 @@ parse_url_char(enum state s, const char ch)
break; break;
case s_req_schema: case s_req_schema:
if (IS_ALPHA(ch)) { if (IS_ALPHANUM(ch) || ch == '+' || ch == '-' || ch == '.') {
return s; return s;
} }
......
...@@ -35,6 +35,8 @@ static transport_definition transports[] = { ...@@ -35,6 +35,8 @@ static transport_definition transports[] = {
{ "file://", git_transport_local, NULL }, { "file://", git_transport_local, NULL },
#ifdef GIT_SSH #ifdef GIT_SSH
{ "ssh://", git_transport_smart, &ssh_subtransport_definition }, { "ssh://", git_transport_smart, &ssh_subtransport_definition },
{ "ssh+git://", git_transport_smart, &ssh_subtransport_definition },
{ "git+ssh://", git_transport_smart, &ssh_subtransport_definition },
#endif #endif
{ NULL, 0, 0 } { NULL, 0, 0 }
}; };
......
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport) #define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport)
static const char prefix_ssh[] = "ssh://"; static const char *ssh_prefixes[] = { "ssh://", "ssh+git://", "git+ssh://" };
static const char cmd_uploadpack[] = "git-upload-pack"; static const char cmd_uploadpack[] = "git-upload-pack";
static const char cmd_receivepack[] = "git-receive-pack"; static const char cmd_receivepack[] = "git-receive-pack";
...@@ -63,17 +64,24 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url) ...@@ -63,17 +64,24 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
{ {
char *repo; char *repo;
int len; int len;
size_t i;
if (!git__prefixcmp(url, prefix_ssh)) { for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) {
url = url + strlen(prefix_ssh); const char *p = ssh_prefixes[i];
repo = strchr(url, '/');
if (repo && repo[1] == '~') if (!git__prefixcmp(url, p)) {
++repo; url = url + strlen(p);
} else { repo = strchr(url, '/');
repo = strchr(url, ':'); if (repo && repo[1] == '~')
if (repo) repo++; ++repo;
goto done;
}
} }
repo = strchr(url, ':');
if (repo) repo++;
done:
if (!repo) { if (!repo) {
giterr_set(GITERR_NET, "Malformed git protocol URL"); giterr_set(GITERR_NET, "Malformed git protocol URL");
return -1; return -1;
...@@ -500,6 +508,7 @@ static int _git_ssh_setup_conn( ...@@ -500,6 +508,7 @@ static int _git_ssh_setup_conn(
char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL; char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
const char *default_port="22"; const char *default_port="22";
int auth_methods, error = 0; int auth_methods, error = 0;
size_t i;
ssh_stream *s; ssh_stream *s;
git_cred *cred = NULL; git_cred *cred = NULL;
LIBSSH2_SESSION* session=NULL; LIBSSH2_SESSION* session=NULL;
...@@ -515,16 +524,22 @@ static int _git_ssh_setup_conn( ...@@ -515,16 +524,22 @@ static int _git_ssh_setup_conn(
s->session = NULL; s->session = NULL;
s->channel = NULL; s->channel = NULL;
if (!git__prefixcmp(url, prefix_ssh)) { for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) {
if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0) const char *p = ssh_prefixes[i];
goto done;
} else { if (!git__prefixcmp(url, p)) {
if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0) if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0)
goto done; goto done;
port = git__strdup(default_port);
GITERR_CHECK_ALLOC(port); goto post_extract;
}
} }
if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0)
goto done;
port = git__strdup(default_port);
GITERR_CHECK_ALLOC(port);
post_extract:
if ((error = git_socket_stream_new(&s->io, host, port)) < 0 || if ((error = git_socket_stream_new(&s->io, host, port)) < 0 ||
(error = git_stream_connect(s->io)) < 0) (error = git_stream_connect(s->io)) < 0)
goto done; goto done;
......
...@@ -44,8 +44,13 @@ void test_transport_register__custom_transport_ssh(void) ...@@ -44,8 +44,13 @@ void test_transport_register__custom_transport_ssh(void)
#ifndef GIT_SSH #ifndef GIT_SSH
cl_git_fail_with(git_transport_new(&transport, NULL, "ssh://somehost:somepath"), -1); cl_git_fail_with(git_transport_new(&transport, NULL, "ssh://somehost:somepath"), -1);
cl_git_fail_with(git_transport_new(&transport, NULL, "ssh+git://somehost:somepath"), -1);
cl_git_fail_with(git_transport_new(&transport, NULL, "git+ssh://somehost:somepath"), -1);
cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1); cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1);
#else #else
cl_git_pass(git_transport_new(&transport, NULL, "ssh://somehost:somepath"));
cl_git_pass(git_transport_new(&transport, NULL, "ssh+git://somehost:somepath"));
cl_git_pass(git_transport_new(&transport, NULL, "git+ssh://somehost:somepath"));
cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath")); cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath"));
transport->free(transport); transport->free(transport);
#endif #endif
...@@ -60,8 +65,13 @@ void test_transport_register__custom_transport_ssh(void) ...@@ -60,8 +65,13 @@ void test_transport_register__custom_transport_ssh(void)
#ifndef GIT_SSH #ifndef GIT_SSH
cl_git_fail_with(git_transport_new(&transport, NULL, "ssh://somehost:somepath"), -1); cl_git_fail_with(git_transport_new(&transport, NULL, "ssh://somehost:somepath"), -1);
cl_git_fail_with(git_transport_new(&transport, NULL, "ssh+git://somehost:somepath"), -1);
cl_git_fail_with(git_transport_new(&transport, NULL, "git+ssh://somehost:somepath"), -1);
cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1); cl_git_fail_with(git_transport_new(&transport, NULL, "git@somehost:somepath"), -1);
#else #else
cl_git_pass(git_transport_new(&transport, NULL, "ssh://somehost:somepath"));
cl_git_pass(git_transport_new(&transport, NULL, "ssh+git://somehost:somepath"));
cl_git_pass(git_transport_new(&transport, NULL, "git+ssh://somehost:somepath"));
cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath")); cl_git_pass(git_transport_new(&transport, NULL, "git@somehost:somepath"));
transport->free(transport); transport->free(transport);
#endif #endif
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment