|
11 | 11 | #include "gettext.h" |
12 | 12 | #include "transport.h" |
13 | 13 |
|
| 14 | +static struct trace_key trace_curl = TRACE_KEY_INIT(CURL); |
14 | 15 | #if LIBCURL_VERSION_NUM >= 0x070a08 |
15 | 16 | long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER; |
16 | 17 | #else |
@@ -477,6 +478,125 @@ static void set_curl_keepalive(CURL *c) |
477 | 478 | } |
478 | 479 | #endif |
479 | 480 |
|
| 481 | +static void redact_sensitive_header(struct strbuf *header) |
| 482 | +{ |
| 483 | + const char *sensitive_header; |
| 484 | + |
| 485 | + if (skip_prefix(header->buf, "Authorization:", &sensitive_header) || |
| 486 | + skip_prefix(header->buf, "Proxy-Authorization:", &sensitive_header)) { |
| 487 | + /* The first token is the type, which is OK to log */ |
| 488 | + while (isspace(*sensitive_header)) |
| 489 | + sensitive_header++; |
| 490 | + while (*sensitive_header && !isspace(*sensitive_header)) |
| 491 | + sensitive_header++; |
| 492 | + /* Everything else is opaque and possibly sensitive */ |
| 493 | + strbuf_setlen(header, sensitive_header - header->buf); |
| 494 | + strbuf_addstr(header, " <redacted>"); |
| 495 | + } |
| 496 | +} |
| 497 | + |
| 498 | +static void curl_dump_header(const char *text, unsigned char *ptr, size_t size, int hide_sensitive_header) |
| 499 | +{ |
| 500 | + struct strbuf out = STRBUF_INIT; |
| 501 | + struct strbuf **headers, **header; |
| 502 | + |
| 503 | + strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n", |
| 504 | + text, (long)size, (long)size); |
| 505 | + trace_strbuf(&trace_curl, &out); |
| 506 | + strbuf_reset(&out); |
| 507 | + strbuf_add(&out, ptr, size); |
| 508 | + headers = strbuf_split_max(&out, '\n', 0); |
| 509 | + |
| 510 | + for (header = headers; *header; header++) { |
| 511 | + if (hide_sensitive_header) |
| 512 | + redact_sensitive_header(*header); |
| 513 | + strbuf_insert((*header), 0, text, strlen(text)); |
| 514 | + strbuf_insert((*header), strlen(text), ": ", 2); |
| 515 | + strbuf_rtrim((*header)); |
| 516 | + strbuf_addch((*header), '\n'); |
| 517 | + trace_strbuf(&trace_curl, (*header)); |
| 518 | + } |
| 519 | + strbuf_list_free(headers); |
| 520 | + strbuf_release(&out); |
| 521 | +} |
| 522 | + |
| 523 | +static void curl_dump_data(const char *text, unsigned char *ptr, size_t size) |
| 524 | +{ |
| 525 | + size_t i; |
| 526 | + struct strbuf out = STRBUF_INIT; |
| 527 | + unsigned int width = 60; |
| 528 | + |
| 529 | + strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n", |
| 530 | + text, (long)size, (long)size); |
| 531 | + trace_strbuf(&trace_curl, &out); |
| 532 | + |
| 533 | + for (i = 0; i < size; i += width) { |
| 534 | + size_t w; |
| 535 | + |
| 536 | + strbuf_reset(&out); |
| 537 | + strbuf_addf(&out, "%s: ", text); |
| 538 | + for (w = 0; (w < width) && (i + w < size); w++) { |
| 539 | + unsigned char ch = ptr[i + w]; |
| 540 | + |
| 541 | + strbuf_addch(&out, |
| 542 | + (ch >= 0x20) && (ch < 0x80) |
| 543 | + ? ch : '.'); |
| 544 | + } |
| 545 | + strbuf_addch(&out, '\n'); |
| 546 | + trace_strbuf(&trace_curl, &out); |
| 547 | + } |
| 548 | + strbuf_release(&out); |
| 549 | +} |
| 550 | + |
| 551 | +static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp) |
| 552 | +{ |
| 553 | + const char *text; |
| 554 | + enum { NO_FILTER = 0, DO_FILTER = 1 }; |
| 555 | + |
| 556 | + switch (type) { |
| 557 | + case CURLINFO_TEXT: |
| 558 | + trace_printf_key(&trace_curl, "== Info: %s", data); |
| 559 | + default: /* we ignore unknown types by default */ |
| 560 | + return 0; |
| 561 | + |
| 562 | + case CURLINFO_HEADER_OUT: |
| 563 | + text = "=> Send header"; |
| 564 | + curl_dump_header(text, (unsigned char *)data, size, DO_FILTER); |
| 565 | + break; |
| 566 | + case CURLINFO_DATA_OUT: |
| 567 | + text = "=> Send data"; |
| 568 | + curl_dump_data(text, (unsigned char *)data, size); |
| 569 | + break; |
| 570 | + case CURLINFO_SSL_DATA_OUT: |
| 571 | + text = "=> Send SSL data"; |
| 572 | + curl_dump_data(text, (unsigned char *)data, size); |
| 573 | + break; |
| 574 | + case CURLINFO_HEADER_IN: |
| 575 | + text = "<= Recv header"; |
| 576 | + curl_dump_header(text, (unsigned char *)data, size, NO_FILTER); |
| 577 | + break; |
| 578 | + case CURLINFO_DATA_IN: |
| 579 | + text = "<= Recv data"; |
| 580 | + curl_dump_data(text, (unsigned char *)data, size); |
| 581 | + break; |
| 582 | + case CURLINFO_SSL_DATA_IN: |
| 583 | + text = "<= Recv SSL data"; |
| 584 | + curl_dump_data(text, (unsigned char *)data, size); |
| 585 | + break; |
| 586 | + } |
| 587 | + return 0; |
| 588 | +} |
| 589 | + |
| 590 | +void setup_curl_trace(CURL *handle) |
| 591 | +{ |
| 592 | + if (!trace_want(&trace_curl)) |
| 593 | + return; |
| 594 | + curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L); |
| 595 | + curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, curl_trace); |
| 596 | + curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL); |
| 597 | +} |
| 598 | + |
| 599 | + |
480 | 600 | static CURL *get_curl_handle(void) |
481 | 601 | { |
482 | 602 | CURL *result = curl_easy_init(); |
@@ -575,9 +695,9 @@ static CURL *get_curl_handle(void) |
575 | 695 | warning("protocol restrictions not applied to curl redirects because\n" |
576 | 696 | "your curl version is too old (>= 7.19.4)"); |
577 | 697 | #endif |
578 | | - |
579 | 698 | if (getenv("GIT_CURL_VERBOSE")) |
580 | | - curl_easy_setopt(result, CURLOPT_VERBOSE, 1); |
| 699 | + curl_easy_setopt(result, CURLOPT_VERBOSE, 1L); |
| 700 | + setup_curl_trace(result); |
581 | 701 |
|
582 | 702 | curl_easy_setopt(result, CURLOPT_USERAGENT, |
583 | 703 | user_agent ? user_agent : git_user_agent()); |
|
0 commit comments