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 | - | } |