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 <ilari.liusvaara@elisanet.fi> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Ilari Liusvaara committed
Dec 9, 2009 at 17:26 UTC
25d5cc488a75cc232e97af42759812d9aa398713
2 files changed
+72
-16
transport-helper.c
+11
-1
@@ -63,6 +63,16 @@ static void write_constant(int fd, const char *str)
63
die_errno("Full write to remote helper failed");
64
}
65
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
+
76
static struct child_process *get_helper(struct transport *transport)
77
{
78
struct helper_data *data = transport->data;
@@ -83,7 +93,7 @@ static struct child_process *get_helper(struct transport *transport)
93
strbuf_addf(&buf, "remote-%s", data->name);
94
helper->argv[0] = strbuf_detach(&buf, NULL);
95
helper->argv[1] = transport->remote->name;
86
- helper->argv[2] = transport->url;
96
+ helper->argv[2] = remove_ext_force(transport->url);
97
helper->git_cmd = 1;
98
if (start_command(helper))
99
die("Unable to run helper: git %s", helper->argv[0]);
transport.c
+61
-15
@@ -780,6 +780,44 @@ static int is_file(const char *url)
780
return S_ISREG(buf.st_mode);
781
}
782
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
+
821
struct transport *transport_get(struct remote *remote, const char *url)
822
{
823
struct transport *ret = xcalloc(1, sizeof(*ret));
@@ -805,30 +843,23 @@ struct transport *transport_get(struct remote *remote, const char *url)
843
844
if (remote && remote->foreign_vcs) {
845
transport_helper_init(ret, remote->foreign_vcs);
808
- return ret;
809
- }
810
-
811
- if (!prefixcmp(url, "rsync:")) {
846
+ } else if (!prefixcmp(url, "rsync:")) {
847
ret->get_refs_list = get_refs_via_rsync;
848
ret->fetch = fetch_objs_via_rsync;
849
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
-
850
} else if (is_local(url) && is_file(url)) {
851
struct bundle_transport_data *data = xcalloc(1, sizeof(*data));
852
ret->data = data;
853
ret->get_refs_list = get_refs_from_bundle;
854
ret->fetch = fetch_refs_from_bundle;
855
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. */
863
struct git_transport_data *data = xcalloc(1, sizeof(*data));
864
ret->data = data;
865
ret->set_option = set_git_option;
@@ -845,6 +876,21 @@ struct transport *transport_get(struct remote *remote, const char *url)
876
data->receivepack = "git-receive-pack";
877
if (remote->receivepack)
878
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);
894
}
895
896
return ret;