]> git.ipfire.org Git - thirdparty/git.git/blobdiff - http.c
The sixth batch
[thirdparty/git.git] / http.c
diff --git a/http.c b/http.c
index e73b136e5897bd8fce2f874b20f316141ba59c31..752c879c1f159495e7a4c3647bd0a078f1aa29f8 100644 (file)
--- a/http.c
+++ b/http.c
@@ -128,7 +128,6 @@ static unsigned long empty_auth_useless =
        | CURLAUTH_DIGEST;
 
 static struct curl_slist *pragma_header;
-static struct curl_slist *no_pragma_header;
 static struct string_list extra_http_headers = STRING_LIST_INIT_DUP;
 
 static struct curl_slist *host_resolutions;
@@ -299,6 +298,11 @@ size_t fwrite_null(char *ptr UNUSED, size_t eltsize UNUSED, size_t nmemb,
        return nmemb;
 }
 
+static struct curl_slist *object_request_headers(void)
+{
+       return curl_slist_append(http_copy_default_headers(), "Pragma:");
+}
+
 static void closedown_active_slot(struct active_request_slot *slot)
 {
        active_requests--;
@@ -557,18 +561,34 @@ static int curl_empty_auth_enabled(void)
        return 0;
 }
 
+struct curl_slist *http_append_auth_header(const struct credential *c,
+                                          struct curl_slist *headers)
+{
+       if (c->authtype && c->credential) {
+               struct strbuf auth = STRBUF_INIT;
+               strbuf_addf(&auth, "Authorization: %s %s",
+                           c->authtype, c->credential);
+               headers = curl_slist_append(headers, auth.buf);
+               strbuf_release(&auth);
+       }
+       return headers;
+}
+
 static void init_curl_http_auth(CURL *result)
 {
-       if (!http_auth.username || !*http_auth.username) {
+       if ((!http_auth.username || !*http_auth.username) &&
+           (!http_auth.credential || !*http_auth.credential)) {
                if (curl_empty_auth_enabled())
                        curl_easy_setopt(result, CURLOPT_USERPWD, ":");
                return;
        }
 
-       credential_fill(&http_auth);
+       credential_fill(&http_auth, 1);
 
-       curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
-       curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+       if (http_auth.password) {
+               curl_easy_setopt(result, CURLOPT_USERNAME, http_auth.username);
+               curl_easy_setopt(result, CURLOPT_PASSWORD, http_auth.password);
+       }
 }
 
 /* *var must be free-able */
@@ -582,17 +602,22 @@ static void var_override(const char **var, char *value)
 
 static void set_proxyauth_name_password(CURL *result)
 {
+       if (proxy_auth.password) {
                curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
                        proxy_auth.username);
                curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
                        proxy_auth.password);
+       } else if (proxy_auth.authtype && proxy_auth.credential) {
+               curl_easy_setopt(result, CURLOPT_PROXYHEADER,
+                                http_append_auth_header(&proxy_auth, NULL));
+       }
 }
 
 static void init_curl_proxy_auth(CURL *result)
 {
        if (proxy_auth.username) {
-               if (!proxy_auth.password)
-                       credential_fill(&proxy_auth);
+               if (!proxy_auth.password && !proxy_auth.credential)
+                       credential_fill(&proxy_auth, 1);
                set_proxyauth_name_password(result);
        }
 
@@ -626,7 +651,7 @@ static int has_cert_password(void)
                cert_auth.host = xstrdup("");
                cert_auth.username = xstrdup("");
                cert_auth.path = xstrdup(ssl_cert);
-               credential_fill(&cert_auth);
+               credential_fill(&cert_auth, 0);
        }
        return 1;
 }
@@ -641,7 +666,7 @@ static int has_proxy_cert_password(void)
                proxy_cert_auth.host = xstrdup("");
                proxy_cert_auth.username = xstrdup("");
                proxy_cert_auth.path = xstrdup(http_proxy_ssl_cert);
-               credential_fill(&proxy_cert_auth);
+               credential_fill(&proxy_cert_auth, 0);
        }
        return 1;
 }
@@ -1275,8 +1300,6 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
 
        pragma_header = curl_slist_append(http_copy_default_headers(),
                "Pragma: no-cache");
-       no_pragma_header = curl_slist_append(http_copy_default_headers(),
-               "Pragma:");
 
        {
                char *http_max_requests = getenv("GIT_HTTP_MAX_REQUESTS");
@@ -1360,9 +1383,6 @@ void http_cleanup(void)
        curl_slist_free_all(pragma_header);
        pragma_header = NULL;
 
-       curl_slist_free_all(no_pragma_header);
-       no_pragma_header = NULL;
-
        curl_slist_free_all(host_resolutions);
        host_resolutions = NULL;
 
@@ -1452,6 +1472,7 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_READFUNCTION, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, NULL);
        curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDS, NULL);
+       curl_easy_setopt(slot->curl, CURLOPT_POSTFIELDSIZE, -1L);
        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
        curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
@@ -1469,7 +1490,7 @@ struct active_request_slot *get_active_slot(void)
 
        curl_easy_setopt(slot->curl, CURLOPT_IPRESOLVE, git_curl_ipresolve);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
-       if (http_auth.password || curl_empty_auth_enabled())
+       if (http_auth.password || http_auth.credential || curl_empty_auth_enabled())
                init_curl_http_auth(slot->curl);
 
        return slot;
