summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@github.com>2016-03-08 13:38:55 +0000
committerEdward Thomson <ethomson@github.com>2016-03-08 13:38:55 +0000
commitb7809b84692b4df7f11d603cc5da0860609e0555 (patch)
tree786f1c6de61b29477d05f688764577db045b1de4
parent534ca8882d0247c749c23911b98423f2845cd1dc (diff)
parent813d73f64d779257fd24cd70bbc281352c34812b (diff)
downloadlibgit2-b7809b84692b4df7f11d603cc5da0860609e0555.tar.gz
Merge pull request #3555 from cbargren/ssh-git-protocols
Support for ssh+git and git+ssh protocols
-rw-r--r--deps/http-parser/http_parser.c7
-rw-r--r--src/transport.c2
-rw-r--r--src/transports/ssh.c49
-rw-r--r--tests/transport/register.c10
4 files changed, 49 insertions, 19 deletions
diff --git a/deps/http-parser/http_parser.c b/deps/http-parser/http_parser.c
index 203530254..27bdd2081 100644
--- a/deps/http-parser/http_parser.c
+++ b/deps/http-parser/http_parser.c
@@ -99,7 +99,7 @@ do { \
FOR##_mark = NULL; \
} \
} while (0)
-
+
/* Run the data callback FOR and consume the current byte */
#define CALLBACK_DATA(FOR) \
CALLBACK_DATA_(FOR, p - FOR##_mark, p - data + 1)
@@ -444,6 +444,9 @@ parse_url_char(enum state s, const char ch)
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)) {
return s_req_schema;
}
@@ -451,7 +454,7 @@ parse_url_char(enum state s, const char ch)
break;
case s_req_schema:
- if (IS_ALPHA(ch)) {
+ if (IS_ALPHANUM(ch) || ch == '+' || ch == '-' || ch == '.') {
return s;
}
diff --git a/src/transport.c b/src/transport.c
index 5c65c7c06..327052fa3 100644
--- a/src/transport.c
+++ b/src/transport.c
@@ -35,6 +35,8 @@ static transport_definition transports[] = {
{ "file://", git_transport_local, NULL },
#ifdef GIT_SSH
{ "ssh://", git_transport_smart, &ssh_subtransport_definition },
+ { "ssh+git://", git_transport_smart, &ssh_subtransport_definition },
+ { "git+ssh://", git_transport_smart, &ssh_subtransport_definition },
#endif
{ NULL, 0, 0 }
};
diff --git a/src/transports/ssh.c b/src/transports/ssh.c
index 35739abe3..cfd573665 100644
--- a/src/transports/ssh.c
+++ b/src/transports/ssh.c
@@ -21,7 +21,8 @@
#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_receivepack[] = "git-receive-pack";
@@ -63,17 +64,24 @@ static int gen_proto(git_buf *request, const char *cmd, const char *url)
{
char *repo;
int len;
+ size_t i;
- if (!git__prefixcmp(url, prefix_ssh)) {
- url = url + strlen(prefix_ssh);
- repo = strchr(url, '/');
- if (repo && repo[1] == '~')
- ++repo;
- } else {
- repo = strchr(url, ':');
- if (repo) repo++;
+ for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) {
+ const char *p = ssh_prefixes[i];
+
+ if (!git__prefixcmp(url, p)) {
+ url = url + strlen(p);
+ repo = strchr(url, '/');
+ if (repo && repo[1] == '~')
+ ++repo;
+
+ goto done;
+ }
}
+ repo = strchr(url, ':');
+ if (repo) repo++;
+done:
if (!repo) {
giterr_set(GITERR_NET, "Malformed git protocol URL");
return -1;
@@ -500,6 +508,7 @@ static int _git_ssh_setup_conn(
char *host=NULL, *port=NULL, *path=NULL, *user=NULL, *pass=NULL;
const char *default_port="22";
int auth_methods, error = 0;
+ size_t i;
ssh_stream *s;
git_cred *cred = NULL;
LIBSSH2_SESSION* session=NULL;
@@ -515,16 +524,22 @@ static int _git_ssh_setup_conn(
s->session = NULL;
s->channel = NULL;
- if (!git__prefixcmp(url, prefix_ssh)) {
- if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0)
- goto done;
- } else {
- if ((error = git_ssh_extract_url_parts(&host, &user, url)) < 0)
- goto done;
- port = git__strdup(default_port);
- GITERR_CHECK_ALLOC(port);
+ for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) {
+ const char *p = ssh_prefixes[i];
+
+ if (!git__prefixcmp(url, p)) {
+ if ((error = gitno_extract_url_parts(&host, &port, &path, &user, &pass, url, default_port)) < 0)
+ goto done;
+
+ 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 ||
(error = git_stream_connect(s->io)) < 0)
goto done;
diff --git a/tests/transport/register.c b/tests/transport/register.c
index ea917d5d3..67a2efd99 100644
--- a/tests/transport/register.c
+++ b/tests/transport/register.c
@@ -44,8 +44,13 @@ void test_transport_register__custom_transport_ssh(void)
#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+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);
#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"));
transport->free(transport);
#endif
@@ -60,8 +65,13 @@ void test_transport_register__custom_transport_ssh(void)
#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+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);
#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"));
transport->free(transport);
#endif