Imported Upstream version 2.17.1
[platform/upstream/git.git] / http.c
diff --git a/http.c b/http.c
index d2e11ec..a5bd5d6 100644 (file)
--- a/http.c
+++ b/http.c
@@ -1,5 +1,6 @@
 #include "git-compat-util.h"
 #include "http.h"
+#include "config.h"
 #include "pack.h"
 #include "sideband.h"
 #include "run-command.h"
 #include "pkt-line.h"
 #include "gettext.h"
 #include "transport.h"
+#include "packfile.h"
+#include "protocol.h"
+#include "string-list.h"
 
 static struct trace_key trace_curl = TRACE_KEY_INIT(CURL);
+static int trace_curl_data = 1;
+static struct string_list cookies_to_redact = STRING_LIST_INIT_DUP;
 #if LIBCURL_VERSION_NUM >= 0x070a08
 long int git_curl_ipresolve = CURL_IPRESOLVE_WHATEVER;
 #else
@@ -63,6 +69,9 @@ static const char *ssl_key;
 #if LIBCURL_VERSION_NUM >= 0x070908
 static const char *ssl_capath;
 #endif
+#if LIBCURL_VERSION_NUM >= 0x071304
+static const char *curl_no_proxy;
+#endif
 #if LIBCURL_VERSION_NUM >= 0x072c00
 static const char *ssl_pinnedkey;
 #endif
@@ -71,7 +80,6 @@ static long curl_low_speed_limit = -1;
 static long curl_low_speed_time = -1;
 static int curl_ftp_no_epsv;
 static const char *curl_http_proxy;
-static const char *curl_no_proxy;
 static const char *http_proxy_authmethod;
 static struct {
        const char *name;
@@ -90,7 +98,7 @@ static struct {
         * here, too
         */
 };
-#if LIBCURL_VERSION_NUM >= 0x071600
+#ifdef CURLGSSAPI_DELEGATION_FLAG
 static const char *curl_deleg;
 static struct {
        const char *name;
@@ -271,10 +279,10 @@ static int http_options(const char *var, const char *value, void *cb)
        if (!strcmp("http.sslversion", var))
                return git_config_string(&ssl_version, var, value);
        if (!strcmp("http.sslcert", var))
-               return git_config_string(&ssl_cert, var, value);
+               return git_config_pathname(&ssl_cert, var, value);
 #if LIBCURL_VERSION_NUM >= 0x070903
        if (!strcmp("http.sslkey", var))
-               return git_config_string(&ssl_key, var, value);
+               return git_config_pathname(&ssl_key, var, value);
 #endif
 #if LIBCURL_VERSION_NUM >= 0x070908
        if (!strcmp("http.sslcapath", var))
@@ -351,7 +359,7 @@ static int http_options(const char *var, const char *value, void *cb)
        }
 
        if (!strcmp("http.delegation", var)) {
-#if LIBCURL_VERSION_NUM >= 0x071600
+#ifdef CURLGSSAPI_DELEGATION_FLAG
                return git_config_string(&curl_deleg, var, value);
 #else
                warning(_("Delegation control is not supported with cURL < 7.22.0"));
@@ -572,6 +580,54 @@ static void redact_sensitive_header(struct strbuf *header)
                /* Everything else is opaque and possibly sensitive */
                strbuf_setlen(header,  sensitive_header - header->buf);
                strbuf_addstr(header, " <redacted>");
+       } else if (cookies_to_redact.nr &&
+                  skip_prefix(header->buf, "Cookie:", &sensitive_header)) {
+               struct strbuf redacted_header = STRBUF_INIT;
+               char *cookie;
+
+               while (isspace(*sensitive_header))
+                       sensitive_header++;
+
+               /*
+                * The contents of header starting from sensitive_header will
+                * subsequently be overridden, so it is fine to mutate this
+                * string (hence the assignment to "char *").
+                */
+               cookie = (char *) sensitive_header;
+
+               while (cookie) {
+                       char *equals;
+                       char *semicolon = strstr(cookie, "; ");
+                       if (semicolon)
+                               *semicolon = 0;
+                       equals = strchrnul(cookie, '=');
+                       if (!equals) {
+                               /* invalid cookie, just append and continue */
+                               strbuf_addstr(&redacted_header, cookie);
+                               continue;
+                       }
+                       *equals = 0; /* temporarily set to NUL for lookup */
+                       if (string_list_lookup(&cookies_to_redact, cookie)) {
+                               strbuf_addstr(&redacted_header, cookie);
+                               strbuf_addstr(&redacted_header, "=<redacted>");
+                       } else {
+                               *equals = '=';
+                               strbuf_addstr(&redacted_header, cookie);
+                       }
+                       if (semicolon) {
+                               /*
+                                * There are more cookies. (Or, for some
+                                * reason, the input string ends in "; ".)
+                                */
+                               strbuf_addstr(&redacted_header, "; ");
+                               cookie = semicolon + strlen("; ");
+                       } else {
+                               cookie = NULL;
+                       }
+               }
+
+               strbuf_setlen(header, sensitive_header - header->buf);
+               strbuf_addbuf(header, &redacted_header);
        }
 }
 
