Skip to content

Commit 25d5cc4

Browse files
Ilari Liusvaaragitster
authored andcommitted
Pass unknown protocols to external protocol handlers
Change URL handling to allow external protocol handlers to implement new protocols without the '::' syntax if helper name does not conflict with any built-in protocol. foo:// now invokes git-remote-foo with foo:// as the URL. Signed-off-by: Ilari Liusvaara <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 28ed5b3 commit 25d5cc4

File tree

2 files changed

+72
-16
lines changed

2 files changed

+72
-16
lines changed

transport-helper.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ static void write_constant(int fd, const char *str)
6363
die_errno("Full write to remote helper failed");
6464
}
6565

66+
const char *remove_ext_force(const char *url)
67+
{
68+
if (url) {
69+
const char *colon = strchr(url, ':');
70+
if (colon && colon[1] == ':')
71+
return colon + 2;
72+
}
73+
return url;
74+
}
75+
6676
static struct child_process *get_helper(struct transport *transport)
6777
{
6878
struct helper_data *data = transport->data;
@@ -83,7 +93,7 @@ static struct child_process *get_helper(struct transport *transport)
8393
strbuf_addf(&buf, "remote-%s", data->name);
8494
helper->argv[0] = strbuf_detach(&buf, NULL);
8595
helper->argv[1] = transport->remote->name;
86-
helper->argv[2] = transport->url;
96+
helper->argv[2] = remove_ext_force(transport->url);
8797
helper->git_cmd = 1;
8898
if (start_command(helper))
8999
die("Unable to run helper: git %s", helper->argv[0]);

transport.c

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,44 @@ static int is_file(const char *url)
780780
return S_ISREG(buf.st_mode);
781781
}
782782

783+
static int is_url(const char *url)
784+
{
785+
const char *url2, *first_slash;
786+
787+
if (!url)
788+
return 0;
789+
url2 = url;
790+
first_slash = strchr(url, '/');
791+
792+
/* Input with no slash at all or slash first can't be URL. */
793+
if (!first_slash || first_slash == url)
794+
return 0;
795+
/* Character before must be : and next must be /. */
796+
if (first_slash[-1] != ':' || first_slash[1] != '/')
797+
return 0;
798+
/* There must be something before the :// */
799+
if (first_slash == url + 1)
800+
return 0;
801+
/*
802+
* Check all characters up to first slash - 1. Only alphanum
803+
* is allowed.
804+
*/
805+
url2 = url;
806+
while (url2 < first_slash - 1) {
807+
if (!isalnum((unsigned char)*url2))
808+
return 0;
809+
url2++;
810+
}
811+
812+
/* Valid enough. */
813+
return 1;
814+
}
815+
816+
static int external_specification_len(const char *url)
817+
{
818+
return strchr(url, ':') - url;
819+
}
820+
783821
struct transport *transport_get(struct remote *remote, const char *url)
784822
{
785823
struct transport *ret = xcalloc(1, sizeof(*ret));
@@ -805,30 +843,23 @@ struct transport *transport_get(struct remote *remote, const char *url)
805843

806844
if (remote && remote->foreign_vcs) {
807845
transport_helper_init(ret, remote->foreign_vcs);
808-
return ret;
809-
}
810-
811-
if (!prefixcmp(url, "rsync:")) {
846+
} else if (!prefixcmp(url, "rsync:")) {
812847
ret->get_refs_list = get_refs_via_rsync;
813848
ret->fetch = fetch_objs_via_rsync;
814849
ret->push = rsync_transport_push;
815-
816-
} else if (!prefixcmp(url, "http://")
817-
|| !prefixcmp(url, "https://")
818-
|| !prefixcmp(url, "ftp://")) {
819-
transport_helper_init(ret, "curl");
820-
#ifdef NO_CURL
821-
error("git was compiled without libcurl support.");
822-
#endif
823-
824850
} else if (is_local(url) && is_file(url)) {
825851
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
826852
ret->data = data;
827853
ret->get_refs_list = get_refs_from_bundle;
828854
ret->fetch = fetch_refs_from_bundle;
829855
ret->disconnect = close_bundle;
830-
831-
} else {
856+
} else if (!is_url(url)
857+
|| !prefixcmp(url, "file://")
858+
|| !prefixcmp(url, "git://")
859+
|| !prefixcmp(url, "ssh://")
860+
|| !prefixcmp(url, "git+ssh://")
861+
|| !prefixcmp(url, "ssh+git://")) {
862+
/* These are builtin smart transports. */
832863
struct git_transport_data *data = xcalloc(1, sizeof(*data));
833864
ret->data = data;
834865
ret->set_option = set_git_option;
@@ -845,6 +876,21 @@ struct transport *transport_get(struct remote *remote, const char *url)
845876
data->receivepack = "git-receive-pack";
846877
if (remote->receivepack)
847878
data->receivepack = remote->receivepack;
879+
} else if (!prefixcmp(url, "http://")
880+
|| !prefixcmp(url, "https://")
881+
|| !prefixcmp(url, "ftp://")) {
882+
/* These three are just plain special. */
883+
transport_helper_init(ret, "curl");
884+
#ifdef NO_CURL
885+
error("git was compiled without libcurl support.");
886+
#endif
887+
} else {
888+
/* Unknown protocol in URL. Pass to external handler. */
889+
int len = external_specification_len(url);
890+
char *handler = xmalloc(len + 1);
891+
handler[len] = 0;
892+
strncpy(handler, url, len);
893+
transport_helper_init(ret, handler);
848894
}
849895

850896
return ret;

0 commit comments

Comments
 (0)