]> git.proxmox.com Git - libgit2.git/blob - src/transport.c
Merge pull request #2644 from libgit2/cmn/remove-supported-url
[libgit2.git] / src / transport.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7 #include "common.h"
8 #include "git2/types.h"
9 #include "git2/remote.h"
10 #include "git2/net.h"
11 #include "git2/transport.h"
12 #include "git2/sys/transport.h"
13 #include "path.h"
14
15 typedef struct transport_definition {
16 char *prefix;
17 git_transport_cb fn;
18 void *param;
19 } transport_definition;
20
21 static git_smart_subtransport_definition http_subtransport_definition = { git_smart_subtransport_http, 1 };
22 static git_smart_subtransport_definition git_subtransport_definition = { git_smart_subtransport_git, 0 };
23 #ifdef GIT_SSH
24 static git_smart_subtransport_definition ssh_subtransport_definition = { git_smart_subtransport_ssh, 0 };
25 #endif
26
27 static transport_definition local_transport_definition = { "file://", git_transport_local, NULL };
28
29 static transport_definition transports[] = {
30 { "git://", git_transport_smart, &git_subtransport_definition },
31 { "http://", git_transport_smart, &http_subtransport_definition },
32 #if defined(GIT_SSL) || defined(GIT_WINHTTP)
33 { "https://", git_transport_smart, &http_subtransport_definition },
34 #endif
35 { "file://", git_transport_local, NULL },
36 #ifdef GIT_SSH
37 { "ssh://", git_transport_smart, &ssh_subtransport_definition },
38 #endif
39 { NULL, 0, 0 }
40 };
41
42 static git_vector custom_transports = GIT_VECTOR_INIT;
43
44 #define GIT_TRANSPORT_COUNT (sizeof(transports)/sizeof(transports[0])) - 1
45
46 static transport_definition * transport_find_by_url(const char *url)
47 {
48 size_t i = 0;
49 transport_definition *d;
50
51 /* Find a user transport who wants to deal with this URI */
52 git_vector_foreach(&custom_transports, i, d) {
53 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
54 return d;
55 }
56 }
57
58 /* Find a system transport for this URI */
59 for (i = 0; i < GIT_TRANSPORT_COUNT; ++i) {
60 d = &transports[i];
61
62 if (strncasecmp(url, d->prefix, strlen(d->prefix)) == 0) {
63 return d;
64 }
65 }
66
67 return NULL;
68 }
69
70 static int transport_find_fn(
71 git_transport_cb *out,
72 const char *url,
73 void **param)
74 {
75 transport_definition *definition = transport_find_by_url(url);
76
77 #ifdef GIT_WIN32
78 /* On Windows, it might not be possible to discern between absolute local
79 * and ssh paths - first check if this is a valid local path that points
80 * to a directory and if so assume local path, else assume SSH */
81
82 /* Check to see if the path points to a file on the local file system */
83 if (!definition && git_path_exists(url) && git_path_isdir(url))
84 definition = &local_transport_definition;
85 #endif
86
87 /* For other systems, perform the SSH check first, to avoid going to the
88 * filesystem if it is not necessary */
89
90 /* It could be a SSH remote path. Check to see if there's a :
91 * SSH is an unsupported transport mechanism in this version of libgit2 */
92 if (!definition && strrchr(url, ':')) {
93 // re-search transports again with ssh:// as url so that we can find a third party ssh transport
94 definition = transport_find_by_url("ssh://");
95 }
96
97 #ifndef GIT_WIN32
98 /* Check to see if the path points to a file on the local file system */
99 if (!definition && git_path_exists(url) && git_path_isdir(url))
100 definition = &local_transport_definition;
101 #endif
102
103 if (!definition)
104 return GIT_ENOTFOUND;
105
106 *out = definition->fn;
107 *param = definition->param;
108
109 return 0;
110 }
111
112 /**************
113 * Public API *
114 **************/
115
116 int git_transport_new(git_transport **out, git_remote *owner, const char *url)
117 {
118 git_transport_cb fn;
119 git_transport *transport;
120 void *param;
121 int error;
122
123 if ((error = transport_find_fn(&fn, url, &param)) == GIT_ENOTFOUND) {
124 giterr_set(GITERR_NET, "Unsupported URL protocol");
125 return -1;
126 } else if (error < 0)
127 return error;
128
129 if ((error = fn(&transport, owner, param)) < 0)
130 return error;
131
132 GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport");
133
134 *out = transport;
135
136 return 0;
137 }
138
139 int git_transport_register(
140 const char *scheme,
141 git_transport_cb cb,
142 void *param)
143 {
144 git_buf prefix = GIT_BUF_INIT;
145 transport_definition *d, *definition = NULL;
146 size_t i;
147 int error = 0;
148
149 assert(scheme);
150 assert(cb);
151
152 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
153 goto on_error;
154
155 git_vector_foreach(&custom_transports, i, d) {
156 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
157 error = GIT_EEXISTS;
158 goto on_error;
159 }
160 }
161
162 definition = git__calloc(1, sizeof(transport_definition));
163 GITERR_CHECK_ALLOC(definition);
164
165 definition->prefix = git_buf_detach(&prefix);
166 definition->fn = cb;
167 definition->param = param;
168
169 if (git_vector_insert(&custom_transports, definition) < 0)
170 goto on_error;
171
172 return 0;
173
174 on_error:
175 git_buf_free(&prefix);
176 git__free(definition);
177 return error;
178 }
179
180 int git_transport_unregister(const char *scheme)
181 {
182 git_buf prefix = GIT_BUF_INIT;
183 transport_definition *d;
184 size_t i;
185 int error = 0;
186
187 assert(scheme);
188
189 if ((error = git_buf_printf(&prefix, "%s://", scheme)) < 0)
190 goto done;
191
192 git_vector_foreach(&custom_transports, i, d) {
193 if (strcasecmp(d->prefix, prefix.ptr) == 0) {
194 if ((error = git_vector_remove(&custom_transports, i)) < 0)
195 goto done;
196
197 git__free(d->prefix);
198 git__free(d);
199
200 if (!custom_transports.length)
201 git_vector_free(&custom_transports);
202
203 error = 0;
204 goto done;
205 }
206 }
207
208 error = GIT_ENOTFOUND;
209
210 done:
211 git_buf_free(&prefix);
212 return error;
213 }
214
215 int git_transport_init(git_transport *opts, unsigned int version)
216 {
217 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
218 opts, version, git_transport, GIT_TRANSPORT_INIT);
219 return 0;
220 }