@@ -636,33 +692,42 @@ static int curl_trace(CURL *handle, curl_infotype type, char *data, size_t size,
        switch (type) {
        case CURLINFO_TEXT:
                trace_printf_key(&trace_curl, "== Info: %s", data);
-       default:                /* we ignore unknown types by default */
-               return 0;
-
+               break;
        case CURLINFO_HEADER_OUT:
                text = "=> Send header";
                curl_dump_header(text, (unsigned char *)data, size, DO_FILTER);
                break;
        case CURLINFO_DATA_OUT:
-               text = "=> Send data";
-               curl_dump_data(text, (unsigned char *)data, size);
+               if (trace_curl_data) {
+                       text = "=> Send data";
+                       curl_dump_data(text, (unsigned char *)data, size);
+               }
                break;
        case CURLINFO_SSL_DATA_OUT:
-               text = "=> Send SSL data";
-               curl_dump_data(text, (unsigned char *)data, size);
+               if (trace_curl_data) {
+                       text = "=> Send SSL data";
+                       curl_dump_data(text, (unsigned char *)data, size);
+               }
                break;
        case CURLINFO_HEADER_IN:
                text = "<= Recv header";
                curl_dump_header(text, (unsigned char *)data, size, NO_FILTER);
                break;
        case CURLINFO_DATA_IN:
-               text = "<= Recv data";
-               curl_dump_data(text, (unsigned char *)data, size);
+               if (trace_curl_data) {
+                       text = "<= Recv data";
+                       curl_dump_data(text, (unsigned char *)data, size);
+               }
                break;
        case CURLINFO_SSL_DATA_IN:
-               text = "<= Recv SSL data";
-               curl_dump_data(text, (unsigned char *)data, size);
+               if (trace_curl_data) {
+                       text = "<= Recv SSL data";
+                       curl_dump_data(text, (unsigned char *)data, size);
+               }
                break;
+
+       default:                /* we ignore unknown types by default */
+               return 0;
        }
        return 0;
 }
@@ -676,6 +741,7 @@ void setup_curl_trace(CURL *handle)
        curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL);
 }
 
+#ifdef CURLPROTO_HTTP
 static long get_curl_allowed_protocols(int from_user)
 {
        long allowed_protocols = 0;
@@ -691,6 +757,7 @@ static long get_curl_allowed_protocols(int from_user)
 
        return allowed_protocols;
 }