@@ -1758,7 +1779,12 @@ static int handle_curl_result(struct slot_results *results)
        } else if (missing_target(results))
                return HTTP_MISSING_TARGET;
        else if (results->http_code == 401) {
-               if (http_auth.username && http_auth.password) {
+               if ((http_auth.username && http_auth.password) ||\
+                   (http_auth.authtype && http_auth.credential)) {
+                       if (http_auth.multistage) {
+                               credential_clear_secrets(&http_auth);
+                               return HTTP_REAUTH;
+                       }
                        credential_reject(&http_auth);
                        return HTTP_NOAUTH;
                } else {
@@ -2066,11 +2092,15 @@ static int http_request(const char *url,
        /* Add additional headers here */
        if (options && options->extra_headers) {
                const struct string_list_item *item;
-               for_each_string_list_item(item, options->extra_headers) {
-                       headers = curl_slist_append(headers, item->string);
+               if (options && options->extra_headers) {
+                       for_each_string_list_item(item, options->extra_headers) {
+                               headers = curl_slist_append(headers, item->string);
+                       }
                }
        }
 
+       headers = http_append_auth_header(&http_auth, headers);
+
        curl_easy_setopt(slot->curl, CURLOPT_URL, url);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPHEADER, headers);
        curl_easy_setopt(slot->curl, CURLOPT_ENCODING, "");
@@ -2152,6 +2182,7 @@ static int http_request_reauth(const char *url,
                               void *result, int target,
                               struct http_get_options *options)
 {
+       int i = 3;
        int ret = http_request(url, result, target, options);
 
        if (ret != HTTP_OK && ret != HTTP_REAUTH)
@@ -2165,35 +2196,35 @@ static int http_request_reauth(const char *url,
                }
        }
 
-       if (ret != HTTP_REAUTH)
-               return ret;
-
-       /*
-        * The previous request may have put cruft into our output stream; we
-        * should clear it out before making our next request.
-        */
-       switch (target) {
-       case HTTP_REQUEST_STRBUF:
-               strbuf_reset(result);
-               break;
-       case HTTP_REQUEST_FILE:
-               if (fflush(result)) {
-                       error_errno("unable to flush a file");
-                       return HTTP_START_FAILED;
-               }
-               rewind(result);
-               if (ftruncate(fileno(result), 0) < 0) {
-                       error_errno("unable to truncate a file");
-                       return HTTP_START_FAILED;
+       while (ret == HTTP_REAUTH && --i) {
+               /*
+                * The previous request may have put cruft into our output stream; we
+                * should clear it out before making our next request.
+                */
+               switch (target) {
+               case HTTP_REQUEST_STRBUF:
+                       strbuf_reset(result);
+                       break;
+               case HTTP_REQUEST_FILE:
+                       if (fflush(result)) {
+                               error_errno("unable to flush a file");
+                               return HTTP_START_FAILED;
+                       }
+                       rewind(result);
+                       if (ftruncate(fileno(result), 0) < 0) {
+                               error_errno("unable to truncate a file");
+                               return HTTP_START_FAILED;
+                       }
+                       break;
+               default:
+                       BUG("Unknown http_request target");
                }
-               break;
-       default:
-               BUG("Unknown http_request target");
-       }
 
-       credential_fill(&http_auth);
+               credential_fill(&http_auth, 1);
 
-       return http_request(url, result, target, options);
+               ret = http_request(url, result, target, options);
+       }
+       return ret;
 }
 
 int http_get_strbuf(const char *url,
@@ -2370,6 +2401,7 @@ void release_http_pack_request(struct http_pack_request *preq)
        }
        preq->slot = NULL;
        strbuf_release(&preq->tmpfile);
+       curl_slist_free_all(preq->headers);
        free(preq->url);
        free(preq);
 }
@@ -2454,11 +2486,11 @@ struct http_pack_request *new_direct_http_pack_request(
        }
 
        preq->slot = get_active_slot();
+       preq->headers = object_request_headers();
        curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEDATA, preq->packfile);
        curl_easy_setopt(preq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite);
        curl_easy_setopt(preq->slot->curl, CURLOPT_URL, preq->url);
-       curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
-               no_pragma_header);
+       curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER, preq->headers);
 
        /*
         * If there is data present from a previous transfer attempt,
@@ -2624,13 +2656,14 @@ struct http_object_request *new_http_object_request(const char *base_url,
        }
 
        freq->slot = get_active_slot();
+       freq->headers = object_request_headers();
 
        curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEDATA, freq);
        curl_easy_setopt(freq->slot->curl, CURLOPT_FAILONERROR, 0);
        curl_easy_setopt(freq->slot->curl, CURLOPT_WRITEFUNCTION, fwrite_sha1_file);
        curl_easy_setopt(freq->slot->curl, CURLOPT_ERRORBUFFER, freq->errorstr);
        curl_easy_setopt(freq->slot->curl, CURLOPT_URL, freq->url);
-       curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, no_pragma_header);
+       curl_easy_setopt(freq->slot->curl, CURLOPT_HTTPHEADER, freq->headers);
 
        /*
         * If we have successfully processed data from a previous fetch
@@ -2718,5 +2751,6 @@ void release_http_object_request(struct http_object_request *freq)
                release_active_slot(freq->slot);
                freq->slot = NULL;
        }
+       curl_slist_free_all(freq->headers);
        strbuf_release(&freq->tmpfile);
 }