Git fork
at reftables-rust 2862 lines 78 kB view raw
1#define USE_THE_REPOSITORY_VARIABLE 2#define DISABLE_SIGN_COMPARE_WARNINGS 3 4#include "git-compat-util.h" 5#include "git-curl-compat.h" 6#include "environment.h" 7#include "hex.h" 8#include "http.h" 9#include "config.h" 10#include "pack.h" 11#include "run-command.h" 12#include "url.h" 13#include "urlmatch.h" 14#include "credential.h" 15#include "version.h" 16#include "pkt-line.h" 17#include "gettext.h" 18#include "trace.h" 19#include "transport.h" 20#include "packfile.h" 21#include "string-list.h" 22#include "object-file.h" 23#include "odb.h" 24#include "tempfile.h" 25 26static struct trace_key trace_curl = TRACE_KEY_INIT(CURL); 27static int trace_curl_data = 1; 28static int trace_curl_redact = 1; 29long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER; 30int active_requests; 31int http_is_verbose; 32ssize_t http_post_buffer = 16 * LARGE_PACKET_MAX; 33 34static int min_curl_sessions = 1; 35static int curl_session_count; 36static int max_requests = -1; 37static CURLM *curlm; 38static CURL *curl_default; 39 40#define PREV_BUF_SIZE 4096 41 42char curl_errorstr[CURL_ERROR_SIZE]; 43 44static int curl_ssl_verify = -1; 45static int curl_ssl_try; 46static char *curl_http_version; 47static char *ssl_cert; 48static char *ssl_cert_type; 49static char *ssl_cipherlist; 50static char *ssl_version; 51static struct { 52 const char *name; 53 long ssl_version; 54} sslversions[] = { 55 { "sslv2", CURL_SSLVERSION_SSLv2 }, 56 { "sslv3", CURL_SSLVERSION_SSLv3 }, 57 { "tlsv1", CURL_SSLVERSION_TLSv1 }, 58 { "tlsv1.0", CURL_SSLVERSION_TLSv1_0 }, 59 { "tlsv1.1", CURL_SSLVERSION_TLSv1_1 }, 60 { "tlsv1.2", CURL_SSLVERSION_TLSv1_2 }, 61 { "tlsv1.3", CURL_SSLVERSION_TLSv1_3 }, 62}; 63static char *ssl_key; 64static char *ssl_key_type; 65static char *ssl_capath; 66static char *curl_no_proxy; 67static char *ssl_pinnedkey; 68static char *ssl_cainfo; 69static long curl_low_speed_limit = -1; 70static long curl_low_speed_time = -1; 71static int curl_ftp_no_epsv; 72static char *curl_http_proxy; 73static char *http_proxy_authmethod; 74 75static char *http_proxy_ssl_cert; 76static char *http_proxy_ssl_key; 77static char *http_proxy_ssl_ca_info; 78static struct credential proxy_cert_auth = CREDENTIAL_INIT; 79static int proxy_ssl_cert_password_required; 80 81static struct { 82 const char *name; 83 long curlauth_param; 84} proxy_authmethods[] = { 85 { "basic", CURLAUTH_BASIC }, 86 { "digest", CURLAUTH_DIGEST }, 87 { "negotiate", CURLAUTH_GSSNEGOTIATE }, 88 { "ntlm", CURLAUTH_NTLM }, 89 { "anyauth", CURLAUTH_ANY }, 90 /* 91 * CURLAUTH_DIGEST_IE has no corresponding command-line option in 92 * curl(1) and is not included in CURLAUTH_ANY, so we leave it out 93 * here, too 94 */ 95}; 96#ifdef CURLGSSAPI_DELEGATION_FLAG 97static char *curl_deleg; 98static struct { 99 const char *name; 100 long curl_deleg_param; 101} curl_deleg_levels[] = { 102 { "none", CURLGSSAPI_DELEGATION_NONE }, 103 { "policy", CURLGSSAPI_DELEGATION_POLICY_FLAG }, 104 { "always", CURLGSSAPI_DELEGATION_FLAG }, 105}; 106#endif 107 108static long curl_tcp_keepidle = -1; 109static long curl_tcp_keepintvl = -1; 110static long curl_tcp_keepcnt = -1; 111 112enum proactive_auth { 113 PROACTIVE_AUTH_NONE = 0, 114 PROACTIVE_AUTH_IF_CREDENTIALS, 115 PROACTIVE_AUTH_AUTO, 116 PROACTIVE_AUTH_BASIC, 117}; 118 119static struct credential proxy_auth = CREDENTIAL_INIT; 120static const char *curl_proxyuserpwd; 121static char *curl_cookie_file; 122static int curl_save_cookies; 123struct credential http_auth = CREDENTIAL_INIT; 124static enum proactive_auth http_proactive_auth; 125static char *user_agent; 126static int curl_empty_auth = -1; 127 128enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL; 129 130static struct credential cert_auth = CREDENTIAL_INIT; 131static int ssl_cert_password_required; 132static unsigned long http_auth_methods = CURLAUTH_ANY; 133static int http_auth_methods_restricted; 134/* Modes for which empty_auth cannot actually help us. */ 135static unsigned long empty_auth_useless = 136 CURLAUTH_BASIC 137 | CURLAUTH_DIGEST_IE 138 | CURLAUTH_DIGEST; 139 140static struct curl_slist *pragma_header; 141static struct string_list extra_http_headers = STRING_LIST_INIT_DUP; 142 143static struct curl_slist *host_resolutions; 144 145static struct active_request_slot *active_queue_head; 146 147static char *cached_accept_language; 148 149static char *http_ssl_backend; 150 151static int http_schannel_check_revoke = 1; 152/* 153 * With the backend being set to `schannel`, setting sslCAinfo would override 154 * the Certificate Store in cURL v7.60.0 and later, which is not what we want 155 * by default. 156 */ 157static int http_schannel_use_ssl_cainfo; 158 159static int always_auth_proactively(void) 160{ 161 return http_proactive_auth != PROACTIVE_AUTH_NONE && 162 http_proactive_auth != PROACTIVE_AUTH_IF_CREDENTIALS; 163} 164 165size_t fread_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) 166{ 167 size_t size = eltsize * nmemb; 168 struct buffer *buffer = buffer_; 169 170 if (size > buffer->buf.len - buffer->posn) 171 size = buffer->buf.len - buffer->posn; 172 memcpy(ptr, buffer->buf.buf + buffer->posn, size); 173 buffer->posn += size; 174 175 return size / eltsize; 176} 177 178int seek_buffer(void *clientp, curl_off_t offset, int origin) 179{ 180 struct buffer *buffer = clientp; 181 182 if (origin != SEEK_SET) 183 BUG("seek_buffer only handles SEEK_SET"); 184 if (offset < 0 || offset >= buffer->buf.len) { 185 error("curl seek would be outside of buffer"); 186 return CURL_SEEKFUNC_FAIL; 187 } 188 189 buffer->posn = offset; 190 return CURL_SEEKFUNC_OK; 191} 192 193size_t fwrite_buffer(char *ptr, size_t eltsize, size_t nmemb, void *buffer_) 194{ 195 size_t size = eltsize * nmemb; 196 struct strbuf *buffer = buffer_; 197 198 strbuf_add(buffer, ptr, size); 199 return nmemb; 200} 201 202/* 203 * A folded header continuation line starts with any number of spaces or 204 * horizontal tab characters (SP or HTAB) as per RFC 7230 section 3.2. 205 * It is not a continuation line if the line starts with any other character. 206 */ 207static inline int is_hdr_continuation(const char *ptr, const size_t size) 208{ 209 return size && (*ptr == ' ' || *ptr == '\t'); 210} 211 212static size_t fwrite_wwwauth(char *ptr, size_t eltsize, size_t nmemb, void *p UNUSED) 213{ 214 size_t size = eltsize * nmemb; 215 struct strvec *values = &http_auth.wwwauth_headers; 216 struct strbuf buf = STRBUF_INIT; 217 const char *val; 218 size_t val_len; 219 220 /* 221 * Header lines may not come NULL-terminated from libcurl so we must 222 * limit all scans to the maximum length of the header line, or leverage 223 * strbufs for all operations. 224 * 225 * In addition, it is possible that header values can be split over 226 * multiple lines as per RFC 7230. 'Line folding' has been deprecated 227 * but older servers may still emit them. A continuation header field 228 * value is identified as starting with a space or horizontal tab. 229 * 230 * The formal definition of a header field as given in RFC 7230 is: 231 * 232 * header-field = field-name ":" OWS field-value OWS 233 * 234 * field-name = token 235 * field-value = *( field-content / obs-fold ) 236 * field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ] 237 * field-vchar = VCHAR / obs-text 238 * 239 * obs-fold = CRLF 1*( SP / HTAB ) 240 * ; obsolete line folding 241 * ; see Section 3.2.4 242 */ 243 244 /* Start of a new WWW-Authenticate header */ 245 if (skip_iprefix_mem(ptr, size, "www-authenticate:", &val, &val_len)) { 246 strbuf_add(&buf, val, val_len); 247 248 /* 249 * Strip the CRLF that should be present at the end of each 250 * field as well as any trailing or leading whitespace from the 251 * value. 252 */ 253 strbuf_trim(&buf); 254 255 strvec_push(values, buf.buf); 256 http_auth.header_is_last_match = 1; 257 goto exit; 258 } 259 260 /* 261 * This line could be a continuation of the previously matched header 262 * field. If this is the case then we should append this value to the 263 * end of the previously consumed value. 264 */ 265 if (http_auth.header_is_last_match && is_hdr_continuation(ptr, size)) { 266 /* 267 * Trim the CRLF and any leading or trailing from this line. 268 */ 269 strbuf_add(&buf, ptr, size); 270 strbuf_trim(&buf); 271 272 /* 273 * At this point we should always have at least one existing 274 * value, even if it is empty. Do not bother appending the new 275 * value if this continuation header is itself empty. 276 */ 277 if (!values->nr) { 278 BUG("should have at least one existing header value"); 279 } else if (buf.len) { 280 char *prev = xstrdup(values->v[values->nr - 1]); 281 282 /* Join two non-empty values with a single space. */ 283 const char *const sp = *prev ? " " : ""; 284 285 strvec_pop(values); 286 strvec_pushf(values, "%s%s%s", prev, sp, buf.buf); 287 free(prev); 288 } 289 290 goto exit; 291 } 292 293 /* Not a continuation of a previously matched auth header line. */ 294 http_auth.header_is_last_match = 0; 295 296 /* 297 * If this is a HTTP status line and not a header field, this signals 298 * a different HTTP response. libcurl writes all the output of all 299 * response headers of all responses, including redirects. 300 * We only care about the last HTTP request response's headers so clear 301 * the existing array. 302 */ 303 if (skip_iprefix_mem(ptr, size, "http/", &val, &val_len)) 304 strvec_clear(values); 305 306exit: 307 strbuf_release(&buf); 308 return size; 309} 310 311size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb, 312 void *data UNUSED) 313{ 314 return nmemb; 315} 316 317static struct curl_slist *object_request_headers(void) 318{ 319 return curl_slist_append(http_copy_default_headers(), "Pragma:"); 320} 321 322static void closedown_active_slot(struct active_request_slot *slot) 323{ 324 active_requests--; 325 slot->in_use = 0; 326} 327 328static void finish_active_slot(struct active_request_slot *slot) 329{ 330 closedown_active_slot(slot); 331 curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code); 332 333 if (slot->finished) 334 (*slot->finished) = 1; 335 336 /* Store slot results so they can be read after the slot is reused */ 337 if (slot->results) { 338 slot->results->curl_result = slot->curl_result; 339 slot->results->http_code = slot->http_code; 340 curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL, 341 &slot->results->auth_avail); 342 343 curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE, 344 &slot->results->http_connectcode); 345 } 346 347 /* Run callback if appropriate */ 348 if (slot->callback_func) 349 slot->callback_func(slot->callback_data); 350} 351 352static void xmulti_remove_handle(struct active_request_slot *slot) 353{ 354 curl_multi_remove_handle(curlm, slot->curl); 355} 356 357static void process_curl_messages(void) 358{ 359 int num_messages; 360 struct active_request_slot *slot; 361 CURLMsg *curl_message = curl_multi_info_read(curlm, &num_messages); 362 363 while (curl_message != NULL) { 364 if (curl_message->msg == CURLMSG_DONE) { 365 int curl_result = curl_message->data.result; 366 slot = active_queue_head; 367 while (slot != NULL && 368 slot->curl != curl_message->easy_handle) 369 slot = slot->next; 370 if (slot) { 371 xmulti_remove_handle(slot); 372 slot->curl_result = curl_result; 373 finish_active_slot(slot); 374 } else { 375 fprintf(stderr, "Received DONE message for unknown request!\n"); 376 } 377 } else { 378 fprintf(stderr, "Unknown CURL message received: %d\n", 379 (int)curl_message->msg); 380 } 381 curl_message = curl_multi_info_read(curlm, &num_messages); 382 } 383} 384 385static int http_options(const char *var, const char *value, 386 const struct config_context *ctx, void *data) 387{ 388 if (!strcmp("http.version", var)) { 389 return git_config_string(&curl_http_version, var, value); 390 } 391 if (!strcmp("http.sslverify", var)) { 392 curl_ssl_verify = git_config_bool(var, value); 393 return 0; 394 } 395 if (!strcmp("http.sslcipherlist", var)) 396 return git_config_string(&ssl_cipherlist, var, value); 397 if (!strcmp("http.sslversion", var)) 398 return git_config_string(&ssl_version, var, value); 399 if (!strcmp("http.sslcert", var)) 400 return git_config_pathname(&ssl_cert, var, value); 401 if (!strcmp("http.sslcerttype", var)) 402 return git_config_string(&ssl_cert_type, var, value); 403 if (!strcmp("http.sslkey", var)) 404 return git_config_pathname(&ssl_key, var, value); 405 if (!strcmp("http.sslkeytype", var)) 406 return git_config_string(&ssl_key_type, var, value); 407 if (!strcmp("http.sslcapath", var)) 408 return git_config_pathname(&ssl_capath, var, value); 409 if (!strcmp("http.sslcainfo", var)) 410 return git_config_pathname(&ssl_cainfo, var, value); 411 if (!strcmp("http.sslcertpasswordprotected", var)) { 412 ssl_cert_password_required = git_config_bool(var, value); 413 return 0; 414 } 415 if (!strcmp("http.ssltry", var)) { 416 curl_ssl_try = git_config_bool(var, value); 417 return 0; 418 } 419 if (!strcmp("http.sslbackend", var)) { 420 free(http_ssl_backend); 421 http_ssl_backend = xstrdup_or_null(value); 422 return 0; 423 } 424 425 if (!strcmp("http.schannelcheckrevoke", var)) { 426 http_schannel_check_revoke = git_config_bool(var, value); 427 return 0; 428 } 429 430 if (!strcmp("http.schannelusesslcainfo", var)) { 431 http_schannel_use_ssl_cainfo = git_config_bool(var, value); 432 return 0; 433 } 434 435 if (!strcmp("http.minsessions", var)) { 436 min_curl_sessions = git_config_int(var, value, ctx->kvi); 437 if (min_curl_sessions > 1) 438 min_curl_sessions = 1; 439 return 0; 440 } 441 if (!strcmp("http.maxrequests", var)) { 442 max_requests = git_config_int(var, value, ctx->kvi); 443 return 0; 444 } 445 if (!strcmp("http.lowspeedlimit", var)) { 446 curl_low_speed_limit = git_config_int(var, value, ctx->kvi); 447 return 0; 448 } 449 if (!strcmp("http.lowspeedtime", var)) { 450 curl_low_speed_time = git_config_int(var, value, ctx->kvi); 451 return 0; 452 } 453 454 if (!strcmp("http.noepsv", var)) { 455 curl_ftp_no_epsv = git_config_bool(var, value); 456 return 0; 457 } 458 if (!strcmp("http.proxy", var)) 459 return git_config_string(&curl_http_proxy, var, value); 460 461 if (!strcmp("http.proxyauthmethod", var)) 462 return git_config_string(&http_proxy_authmethod, var, value); 463 464 if (!strcmp("http.proxysslcert", var)) 465 return git_config_string(&http_proxy_ssl_cert, var, value); 466 467 if (!strcmp("http.proxysslkey", var)) 468 return git_config_string(&http_proxy_ssl_key, var, value); 469 470 if (!strcmp("http.proxysslcainfo", var)) 471 return git_config_string(&http_proxy_ssl_ca_info, var, value); 472 473 if (!strcmp("http.proxysslcertpasswordprotected", var)) { 474 proxy_ssl_cert_password_required = git_config_bool(var, value); 475 return 0; 476 } 477 478 if (!strcmp("http.cookiefile", var)) 479 return git_config_pathname(&curl_cookie_file, var, value); 480 if (!strcmp("http.savecookies", var)) { 481 curl_save_cookies = git_config_bool(var, value); 482 return 0; 483 } 484 485 if (!strcmp("http.postbuffer", var)) { 486 http_post_buffer = git_config_ssize_t(var, value, ctx->kvi); 487 if (http_post_buffer < 0) 488 warning(_("negative value for http.postBuffer; defaulting to %d"), LARGE_PACKET_MAX); 489 if (http_post_buffer < LARGE_PACKET_MAX) 490 http_post_buffer = LARGE_PACKET_MAX; 491 return 0; 492 } 493 494 if (!strcmp("http.useragent", var)) 495 return git_config_string(&user_agent, var, value); 496 497 if (!strcmp("http.emptyauth", var)) { 498 if (value && !strcmp("auto", value)) 499 curl_empty_auth = -1; 500 else 501 curl_empty_auth = git_config_bool(var, value); 502 return 0; 503 } 504 505 if (!strcmp("http.delegation", var)) { 506#ifdef CURLGSSAPI_DELEGATION_FLAG 507 return git_config_string(&curl_deleg, var, value); 508#else 509 warning(_("Delegation control is not supported with cURL < 7.22.0")); 510 return 0; 511#endif 512 } 513 514 if (!strcmp("http.pinnedpubkey", var)) { 515 return git_config_pathname(&ssl_pinnedkey, var, value); 516 } 517 518 if (!strcmp("http.extraheader", var)) { 519 if (!value) { 520 return config_error_nonbool(var); 521 } else if (!*value) { 522 string_list_clear(&extra_http_headers, 0); 523 } else { 524 string_list_append(&extra_http_headers, value); 525 } 526 return 0; 527 } 528 529 if (!strcmp("http.curloptresolve", var)) { 530 if (!value) { 531 return config_error_nonbool(var); 532 } else if (!*value) { 533 curl_slist_free_all(host_resolutions); 534 host_resolutions = NULL; 535 } else { 536 host_resolutions = curl_slist_append(host_resolutions, value); 537 } 538 return 0; 539 } 540 541 if (!strcmp("http.followredirects", var)) { 542 if (value && !strcmp(value, "initial")) 543 http_follow_config = HTTP_FOLLOW_INITIAL; 544 else if (git_config_bool(var, value)) 545 http_follow_config = HTTP_FOLLOW_ALWAYS; 546 else 547 http_follow_config = HTTP_FOLLOW_NONE; 548 return 0; 549 } 550 551 if (!strcmp("http.proactiveauth", var)) { 552 if (!value) 553 return config_error_nonbool(var); 554 if (!strcmp(value, "auto")) 555 http_proactive_auth = PROACTIVE_AUTH_AUTO; 556 else if (!strcmp(value, "basic")) 557 http_proactive_auth = PROACTIVE_AUTH_BASIC; 558 else if (!strcmp(value, "none")) 559 http_proactive_auth = PROACTIVE_AUTH_NONE; 560 else 561 warning(_("Unknown value for http.proactiveauth")); 562 return 0; 563 } 564 565 if (!strcmp("http.keepaliveidle", var)) { 566 curl_tcp_keepidle = git_config_int(var, value, ctx->kvi); 567 return 0; 568 } 569 if (!strcmp("http.keepaliveinterval", var)) { 570 curl_tcp_keepintvl = git_config_int(var, value, ctx->kvi); 571 return 0; 572 } 573 if (!strcmp("http.keepalivecount", var)) { 574 curl_tcp_keepcnt = git_config_int(var, value, ctx->kvi); 575 return 0; 576 } 577 578 /* Fall back on the default ones */ 579 return git_default_config(var, value, ctx, data); 580} 581 582static int curl_empty_auth_enabled(void) 583{ 584 if (curl_empty_auth >= 0) 585 return curl_empty_auth; 586 587 /* 588 * In the automatic case, kick in the empty-auth 589 * hack as long as we would potentially try some 590 * method more exotic than "Basic" or "Digest". 591 * 592 * But only do this when this is our second or 593 * subsequent request, as by then we know what 594 * methods are available. 595 */ 596 if (http_auth_methods_restricted && 597 (http_auth_methods & ~empty_auth_useless)) 598 return 1; 599 return 0; 600} 601 602struct curl_slist *http_append_auth_header(const struct credential *c, 603 struct curl_slist *headers) 604{ 605 if (c->authtype && c->credential) { 606 struct strbuf auth = STRBUF_INIT; 607 strbuf_addf(&auth, "Authorization: %s %s", 608 c->authtype, c->credential); 609 headers = curl_slist_append(headers, auth.buf); 610 strbuf_release(&auth); 611 } 612 return headers; 613} 614 615static void init_curl_http_auth(CURL *result) 616{ 617 if ((!http_auth.username || !*http_auth.username) && 618 (!http_auth.credential || !*http_auth.credential)) { 619 if (!always_auth_proactively() && curl_empty_auth_enabled()) { 620 curl_easy_setopt(result, CURLOPT_USERPWD, ":"); 621 return; 622 } else if (!always_auth_proactively()) { 623 return; 624 } else if (http_proactive_auth == PROACTIVE_AUTH_BASIC) { 625 strvec_push(&http_auth.wwwauth_headers, "Basic"); 626 } 627 } 628 629 credential_fill(the_repository, &http_auth, 1); 630 631 if (http_auth.password) { 632 if (always_auth_proactively()) { 633 /* 634 * We got a credential without an authtype and we don't 635 * know what's available. Since our only two options at 636 * the moment are auto (which defaults to basic) and 637 * basic, use basic for now. 638 */ 639 curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); 640 } 641 curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username); 642 curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password); 643 } 644} 645 646/* *var must be free-able */ 647static void var_override(char **var, char *value) 648{ 649 if (value) { 650 free(*var); 651 *var = xstrdup(value); 652 } 653} 654 655static void set_proxyauth_name_password(CURL *result) 656{ 657 if (proxy_auth.password) { 658 curl_easy_setopt(result, CURLOPT_PROXYUSERNAME, 659 proxy_auth.username); 660 curl_easy_setopt(result, CURLOPT_PROXYPASSWORD, 661 proxy_auth.password); 662 } else if (proxy_auth.authtype && proxy_auth.credential) { 663 curl_easy_setopt(result, CURLOPT_PROXYHEADER, 664 http_append_auth_header(&proxy_auth, NULL)); 665 } 666} 667 668static void init_curl_proxy_auth(CURL *result) 669{ 670 if (proxy_auth.username) { 671 if (!proxy_auth.password && !proxy_auth.credential) 672 credential_fill(the_repository, &proxy_auth, 1); 673 set_proxyauth_name_password(result); 674 } 675 676 var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD")); 677 678 if (http_proxy_authmethod) { 679 int i; 680 for (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) { 681 if (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) { 682 curl_easy_setopt(result, CURLOPT_PROXYAUTH, 683 proxy_authmethods[i].curlauth_param); 684 break; 685 } 686 } 687 if (i == ARRAY_SIZE(proxy_authmethods)) { 688 warning("unsupported proxy authentication method %s: using anyauth", 689 http_proxy_authmethod); 690 curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); 691 } 692 } 693 else 694 curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY); 695} 696 697static int has_cert_password(void) 698{ 699 if (ssl_cert == NULL || ssl_cert_password_required != 1) 700 return 0; 701 if (!cert_auth.password) { 702 cert_auth.protocol = xstrdup("cert"); 703 cert_auth.host = xstrdup(""); 704 cert_auth.username = xstrdup(""); 705 cert_auth.path = xstrdup(ssl_cert); 706 credential_fill(the_repository, &cert_auth, 0); 707 } 708 return 1; 709} 710 711static int has_proxy_cert_password(void) 712{ 713 if (http_proxy_ssl_cert == NULL || proxy_ssl_cert_password_required != 1) 714 return 0; 715 if (!proxy_cert_auth.password) { 716 proxy_cert_auth.protocol = xstrdup("cert"); 717 proxy_cert_auth.host = xstrdup(""); 718 proxy_cert_auth.username = xstrdup(""); 719 proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert); 720 credential_fill(the_repository, &proxy_cert_auth, 0); 721 } 722 return 1; 723} 724 725/* Return 1 if redactions have been made, 0 otherwise. */ 726static int redact_sensitive_header(struct strbuf *header, size_t offset) 727{ 728 int ret = 0; 729 const char *sensitive_header; 730 731 if (trace_curl_redact && 732 (skip_iprefix(header->buf + offset, "Authorization:", &sensitive_header) || 733 skip_iprefix(header->buf + offset, "Proxy-Authorization:", &sensitive_header))) { 734 /* The first token is the type, which is OK to log */ 735 while (isspace(*sensitive_header)) 736 sensitive_header++; 737 while (*sensitive_header && !isspace(*sensitive_header)) 738 sensitive_header++; 739 /* Everything else is opaque and possibly sensitive */ 740 strbuf_setlen(header, sensitive_header - header->buf); 741 strbuf_addstr(header, " <redacted>"); 742 ret = 1; 743 } else if (trace_curl_redact && 744 skip_iprefix(header->buf + offset, "Cookie:", &sensitive_header)) { 745 struct strbuf redacted_header = STRBUF_INIT; 746 const char *cookie; 747 748 while (isspace(*sensitive_header)) 749 sensitive_header++; 750 751 cookie = sensitive_header; 752 753 while (cookie) { 754 char *equals; 755 char *semicolon = strstr(cookie, "; "); 756 if (semicolon) 757 *semicolon = 0; 758 equals = strchrnul(cookie, '='); 759 if (!equals) { 760 /* invalid cookie, just append and continue */ 761 strbuf_addstr(&redacted_header, cookie); 762 continue; 763 } 764 strbuf_add(&redacted_header, cookie, equals - cookie); 765 strbuf_addstr(&redacted_header, "=<redacted>"); 766 if (semicolon) { 767 /* 768 * There are more cookies. (Or, for some 769 * reason, the input string ends in "; ".) 770 */ 771 strbuf_addstr(&redacted_header, "; "); 772 cookie = semicolon + strlen("; "); 773 } else { 774 cookie = NULL; 775 } 776 } 777 778 strbuf_setlen(header, sensitive_header - header->buf); 779 strbuf_addbuf(header, &redacted_header); 780 strbuf_release(&redacted_header); 781 ret = 1; 782 } 783 return ret; 784} 785 786static int match_curl_h2_trace(const char *line, const char **out) 787{ 788 const char *p; 789 790 /* 791 * curl prior to 8.1.0 gives us: 792 * 793 * h2h3 [<header-name>: <header-val>] 794 * 795 * Starting in 8.1.0, the first token became just "h2". 796 */ 797 if (skip_iprefix(line, "h2h3 [", out) || 798 skip_iprefix(line, "h2 [", out)) 799 return 1; 800 801 /* 802 * curl 8.3.0 uses: 803 * [HTTP/2] [<stream-id>] [<header-name>: <header-val>] 804 * where <stream-id> is numeric. 805 */ 806 if (skip_iprefix(line, "[HTTP/2] [", &p)) { 807 while (isdigit(*p)) 808 p++; 809 if (skip_prefix(p, "] [", out)) 810 return 1; 811 } 812 813 return 0; 814} 815 816/* Redact headers in info */ 817static void redact_sensitive_info_header(struct strbuf *header) 818{ 819 const char *sensitive_header; 820 821 if (trace_curl_redact && 822 match_curl_h2_trace(header->buf, &sensitive_header)) { 823 if (redact_sensitive_header(header, sensitive_header - header->buf)) { 824 /* redaction ate our closing bracket */ 825 strbuf_addch(header, ']'); 826 } 827 } 828} 829 830static void curl_dump_header(const char *text, unsigned char *ptr, size_t size, int hide_sensitive_header) 831{ 832 struct strbuf out = STRBUF_INIT; 833 struct strbuf **headers, **header; 834 835 strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n", 836 text, (long)size, (long)size); 837 trace_strbuf(&trace_curl, &out); 838 strbuf_reset(&out); 839 strbuf_add(&out, ptr, size); 840 headers = strbuf_split_max(&out, '\n', 0); 841 842 for (header = headers; *header; header++) { 843 if (hide_sensitive_header) 844 redact_sensitive_header(*header, 0); 845 strbuf_insertstr((*header), 0, text); 846 strbuf_insertstr((*header), strlen(text), ": "); 847 strbuf_rtrim((*header)); 848 strbuf_addch((*header), '\n'); 849 trace_strbuf(&trace_curl, (*header)); 850 } 851 strbuf_list_free(headers); 852 strbuf_release(&out); 853} 854 855static void curl_dump_data(const char *text, unsigned char *ptr, size_t size) 856{ 857 size_t i; 858 struct strbuf out = STRBUF_INIT; 859 unsigned int width = 60; 860 861 strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n", 862 text, (long)size, (long)size); 863 trace_strbuf(&trace_curl, &out); 864 865 for (i = 0; i < size; i += width) { 866 size_t w; 867 868 strbuf_reset(&out); 869 strbuf_addf(&out, "%s: ", text); 870 for (w = 0; (w < width) && (i + w < size); w++) { 871 unsigned char ch = ptr[i + w]; 872 873 strbuf_addch(&out, 874 (ch >= 0x20) && (ch < 0x80) 875 ? ch : '.'); 876 } 877 strbuf_addch(&out, '\n'); 878 trace_strbuf(&trace_curl, &out); 879 } 880 strbuf_release(&out); 881} 882 883static void curl_dump_info(char *data, size_t size) 884{ 885 struct strbuf buf = STRBUF_INIT; 886 887 strbuf_add(&buf, data, size); 888 889 redact_sensitive_info_header(&buf); 890 trace_printf_key(&trace_curl, "== Info: %s", buf.buf); 891 892 strbuf_release(&buf); 893} 894 895static int curl_trace(CURL *handle UNUSED, curl_infotype type, 896 char *data, size_t size, 897 void *userp UNUSED) 898{ 899 const char *text; 900 enum { NO_FILTER = 0, DO_FILTER = 1 }; 901 902 switch (type) { 903 case CURLINFO_TEXT: 904 curl_dump_info(data, size); 905 break; 906 case CURLINFO_HEADER_OUT: 907 text = "=> Send header"; 908 curl_dump_header(text, (unsigned char *)data, size, DO_FILTER); 909 break; 910 case CURLINFO_DATA_OUT: 911 if (trace_curl_data) { 912 text = "=> Send data"; 913 curl_dump_data(text, (unsigned char *)data, size); 914 } 915 break; 916 case CURLINFO_SSL_DATA_OUT: 917 if (trace_curl_data) { 918 text = "=> Send SSL data"; 919 curl_dump_data(text, (unsigned char *)data, size); 920 } 921 break; 922 case CURLINFO_HEADER_IN: 923 text = "<= Recv header"; 924 curl_dump_header(text, (unsigned char *)data, size, NO_FILTER); 925 break; 926 case CURLINFO_DATA_IN: 927 if (trace_curl_data) { 928 text = "<= Recv data"; 929 curl_dump_data(text, (unsigned char *)data, size); 930 } 931 break; 932 case CURLINFO_SSL_DATA_IN: 933 if (trace_curl_data) { 934 text = "<= Recv SSL data"; 935 curl_dump_data(text, (unsigned char *)data, size); 936 } 937 break; 938 939 default: /* we ignore unknown types by default */ 940 return 0; 941 } 942 return 0; 943} 944 945void http_trace_curl_no_data(void) 946{ 947 trace_override_envvar(&trace_curl, "1"); 948 trace_curl_data = 0; 949} 950 951void setup_curl_trace(CURL *handle) 952{ 953 if (!trace_want(&trace_curl)) 954 return; 955 curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); 956 curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, curl_trace); 957 curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL); 958} 959 960static void proto_list_append(struct strbuf *list, const char *proto) 961{ 962 if (!list) 963 return; 964 if (list->len) 965 strbuf_addch(list, ','); 966 strbuf_addstr(list, proto); 967} 968 969static long get_curl_allowed_protocols(int from_user, struct strbuf *list) 970{ 971 long bits = 0; 972 973 if (is_transport_allowed("http", from_user)) { 974 bits |= CURLPROTO_HTTP; 975 proto_list_append(list, "http"); 976 } 977 if (is_transport_allowed("https", from_user)) { 978 bits |= CURLPROTO_HTTPS; 979 proto_list_append(list, "https"); 980 } 981 if (is_transport_allowed("ftp", from_user)) { 982 bits |= CURLPROTO_FTP; 983 proto_list_append(list, "ftp"); 984 } 985 if (is_transport_allowed("ftps", from_user)) { 986 bits |= CURLPROTO_FTPS; 987 proto_list_append(list, "ftps"); 988 } 989 990 return bits; 991} 992 993static int get_curl_http_version_opt(const char *version_string, long *opt) 994{ 995 int i; 996 static struct { 997 const char *name; 998 long opt_token; 999 } choice[] = { 1000 { "HTTP/1.1", CURL_HTTP_VERSION_1_1 }, 1001 { "HTTP/2", CURL_HTTP_VERSION_2 } 1002 }; 1003 1004 for (i = 0; i < ARRAY_SIZE(choice); i++) { 1005 if (!strcmp(version_string, choice[i].name)) { 1006 *opt = choice[i].opt_token; 1007 return 0; 1008 } 1009 } 1010 1011 warning("unknown value given to http.version: '%s'", version_string); 1012 return -1; /* not found */ 1013} 1014 1015static CURL *get_curl_handle(void) 1016{ 1017 CURL *result = curl_easy_init(); 1018 1019 if (!result) 1020 die("curl_easy_init failed"); 1021 1022 if (!curl_ssl_verify) { 1023 curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 0L); 1024 curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 0L); 1025 } else { 1026 /* Verify authenticity of the peer's certificate */ 1027 curl_easy_setopt(result, CURLOPT_SSL_VERIFYPEER, 1L); 1028 /* The name in the cert must match whom we tried to connect */ 1029 curl_easy_setopt(result, CURLOPT_SSL_VERIFYHOST, 2L); 1030 } 1031 1032 if (curl_http_version) { 1033 long opt; 1034 if (!get_curl_http_version_opt(curl_http_version, &opt)) { 1035 /* Set request use http version */ 1036 curl_easy_setopt(result, CURLOPT_HTTP_VERSION, opt); 1037 } 1038 } 1039 1040 curl_easy_setopt(result, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); 1041 curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY); 1042 1043#ifdef CURLGSSAPI_DELEGATION_FLAG 1044 if (curl_deleg) { 1045 int i; 1046 for (i = 0; i < ARRAY_SIZE(curl_deleg_levels); i++) { 1047 if (!strcmp(curl_deleg, curl_deleg_levels[i].name)) { 1048 curl_easy_setopt(result, CURLOPT_GSSAPI_DELEGATION, 1049 curl_deleg_levels[i].curl_deleg_param); 1050 break; 1051 } 1052 } 1053 if (i == ARRAY_SIZE(curl_deleg_levels)) 1054 warning("Unknown delegation method '%s': using default", 1055 curl_deleg); 1056 } 1057#endif 1058 1059 if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) && 1060 !http_schannel_check_revoke) { 1061 curl_easy_setopt(result, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_NO_REVOKE); 1062 } 1063 1064 if (http_proactive_auth != PROACTIVE_AUTH_NONE) 1065 init_curl_http_auth(result); 1066 1067 if (getenv("GIT_SSL_VERSION")) 1068 ssl_version = getenv("GIT_SSL_VERSION"); 1069 if (ssl_version && *ssl_version) { 1070 int i; 1071 for (i = 0; i < ARRAY_SIZE(sslversions); i++) { 1072 if (!strcmp(ssl_version, sslversions[i].name)) { 1073 curl_easy_setopt(result, CURLOPT_SSLVERSION, 1074 sslversions[i].ssl_version); 1075 break; 1076 } 1077 } 1078 if (i == ARRAY_SIZE(sslversions)) 1079 warning("unsupported ssl version %s: using default", 1080 ssl_version); 1081 } 1082 1083 if (getenv("GIT_SSL_CIPHER_LIST")) 1084 ssl_cipherlist = getenv("GIT_SSL_CIPHER_LIST"); 1085 if (ssl_cipherlist != NULL && *ssl_cipherlist) 1086 curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST, 1087 ssl_cipherlist); 1088 1089 if (ssl_cert) 1090 curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert); 1091 if (ssl_cert_type) 1092 curl_easy_setopt(result, CURLOPT_SSLCERTTYPE, ssl_cert_type); 1093 if (has_cert_password()) 1094 curl_easy_setopt(result, CURLOPT_KEYPASSWD, cert_auth.password); 1095 if (ssl_key) 1096 curl_easy_setopt(result, CURLOPT_SSLKEY, ssl_key); 1097 if (ssl_key_type) 1098 curl_easy_setopt(result, CURLOPT_SSLKEYTYPE, ssl_key_type); 1099 if (ssl_capath) 1100 curl_easy_setopt(result, CURLOPT_CAPATH, ssl_capath); 1101 if (ssl_pinnedkey) 1102 curl_easy_setopt(result, CURLOPT_PINNEDPUBLICKEY, ssl_pinnedkey); 1103 if (http_ssl_backend && !strcmp("schannel", http_ssl_backend) && 1104 !http_schannel_use_ssl_cainfo) { 1105 curl_easy_setopt(result, CURLOPT_CAINFO, NULL); 1106 curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, NULL); 1107 } else if (ssl_cainfo != NULL || http_proxy_ssl_ca_info != NULL) { 1108 if (ssl_cainfo) 1109 curl_easy_setopt(result, CURLOPT_CAINFO, ssl_cainfo); 1110 if (http_proxy_ssl_ca_info) 1111 curl_easy_setopt(result, CURLOPT_PROXY_CAINFO, http_proxy_ssl_ca_info); 1112 } 1113 1114 if (curl_low_speed_limit > 0 && curl_low_speed_time > 0) { 1115 curl_easy_setopt(result, CURLOPT_LOW_SPEED_LIMIT, 1116 curl_low_speed_limit); 1117 curl_easy_setopt(result, CURLOPT_LOW_SPEED_TIME, 1118 curl_low_speed_time); 1119 } 1120 1121 curl_easy_setopt(result, CURLOPT_MAXREDIRS, 20L); 1122 curl_easy_setopt(result, CURLOPT_POSTREDIR, (long)CURL_REDIR_POST_ALL); 1123 1124#ifdef GIT_CURL_HAVE_CURLOPT_PROTOCOLS_STR 1125 { 1126 struct strbuf buf = STRBUF_INIT; 1127 1128 get_curl_allowed_protocols(0, &buf); 1129 curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS_STR, buf.buf); 1130 strbuf_reset(&buf); 1131 1132 get_curl_allowed_protocols(-1, &buf); 1133 curl_easy_setopt(result, CURLOPT_PROTOCOLS_STR, buf.buf); 1134 strbuf_release(&buf); 1135 } 1136#else 1137 curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, 1138 get_curl_allowed_protocols(0, NULL)); 1139 curl_easy_setopt(result, CURLOPT_PROTOCOLS, 1140 get_curl_allowed_protocols(-1, NULL)); 1141#endif 1142 1143 if (getenv("GIT_CURL_VERBOSE")) 1144 http_trace_curl_no_data(); 1145 setup_curl_trace(result); 1146 if (getenv("GIT_TRACE_CURL_NO_DATA")) 1147 trace_curl_data = 0; 1148 if (!git_env_bool("GIT_TRACE_REDACT", 1)) 1149 trace_curl_redact = 0; 1150 1151 curl_easy_setopt(result, CURLOPT_USERAGENT, 1152 user_agent ? user_agent : git_user_agent()); 1153 1154 if (curl_ftp_no_epsv) 1155 curl_easy_setopt(result, CURLOPT_FTP_USE_EPSV, 0L); 1156 1157 if (curl_ssl_try) 1158 curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY); 1159 1160 /* 1161 * CURL also examines these variables as a fallback; but we need to query 1162 * them here in order to decide whether to prompt for missing password (cf. 1163 * init_curl_proxy_auth()). 1164 * 1165 * Unlike many other common environment variables, these are historically 1166 * lowercase only. It appears that CURL did not know this and implemented 1167 * only uppercase variants, which was later corrected to take both - with 1168 * the exception of http_proxy, which is lowercase only also in CURL. As 1169 * the lowercase versions are the historical quasi-standard, they take 1170 * precedence here, as in CURL. 1171 */ 1172 if (!curl_http_proxy) { 1173 if (http_auth.protocol && !strcmp(http_auth.protocol, "https")) { 1174 var_override(&curl_http_proxy, getenv("HTTPS_PROXY")); 1175 var_override(&curl_http_proxy, getenv("https_proxy")); 1176 } else { 1177 var_override(&curl_http_proxy, getenv("http_proxy")); 1178 } 1179 if (!curl_http_proxy) { 1180 var_override(&curl_http_proxy, getenv("ALL_PROXY")); 1181 var_override(&curl_http_proxy, getenv("all_proxy")); 1182 } 1183 } 1184 1185 if (curl_http_proxy && curl_http_proxy[0] == '\0') { 1186 /* 1187 * Handle case with the empty http.proxy value here to keep 1188 * common code clean. 1189 * NB: empty option disables proxying at all. 1190 */ 1191 curl_easy_setopt(result, CURLOPT_PROXY, ""); 1192 } else if (curl_http_proxy) { 1193 struct strbuf proxy = STRBUF_INIT; 1194 1195 if (starts_with(curl_http_proxy, "socks5h")) 1196 curl_easy_setopt(result, 1197 CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS5_HOSTNAME); 1198 else if (starts_with(curl_http_proxy, "socks5")) 1199 curl_easy_setopt(result, 1200 CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS5); 1201 else if (starts_with(curl_http_proxy, "socks4a")) 1202 curl_easy_setopt(result, 1203 CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS4A); 1204 else if (starts_with(curl_http_proxy, "socks")) 1205 curl_easy_setopt(result, 1206 CURLOPT_PROXYTYPE, (long)CURLPROXY_SOCKS4); 1207 else if (starts_with(curl_http_proxy, "https")) { 1208 curl_easy_setopt(result, CURLOPT_PROXYTYPE, (long)CURLPROXY_HTTPS); 1209 1210 if (http_proxy_ssl_cert) 1211 curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT, http_proxy_ssl_cert); 1212 1213 if (http_proxy_ssl_key) 1214 curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY, http_proxy_ssl_key); 1215 1216 if (has_proxy_cert_password()) 1217 curl_easy_setopt(result, CURLOPT_PROXY_KEYPASSWD, proxy_cert_auth.password); 1218 } 1219 if (strstr(curl_http_proxy, "://")) 1220 credential_from_url(&proxy_auth, curl_http_proxy); 1221 else { 1222 struct strbuf url = STRBUF_INIT; 1223 strbuf_addf(&url, "http://%s", curl_http_proxy); 1224 credential_from_url(&proxy_auth, url.buf); 1225 strbuf_release(&url); 1226 } 1227 1228 if (!proxy_auth.host) 1229 die("Invalid proxy URL '%s'", curl_http_proxy); 1230 1231 strbuf_addstr(&proxy, proxy_auth.host); 1232 if (proxy_auth.path) { 1233 curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW); 1234 1235 if (ver->version_num < 0x075400) 1236 die("libcurl 7.84 or later is required to support paths in proxy URLs"); 1237 1238 if (!starts_with(proxy_auth.protocol, "socks")) 1239 die("Invalid proxy URL '%s': only SOCKS proxies support paths", 1240 curl_http_proxy); 1241 1242 if (strcasecmp(proxy_auth.host, "localhost")) 1243 die("Invalid proxy URL '%s': host must be localhost if a path is present", 1244 curl_http_proxy); 1245 1246 strbuf_addch(&proxy, '/'); 1247 strbuf_add_percentencode(&proxy, proxy_auth.path, 0); 1248 } 1249 curl_easy_setopt(result, CURLOPT_PROXY, proxy.buf); 1250 strbuf_release(&proxy); 1251 1252 var_override(&curl_no_proxy, getenv("NO_PROXY")); 1253 var_override(&curl_no_proxy, getenv("no_proxy")); 1254 curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy); 1255 } 1256 init_curl_proxy_auth(result); 1257 1258 curl_easy_setopt(result, CURLOPT_TCP_KEEPALIVE, 1L); 1259 1260 if (curl_tcp_keepidle > -1) 1261 curl_easy_setopt(result, CURLOPT_TCP_KEEPIDLE, 1262 curl_tcp_keepidle); 1263 if (curl_tcp_keepintvl > -1) 1264 curl_easy_setopt(result, CURLOPT_TCP_KEEPINTVL, 1265 curl_tcp_keepintvl); 1266#ifdef GIT_CURL_HAVE_CURLOPT_TCP_KEEPCNT 1267 if (curl_tcp_keepcnt > -1) 1268 curl_easy_setopt(result, CURLOPT_TCP_KEEPCNT, curl_tcp_keepcnt); 1269#endif 1270 1271 return result; 1272} 1273 1274static void set_from_env(char **var, const char *envname) 1275{ 1276 const char *val = getenv(envname); 1277 if (val) { 1278 FREE_AND_NULL(*var); 1279 *var = xstrdup(val); 1280 } 1281} 1282 1283static void set_long_from_env(long *var, const char *envname) 1284{ 1285 const char *val = getenv(envname); 1286 if (val) { 1287 long tmp; 1288 char *endp; 1289 int saved_errno = errno; 1290 1291 errno = 0; 1292 tmp = strtol(val, &endp, 10); 1293 1294 if (errno) 1295 warning_errno(_("failed to parse %s"), envname); 1296 else if (*endp || endp == val) 1297 warning(_("failed to parse %s"), envname); 1298 else 1299 *var = tmp; 1300 1301 errno = saved_errno; 1302 } 1303} 1304 1305void http_init(struct remote *remote, const char *url, int proactive_auth) 1306{ 1307 char *normalized_url; 1308 struct urlmatch_config config = URLMATCH_CONFIG_INIT; 1309 1310 config.section = "http"; 1311 config.key = NULL; 1312 config.collect_fn = http_options; 1313 config.cascade_fn = git_default_config; 1314 config.cb = NULL; 1315 1316 http_is_verbose = 0; 1317 normalized_url = url_normalize(url, &config.url); 1318 1319 repo_config(the_repository, urlmatch_config_entry, &config); 1320 free(normalized_url); 1321 string_list_clear(&config.vars, 1); 1322 1323 if (http_ssl_backend) { 1324 const curl_ssl_backend **backends; 1325 struct strbuf buf = STRBUF_INIT; 1326 int i; 1327 1328 switch (curl_global_sslset(-1, http_ssl_backend, &backends)) { 1329 case CURLSSLSET_UNKNOWN_BACKEND: 1330 strbuf_addf(&buf, _("Unsupported SSL backend '%s'. " 1331 "Supported SSL backends:"), 1332 http_ssl_backend); 1333 for (i = 0; backends[i]; i++) 1334 strbuf_addf(&buf, "\n\t%s", backends[i]->name); 1335 die("%s", buf.buf); 1336 case CURLSSLSET_NO_BACKENDS: 1337 die(_("Could not set SSL backend to '%s': " 1338 "cURL was built without SSL backends"), 1339 http_ssl_backend); 1340 case CURLSSLSET_TOO_LATE: 1341 die(_("Could not set SSL backend to '%s': already set"), 1342 http_ssl_backend); 1343 case CURLSSLSET_OK: 1344 break; /* Okay! */ 1345 } 1346 } 1347 1348 if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) 1349 die("curl_global_init failed"); 1350 1351#ifdef GIT_CURL_HAVE_GLOBAL_TRACE 1352 { 1353 const char *comp = getenv("GIT_TRACE_CURL_COMPONENTS"); 1354 if (comp) 1355 curl_global_trace(comp); 1356 } 1357#endif 1358 1359 if (proactive_auth && http_proactive_auth == PROACTIVE_AUTH_NONE) 1360 http_proactive_auth = PROACTIVE_AUTH_IF_CREDENTIALS; 1361 1362 if (remote && remote->http_proxy) 1363 curl_http_proxy = xstrdup(remote->http_proxy); 1364 1365 if (remote) 1366 var_override(&http_proxy_authmethod, remote->http_proxy_authmethod); 1367 1368 pragma_header = curl_slist_append(http_copy_default_headers(), 1369 "Pragma: no-cache"); 1370 1371 { 1372 char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS"); 1373 if (http_max_requests) 1374 max_requests = atoi(http_max_requests); 1375 } 1376 1377 curlm = curl_multi_init(); 1378 if (!curlm) 1379 die("curl_multi_init failed"); 1380 1381 if (getenv("GIT_SSL_NO_VERIFY")) 1382 curl_ssl_verify = 0; 1383 1384 set_from_env(&ssl_cert, "GIT_SSL_CERT"); 1385 set_from_env(&ssl_cert_type, "GIT_SSL_CERT_TYPE"); 1386 set_from_env(&ssl_key, "GIT_SSL_KEY"); 1387 set_from_env(&ssl_key_type, "GIT_SSL_KEY_TYPE"); 1388 set_from_env(&ssl_capath, "GIT_SSL_CAPATH"); 1389 set_from_env(&ssl_cainfo, "GIT_SSL_CAINFO"); 1390 1391 set_from_env(&user_agent, "GIT_HTTP_USER_AGENT"); 1392 1393 set_long_from_env(&curl_low_speed_limit, "GIT_HTTP_LOW_SPEED_LIMIT"); 1394 set_long_from_env(&curl_low_speed_time, "GIT_HTTP_LOW_SPEED_TIME"); 1395 1396 if (curl_ssl_verify == -1) 1397 curl_ssl_verify = 1; 1398 1399 curl_session_count = 0; 1400 if (max_requests < 1) 1401 max_requests = DEFAULT_MAX_REQUESTS; 1402 1403 set_from_env(&http_proxy_ssl_cert, "GIT_PROXY_SSL_CERT"); 1404 set_from_env(&http_proxy_ssl_key, "GIT_PROXY_SSL_KEY"); 1405 set_from_env(&http_proxy_ssl_ca_info, "GIT_PROXY_SSL_CAINFO"); 1406 1407 if (getenv("GIT_PROXY_SSL_CERT_PASSWORD_PROTECTED")) 1408 proxy_ssl_cert_password_required = 1; 1409 1410 if (getenv("GIT_CURL_FTP_NO_EPSV")) 1411 curl_ftp_no_epsv = 1; 1412 1413 if (url) { 1414 credential_from_url(&http_auth, url); 1415 if (!ssl_cert_password_required && 1416 getenv("GIT_SSL_CERT_PASSWORD_PROTECTED") && 1417 starts_with(url, "https://")) 1418 ssl_cert_password_required = 1; 1419 } 1420 1421 set_long_from_env(&curl_tcp_keepidle, "GIT_TCP_KEEPIDLE"); 1422 set_long_from_env(&curl_tcp_keepintvl, "GIT_TCP_KEEPINTVL"); 1423 set_long_from_env(&curl_tcp_keepcnt, "GIT_TCP_KEEPCNT"); 1424 1425 curl_default = get_curl_handle(); 1426} 1427 1428void http_cleanup(void) 1429{ 1430 struct active_request_slot *slot = active_queue_head; 1431 1432 while (slot != NULL) { 1433 struct active_request_slot *next = slot->next; 1434 if (slot->curl) { 1435 xmulti_remove_handle(slot); 1436 curl_easy_cleanup(slot->curl); 1437 } 1438 free(slot); 1439 slot = next; 1440 } 1441 active_queue_head = NULL; 1442 1443 curl_easy_cleanup(curl_default); 1444 1445 curl_multi_cleanup(curlm); 1446 curl_global_cleanup(); 1447 1448 string_list_clear(&extra_http_headers, 0); 1449 1450 curl_slist_free_all(pragma_header); 1451 pragma_header = NULL; 1452 1453 curl_slist_free_all(host_resolutions); 1454 host_resolutions = NULL; 1455 1456 if (curl_http_proxy) { 1457 free((void *)curl_http_proxy); 1458 curl_http_proxy = NULL; 1459 } 1460 1461 if (proxy_auth.password) { 1462 memset(proxy_auth.password, 0, strlen(proxy_auth.password)); 1463 FREE_AND_NULL(proxy_auth.password); 1464 } 1465 1466 free((void *)curl_proxyuserpwd); 1467 curl_proxyuserpwd = NULL; 1468 1469 free((void *)http_proxy_authmethod); 1470 http_proxy_authmethod = NULL; 1471 1472 if (cert_auth.password) { 1473 memset(cert_auth.password, 0, strlen(cert_auth.password)); 1474 FREE_AND_NULL(cert_auth.password); 1475 } 1476 ssl_cert_password_required = 0; 1477 1478 if (proxy_cert_auth.password) { 1479 memset(proxy_cert_auth.password, 0, strlen(proxy_cert_auth.password)); 1480 FREE_AND_NULL(proxy_cert_auth.password); 1481 } 1482 proxy_ssl_cert_password_required = 0; 1483 1484 FREE_AND_NULL(cached_accept_language); 1485} 1486 1487struct active_request_slot *get_active_slot(void) 1488{ 1489 struct active_request_slot *slot = active_queue_head; 1490 struct active_request_slot *newslot; 1491 1492 int num_transfers; 1493 1494 /* Wait for a slot to open up if the queue is full */ 1495 while (active_requests >= max_requests) { 1496 curl_multi_perform(curlm, &num_transfers); 1497 if (num_transfers < active_requests) 1498 process_curl_messages(); 1499 } 1500 1501 while (slot != NULL && slot->in_use) 1502 slot = slot->next; 1503 1504 if (!slot) { 1505 newslot = xmalloc(sizeof(*newslot)); 1506 newslot->curl = NULL; 1507 newslot->in_use = 0; 1508 newslot->next = NULL; 1509 1510 slot = active_queue_head; 1511 if (!slot) { 1512 active_queue_head = newslot; 1513 } else { 1514 while (slot->next != NULL) 1515 slot = slot->next; 1516 slot->next = newslot; 1517 } 1518 slot = newslot; 1519 } 1520 1521 if (!slot->curl) { 1522 slot->curl = curl_easy_duphandle(curl_default); 1523 curl_session_count++; 1524 } 1525 1526 active_requests++; 1527 slot->in_use = 1; 1528 slot->results = NULL; 1529 slot->finished = NULL; 1530 slot->callback_data = NULL; 1531 slot->callback_func = NULL; 1532 1533 if (curl_cookie_file && !strcmp(curl_cookie_file, "-")) { 1534 warning(_("refusing to read cookies from http.cookiefile '-'")); 1535 FREE_AND_NULL(curl_cookie_file); 1536 } 1537 curl_easy_setopt(slot->curl, CURLOPT_COOKIEFILE, curl_cookie_file); 1538 if (curl_save_cookies && (!curl_cookie_file || !curl_cookie_file[0])) { 1539 curl_save_cookies = 0; 1540 warning(_("ignoring http.savecookies for empty http.cookiefile")); 1541 } 1542 if (curl_save_cookies) 1543 curl_easy_setopt(slot->curl, CURLOPT_COOKIEJAR, curl_cookie_file); 1544 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, pragma_header); 1545 curl_easy_setopt(slot->curl, CURLOPT_RESOLVE, host_resolutions); 1546 curl_easy_setopt(slot->curl, CURLOPT_ERRORBUFFER, curl_errorstr); 1547 curl_easy_setopt(slot->curl, CURLOPT_CUSTOMREQUEST, NULL); 1548 curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL); 1549 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL); 1550 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL); 1551 curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, -1L); 1552 curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0L); 1553 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1L); 1554 curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1L); 1555 curl_easy_setopt(slot->curl, CURLOPT_RANGE, NULL); 1556 1557 /* 1558 * Default following to off unless "ALWAYS" is configured; this gives 1559 * callers a sane starting point, and they can tweak for individual 1560 * HTTP_FOLLOW_* cases themselves. 1561 */ 1562 if (http_follow_config == HTTP_FOLLOW_ALWAYS) 1563 curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 1L); 1564 else 1565 curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 0L); 1566 1567 curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve); 1568 curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods); 1569 if (http_auth.password || http_auth.credential || curl_empty_auth_enabled()) 1570 init_curl_http_auth(slot->curl); 1571 1572 return slot; 1573} 1574 1575int start_active_slot(struct active_request_slot *slot) 1576{ 1577 CURLMcode curlm_result = curl_multi_add_handle(curlm, slot->curl); 1578 int num_transfers; 1579 1580 if (curlm_result != CURLM_OK && 1581 curlm_result != CURLM_CALL_MULTI_PERFORM) { 1582 warning("curl_multi_add_handle failed: %s", 1583 curl_multi_strerror(curlm_result)); 1584 active_requests--; 1585 slot->in_use = 0; 1586 return 0; 1587 } 1588 1589 /* 1590 * We know there must be something to do, since we just added 1591 * something. 1592 */ 1593 curl_multi_perform(curlm, &num_transfers); 1594 return 1; 1595} 1596 1597struct fill_chain { 1598 void *data; 1599 int (*fill)(void *); 1600 struct fill_chain *next; 1601}; 1602 1603static struct fill_chain *fill_cfg; 1604 1605void add_fill_function(void *data, int (*fill)(void *)) 1606{ 1607 struct fill_chain *new_fill = xmalloc(sizeof(*new_fill)); 1608 struct fill_chain **linkp = &fill_cfg; 1609 new_fill->data = data; 1610 new_fill->fill = fill; 1611 new_fill->next = NULL; 1612 while (*linkp) 1613 linkp = &(*linkp)->next; 1614 *linkp = new_fill; 1615} 1616 1617void fill_active_slots(void) 1618{ 1619 struct active_request_slot *slot = active_queue_head; 1620 1621 while (active_requests < max_requests) { 1622 struct fill_chain *fill; 1623 for (fill = fill_cfg; fill; fill = fill->next) 1624 if (fill->fill(fill->data)) 1625 break; 1626 1627 if (!fill) 1628 break; 1629 } 1630 1631 while (slot != NULL) { 1632 if (!slot->in_use && slot->curl != NULL 1633 && curl_session_count > min_curl_sessions) { 1634 curl_easy_cleanup(slot->curl); 1635 slot->curl = NULL; 1636 curl_session_count--; 1637 } 1638 slot = slot->next; 1639 } 1640} 1641 1642void step_active_slots(void) 1643{ 1644 int num_transfers; 1645 CURLMcode curlm_result; 1646 1647 do { 1648 curlm_result = curl_multi_perform(curlm, &num_transfers); 1649 } while (curlm_result == CURLM_CALL_MULTI_PERFORM); 1650 if (num_transfers < active_requests) { 1651 process_curl_messages(); 1652 fill_active_slots(); 1653 } 1654} 1655 1656void run_active_slot(struct active_request_slot *slot) 1657{ 1658 fd_set readfds; 1659 fd_set writefds; 1660 fd_set excfds; 1661 int max_fd; 1662 struct timeval select_timeout; 1663 int finished = 0; 1664 1665 slot->finished = &finished; 1666 while (!finished) { 1667 step_active_slots(); 1668 1669 if (slot->in_use) { 1670 long curl_timeout; 1671 curl_multi_timeout(curlm, &curl_timeout); 1672 if (curl_timeout == 0) { 1673 continue; 1674 } else if (curl_timeout == -1) { 1675 select_timeout.tv_sec = 0; 1676 select_timeout.tv_usec = 50000; 1677 } else { 1678 select_timeout.tv_sec = curl_timeout / 1000; 1679 select_timeout.tv_usec = (curl_timeout % 1000) * 1000; 1680 } 1681 1682 max_fd = -1; 1683 FD_ZERO(&readfds); 1684 FD_ZERO(&writefds); 1685 FD_ZERO(&excfds); 1686 curl_multi_fdset(curlm, &readfds, &writefds, &excfds, &max_fd); 1687 1688 /* 1689 * It can happen that curl_multi_timeout returns a pathologically 1690 * long timeout when curl_multi_fdset returns no file descriptors 1691 * to read. See commit message for more details. 1692 */ 1693 if (max_fd < 0 && 1694 (select_timeout.tv_sec > 0 || 1695 select_timeout.tv_usec > 50000)) { 1696 select_timeout.tv_sec = 0; 1697 select_timeout.tv_usec = 50000; 1698 } 1699 1700 select(max_fd+1, &readfds, &writefds, &excfds, &select_timeout); 1701 } 1702 } 1703 1704 /* 1705 * The value of slot->finished we set before the loop was used 1706 * to set our "finished" variable when our request completed. 1707 * 1708 * 1. The slot may not have been reused for another request 1709 * yet, in which case it still has &finished. 1710 * 1711 * 2. The slot may already be in-use to serve another request, 1712 * which can further be divided into two cases: 1713 * 1714 * (a) If call run_active_slot() hasn't been called for that 1715 * other request, slot->finished would have been cleared 1716 * by get_active_slot() and has NULL. 1717 * 1718 * (b) If the request did call run_active_slot(), then the 1719 * call would have updated slot->finished at the beginning 1720 * of this function, and with the clearing of the member 1721 * below, we would find that slot->finished is now NULL. 1722 * 1723 * In all cases, slot->finished has no useful information to 1724 * anybody at this point. Some compilers warn us for 1725 * attempting to smuggle a pointer that is about to become 1726 * invalid, i.e. &finished. We clear it here to assure them. 1727 */ 1728 slot->finished = NULL; 1729} 1730 1731static void release_active_slot(struct active_request_slot *slot) 1732{ 1733 closedown_active_slot(slot); 1734 if (slot->curl) { 1735 xmulti_remove_handle(slot); 1736 if (curl_session_count > min_curl_sessions) { 1737 curl_easy_cleanup(slot->curl); 1738 slot->curl = NULL; 1739 curl_session_count--; 1740 } 1741 } 1742 fill_active_slots(); 1743} 1744 1745void finish_all_active_slots(void) 1746{ 1747 struct active_request_slot *slot = active_queue_head; 1748 1749 while (slot != NULL) 1750 if (slot->in_use) { 1751 run_active_slot(slot); 1752 slot = active_queue_head; 1753 } else { 1754 slot = slot->next; 1755 } 1756} 1757 1758/* Helpers for modifying and creating URLs */ 1759static inline int needs_quote(int ch) 1760{ 1761 if (((ch >= 'A') && (ch <= 'Z')) 1762 || ((ch >= 'a') && (ch <= 'z')) 1763 || ((ch >= '0') && (ch <= '9')) 1764 || (ch == '/') 1765 || (ch == '-') 1766 || (ch == '.')) 1767 return 0; 1768 return 1; 1769} 1770 1771static char *quote_ref_url(const char *base, const char *ref) 1772{ 1773 struct strbuf buf = STRBUF_INIT; 1774 const char *cp; 1775 int ch; 1776 1777 end_url_with_slash(&buf, base); 1778 1779 for (cp = ref; (ch = *cp) != 0; cp++) 1780 if (needs_quote(ch)) 1781 strbuf_addf(&buf, "%%%02x", ch); 1782 else 1783 strbuf_addch(&buf, *cp); 1784 1785 return strbuf_detach(&buf, NULL); 1786} 1787 1788void append_remote_object_url(struct strbuf *buf, const char *url, 1789 const char *hex, 1790 int only_two_digit_prefix) 1791{ 1792 end_url_with_slash(buf, url); 1793 1794 strbuf_addf(buf, "objects/%.*s/", 2, hex); 1795 if (!only_two_digit_prefix) 1796 strbuf_addstr(buf, hex + 2); 1797} 1798 1799char *get_remote_object_url(const char *url, const char *hex, 1800 int only_two_digit_prefix) 1801{ 1802 struct strbuf buf = STRBUF_INIT; 1803 append_remote_object_url(&buf, url, hex, only_two_digit_prefix); 1804 return strbuf_detach(&buf, NULL); 1805} 1806 1807void normalize_curl_result(CURLcode *result, long http_code, 1808 char *errorstr, size_t errorlen) 1809{ 1810 /* 1811 * If we see a failing http code with CURLE_OK, we have turned off 1812 * FAILONERROR (to keep the server's custom error response), and should 1813 * translate the code into failure here. 1814 * 1815 * Likewise, if we see a redirect (30x code), that means we turned off 1816 * redirect-following, and we should treat the result as an error. 1817 */ 1818 if (*result == CURLE_OK && http_code >= 300) { 1819 *result = CURLE_HTTP_RETURNED_ERROR; 1820 /* 1821 * Normally curl will already have put the "reason phrase" 1822 * from the server into curl_errorstr; unfortunately without 1823 * FAILONERROR it is lost, so we can give only the numeric 1824 * status code. 1825 */ 1826 xsnprintf(errorstr, errorlen, 1827 "The requested URL returned error: %ld", 1828 http_code); 1829 } 1830} 1831 1832static int handle_curl_result(struct slot_results *results) 1833{ 1834 normalize_curl_result(&results->curl_result, results->http_code, 1835 curl_errorstr, sizeof(curl_errorstr)); 1836 1837 if (results->curl_result == CURLE_OK) { 1838 credential_approve(the_repository, &http_auth); 1839 credential_approve(the_repository, &proxy_auth); 1840 credential_approve(the_repository, &cert_auth); 1841 return HTTP_OK; 1842 } else if (results->curl_result == CURLE_SSL_CERTPROBLEM) { 1843 /* 1844 * We can't tell from here whether it's a bad path, bad 1845 * certificate, bad password, or something else wrong 1846 * with the certificate. So we reject the credential to 1847 * avoid caching or saving a bad password. 1848 */ 1849 credential_reject(the_repository, &cert_auth); 1850 return HTTP_NOAUTH; 1851 } else if (results->curl_result == CURLE_SSL_PINNEDPUBKEYNOTMATCH) { 1852 return HTTP_NOMATCHPUBLICKEY; 1853 } else if (missing_target(results)) 1854 return HTTP_MISSING_TARGET; 1855 else if (results->http_code == 401) { 1856 if ((http_auth.username && http_auth.password) ||\ 1857 (http_auth.authtype && http_auth.credential)) { 1858 if (http_auth.multistage) { 1859 credential_clear_secrets(&http_auth); 1860 return HTTP_REAUTH; 1861 } 1862 credential_reject(the_repository, &http_auth); 1863 if (always_auth_proactively()) 1864 http_proactive_auth = PROACTIVE_AUTH_NONE; 1865 return HTTP_NOAUTH; 1866 } else { 1867 http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE; 1868 if (results->auth_avail) { 1869 http_auth_methods &= results->auth_avail; 1870 http_auth_methods_restricted = 1; 1871 } 1872 return HTTP_REAUTH; 1873 } 1874 } else { 1875 if (results->http_connectcode == 407) 1876 credential_reject(the_repository, &proxy_auth); 1877 if (!curl_errorstr[0]) 1878 strlcpy(curl_errorstr, 1879 curl_easy_strerror(results->curl_result), 1880 sizeof(curl_errorstr)); 1881 return HTTP_ERROR; 1882 } 1883} 1884 1885int run_one_slot(struct active_request_slot *slot, 1886 struct slot_results *results) 1887{ 1888 slot->results = results; 1889 if (!start_active_slot(slot)) { 1890 xsnprintf(curl_errorstr, sizeof(curl_errorstr), 1891 "failed to start HTTP request"); 1892 return HTTP_START_FAILED; 1893 } 1894 1895 run_active_slot(slot); 1896 return handle_curl_result(results); 1897} 1898 1899struct curl_slist *http_copy_default_headers(void) 1900{ 1901 struct curl_slist *headers = NULL; 1902 const struct string_list_item *item; 1903 1904 for_each_string_list_item(item, &extra_http_headers) 1905 headers = curl_slist_append(headers, item->string); 1906 1907 return headers; 1908} 1909 1910static CURLcode curlinfo_strbuf(CURL *curl, CURLINFO info, struct strbuf *buf) 1911{ 1912 char *ptr; 1913 CURLcode ret; 1914 1915 strbuf_reset(buf); 1916 ret = curl_easy_getinfo(curl, info, &ptr); 1917 if (!ret && ptr) 1918 strbuf_addstr(buf, ptr); 1919 return ret; 1920} 1921 1922/* 1923 * Check for and extract a content-type parameter. "raw" 1924 * should be positioned at the start of the potential 1925 * parameter, with any whitespace already removed. 1926 * 1927 * "name" is the name of the parameter. The value is appended 1928 * to "out". 1929 */ 1930static int extract_param(const char *raw, const char *name, 1931 struct strbuf *out) 1932{ 1933 size_t len = strlen(name); 1934 1935 if (strncasecmp(raw, name, len)) 1936 return -1; 1937 raw += len; 1938 1939 if (*raw != '=') 1940 return -1; 1941 raw++; 1942 1943 while (*raw && !isspace(*raw) && *raw != ';') 1944 strbuf_addch(out, *raw++); 1945 return 0; 1946} 1947 1948/* 1949 * Extract a normalized version of the content type, with any 1950 * spaces suppressed, all letters lowercased, and no trailing ";" 1951 * or parameters. 1952 * 1953 * Note that we will silently remove even invalid whitespace. For 1954 * example, "text / plain" is specifically forbidden by RFC 2616, 1955 * but "text/plain" is the only reasonable output, and this keeps 1956 * our code simple. 1957 * 1958 * If the "charset" argument is not NULL, store the value of any 1959 * charset parameter there. 1960 * 1961 * Example: 1962 * "TEXT/PLAIN; charset=utf-8" -> "text/plain", "utf-8" 1963 * "text / plain" -> "text/plain" 1964 */ 1965static void extract_content_type(struct strbuf *raw, struct strbuf *type, 1966 struct strbuf *charset) 1967{ 1968 const char *p; 1969 1970 strbuf_reset(type); 1971 strbuf_grow(type, raw->len); 1972 for (p = raw->buf; *p; p++) { 1973 if (isspace(*p)) 1974 continue; 1975 if (*p == ';') { 1976 p++; 1977 break; 1978 } 1979 strbuf_addch(type, tolower(*p)); 1980 } 1981 1982 if (!charset) 1983 return; 1984 1985 strbuf_reset(charset); 1986 while (*p) { 1987 while (isspace(*p) || *p == ';') 1988 p++; 1989 if (!extract_param(p, "charset", charset)) 1990 return; 1991 while (*p && !isspace(*p)) 1992 p++; 1993 } 1994 1995 if (!charset->len && starts_with(type->buf, "text/")) 1996 strbuf_addstr(charset, "ISO-8859-1"); 1997} 1998 1999static void write_accept_language(struct strbuf *buf) 2000{ 2001 /* 2002 * MAX_DECIMAL_PLACES must not be larger than 3. If it is larger than 2003 * that, q-value will be smaller than 0.001, the minimum q-value the 2004 * HTTP specification allows. See 2005 * https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.1 for q-value. 2006 */ 2007 const int MAX_DECIMAL_PLACES = 3; 2008 const int MAX_LANGUAGE_TAGS = 1000; 2009 const int MAX_ACCEPT_LANGUAGE_HEADER_SIZE = 4000; 2010 char **language_tags = NULL; 2011 int num_langs = 0; 2012 const char *s = get_preferred_languages(); 2013 int i; 2014 struct strbuf tag = STRBUF_INIT; 2015 2016 /* Don't add Accept-Language header if no language is preferred. */ 2017 if (!s) 2018 return; 2019 2020 /* 2021 * Split the colon-separated string of preferred languages into 2022 * language_tags array. 2023 */ 2024 do { 2025 /* collect language tag */ 2026 for (; *s && (isalnum(*s) || *s == '_'); s++) 2027 strbuf_addch(&tag, *s == '_' ? '-' : *s); 2028 2029 /* skip .codeset, @modifier and any other unnecessary parts */ 2030 while (*s && *s != ':') 2031 s++; 2032 2033 if (tag.len) { 2034 num_langs++; 2035 REALLOC_ARRAY(language_tags, num_langs); 2036 language_tags[num_langs - 1] = strbuf_detach(&tag, NULL); 2037 if (num_langs >= MAX_LANGUAGE_TAGS - 1) /* -1 for '*' */ 2038 break; 2039 } 2040 } while (*s++); 2041 2042 /* write Accept-Language header into buf */ 2043 if (num_langs) { 2044 int last_buf_len = 0; 2045 int max_q; 2046 int decimal_places; 2047 char q_format[32]; 2048 2049 /* add '*' */ 2050 REALLOC_ARRAY(language_tags, num_langs + 1); 2051 language_tags[num_langs++] = xstrdup("*"); 2052 2053 /* compute decimal_places */ 2054 for (max_q = 1, decimal_places = 0; 2055 max_q < num_langs && decimal_places <= MAX_DECIMAL_PLACES; 2056 decimal_places++, max_q *= 10) 2057 ; 2058 2059 xsnprintf(q_format, sizeof(q_format), ";q=0.%%0%dd", decimal_places); 2060 2061 strbuf_addstr(buf, "Accept-Language: "); 2062 2063 for (i = 0; i < num_langs; i++) { 2064 if (i > 0) 2065 strbuf_addstr(buf, ", "); 2066 2067 strbuf_addstr(buf, language_tags[i]); 2068 2069 if (i > 0) 2070 strbuf_addf(buf, q_format, max_q - i); 2071 2072 if (buf->len > MAX_ACCEPT_LANGUAGE_HEADER_SIZE) { 2073 strbuf_remove(buf, last_buf_len, buf->len - last_buf_len); 2074 break; 2075 } 2076 2077 last_buf_len = buf->len; 2078 } 2079 } 2080 2081 for (i = 0; i < num_langs; i++) 2082 free(language_tags[i]); 2083 free(language_tags); 2084} 2085 2086/* 2087 * Get an Accept-Language header which indicates user's preferred languages. 2088 * 2089 * Examples: 2090 * LANGUAGE= -> "" 2091 * LANGUAGE=ko:en -> "Accept-Language: ko, en; q=0.9, *; q=0.1" 2092 * LANGUAGE=ko_KR.UTF-8:sr@latin -> "Accept-Language: ko-KR, sr; q=0.9, *; q=0.1" 2093 * LANGUAGE=ko LANG=en_US.UTF-8 -> "Accept-Language: ko, *; q=0.1" 2094 * LANGUAGE= LANG=en_US.UTF-8 -> "Accept-Language: en-US, *; q=0.1" 2095 * LANGUAGE= LANG=C -> "" 2096 */ 2097const char *http_get_accept_language_header(void) 2098{ 2099 if (!cached_accept_language) { 2100 struct strbuf buf = STRBUF_INIT; 2101 write_accept_language(&buf); 2102 if (buf.len > 0) 2103 cached_accept_language = strbuf_detach(&buf, NULL); 2104 } 2105 2106 return cached_accept_language; 2107} 2108 2109static void http_opt_request_remainder(CURL *curl, off_t pos) 2110{ 2111 char buf[128]; 2112 xsnprintf(buf, sizeof(buf), "%"PRIuMAX"-", (uintmax_t)pos); 2113 curl_easy_setopt(curl, CURLOPT_RANGE, buf); 2114} 2115 2116/* http_request() targets */ 2117#define HTTP_REQUEST_STRBUF 0 2118#define HTTP_REQUEST_FILE 1 2119 2120static int http_request(const char *url, 2121 void *result, int target, 2122 const struct http_get_options *options) 2123{ 2124 struct active_request_slot *slot; 2125 struct slot_results results; 2126 struct curl_slist *headers = http_copy_default_headers(); 2127 struct strbuf buf = STRBUF_INIT; 2128 const char *accept_language; 2129 int ret; 2130 2131 slot = get_active_slot(); 2132 curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1L); 2133 2134 if (!result) { 2135 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 1L); 2136 } else { 2137 curl_easy_setopt(slot->curl, CURLOPT_NOBODY, 0L); 2138 curl_easy_setopt(slot->curl, CURLOPT_WRITEDATA, result); 2139 2140 if (target == HTTP_REQUEST_FILE) { 2141 off_t posn = ftello(result); 2142 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, 2143 fwrite); 2144 if (posn > 0) 2145 http_opt_request_remainder(slot->curl, posn); 2146 } else 2147 curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, 2148 fwrite_buffer); 2149 } 2150 2151 curl_easy_setopt(slot->curl, CURLOPT_HEADERFUNCTION, fwrite_wwwauth); 2152 2153 accept_language = http_get_accept_language_header(); 2154 2155 if (accept_language) 2156 headers = curl_slist_append(headers, accept_language); 2157 2158 strbuf_addstr(&buf, "Pragma:"); 2159 if (options && options->no_cache) 2160 strbuf_addstr(&buf, " no-cache"); 2161 if (options && options->initial_request && 2162 http_follow_config == HTTP_FOLLOW_INITIAL) 2163 curl_easy_setopt(slot->curl, CURLOPT_FOLLOWLOCATION, 1L); 2164 2165 headers = curl_slist_append(headers, buf.buf); 2166 2167 /* Add additional headers here */ 2168 if (options && options->extra_headers) { 2169 const struct string_list_item *item; 2170 if (options && options->extra_headers) { 2171 for_each_string_list_item(item, options->extra_headers) { 2172 headers = curl_slist_append(headers, item->string); 2173 } 2174 } 2175 } 2176 2177 headers = http_append_auth_header(&http_auth, headers); 2178 2179 curl_easy_setopt(slot->curl, CURLOPT_URL, url); 2180 curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers); 2181 curl_easy_setopt(slot->curl, CURLOPT_ENCODING, ""); 2182 curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 0L); 2183 2184 ret = run_one_slot(slot, &results); 2185 2186 if (options && options->content_type) { 2187 struct strbuf raw = STRBUF_INIT; 2188 curlinfo_strbuf(slot->curl, CURLINFO_CONTENT_TYPE, &raw); 2189 extract_content_type(&raw, options->content_type, 2190 options->charset); 2191 strbuf_release(&raw); 2192 } 2193 2194 if (options && options->effective_url) 2195 curlinfo_strbuf(slot->curl, CURLINFO_EFFECTIVE_URL, 2196 options->effective_url); 2197 2198 curl_slist_free_all(headers); 2199 strbuf_release(&buf); 2200 2201 return ret; 2202} 2203 2204/* 2205 * Update the "base" url to a more appropriate value, as deduced by 2206 * redirects seen when requesting a URL starting with "url". 2207 * 2208 * The "asked" parameter is a URL that we asked curl to access, and must begin 2209 * with "base". 2210 * 2211 * The "got" parameter is the URL that curl reported to us as where we ended 2212 * up. 2213 * 2214 * Returns 1 if we updated the base url, 0 otherwise. 2215 * 2216 * Our basic strategy is to compare "base" and "asked" to find the bits 2217 * specific to our request. We then strip those bits off of "got" to yield the 2218 * new base. So for example, if our base is "http://example.com/foo.git", 2219 * and we ask for "http://example.com/foo.git/info/refs", we might end up 2220 * with "https://other.example.com/foo.git/info/refs". We would want the 2221 * new URL to become "https://other.example.com/foo.git". 2222 * 2223 * Note that this assumes a sane redirect scheme. It's entirely possible 2224 * in the example above to end up at a URL that does not even end in 2225 * "info/refs". In such a case we die. There's not much we can do, such a 2226 * scheme is unlikely to represent a real git repository, and failing to 2227 * rewrite the base opens options for malicious redirects to do funny things. 2228 */ 2229static int update_url_from_redirect(struct strbuf *base, 2230 const char *asked, 2231 const struct strbuf *got) 2232{ 2233 const char *tail; 2234 size_t new_len; 2235 2236 if (!strcmp(asked, got->buf)) 2237 return 0; 2238 2239 if (!skip_prefix(asked, base->buf, &tail)) 2240 BUG("update_url_from_redirect: %s is not a superset of %s", 2241 asked, base->buf); 2242 2243 new_len = got->len; 2244 if (!strip_suffix_mem(got->buf, &new_len, tail)) 2245 die(_("unable to update url base from redirection:\n" 2246 " asked for: %s\n" 2247 " redirect: %s"), 2248 asked, got->buf); 2249 2250 strbuf_reset(base); 2251 strbuf_add(base, got->buf, new_len); 2252 2253 return 1; 2254} 2255 2256static int http_request_reauth(const char *url, 2257 void *result, int target, 2258 struct http_get_options *options) 2259{ 2260 int i = 3; 2261 int ret; 2262 2263 if (always_auth_proactively()) 2264 credential_fill(the_repository, &http_auth, 1); 2265 2266 ret = http_request(url, result, target, options); 2267 2268 if (ret != HTTP_OK && ret != HTTP_REAUTH) 2269 return ret; 2270 2271 if (options && options->effective_url && options->base_url) { 2272 if (update_url_from_redirect(options->base_url, 2273 url, options->effective_url)) { 2274 credential_from_url(&http_auth, options->base_url->buf); 2275 url = options->effective_url->buf; 2276 } 2277 } 2278 2279 while (ret == HTTP_REAUTH && --i) { 2280 /* 2281 * The previous request may have put cruft into our output stream; we 2282 * should clear it out before making our next request. 2283 */ 2284 switch (target) { 2285 case HTTP_REQUEST_STRBUF: 2286 strbuf_reset(result); 2287 break; 2288 case HTTP_REQUEST_FILE: { 2289 FILE *f = result; 2290 if (fflush(f)) { 2291 error_errno("unable to flush a file"); 2292 return HTTP_START_FAILED; 2293 } 2294 rewind(f); 2295 if (ftruncate(fileno(f), 0) < 0) { 2296 error_errno("unable to truncate a file"); 2297 return HTTP_START_FAILED; 2298 } 2299 break; 2300 } 2301 default: 2302 BUG("Unknown http_request target"); 2303 } 2304 2305 credential_fill(the_repository, &http_auth, 1); 2306 2307 ret = http_request(url, result, target, options); 2308 } 2309 return ret; 2310} 2311 2312int http_get_strbuf(const char *url, 2313 struct strbuf *result, 2314 struct http_get_options *options) 2315{ 2316 return http_request_reauth(url, result, HTTP_REQUEST_STRBUF, options); 2317} 2318 2319/* 2320 * Downloads a URL and stores the result in the given file. 2321 * 2322 * If a previous interrupted download is detected (i.e. a previous temporary 2323 * file is still around) the download is resumed. 2324 */ 2325int http_get_file(const char *url, const char *filename, 2326 struct http_get_options *options) 2327{ 2328 int ret; 2329 struct strbuf tmpfile = STRBUF_INIT; 2330 FILE *result; 2331 2332 strbuf_addf(&tmpfile, "%s.temp", filename); 2333 result = fopen(tmpfile.buf, "a"); 2334 if (!result) { 2335 error("Unable to open local file %s", tmpfile.buf); 2336 ret = HTTP_ERROR; 2337 goto cleanup; 2338 } 2339 2340 ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options); 2341 fclose(result); 2342 2343 if (ret == HTTP_OK && finalize_object_file(the_repository, tmpfile.buf, filename)) 2344 ret = HTTP_ERROR; 2345cleanup: 2346 strbuf_release(&tmpfile); 2347 return ret; 2348} 2349 2350int http_fetch_ref(const char *base, struct ref *ref) 2351{ 2352 struct http_get_options options = {0}; 2353 char *url; 2354 struct strbuf buffer = STRBUF_INIT; 2355 int ret = -1; 2356 2357 options.no_cache = 1; 2358 2359 url = quote_ref_url(base, ref->name); 2360 if (http_get_strbuf(url, &buffer, &options) == HTTP_OK) { 2361 strbuf_rtrim(&buffer); 2362 if (buffer.len == the_hash_algo->hexsz) 2363 ret = get_oid_hex(buffer.buf, &ref->old_oid); 2364 else if (starts_with(buffer.buf, "ref: ")) { 2365 ref->symref = xstrdup(buffer.buf + 5); 2366 ret = 0; 2367 } 2368 } 2369 2370 strbuf_release(&buffer); 2371 free(url); 2372 return ret; 2373} 2374 2375/* Helpers for fetching packs */ 2376static char *fetch_pack_index(unsigned char *hash, const char *base_url) 2377{ 2378 char *url, *tmp; 2379 struct strbuf buf = STRBUF_INIT; 2380 2381 if (http_is_verbose) 2382 fprintf(stderr, "Getting index for pack %s\n", hash_to_hex(hash)); 2383 2384 end_url_with_slash(&buf, base_url); 2385 strbuf_addf(&buf, "objects/pack/pack-%s.idx", hash_to_hex(hash)); 2386 url = strbuf_detach(&buf, NULL); 2387 2388 /* 2389 * Don't put this into packs/, since it's just temporary and we don't 2390 * want to confuse it with our local .idx files. We'll generate our 2391 * own index if we choose to download the matching packfile. 2392 * 2393 * It's tempting to use xmks_tempfile() here, but it's important that 2394 * the file not exist, otherwise http_get_file() complains. So we 2395 * create a filename that should be unique, and then just register it 2396 * as a tempfile so that it will get cleaned up on exit. 2397 * 2398 * In theory we could hold on to the tempfile and delete these as soon 2399 * as we download the matching pack, but it would take a bit of 2400 * refactoring. Leaving them until the process ends is probably OK. 2401 */ 2402 tmp = xstrfmt("%s/tmp_pack_%s.idx", 2403 repo_get_object_directory(the_repository), 2404 hash_to_hex(hash)); 2405 register_tempfile(tmp); 2406 2407 if (http_get_file(url, tmp, NULL) != HTTP_OK) { 2408 error("Unable to get pack index %s", url); 2409 FREE_AND_NULL(tmp); 2410 } 2411 2412 free(url); 2413 return tmp; 2414} 2415 2416static int fetch_and_setup_pack_index(struct packed_git **packs_head, 2417 unsigned char *sha1, const char *base_url) 2418{ 2419 struct packfile_store *packs = the_repository->objects->packfiles; 2420 struct packed_git *new_pack, *p; 2421 char *tmp_idx = NULL; 2422 int ret; 2423 2424 /* 2425 * If we already have the pack locally, no need to fetch its index or 2426 * even add it to list; we already have all of its objects. 2427 */ 2428 for (p = packfile_store_get_all_packs(packs); p; p = p->next) { 2429 if (hasheq(p->hash, sha1, the_repository->hash_algo)) 2430 return 0; 2431 } 2432 2433 tmp_idx = fetch_pack_index(sha1, base_url); 2434 if (!tmp_idx) 2435 return -1; 2436 2437 new_pack = parse_pack_index(the_repository, sha1, tmp_idx); 2438 if (!new_pack) { 2439 unlink(tmp_idx); 2440 free(tmp_idx); 2441 2442 return -1; /* parse_pack_index() already issued error message */ 2443 } 2444 2445 ret = verify_pack_index(new_pack); 2446 if (!ret) 2447 close_pack_index(new_pack); 2448 free(tmp_idx); 2449 if (ret) 2450 return -1; 2451 2452 new_pack->next = *packs_head; 2453 *packs_head = new_pack; 2454 return 0; 2455} 2456 2457int http_get_info_packs(const char *base_url, struct packed_git **packs_head) 2458{ 2459 struct http_get_options options = {0}; 2460 int ret = 0; 2461 char *url; 2462 const char *data; 2463 struct strbuf buf = STRBUF_INIT; 2464 struct object_id oid; 2465 2466 end_url_with_slash(&buf, base_url); 2467 strbuf_addstr(&buf, "objects/info/packs"); 2468 url = strbuf_detach(&buf, NULL); 2469 2470 options.no_cache = 1; 2471 ret = http_get_strbuf(url, &buf, &options); 2472 if (ret != HTTP_OK) 2473 goto cleanup; 2474 2475 data = buf.buf; 2476 while (*data) { 2477 if (skip_prefix(data, "P pack-", &data) && 2478 !parse_oid_hex(data, &oid, &data) && 2479 skip_prefix(data, ".pack", &data) && 2480 (*data == '\n' || *data == '\0')) { 2481 fetch_and_setup_pack_index(packs_head, oid.hash, base_url); 2482 } else { 2483 data = strchrnul(data, '\n'); 2484 } 2485 if (*data) 2486 data++; /* skip past newline */ 2487 } 2488 2489cleanup: 2490 free(url); 2491 strbuf_release(&buf); 2492 return ret; 2493} 2494 2495void release_http_pack_request(struct http_pack_request *preq) 2496{ 2497 if (preq->packfile) { 2498 fclose(preq->packfile); 2499 preq->packfile = NULL; 2500 } 2501 preq->slot = NULL; 2502 strbuf_release(&preq->tmpfile); 2503 curl_slist_free_all(preq->headers); 2504 free(preq->url); 2505 free(preq); 2506} 2507 2508static const char *default_index_pack_args[] = 2509 {"index-pack", "--stdin", NULL}; 2510 2511int finish_http_pack_request(struct http_pack_request *preq) 2512{ 2513 struct child_process ip = CHILD_PROCESS_INIT; 2514 int tmpfile_fd; 2515 int ret = 0; 2516 2517 fclose(preq->packfile); 2518 preq->packfile = NULL; 2519 2520 tmpfile_fd = xopen(preq->tmpfile.buf, O_RDONLY); 2521 2522 ip.git_cmd = 1; 2523 ip.in = tmpfile_fd; 2524 strvec_pushv(&ip.args, preq->index_pack_args ? 2525 preq->index_pack_args : 2526 default_index_pack_args); 2527 2528 if (preq->preserve_index_pack_stdout) 2529 ip.out = 0; 2530 else 2531 ip.no_stdout = 1; 2532 2533 if (run_command(&ip)) { 2534 ret = -1; 2535 goto cleanup; 2536 } 2537 2538cleanup: 2539 close(tmpfile_fd); 2540 unlink(preq->tmpfile.buf); 2541 return ret; 2542} 2543 2544void http_install_packfile(struct packed_git *p, 2545 struct packed_git **list_to_remove_from) 2546{ 2547 struct packed_git **lst = list_to_remove_from; 2548 2549 while (*lst != p) 2550 lst = &((*lst)->next); 2551 *lst = (*lst)->next; 2552 2553 packfile_store_add_pack(the_repository->objects->packfiles, p); 2554} 2555 2556struct http_pack_request *new_http_pack_request( 2557 const unsigned char *packed_git_hash, const char *base_url) { 2558 2559 struct strbuf buf = STRBUF_INIT; 2560 2561 end_url_with_slash(&buf, base_url); 2562 strbuf_addf(&buf, "objects/pack/pack-%s.pack", 2563 hash_to_hex(packed_git_hash)); 2564 return new_direct_http_pack_request(packed_git_hash, 2565 strbuf_detach(&buf, NULL)); 2566} 2567 2568struct http_pack_request *new_direct_http_pack_request( 2569 const unsigned char *packed_git_hash, char *url) 2570{ 2571 off_t prev_posn = 0; 2572 struct http_pack_request *preq; 2573 2574 CALLOC_ARRAY(preq, 1); 2575 strbuf_init(&preq->tmpfile, 0); 2576 2577 preq->url = url; 2578 2579 odb_pack_name(the_repository, &preq->tmpfile, packed_git_hash, "pack"); 2580 strbuf_addstr(&preq->tmpfile, ".temp"); 2581 preq->packfile = fopen(preq->tmpfile.buf, "a"); 2582 if (!preq->packfile) { 2583 error("Unable to open local file %s for pack", 2584 preq->tmpfile.buf); 2585 goto abort; 2586 } 2587 2588 preq->slot = get_active_slot(); 2589 preq->headers = object_request_headers(); 2590 curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEDATA, preq->packfile); 2591 curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite); 2592 curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url); 2593 curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, preq->headers); 2594 2595 /* 2596 * If there is data present from a previous transfer attempt, 2597 * resume where it left off 2598 */ 2599 prev_posn = ftello(preq->packfile); 2600 if (prev_posn>0) { 2601 if (http_is_verbose) 2602 fprintf(stderr, 2603 "Resuming fetch of pack %s at byte %"PRIuMAX"\n", 2604 hash_to_hex(packed_git_hash), 2605 (uintmax_t)prev_posn); 2606 http_opt_request_remainder(preq->slot->curl, prev_posn); 2607 } 2608 2609 return preq; 2610 2611abort: 2612 strbuf_release(&preq->tmpfile); 2613 free(preq->url); 2614 free(preq); 2615 return NULL; 2616} 2617 2618/* Helpers for fetching objects (loose) */ 2619static size_t fwrite_sha1_file(char *ptr, size_t eltsize, size_t nmemb, 2620 void *data) 2621{ 2622 unsigned char expn[4096]; 2623 size_t size = eltsize * nmemb; 2624 int posn = 0; 2625 struct http_object_request *freq = data; 2626 struct active_request_slot *slot = freq->slot; 2627 2628 if (slot) { 2629 CURLcode c = curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, 2630 &slot->http_code); 2631 if (c != CURLE_OK) 2632 BUG("curl_easy_getinfo for HTTP code failed: %s", 2633 curl_easy_strerror(c)); 2634 if (slot->http_code >= 300) 2635 return nmemb; 2636 } 2637 2638 do { 2639 ssize_t retval = xwrite(freq->localfile, 2640 (char *) ptr + posn, size - posn); 2641 if (retval < 0) 2642 return posn / eltsize; 2643 posn += retval; 2644 } while (posn < size); 2645 2646 freq->stream.avail_in = size; 2647 freq->stream.next_in = (void *)ptr; 2648 do { 2649 freq->stream.next_out = expn; 2650 freq->stream.avail_out = sizeof(expn); 2651 freq->zret = git_inflate(&freq->stream, Z_SYNC_FLUSH); 2652 git_hash_update(&freq->c, expn, 2653 sizeof(expn) - freq->stream.avail_out); 2654 } while (freq->stream.avail_in && freq->zret == Z_OK); 2655 return nmemb; 2656} 2657 2658struct http_object_request *new_http_object_request(const char *base_url, 2659 const struct object_id *oid) 2660{ 2661 char *hex = oid_to_hex(oid); 2662 struct strbuf filename = STRBUF_INIT; 2663 struct strbuf prevfile = STRBUF_INIT; 2664 int prevlocal; 2665 char prev_buf[PREV_BUF_SIZE]; 2666 ssize_t prev_read = 0; 2667 off_t prev_posn = 0; 2668 struct http_object_request *freq; 2669 2670 CALLOC_ARRAY(freq, 1); 2671 strbuf_init(&freq->tmpfile, 0); 2672 oidcpy(&freq->oid, oid); 2673 freq->localfile = -1; 2674 2675 odb_loose_path(the_repository->objects->sources, &filename, oid); 2676 strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf); 2677 2678 strbuf_addf(&prevfile, "%s.prev", filename.buf); 2679 unlink_or_warn(prevfile.buf); 2680 rename(freq->tmpfile.buf, prevfile.buf); 2681 unlink_or_warn(freq->tmpfile.buf); 2682 strbuf_release(&filename); 2683 2684 if (freq->localfile != -1) 2685 error("fd leakage in start: %d", freq->localfile); 2686 freq->localfile = open(freq->tmpfile.buf, 2687 O_WRONLY | O_CREAT | O_EXCL, 0666); 2688 /* 2689 * This could have failed due to the "lazy directory creation"; 2690 * try to mkdir the last path component. 2691 */ 2692 if (freq->localfile < 0 && errno == ENOENT) { 2693 char *dir = strrchr(freq->tmpfile.buf, '/'); 2694 if (dir) { 2695 *dir = 0; 2696 mkdir(freq->tmpfile.buf, 0777); 2697 *dir = '/'; 2698 } 2699 freq->localfile = open(freq->tmpfile.buf, 2700 O_WRONLY | O_CREAT | O_EXCL, 0666); 2701 } 2702 2703 if (freq->localfile < 0) { 2704 error_errno("Couldn't create temporary file %s", 2705 freq->tmpfile.buf); 2706 goto abort; 2707 } 2708 2709 git_inflate_init(&freq->stream); 2710 2711 the_hash_algo->init_fn(&freq->c); 2712 2713 freq->url = get_remote_object_url(base_url, hex, 0); 2714 2715 /* 2716 * If a previous temp file is present, process what was already 2717 * fetched. 2718 */ 2719 prevlocal = open(prevfile.buf, O_RDONLY); 2720 if (prevlocal != -1) { 2721 do { 2722 prev_read = xread(prevlocal, prev_buf, PREV_BUF_SIZE); 2723 if (prev_read>0) { 2724 if (fwrite_sha1_file(prev_buf, 2725 1, 2726 prev_read, 2727 freq) == prev_read) { 2728 prev_posn += prev_read; 2729 } else { 2730 prev_read = -1; 2731 } 2732 } 2733 } while (prev_read > 0); 2734 close(prevlocal); 2735 } 2736 unlink_or_warn(prevfile.buf); 2737 strbuf_release(&prevfile); 2738 2739 /* 2740 * Reset inflate/SHA1 if there was an error reading the previous temp 2741 * file; also rewind to the beginning of the local file. 2742 */ 2743 if (prev_read == -1) { 2744 git_inflate_end(&freq->stream); 2745 memset(&freq->stream, 0, sizeof(freq->stream)); 2746 git_inflate_init(&freq->stream); 2747 the_hash_algo->init_fn(&freq->c); 2748 if (prev_posn>0) { 2749 prev_posn = 0; 2750 lseek(freq->localfile, 0, SEEK_SET); 2751 if (ftruncate(freq->localfile, 0) < 0) { 2752 error_errno("Couldn't truncate temporary file %s", 2753 freq->tmpfile.buf); 2754 goto abort; 2755 } 2756 } 2757 } 2758 2759 freq->slot = get_active_slot(); 2760 freq->headers = object_request_headers(); 2761 2762 curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEDATA, freq); 2763 curl_easy_setopt(freq->slot->curl, CURLOPT_FAILONERROR, 0L); 2764 curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file); 2765 curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr); 2766 curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url); 2767 curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, freq->headers); 2768 2769 /* 2770 * If we have successfully processed data from a previous fetch 2771 * attempt, only fetch the data we don't already have. 2772 */ 2773 if (prev_posn>0) { 2774 if (http_is_verbose) 2775 fprintf(stderr, 2776 "Resuming fetch of object %s at byte %"PRIuMAX"\n", 2777 hex, (uintmax_t)prev_posn); 2778 http_opt_request_remainder(freq->slot->curl, prev_posn); 2779 } 2780 2781 return freq; 2782 2783abort: 2784 strbuf_release(&prevfile); 2785 free(freq->url); 2786 free(freq); 2787 return NULL; 2788} 2789 2790void process_http_object_request(struct http_object_request *freq) 2791{ 2792 if (!freq->slot) 2793 return; 2794 freq->curl_result = freq->slot->curl_result; 2795 freq->http_code = freq->slot->http_code; 2796 freq->slot = NULL; 2797} 2798 2799int finish_http_object_request(struct http_object_request *freq) 2800{ 2801 struct stat st; 2802 struct strbuf filename = STRBUF_INIT; 2803 2804 close(freq->localfile); 2805 freq->localfile = -1; 2806 2807 process_http_object_request(freq); 2808 2809 if (freq->http_code == 416) { 2810 warning("requested range invalid; we may already have all the data."); 2811 } else if (freq->curl_result != CURLE_OK) { 2812 if (stat(freq->tmpfile.buf, &st) == 0) 2813 if (st.st_size == 0) 2814 unlink_or_warn(freq->tmpfile.buf); 2815 return -1; 2816 } 2817 2818 git_hash_final_oid(&freq->real_oid, &freq->c); 2819 if (freq->zret != Z_STREAM_END) { 2820 unlink_or_warn(freq->tmpfile.buf); 2821 return -1; 2822 } 2823 if (!oideq(&freq->oid, &freq->real_oid)) { 2824 unlink_or_warn(freq->tmpfile.buf); 2825 return -1; 2826 } 2827 odb_loose_path(the_repository->objects->sources, &filename, &freq->oid); 2828 freq->rename = finalize_object_file(the_repository, freq->tmpfile.buf, filename.buf); 2829 strbuf_release(&filename); 2830 2831 return freq->rename; 2832} 2833 2834void abort_http_object_request(struct http_object_request **freq_p) 2835{ 2836 struct http_object_request *freq = *freq_p; 2837 unlink_or_warn(freq->tmpfile.buf); 2838 2839 release_http_object_request(freq_p); 2840} 2841 2842void release_http_object_request(struct http_object_request **freq_p) 2843{ 2844 struct http_object_request *freq = *freq_p; 2845 if (freq->localfile != -1) { 2846 close(freq->localfile); 2847 freq->localfile = -1; 2848 } 2849 FREE_AND_NULL(freq->url); 2850 if (freq->slot) { 2851 freq->slot->callback_func = NULL; 2852 freq->slot->callback_data = NULL; 2853 release_active_slot(freq->slot); 2854 freq->slot = NULL; 2855 } 2856 curl_slist_free_all(freq->headers); 2857 strbuf_release(&freq->tmpfile); 2858 git_inflate_end(&freq->stream); 2859 2860 free(freq); 2861 *freq_p = NULL; 2862}