Skip to content

Commit 2f84df2

Browse files
committed
Merge branch 'ep/http-curl-trace'
HTTP transport gained an option to produce more detailed debugging trace. * ep/http-curl-trace: imap-send.c: introduce the GIT_TRACE_CURL enviroment variable http.c: implement the GIT_TRACE_CURL environment variable
2 parents cf4c2cf + 73e57aa commit 2f84df2

File tree

4 files changed

+133
-2
lines changed

4 files changed

+133
-2
lines changed

Documentation/git.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,14 @@ of clones and fetches.
10831083
cloning of shallow repositories.
10841084
See `GIT_TRACE` for available trace output options.
10851085

1086+
`GIT_TRACE_CURL`::
1087+
Enables a curl full trace dump of all incoming and outgoing data,
1088+
including descriptive information, of the git transport protocol.
1089+
This is similar to doing curl `--trace-ascii` on the command line.
1090+
This option overrides setting the `GIT_CURL_VERBOSE` environment
1091+
variable.
1092+
See `GIT_TRACE` for available trace output options.
1093+
10861094
`GIT_LITERAL_PATHSPECS`::
10871095
Setting this variable to `1` will cause Git to treat all
10881096
pathspecs literally, rather than as glob patterns. For example,

http.c

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "gettext.h"
1212
#include "transport.h"
1313

14+
static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
1415
#if LIBCURL_VERSION_NUM >= 0x070a08
1516
long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
1617
#else
@@ -477,6 +478,125 @@ static void set_curl_keepalive(CURL *c)
477478
}
478479
#endif
479480

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+
480600
static CURL *get_curl_handle(void)
481601
{
482602
CURL *result = curl_easy_init();
@@ -575,9 +695,9 @@ static CURL *get_curl_handle(void)
575695
warning("protocol restrictions not applied to curl redirects because\n"
576696
"your curl version is too old (>= 7.19.4)");
577697
#endif
578-
579698
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);
581701

582702
curl_easy_setopt(result, CURLOPT_USERAGENT,
583703
user_agent ? user_agent : git_user_agent());

http.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,4 +225,6 @@ extern int finish_http_object_request(struct http_object_request *freq);
225225
extern void abort_http_object_request(struct http_object_request *freq);
226226
extern void release_http_object_request(struct http_object_request *freq);
227227

228+
/* setup routine for curl_easy_setopt CURLOPT_DEBUGFUNCTION */
229+
void setup_curl_trace(CURL *handle);
228230
#endif /* HTTP_H */

imap-send.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1443,6 +1443,7 @@ static CURL *setup_curl(struct imap_server_conf *srvc)
14431443

14441444
if (0 < verbosity || getenv("GIT_CURL_VERBOSE"))
14451445
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
1446+
setup_curl_trace(curl);
14461447

14471448
return curl;
14481449
}

0 commit comments

Comments
 (0)