source src/transports/smart.c
Line | Flow | Count | Block(s) | Source |
---|---|---|---|---|
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 | - | |||
8 | - | #include "smart.h" | ||
9 | - | |||
10 | - | #include "git2.h" | ||
11 | - | #include "refs.h" | ||
12 | - | #include "refspec.h" | ||
13 | - | #include "proxy.h" | ||
14 | - | |||
15 | 643 | 2 | static int git_smart__recv_cb(gitno_buffer *buf) | |
16 | - | { | ||
17 | 643 | 2 | transport_smart *t = (transport_smart *) buf->cb_data; | |
18 | - | size_t old_len, bytes_read; | ||
19 | - | int error; | ||
20 | - | |||
21 | 643 | 2,3 | assert(t->current_stream); | |
22 | - | |||
23 | 643 | 4 | old_len = buf->offset; | |
24 | - | |||
25 | 643 | 4,5 | if ((error = t->current_stream->read(t->current_stream, buf->data + buf->offset, buf->len - buf->offset, &bytes_read)) < 0) | |
26 | 11 | 6 | return error; | |
27 | - | |||
28 | 632 | 7 | buf->offset += bytes_read; | |
29 | - | |||
30 | 632 | 7,8 | if (t->packetsize_cb && !t->cancelled.val) { | |
31 | 49 | 9 | error = t->packetsize_cb(bytes_read, t->packetsize_payload); | |
32 | 49 | 10 | if (error) { | |
33 | ##### | 11 | git_atomic_set(&t->cancelled, 1); | |
34 | ##### | 12 | return GIT_EUSER; | |
35 | - | } | ||
36 | - | } | ||
37 | - | |||
38 | 632 | 13 | return (int)(buf->offset - old_len); | |
39 | - | } | ||
40 | - | |||
41 | 250 | 2 | GIT_INLINE(int) git_smart__reset_stream(transport_smart *t, bool close_subtransport) | |
42 | - | { | ||
43 | 250 | 2 | if (t->current_stream) { | |
44 | 92 | 3 | t->current_stream->free(t->current_stream); | |
45 | 92 | 4 | t->current_stream = NULL; | |
46 | - | } | ||
47 | - | |||
48 | 250 | 5 | if (close_subtransport) { | |
49 | 195 | 6 | git__free(t->url); | |
50 | 195 | 7 | t->url = NULL; | |
51 | - | |||
52 | 195 | 7,8 | if (t->wrapped->close(t->wrapped) < 0) | |
53 | ##### | 9 | return -1; | |
54 | - | } | ||
55 | - | |||
56 | 250 | 10 | return 0; | |
57 | - | } | ||
58 | - | |||
59 | 56 | 2 | static int git_smart__set_callbacks( | |
60 | - | git_transport *transport, | ||
61 | - | git_transport_message_cb progress_cb, | ||
62 | - | git_transport_message_cb error_cb, | ||
63 | - | git_transport_certificate_check_cb certificate_check_cb, | ||
64 | - | void *message_cb_payload) | ||
65 | - | { | ||
66 | 56 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
67 | - | |||
68 | 56 | 2 | t->progress_cb = progress_cb; | |
69 | 56 | 2 | t->error_cb = error_cb; | |
70 | 56 | 2 | t->certificate_check_cb = certificate_check_cb; | |
71 | 56 | 2 | t->message_cb_payload = message_cb_payload; | |
72 | - | |||
73 | 56 | 2 | return 0; | |
74 | - | } | ||
75 | - | |||
76 | 10 | 2 | static size_t http_header_name_length(const char *http_header) | |
77 | - | { | ||
78 | 10 | 2 | const char *colon = strchr(http_header, ':'); | |
79 | 10 | 2 | if (!colon) | |
80 | 2 | 3 | return 0; | |
81 | 8 | 4 | return colon - http_header; | |
82 | - | } | ||
83 | - | |||
84 | 7 | 2 | static bool is_malformed_http_header(const char *http_header) | |
85 | - | { | ||
86 | - | const char *c; | ||
87 | - | size_t name_len; | ||
88 | - | |||
89 | - | /* Disallow \r and \n */ | ||
90 | 7 | 2 | c = strchr(http_header, '\r'); | |
91 | 7 | 2 | if (c) | |
92 | ##### | 3 | return true; | |
93 | 7 | 4 | c = strchr(http_header, '\n'); | |
94 | 7 | 4 | if (c) | |
95 | 1 | 5 | return true; | |
96 | - | |||
97 | - | /* Require a header name followed by : */ | ||
98 | 6 | 6 | name_len = http_header_name_length(http_header); | |
99 | 6 | 7 | if (name_len < 1) | |
100 | 2 | 8 | return true; | |
101 | - | |||
102 | 4 | 9 | return false; | |
103 | - | } | ||
104 | - | |||
105 | - | static char *forbidden_custom_headers[] = { | ||
106 | - | "User-Agent", | ||
107 | - | "Host", | ||
108 | - | "Accept", | ||
109 | - | "Content-Type", | ||
110 | - | "Transfer-Encoding", | ||
111 | - | "Content-Length", | ||
112 | - | }; | ||
113 | - | |||
114 | 4 | 2 | static bool is_forbidden_custom_header(const char *custom_header) | |
115 | - | { | ||
116 | - | unsigned long i; | ||
117 | 4 | 2 | size_t name_len = http_header_name_length(custom_header); | |
118 | - | |||
119 | - | /* Disallow headers that we set */ | ||
120 | 24 | 3,6,7 | for (i = 0; i < ARRAY_SIZE(forbidden_custom_headers); i++) | |
121 | 21 | 4 | if (strncmp(forbidden_custom_headers[i], custom_header, name_len) == 0) | |
122 | 1 | 5 | return true; | |
123 | - | |||
124 | 3 | 8 | return false; | |
125 | - | } | ||
126 | - | |||
127 | 73 | 2 | static int git_smart__set_custom_headers( | |
128 | - | git_transport *transport, | ||
129 | - | const git_strarray *custom_headers) | ||
130 | - | { | ||
131 | 73 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
132 | - | size_t i; | ||
133 | - | |||
134 | 73 | 2 | if (t->custom_headers.count) | |
135 | ##### | 3 | git_strarray_dispose(&t->custom_headers); | |
136 | - | |||
137 | 73 | 4 | if (!custom_headers) | |
138 | 13 | 5 | return 0; | |
139 | - | |||
140 | 63 | 6,15,16 | for (i = 0; i < custom_headers->count; i++) { | |
141 | 7 | 7,8 | if (is_malformed_http_header(custom_headers->strings[i])) { | |
142 | 3 | 9 | git_error_set(GIT_ERROR_INVALID, "custom HTTP header '%s' is malformed", custom_headers->strings[i]); | |
143 | 3 | 10 | return -1; | |
144 | - | } | ||
145 | 4 | 11,12 | if (is_forbidden_custom_header(custom_headers->strings[i])) { | |
146 | 1 | 13 | git_error_set(GIT_ERROR_INVALID, "custom HTTP header '%s' is already set by libgit2", custom_headers->strings[i]); | |
147 | 1 | 14 | return -1; | |
148 | - | } | ||
149 | - | } | ||
150 | - | |||
151 | 56 | 17 | return git_strarray_copy(&t->custom_headers, custom_headers); | |
152 | - | } | ||
153 | - | |||
154 | 54 | 2 | int git_smart__update_heads(transport_smart *t, git_vector *symrefs) | |
155 | - | { | ||
156 | - | size_t i; | ||
157 | - | git_pkt *pkt; | ||
158 | - | |||
159 | 54 | 2 | git_vector_clear(&t->heads); | |
160 | 517 | 3,26-28 | git_vector_foreach(&t->refs, i, pkt) { | |
161 | 463 | 4 | git_pkt_ref *ref = (git_pkt_ref *) pkt; | |
162 | 463 | 4 | if (pkt->type != GIT_PKT_REF) | |
163 | ##### | 5 | continue; | |
164 | - | |||
165 | 463 | 6 | if (symrefs) { | |
166 | - | git_refspec *spec; | ||
167 | 463 | 7 | git_buf buf = GIT_BUF_INIT; | |
168 | - | size_t j; | ||
169 | 463 | 7 | int error = 0; | |
170 | - | |||
171 | 926 | 7,16-18 | git_vector_foreach(symrefs, j, spec) { | |
172 | 463 | 8 | git_buf_clear(&buf); | |
173 | 463 | 9-12 | if (git_refspec_src_matches(spec, ref->head.name) && | |
174 | 54 | 11 | !(error = git_refspec_transform(&buf, spec, ref->head.name))) { | |
175 | 54 | 13 | git__free(ref->head.symref_target); | |
176 | 54 | 14,15 | ref->head.symref_target = git_buf_detach(&buf); | |
177 | - | } | ||
178 | - | } | ||
179 | - | |||
180 | 463 | 19 | git_buf_dispose(&buf); | |
181 | - | |||
182 | 463 | 20 | if (error < 0) | |
183 | 463 | 21,22 | return error; | |
184 | - | } | ||
185 | - | |||
186 | 463 | 23,24 | if (git_vector_insert(&t->heads, &ref->head) < 0) | |
187 | ##### | 25 | return -1; | |
188 | - | } | ||
189 | - | |||
190 | 54 | 29 | return 0; | |
191 | - | } | ||
192 | - | |||
193 | 55 | 2 | static void free_symrefs(git_vector *symrefs) | |
194 | - | { | ||
195 | - | git_refspec *spec; | ||
196 | - | size_t i; | ||
197 | - | |||
198 | 109 | 2,5-7 | git_vector_foreach(symrefs, i, spec) { | |
199 | 54 | 3 | git_refspec__dispose(spec); | |
200 | 54 | 4 | git__free(spec); | |
201 | - | } | ||
202 | - | |||
203 | 55 | 8 | git_vector_free(symrefs); | |
204 | 55 | 9 | } | |
205 | - | |||
206 | 69 | 2 | static int git_smart__connect( | |
207 | - | git_transport *transport, | ||
208 | - | const char *url, | ||
209 | - | git_credential_acquire_cb cred_acquire_cb, | ||
210 | - | void *cred_acquire_payload, | ||
211 | - | const git_proxy_options *proxy, | ||
212 | - | int direction, | ||
213 | - | int flags) | ||
214 | - | { | ||
215 | 69 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
216 | - | git_smart_subtransport_stream *stream; | ||
217 | - | int error; | ||
218 | - | git_pkt *pkt; | ||
219 | - | git_pkt_ref *first; | ||
220 | - | git_vector symrefs; | ||
221 | - | git_smart_service_t service; | ||
222 | - | |||
223 | 69 | 2,3 | if (git_smart__reset_stream(t, true) < 0) | |
224 | ##### | 4 | return -1; | |
225 | - | |||
226 | 69 | 5 | t->url = git__strdup(url); | |
227 | 69 | 6,7 | GIT_ERROR_CHECK_ALLOC(t->url); | |
228 | - | |||
229 | 69 | 8,9 | if (git_proxy_options_dup(&t->proxy, proxy) < 0) | |
230 | ##### | 10 | return -1; | |
231 | - | |||
232 | 69 | 11 | t->direction = direction; | |
233 | 69 | 11 | t->flags = flags; | |
234 | 69 | 11 | t->cred_acquire_cb = cred_acquire_cb; | |
235 | 69 | 11 | t->cred_acquire_payload = cred_acquire_payload; | |
236 | - | |||
237 | 69 | 11 | if (GIT_DIRECTION_FETCH == t->direction) | |
238 | 69 | 12 | service = GIT_SERVICE_UPLOADPACK_LS; | |
239 | ##### | 13 | else if (GIT_DIRECTION_PUSH == t->direction) | |
240 | ##### | 14 | service = GIT_SERVICE_RECEIVEPACK_LS; | |
241 | - | else { | ||
242 | ##### | 15 | git_error_set(GIT_ERROR_NET, "invalid direction"); | |
243 | ##### | 16 | return -1; | |
244 | - | } | ||
245 | - | |||
246 | 69 | 17,18 | if ((error = t->wrapped->action(&stream, t->wrapped, t->url, service)) < 0) | |
247 | 2 | 19 | return error; | |
248 | - | |||
249 | - | /* Save off the current stream (i.e. socket) that we are working with */ | ||
250 | 67 | 20 | t->current_stream = stream; | |
251 | - | |||
252 | 67 | 20 | gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); | |
253 | - | |||
254 | - | /* 2 flushes for RPC; 1 for stateful */ | ||
255 | 67 | 21-25 | if ((error = git_smart__store_refs(t, t->rpc ? 2 : 1)) < 0) | |
256 | 12 | 26 | return error; | |
257 | - | |||
258 | - | /* Strip the comment packet for RPC */ | ||
259 | 55 | 27 | if (t->rpc) { | |
260 | 30 | 28 | pkt = (git_pkt *)git_vector_get(&t->refs, 0); | |
261 | - | |||
262 | 30 | 29,30 | if (!pkt || GIT_PKT_COMMENT != pkt->type) { | |
263 | ##### | 31 | git_error_set(GIT_ERROR_NET, "invalid response"); | |
264 | ##### | 32 | return -1; | |
265 | - | } else { | ||
266 | - | /* Remove the comment pkt from the list */ | ||
267 | 30 | 33 | git_vector_remove(&t->refs, 0); | |
268 | 30 | 34 | git__free(pkt); | |
269 | - | } | ||
270 | - | } | ||
271 | - | |||
272 | - | /* We now have loaded the refs. */ | ||
273 | 55 | 35 | t->have_refs = 1; | |
274 | - | |||
275 | 55 | 35 | pkt = (git_pkt *)git_vector_get(&t->refs, 0); | |
276 | 55 | 36,37 | if (pkt && GIT_PKT_REF != pkt->type) { | |
277 | ##### | 38 | git_error_set(GIT_ERROR_NET, "invalid response"); | |
278 | ##### | 39 | return -1; | |
279 | - | } | ||
280 | 55 | 40 | first = (git_pkt_ref *)pkt; | |
281 | - | |||
282 | 55 | 40,41 | if ((error = git_vector_init(&symrefs, 1, NULL)) < 0) | |
283 | ##### | 42 | return error; | |
284 | - | |||
285 | - | /* Detect capabilities */ | ||
286 | 55 | 43,44 | if ((error = git_smart__detect_caps(first, &t->caps, &symrefs)) == 0) { | |
287 | - | /* If the only ref in the list is capabilities^{} with OID_ZERO, remove it */ | ||
288 | 54 | 45,46,48 | if (1 == t->refs.length && !strcmp(first->head.name, "capabilities^{}") && | |
289 | ##### | 47 | git_oid_is_zero(&first->head.oid)) { | |
290 | ##### | 49 | git_vector_clear(&t->refs); | |
291 | ##### | 50 | git_pkt_free((git_pkt *)first); | |
292 | - | } | ||
293 | - | |||
294 | - | /* Keep a list of heads for _ls */ | ||
295 | 54 | 51 | git_smart__update_heads(t, &symrefs); | |
296 | 1 | 52 | } else if (error == GIT_ENOTFOUND) { | |
297 | - | /* There was no ref packet received, or the cap list was empty */ | ||
298 | 1 | 53 | error = 0; | |
299 | - | } else { | ||
300 | ##### | 54 | git_error_set(GIT_ERROR_NET, "invalid response"); | |
301 | ##### | 55 | goto cleanup; | |
302 | - | } | ||
303 | - | |||
304 | 55 | 56-58 | if (t->rpc && (error = git_smart__reset_stream(t, false)) < 0) | |
305 | ##### | 59 | goto cleanup; | |
306 | - | |||
307 | - | /* We're now logically connected. */ | ||
308 | 55 | 60 | t->connected = 1; | |
309 | - | |||
310 | - | cleanup: | ||
311 | 55 | 61 | free_symrefs(&symrefs); | |
312 | - | |||
313 | 55 | 62 | return error; | |
314 | - | } | ||
315 | - | |||
316 | 198 | 2 | static int git_smart__ls(const git_remote_head ***out, size_t *size, git_transport *transport) | |
317 | - | { | ||
318 | 198 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
319 | - | |||
320 | 198 | 2 | if (!t->have_refs) { | |
321 | ##### | 3 | git_error_set(GIT_ERROR_NET, "the transport has not yet loaded the refs"); | |
322 | ##### | 4 | return -1; | |
323 | - | } | ||
324 | - | |||
325 | 198 | 5 | *out = (const git_remote_head **) t->heads.contents; | |
326 | 198 | 5 | *size = t->heads.length; | |
327 | - | |||
328 | 198 | 5 | return 0; | |
329 | - | } | ||
330 | - | |||
331 | 36 | 2 | int git_smart__negotiation_step(git_transport *transport, void *data, size_t len) | |
332 | - | { | ||
333 | 36 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
334 | - | git_smart_subtransport_stream *stream; | ||
335 | - | int error; | ||
336 | - | |||
337 | 36 | 2-4 | if (t->rpc && git_smart__reset_stream(t, false) < 0) | |
338 | ##### | 5 | return -1; | |
339 | - | |||
340 | 36 | 6 | if (GIT_DIRECTION_FETCH != t->direction) { | |
341 | ##### | 7 | git_error_set(GIT_ERROR_NET, "this operation is only valid for fetch"); | |
342 | ##### | 8 | return -1; | |
343 | - | } | ||
344 | - | |||
345 | 36 | 9,10 | if ((error = t->wrapped->action(&stream, t->wrapped, t->url, GIT_SERVICE_UPLOADPACK)) < 0) | |
346 | ##### | 11 | return error; | |
347 | - | |||
348 | - | /* If this is a stateful implementation, the stream we get back should be the same */ | ||
349 | 36 | 12-14 | assert(t->rpc || t->current_stream == stream); | |
350 | - | |||
351 | - | /* Save off the current stream (i.e. socket) that we are working with */ | ||
352 | 36 | 15 | t->current_stream = stream; | |
353 | - | |||
354 | 36 | 15,16 | if ((error = stream->write(stream, (const char *)data, len)) < 0) | |
355 | ##### | 17 | return error; | |
356 | - | |||
357 | 36 | 18 | gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); | |
358 | - | |||
359 | 36 | 19 | return 0; | |
360 | - | } | ||
361 | - | |||
362 | ##### | 2 | int git_smart__get_push_stream(transport_smart *t, git_smart_subtransport_stream **stream) | |
363 | - | { | ||
364 | - | int error; | ||
365 | - | |||
366 | ##### | 2-4 | if (t->rpc && git_smart__reset_stream(t, false) < 0) | |
367 | ##### | 5 | return -1; | |
368 | - | |||
369 | ##### | 6 | if (GIT_DIRECTION_PUSH != t->direction) { | |
370 | ##### | 7 | git_error_set(GIT_ERROR_NET, "this operation is only valid for push"); | |
371 | ##### | 8 | return -1; | |
372 | - | } | ||
373 | - | |||
374 | ##### | 9,10 | if ((error = t->wrapped->action(stream, t->wrapped, t->url, GIT_SERVICE_RECEIVEPACK)) < 0) | |
375 | ##### | 11 | return error; | |
376 | - | |||
377 | - | /* If this is a stateful implementation, the stream we get back should be the same */ | ||
378 | ##### | 12-14 | assert(t->rpc || t->current_stream == *stream); | |
379 | - | |||
380 | - | /* Save off the current stream (i.e. socket) that we are working with */ | ||
381 | ##### | 15 | t->current_stream = *stream; | |
382 | - | |||
383 | ##### | 15 | gitno_buffer_setup_callback(&t->buffer, t->buffer_data, sizeof(t->buffer_data), git_smart__recv_cb, t); | |
384 | - | |||
385 | ##### | 16 | return 0; | |
386 | - | } | ||
387 | - | |||
388 | ##### | 2 | static void git_smart__cancel(git_transport *transport) | |
389 | - | { | ||
390 | ##### | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
391 | - | |||
392 | ##### | 2 | git_atomic_set(&t->cancelled, 1); | |
393 | ##### | 3 | } | |
394 | - | |||
395 | 153 | 2 | static int git_smart__is_connected(git_transport *transport) | |
396 | - | { | ||
397 | 153 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
398 | - | |||
399 | 153 | 2 | return t->connected; | |
400 | - | } | ||
401 | - | |||
402 | ##### | 2 | static int git_smart__read_flags(git_transport *transport, int *flags) | |
403 | - | { | ||
404 | ##### | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
405 | - | |||
406 | ##### | 2 | *flags = t->flags; | |
407 | - | |||
408 | ##### | 2 | return 0; | |
409 | - | } | ||
410 | - | |||
411 | 126 | 2 | static int git_smart__close(git_transport *transport) | |
412 | - | { | ||
413 | 126 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
414 | 126 | 2 | git_vector *common = &t->common; | |
415 | - | unsigned int i; | ||
416 | - | git_pkt *p; | ||
417 | - | int ret; | ||
418 | - | git_smart_subtransport_stream *stream; | ||
419 | 126 | 2 | const char flush[] = "0000"; | |
420 | - | |||
421 | - | /* | ||
422 | - | * If we're still connected at this point and not using RPC, | ||
423 | - | * we should say goodbye by sending a flush, or git-daemon | ||
424 | - | * will complain that we disconnected unexpectedly. | ||
425 | - | */ | ||
426 | 126 | 2,3,5 | if (t->connected && !t->rpc && | |
427 | 25 | 4 | !t->wrapped->action(&stream, t->wrapped, t->url, GIT_SERVICE_UPLOADPACK)) { | |
428 | 25 | 6 | t->current_stream->write(t->current_stream, flush, 4); | |
429 | - | } | ||
430 | - | |||
431 | 126 | 7 | ret = git_smart__reset_stream(t, true); | |
432 | - | |||
433 | 126 | 8,10-12 | git_vector_foreach(common, i, p) | |
434 | ##### | 9 | git_pkt_free(p); | |
435 | - | |||
436 | 126 | 13 | git_vector_free(common); | |
437 | - | |||
438 | 126 | 14 | if (t->url) { | |
439 | ##### | 15 | git__free(t->url); | |
440 | ##### | 16 | t->url = NULL; | |
441 | - | } | ||
442 | - | |||
443 | 126 | 17 | t->connected = 0; | |
444 | - | |||
445 | 126 | 17 | return ret; | |
446 | - | } | ||
447 | - | |||
448 | 71 | 2 | static void git_smart__free(git_transport *transport) | |
449 | - | { | ||
450 | 71 | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
451 | 71 | 2 | git_vector *refs = &t->refs; | |
452 | - | unsigned int i; | ||
453 | - | git_pkt *p; | ||
454 | - | |||
455 | - | /* Make sure that the current stream is closed, if we have one. */ | ||
456 | 71 | 2 | git_smart__close(transport); | |
457 | - | |||
458 | - | /* Free the subtransport */ | ||
459 | 71 | 3 | t->wrapped->free(t->wrapped); | |
460 | - | |||
461 | 71 | 4 | git_vector_free(&t->heads); | |
462 | 516 | 5,7-9 | git_vector_foreach(refs, i, p) | |
463 | 445 | 6 | git_pkt_free(p); | |
464 | - | |||
465 | 71 | 10 | git_vector_free(refs); | |
466 | 71 | 11 | git__free((char *)t->proxy.url); | |
467 | - | |||
468 | 71 | 12 | git_strarray_dispose(&t->custom_headers); | |
469 | - | |||
470 | 71 | 13 | git__free(t); | |
471 | 71 | 14 | } | |
472 | - | |||
473 | ##### | 2 | static int ref_name_cmp(const void *a, const void *b) | |
474 | - | { | ||
475 | ##### | 2 | const git_pkt_ref *ref_a = a, *ref_b = b; | |
476 | - | |||
477 | ##### | 2 | return strcmp(ref_a->head.name, ref_b->head.name); | |
478 | - | } | ||
479 | - | |||
480 | ##### | 2 | int git_transport_smart_certificate_check(git_transport *transport, git_cert *cert, int valid, const char *hostname) | |
481 | - | { | ||
482 | ##### | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
483 | - | |||
484 | ##### | 2-5 | assert(transport && cert && hostname); | |
485 | - | |||
486 | ##### | 6 | if (!t->certificate_check_cb) | |
487 | ##### | 7 | return GIT_PASSTHROUGH; | |
488 | - | |||
489 | ##### | 8 | return t->certificate_check_cb(cert, valid, hostname, t->message_cb_payload); | |
490 | - | } | ||
491 | - | |||
492 | ##### | 2 | int git_transport_smart_credentials(git_credential **out, git_transport *transport, const char *user, int methods) | |
493 | - | { | ||
494 | ##### | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
495 | - | |||
496 | ##### | 2-4 | assert(out && transport); | |
497 | - | |||
498 | ##### | 5 | if (!t->cred_acquire_cb) | |
499 | ##### | 6 | return GIT_PASSTHROUGH; | |
500 | - | |||
501 | ##### | 7 | return t->cred_acquire_cb(out, t->url, user, methods, t->cred_acquire_payload); | |
502 | - | } | ||
503 | - | |||
504 | ##### | 2 | int git_transport_smart_proxy_options(git_proxy_options *out, git_transport *transport) | |
505 | - | { | ||
506 | ##### | 2 | transport_smart *t = GIT_CONTAINER_OF(transport, transport_smart, parent); | |
507 | ##### | 2 | return git_proxy_options_dup(out, &t->proxy); | |
508 | - | } | ||
509 | - | |||
510 | 71 | 2 | int git_transport_smart(git_transport **out, git_remote *owner, void *param) | |
511 | - | { | ||
512 | - | transport_smart *t; | ||
513 | 71 | 2 | git_smart_subtransport_definition *definition = (git_smart_subtransport_definition *)param; | |
514 | - | |||
515 | 71 | 2 | if (!param) | |
516 | ##### | 3 | return -1; | |
517 | - | |||
518 | 71 | 4 | t = git__calloc(1, sizeof(transport_smart)); | |
519 | 71 | 5,6 | GIT_ERROR_CHECK_ALLOC(t); | |
520 | - | |||
521 | 71 | 7 | t->parent.version = GIT_TRANSPORT_VERSION; | |
522 | 71 | 7 | t->parent.set_callbacks = git_smart__set_callbacks; | |
523 | 71 | 7 | t->parent.set_custom_headers = git_smart__set_custom_headers; | |
524 | 71 | 7 | t->parent.connect = git_smart__connect; | |
525 | 71 | 7 | t->parent.close = git_smart__close; | |
526 | 71 | 7 | t->parent.free = git_smart__free; | |
527 | 71 | 7 | t->parent.negotiate_fetch = git_smart__negotiate_fetch; | |
528 | 71 | 7 | t->parent.download_pack = git_smart__download_pack; | |
529 | 71 | 7 | t->parent.push = git_smart__push; | |
530 | 71 | 7 | t->parent.ls = git_smart__ls; | |
531 | 71 | 7 | t->parent.is_connected = git_smart__is_connected; | |
532 | 71 | 7 | t->parent.read_flags = git_smart__read_flags; | |
533 | 71 | 7 | t->parent.cancel = git_smart__cancel; | |
534 | - | |||
535 | 71 | 7 | t->owner = owner; | |
536 | 71 | 7 | t->rpc = definition->rpc; | |
537 | - | |||
538 | 71 | 7,8 | if (git_vector_init(&t->refs, 16, ref_name_cmp) < 0) { | |
539 | ##### | 9 | git__free(t); | |
540 | ##### | 10 | return -1; | |
541 | - | } | ||
542 | - | |||
543 | 71 | 11,12 | if (git_vector_init(&t->heads, 16, ref_name_cmp) < 0) { | |
544 | ##### | 13 | git__free(t); | |
545 | ##### | 14 | return -1; | |
546 | - | } | ||
547 | - | |||
548 | 71 | 15,16 | if (definition->callback(&t->wrapped, &t->parent, definition->param) < 0) { | |
549 | ##### | 17 | git__free(t); | |
550 | ##### | 18 | return -1; | |
551 | - | } | ||
552 | - | |||
553 | 71 | 19 | *out = (git_transport *) t; | |
554 | 71 | 19 | return 0; | |
555 | - | } |