+#endif
 
 static CURL *get_curl_handle(void)
 {
@@ -716,7 +783,7 @@ static CURL *get_curl_handle(void)
        curl_easy_setopt(result, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
 #endif
 
-#if LIBCURL_VERSION_NUM >= 0x071600
+#ifdef CURLGSSAPI_DELEGATION_FLAG
        if (curl_deleg) {
                int i;
                for (i = 0; i < ARRAY_SIZE(curl_deleg_levels); i++) {
@@ -789,7 +856,7 @@ static CURL *get_curl_handle(void)
 #elif LIBCURL_VERSION_NUM >= 0x071101
        curl_easy_setopt(result, CURLOPT_POST301, 1);
 #endif
-#if LIBCURL_VERSION_NUM >= 0x071304
+#ifdef CURLPROTO_HTTP
        curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS,
                         get_curl_allowed_protocols(0));
        curl_easy_setopt(result, CURLOPT_PROTOCOLS,
@@ -801,6 +868,13 @@ static CURL *get_curl_handle(void)
        if (getenv("GIT_CURL_VERBOSE"))
                curl_easy_setopt(result, CURLOPT_VERBOSE, 1L);
        setup_curl_trace(result);
+       if (getenv("GIT_TRACE_CURL_NO_DATA"))
+               trace_curl_data = 0;
+       if (getenv("GIT_REDACT_COOKIES")) {
+               string_list_split(&cookies_to_redact,
+                                 getenv("GIT_REDACT_COOKIES"), ',', -1);
+               string_list_sort(&cookies_to_redact);
+       }
 
        curl_easy_setopt(result, CURLOPT_USERAGENT,
                user_agent ? user_agent : git_user_agent());
@@ -860,6 +934,11 @@ static CURL *get_curl_handle(void)
                        curl_easy_setopt(result,
                                CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
 #endif
+#if LIBCURL_VERSION_NUM >= 0x073400
+               else if (starts_with(curl_http_proxy, "https"))
+                       curl_easy_setopt(result,
+                               CURLOPT_PROXYTYPE, CURLPROXY_HTTPS);
+#endif
                if (strstr(curl_http_proxy, "://"))
                        credential_from_url(&proxy_auth, curl_http_proxy);
                else {
@@ -893,6 +972,21 @@ static void set_from_env(const char **var, const char *envname)
                *var = val;
 }
 
+static void protocol_http_header(void)
+{
+       if (get_protocol_version_config() > 0) {
+               struct strbuf protocol_header = STRBUF_INIT;
+
+               strbuf_addf(&protocol_header, GIT_PROTOCOL_HEADER ": version=%d",
+                           get_protocol_version_config());
+
+
+               extra_http_headers = curl_slist_append(extra_http_headers,
+                                                      protocol_header.buf);
+               strbuf_release(&protocol_header);
+       }
+}
+
 void http_init(struct remote *remote, const char *url, int proactive_auth)
 {
        char *low_speed_limit;
@@ -923,6 +1017,8 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
        if (remote)
                var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);
 
+       protocol_http_header();
+
        pragma_header = curl_slist_append(http_copy_default_headers(),
                "Pragma: no-cache");
        no_pragma_header = curl_slist_append(http_copy_default_headers(),
@@ -1026,8 +1122,7 @@ void http_cleanup(void)
 
        if (proxy_auth.password) {
                memset(proxy_auth.password, 0, strlen(proxy_auth.password));
-               free(proxy_auth.password);
-               proxy_auth.password = NULL;
+               FREE_AND_NULL(proxy_auth.password);
        }
 
        free((void *)curl_proxyuserpwd);
@@ -1038,13 +1133,11 @@ void http_cleanup(void)
 
        if (cert_auth.password != NULL) {
                memset(cert_auth.password, 0, strlen(cert_auth.password));
-               free(cert_auth.password);
-               cert_auth.password = NULL;
+               FREE_AND_NULL(cert_auth.password);
        }
        ssl_cert_password_required = 0;
 
-       free(cached_accept_language);
-       cached_accept_language = NULL;
+       FREE_AND_NULL(cached_accept_language);
 }
 
 struct active_request_slot *get_active_slot(void)
@@ -1169,14 +1262,14 @@ static struct fill_chain *fill_cfg;
 
 void add_fill_function(void *data, int (*fill)(void *))
 {
-       struct fill_chain *new = xmalloc(sizeof(*new));
+       struct fill_chain *new_fill = xmalloc(sizeof(*new_fill));
        struct fill_chain **linkp = &fill_cfg;
-       new->data = data;
-       new->fill = fill;
-       new->next = NULL;
+       new_fill->data = data;
+       new_fill->fill = fill;
+       new_fill->next = NULL;
        while (*linkp)
                linkp = &(*linkp)->next;
-       *linkp = new;
+       *linkp = new_fill;
 }
 
 void fill_active_slots(void)
@@ -1896,8 +1989,7 @@ static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
 
        if (http_get_file(url, tmp, NULL) != HTTP_OK) {
                error("Unable to get pack index %s", url);
-               free(tmp);
-               tmp = NULL;
+               FREE_AND_NULL(tmp);
        }
 
        free(url);
@@ -2006,7 +2098,6 @@ int finish_http_pack_request(struct http_pack_request *preq)
        char *tmp_idx;
        size_t len;
        struct child_process ip = CHILD_PROCESS_INIT;
-       const char *ip_argv[8];
 
        close_pack_index(p);
 
@@ -2022,13 +2113,9 @@ int finish_http_pack_request(struct http_pack_request *preq)
                die("BUG: pack tmpfile does not end in .pack.temp?");
        tmp_idx = xstrfmt("%.*s.idx.temp", (int)len, preq->tmpfile);
 
-       ip_argv[0] = "index-pack";
-       ip_argv[1] = "-o";
-       ip_argv[2] = tmp_idx;
-       ip_argv[3] = preq->tmpfile;
-       ip_argv[4] = NULL;
-
-       ip.argv = ip_argv;
+       argv_array_push(&ip.args, "index-pack");
+       argv_array_pushl(&ip.args, "-o", tmp_idx, NULL);
+       argv_array_push(&ip.args, preq->tmpfile);
        ip.git_cmd = 1;
        ip.no_stdin = 1;
        ip.no_stdout = 1;
@@ -2149,7 +2236,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
        unsigned char *sha1)
 {
        char *hex = sha1_to_hex(sha1);
-       const char *filename;
+       struct strbuf filename = STRBUF_INIT;
        char prevfile[PATH_MAX];
        int prevlocal;
        char prev_buf[PREV_BUF_SIZE];
@@ -2161,14 +2248,15 @@ struct http_object_request *new_http_object_request(const char *base_url,
        hashcpy(freq->sha1, sha1);
        freq->localfile = -1;
 
-       filename = sha1_file_name(sha1);
+       sha1_file_name(&filename, sha1);
        snprintf(freq->tmpfile, sizeof(freq->tmpfile),
-                "%s.temp", filename);
+                "%s.temp", filename.buf);
 
-       snprintf(prevfile, sizeof(prevfile), "%s.prev", filename);
+       snprintf(prevfile, sizeof(prevfile), "%s.prev", filename.buf);
        unlink_or_warn(prevfile);
        rename(freq->tmpfile, prevfile);
        unlink_or_warn(freq->tmpfile);
+       strbuf_release(&filename);
 
        if (freq->localfile != -1)
                error("fd leakage in start: %d", freq->localfile);
@@ -2283,6 +2371,7 @@ void process_http_object_request(struct http_object_request *freq)
 int finish_http_object_request(struct http_object_request *freq)
 {
        struct stat st;
+       struct strbuf filename = STRBUF_INIT;
 
        close(freq->localfile);
        freq->localfile = -1;
@@ -2308,8 +2397,10 @@ int finish_http_object_request(struct http_object_request *freq)
                unlink_or_warn(freq->tmpfile);
                return -1;
        }
-       freq->rename =
-               finalize_object_file(freq->tmpfile, sha1_file_name(freq->sha1));
+
+       sha1_file_name(&filename, freq->sha1);
+       freq->rename = finalize_object_file(freq->tmpfile, filename.buf);
+       strbuf_release(&filename);
 
        return freq->rename;
 }
@@ -2328,8 +2419,7 @@ void release_http_object_request(struct http_object_request *freq)
                freq->localfile = -1;
        }
        if (freq->url != NULL) {
-               free(freq->url);
-               freq->url = NULL;
+               FREE_AND_NULL(freq->url);
        }
        if (freq->slot != NULL) {
                freq->slot->callback_func = NULL;