http.c: implement the GIT_TRACE_CURL environment variable
Implement the GIT_TRACE_CURL environment variable to allow a greater degree of detail of GIT_CURL_VERBOSE, in particular the complete transport header and all the data payload exchanged. It might be useful if a particular situation could require a more thorough debugging analysis. Document the new GIT_TRACE_CURL environment variable. Helped-by: Torsten Bögershausen <tboegi@web.de> Helped-by: Ramsay Jones <ramsay@ramsayjones.plus.com> Helped-by: Junio C Hamano <gitster@pobox.com> Helped-by: Eric Sunshine <sunshine@sunshineco.com> Helped-by: Jeff King <peff@peff.net> Signed-off-by: Elia Pinto <gitter.spiros@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Elia Pinto committed
May 23, 2016 at 13:44 UTC
74c682d3c63bff8860af5caf9bd38a5413568709
3 files changed
+132
-2
Documentation/git.txt
+8
@@ -1075,6 +1075,14 @@ of clones and fetches.
1075
cloning of shallow repositories.
1076
See 'GIT_TRACE' for available trace output options.
1077
1078
+'GIT_TRACE_CURL'::
1079
+ Enables a curl full trace dump of all incoming and outgoing data,
1080
+ including descriptive information, of the git transport protocol.
1081
+ This is similar to doing curl --trace-ascii on the command line.
1082
+ This option overrides setting the GIT_CURL_VERBOSE environment
1083
+ variable.
1084
+ See 'GIT_TRACE' for available trace output options.
1085
+
1086
'GIT_LITERAL_PATHSPECS'::
1087
Setting this variable to `1` will cause Git to treat all
1088
pathspecs literally, rather than as glob patterns. For example,
http.c
+122
-2
@@ -11,6 +11,7 @@
11
#include "gettext.h"
12
#include "transport.h"
13
14
+static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
15
#if LIBCURL_VERSION_NUM >= 0x070a08
16
long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
17
#else
@@ -464,6 +465,125 @@ static void set_curl_keepalive(CURL *c)
465
}
466
#endif
467
468
+static void redact_sensitive_header(struct strbuf *header)
469
+{
470
+ const char *sensitive_header;
471
+
472
+ if (skip_prefix(header->buf, "Authorization:", &sensitive_header) ||
473
+ skip_prefix(header->buf, "Proxy-Authorization:", &sensitive_header)) {
474
+ /* The first token is the type, which is OK to log */
475
+ while (isspace(*sensitive_header))
476
+ sensitive_header++;
477
+ while (*sensitive_header && !isspace(*sensitive_header))
478
+ sensitive_header++;
479
+ /* Everything else is opaque and possibly sensitive */
480
+ strbuf_setlen(header, sensitive_header - header->buf);
481
+ strbuf_addstr(header, " <redacted>");
482
+ }
483
+}
484
+
485
+static void curl_dump_header(const char *text, unsigned char *ptr, size_t size, int hide_sensitive_header)
486
+{
487
+ struct strbuf out = STRBUF_INIT;
488
+ struct strbuf **headers, **header;
489
+
490
+ strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n",
491
+ text, (long)size, (long)size);
492
+ trace_strbuf(&trace_curl, &out);
493
+ strbuf_reset(&out);
494
+ strbuf_add(&out, ptr, size);
495
+ headers = strbuf_split_max(&out, '\n', 0);
496
+
497
+ for (header = headers; *header; header++) {
498
+ if (hide_sensitive_header)
499
+ redact_sensitive_header(*header);
500
+ strbuf_insert((*header), 0, text, strlen(text));
501
+ strbuf_insert((*header), strlen(text), ": ", 2);
502
+ strbuf_rtrim((*header));
503
+ strbuf_addch((*header), '\n');
504
+ trace_strbuf(&trace_curl, (*header));
505
+ }
506
+ strbuf_list_free(headers);
507
+ strbuf_release(&out);
508
+}
509
+
510
+static void curl_dump_data(const char *text, unsigned char *ptr, size_t size)
511
+{
512
+ size_t i;
513
+ struct strbuf out = STRBUF_INIT;
514
+ unsigned int width = 60;
515
+
516
+ strbuf_addf(&out, "%s, %10.10ld bytes (0x%8.8lx)\n",
517
+ text, (long)size, (long)size);
518
+ trace_strbuf(&trace_curl, &out);
519
+
520
+ for (i = 0; i < size; i += width) {
521
+ size_t w;
522
+
523
+ strbuf_reset(&out);
524
+ strbuf_addf(&out, "%s: ", text);
525
+ for (w = 0; (w < width) && (i + w < size); w++) {
526
+ unsigned char ch = ptr[i + w];
527
+
528
+ strbuf_addch(&out,
529
+ (ch >= 0x20) && (ch < 0x80)
530
+ ? ch : '.');
531
+ }
532
+ strbuf_addch(&out, '\n');
533
+ trace_strbuf(&trace_curl, &out);
534
+ }
535
+ strbuf_release(&out);
536
+}
537
+
538
+static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size, void *userp)
539
+{
540
+ const char *text;
541
+ enum { NO_FILTER = 0, DO_FILTER = 1 };
542
+
543
+ switch (type) {
544
+ case CURLINFO_TEXT:
545
+ trace_printf_key(&trace_curl, "== Info: %s", data);
546
+ default: /* we ignore unknown types by default */
547
+ return 0;
548
+
549
+ case CURLINFO_HEADER_OUT:
550
+ text = "=> Send header";
551
+ curl_dump_header(text, (unsigned char *)data, size, DO_FILTER);
552
+ break;
553
+ case CURLINFO_DATA_OUT:
554
+ text = "=> Send data";
555
+ curl_dump_data(text, (unsigned char *)data, size);
556
+ break;
557
+ case CURLINFO_SSL_DATA_OUT:
558
+ text = "=> Send SSL data";
559
+ curl_dump_data(text, (unsigned char *)data, size);
560
+ break;
561
+ case CURLINFO_HEADER_IN:
562
+ text = "<= Recv header";
563
+ curl_dump_header(text, (unsigned char *)data, size, NO_FILTER);
564
+ break;
565
+ case CURLINFO_DATA_IN:
566
+ text = "<= Recv data";
567
+ curl_dump_data(text, (unsigned char *)data, size);
568
+ break;
569
+ case CURLINFO_SSL_DATA_IN:
570
+ text = "<= Recv SSL data";
571
+ curl_dump_data(text, (unsigned char *)data, size);
572
+ break;
573
+ }
574
+ return 0;
575
+}
576
+
577
+void setup_curl_trace(CURL *handle)
578
+{
579
+ if (!trace_want(&trace_curl))
580
+ return;
581
+ curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
582
+ curl_easy_setopt(handle, CURLOPT_DEBUGFUNCTION, curl_trace);
583
+ curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL);
584
+}
585
+
586
+
587
static CURL *get_curl_handle(void)
588
{
589
CURL *result = curl_easy_init();
@@ -562,9 +682,9 @@ static CURL *get_curl_handle(void)
682
warning("protocol restrictions not applied to curl redirects because\n"
683
"your curl version is too old (>= 7.19.4)");
684
#endif
565
-
685
if (getenv("GIT_CURL_VERBOSE"))
567
- curl_easy_setopt(result, CURLOPT_VERBOSE, 1);
686
+ curl_easy_setopt(result, CURLOPT_VERBOSE, 1L);
687
+ setup_curl_trace(result);
688
689
curl_easy_setopt(result, CURLOPT_USERAGENT,
690
user_agent ? user_agent : git_user_agent());
http.h
+2
@@ -224,4 +224,6 @@ extern int finish_http_object_request(struct http_object_request *freq);
224
extern void abort_http_object_request(struct http_object_request *freq);
225
extern void release_http_object_request(struct http_object_request *freq);
226
227
+/* setup routine for curl_easy_setopt CURLOPT_DEBUGFUNCTION */
228
+void setup_curl_trace(CURL *handle);
229
#endif /* HTTP_H */