Commit 27307ed6 by Edward Thomson

ssh: use url parsing functionality

Instead of trying to figure out a repo's path from a URL by hand, parse
a URL using the parsing functionality.
parent e02e6a5c
......@@ -24,8 +24,6 @@
#define OWNING_SUBTRANSPORT(s) ((ssh_subtransport *)(s)->parent.subtransport)
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";
......@@ -35,7 +33,7 @@ typedef struct {
LIBSSH2_SESSION *session;
LIBSSH2_CHANNEL *channel;
const char *cmd;
char *url;
git_net_url url;
unsigned sent_command : 1;
} ssh_stream;
......@@ -63,39 +61,23 @@ static void ssh_error(LIBSSH2_SESSION *session, const char *errmsg)
*
* For example: git-upload-pack '/libgit2/libgit2'
*/
static int gen_proto(git_str *request, const char *cmd, const char *url)
static int gen_proto(git_str *request, const char *cmd, git_net_url *url)
{
const char *repo;
int len;
size_t i;
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;
repo = url->path;
goto done;
}
}
repo = strchr(url, ':');
if (repo) repo++;
if (repo && repo[0] == '/' && repo[1] == '~')
repo++;
done:
if (!repo) {
if (!repo || !repo[0]) {
git_error_set(GIT_ERROR_NET, "malformed git protocol URL");
return -1;
}
len = strlen(cmd) + 1 /* Space */ + 1 /* Quote */ + strlen(repo) + 1 /* Quote */ + 1;
git_str_grow(request, len);
git_str_puts(request, cmd);
git_str_puts(request, " '");
git_str_decode_percent(request, repo, strlen(repo));
git_str_puts(request, repo);
git_str_puts(request, "'");
if (git_str_oom(request))
......@@ -109,7 +91,7 @@ static int send_command(ssh_stream *s)
int error;
git_str request = GIT_STR_INIT;
error = gen_proto(&request, s->cmd, s->url);
error = gen_proto(&request, s->cmd, &s->url);
if (error < 0)
goto cleanup;
......@@ -224,13 +206,12 @@ static void ssh_stream_free(git_smart_subtransport_stream *stream)
s->io = NULL;
}
git__free(s->url);
git_net_url_dispose(&s->url);
git__free(s);
}
static int ssh_stream_alloc(
ssh_subtransport *t,
const char *url,
const char *cmd,
git_smart_subtransport_stream **stream)
{
......@@ -248,12 +229,6 @@ static int ssh_stream_alloc(
s->cmd = cmd;
s->url = git__strdup(url);
if (!s->url) {
git__free(s);
return -1;
}
*stream = &s->parent;
return 0;
}
......@@ -487,9 +462,7 @@ static int _git_ssh_setup_conn(
const char *cmd,
git_smart_subtransport_stream **stream)
{
git_net_url urldata = GIT_NET_URL_INIT;
int auth_methods, error = 0;
size_t i;
ssh_stream *s;
git_credential *cred = NULL;
LIBSSH2_SESSION *session=NULL;
......@@ -498,28 +471,22 @@ static int _git_ssh_setup_conn(
t->current_stream = NULL;
*stream = NULL;
if (ssh_stream_alloc(t, url, cmd, stream) < 0)
if (ssh_stream_alloc(t, cmd, stream) < 0)
return -1;
s = (ssh_stream *)*stream;
s->session = NULL;
s->channel = NULL;
for (i = 0; i < ARRAY_SIZE(ssh_prefixes); ++i) {
const char *p = ssh_prefixes[i];
if (!git__prefixcmp(url, p)) {
if ((error = git_net_url_parse(&urldata, url)) < 0)
goto done;
if (git_net_str_is_url(url))
error = git_net_url_parse(&s->url, url);
else
error = git_net_url_parse_scp(&s->url, url);
goto post_extract;
}
}
if ((error = git_net_url_parse_scp(&urldata, url)) < 0)
if (error < 0)
goto done;
post_extract:
if ((error = git_socket_stream_new(&s->io, urldata.host, urldata.port)) < 0 ||
if ((error = git_socket_stream_new(&s->io, s->url.host, s->url.port)) < 0 ||
(error = git_stream_connect(s->io)) < 0)
goto done;
......@@ -603,7 +570,7 @@ post_extract:
error = t->owner->connect_opts.callbacks.certificate_check(
(git_cert *)cert_ptr,
0,
urldata.host,
s->url.host,
t->owner->connect_opts.callbacks.payload);
if (error < 0 && error != GIT_PASSTHROUGH) {
......@@ -615,21 +582,21 @@ post_extract:
}
/* we need the username to ask for auth methods */
if (!urldata.username) {
if (!s->url.username) {
if ((error = request_creds(&cred, t, NULL, GIT_CREDENTIAL_USERNAME)) < 0)
goto done;
urldata.username = git__strdup(((git_credential_username *) cred)->username);
s->url.username = git__strdup(((git_credential_username *) cred)->username);
cred->free(cred);
cred = NULL;
if (!urldata.username)
if (!s->url.username)
goto done;
} else if (urldata.username && urldata.password) {
if ((error = git_credential_userpass_plaintext_new(&cred, urldata.username, urldata.password)) < 0)
} else if (s->url.username && s->url.password) {
if ((error = git_credential_userpass_plaintext_new(&cred, s->url.username, s->url.password)) < 0)
goto done;
}
if ((error = list_auth_methods(&auth_methods, session, urldata.username)) < 0)
if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0)
goto done;
error = GIT_EAUTH;
......@@ -643,10 +610,10 @@ post_extract:
cred = NULL;
}
if ((error = request_creds(&cred, t, urldata.username, auth_methods)) < 0)
if ((error = request_creds(&cred, t, s->url.username, auth_methods)) < 0)
goto done;
if (strcmp(urldata.username, git_credential_get_username(cred))) {
if (strcmp(s->url.username, git_credential_get_username(cred))) {
git_error_set(GIT_ERROR_SSH, "username does not match previous request");
error = -1;
goto done;
......@@ -656,7 +623,7 @@ post_extract:
if (error == GIT_EAUTH) {
/* refresh auth methods */
if ((error = list_auth_methods(&auth_methods, session, urldata.username)) < 0)
if ((error = list_auth_methods(&auth_methods, session, s->url.username)) < 0)
goto done;
else
error = GIT_EAUTH;
......@@ -691,8 +658,6 @@ done:
if (cred)
cred->free(cred);
git_net_url_dispose(&urldata);
return error;
}
......
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