add_packed_git: convert strcpy into xsnprintf
[gitweb.git] / http.c
diff --git a/http.c b/http.c
index 007b29b8bb4cf27b619467d69a88ef5c79db282d..7b0225996189fc5e860249b484947285a1281d63 100644 (file)
--- a/http.c
+++ b/http.c
@@ -36,6 +36,21 @@ char curl_errorstr[CURL_ERROR_SIZE];
 static int curl_ssl_verify = -1;
 static int curl_ssl_try;
 static const char *ssl_cert;
+static const char *ssl_cipherlist;
+static const char *ssl_version;
+static struct {
+       const char *name;
+       long ssl_version;
+} sslversions[] = {
+       { "sslv2", CURL_SSLVERSION_SSLv2 },
+       { "sslv3", CURL_SSLVERSION_SSLv3 },
+       { "tlsv1", CURL_SSLVERSION_TLSv1 },
+#if LIBCURL_VERSION_NUM >= 0x072200
+       { "tlsv1.0", CURL_SSLVERSION_TLSv1_0 },
+       { "tlsv1.1", CURL_SSLVERSION_TLSv1_1 },
+       { "tlsv1.2", CURL_SSLVERSION_TLSv1_2 },
+#endif
+};
 #if LIBCURL_VERSION_NUM >= 0x070903
 static const char *ssl_key;
 #endif
@@ -63,6 +78,9 @@ static const char *user_agent;
 
 static struct credential cert_auth = CREDENTIAL_INIT;
 static int ssl_cert_password_required;
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+static unsigned long http_auth_methods = CURLAUTH_ANY;
+#endif
 
 static struct curl_slist *pragma_header;
 static struct curl_slist *no_pragma_header;
@@ -117,6 +135,37 @@ size_t fwrite_null(char *ptr, size_t eltsize, size_t nmemb, void *strbuf)
        return eltsize * nmemb;
 }
 
+static void closedown_active_slot(struct active_request_slot *slot)
+{
+       active_requests--;
+       slot->in_use = 0;
+}
+
+static void finish_active_slot(struct active_request_slot *slot)
+{
+       closedown_active_slot(slot);
+       curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
+
+       if (slot->finished != NULL)
+               (*slot->finished) = 1;
+
+       /* Store slot results so they can be read after the slot is reused */
+       if (slot->results != NULL) {
+               slot->results->curl_result = slot->curl_result;
+               slot->results->http_code = slot->http_code;
+#if LIBCURL_VERSION_NUM >= 0x070a08
+               curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
+                                 &slot->results->auth_avail);
+#else
+               slot->results->auth_avail = 0;
+#endif
+       }
+
+       /* Run callback if appropriate */
+       if (slot->callback_func != NULL)
+               slot->callback_func(slot->callback_data);
+}
+
 #ifdef USE_CURL_MULTI
 static void process_curl_messages(void)
 {
@@ -153,6 +202,10 @@ static int http_options(const char *var, const char *value, void *cb)
                curl_ssl_verify = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp("http.sslcipherlist", var))
+               return git_config_string(&ssl_cipherlist, var, value);
+       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);
 #if LIBCURL_VERSION_NUM >= 0x070903
@@ -327,6 +380,28 @@ static CURL *get_curl_handle(void)
        if (http_proactive_auth)
                init_curl_http_auth(result);
 
+       if (getenv("GIT_SSL_VERSION"))
+               ssl_version = getenv("GIT_SSL_VERSION");
+       if (ssl_version && *ssl_version) {
+               int i;
+               for (i = 0; i < ARRAY_SIZE(sslversions); i++) {
+                       if (!strcmp(ssl_version, sslversions[i].name)) {
+                               curl_easy_setopt(result, CURLOPT_SSLVERSION,
+                                                sslversions[i].ssl_version);
+                               break;
+                       }
+               }
+               if (i == ARRAY_SIZE(sslversions))
+                       warning("unsupported ssl version %s: using default",
+                               ssl_version);
+       }
+
+       if (getenv("GIT_SSL_CIPHER_LIST"))
+               ssl_cipherlist = getenv("GIT_SSL_CIPHER_LIST");
+       if (ssl_cipherlist != NULL && *ssl_cipherlist)
+               curl_easy_setopt(result, CURLOPT_SSL_CIPHER_LIST,
+                               ssl_cipherlist);
+
        if (ssl_cert != NULL)
                curl_easy_setopt(result, CURLOPT_SSLCERT, ssl_cert);
        if (has_cert_password())
@@ -372,8 +447,10 @@ static CURL *get_curl_handle(void)
 
        if (curl_http_proxy) {
                curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
-               curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
        }
+#if LIBCURL_VERSION_NUM >= 0x070a07
+       curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+#endif
 
        set_curl_keepalive(result);
 
@@ -586,6 +663,9 @@ struct active_request_slot *get_active_slot(void)
        curl_easy_setopt(slot->curl, CURLOPT_UPLOAD, 0);
        curl_easy_setopt(slot->curl, CURLOPT_HTTPGET, 1);
        curl_easy_setopt(slot->curl, CURLOPT_FAILONERROR, 1);
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+       curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
+#endif
        if (http_auth.password)
                init_curl_http_auth(slot->curl);
 
@@ -736,12 +816,6 @@ void run_active_slot(struct active_request_slot *slot)
 #endif
 }
 
-static void closedown_active_slot(struct active_request_slot *slot)
-{
-       active_requests--;
-       slot->in_use = 0;
-}
-
 static void release_active_slot(struct active_request_slot *slot)
 {
        closedown_active_slot(slot);
@@ -758,31 +832,6 @@ static void release_active_slot(struct active_request_slot *slot)
 #endif
 }
 
-void finish_active_slot(struct active_request_slot *slot)
-{
-       closedown_active_slot(slot);
-       curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CODE, &slot->http_code);
-
-       if (slot->finished != NULL)
-               (*slot->finished) = 1;
-
-       /* Store slot results so they can be read after the slot is reused */
-       if (slot->results != NULL) {
-               slot->results->curl_result = slot->curl_result;
-               slot->results->http_code = slot->http_code;
-#if LIBCURL_VERSION_NUM >= 0x070a08
-               curl_easy_getinfo(slot->curl, CURLINFO_HTTPAUTH_AVAIL,
-                                 &slot->results->auth_avail);
-#else
-               slot->results->auth_avail = 0;
-#endif
-       }
-
-       /* Run callback if appropriate */
-       if (slot->callback_func != NULL)
-               slot->callback_func(slot->callback_data);
-}
-
 void finish_all_active_slots(void)
 {
        struct active_request_slot *slot = active_queue_head;
@@ -845,7 +894,7 @@ char *get_remote_object_url(const char *url, const char *hex,
        return strbuf_detach(&buf, NULL);
 }
 
-int handle_curl_result(struct slot_results *results)
+static int handle_curl_result(struct slot_results *results)
 {
        /*
         * If we see a failing http code with CURLE_OK, we have turned off
@@ -876,6 +925,9 @@ int handle_curl_result(struct slot_results *results)
                        credential_reject(&http_auth);
                        return HTTP_NOAUTH;
                } else {
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+                       http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
+#endif
                        return HTTP_REAUTH;
                }
        } else {
@@ -1052,7 +1104,7 @@ static void write_accept_language(struct strbuf *buf)
                     decimal_places++, max_q *= 10)
                        ;
 
-               sprintf(q_format, ";q=0.%%0%dd", decimal_places);
+               xsnprintf(q_format, sizeof(q_format), ";q=0.%%0%dd", decimal_places);
 
                strbuf_addstr(buf, "Accept-Language: ");
 
@@ -1297,7 +1349,7 @@ static int http_get_file(const char *url, const char *filename,
        ret = http_request_reauth(url, result, HTTP_REQUEST_FILE, options);
        fclose(result);
 
-       if (ret == HTTP_OK && move_temp_to_file(tmpfile.buf, filename))
+       if (ret == HTTP_OK && finalize_object_file(tmpfile.buf, filename))
                ret = HTTP_ERROR;
 cleanup:
        strbuf_release(&tmpfile);
@@ -1363,7 +1415,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
        int ret;
 
        if (has_pack_index(sha1)) {
-               new_pack = parse_pack_index(sha1, NULL);
+               new_pack = parse_pack_index(sha1, sha1_pack_index_name(sha1));
                if (!new_pack)
                        return -1; /* parse_pack_index() already issued error message */
                goto add_pack;
@@ -1384,7 +1436,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
        ret = verify_pack_index(new_pack);
        if (!ret) {
                close_pack_index(new_pack);
-               ret = move_temp_to_file(tmp_idx, sha1_pack_index_name(sha1));
+               ret = finalize_object_file(tmp_idx, sha1_pack_index_name(sha1));
        }
        free(tmp_idx);
        if (ret)
@@ -1451,6 +1503,7 @@ void release_http_pack_request(struct http_pack_request *preq)
        }
        preq->slot = NULL;
        free(preq->url);
+       free(preq);
 }
 
 int finish_http_pack_request(struct http_pack_request *preq)
@@ -1495,8 +1548,8 @@ int finish_http_pack_request(struct http_pack_request *preq)
 
        unlink(sha1_pack_index_name(p->sha1));
 
-       if (move_temp_to_file(preq->tmpfile, sha1_pack_name(p->sha1))
-        || move_temp_to_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
+       if (finalize_object_file(preq->tmpfile, sha1_pack_name(p->sha1))
+        || finalize_object_file(tmp_idx, sha1_pack_index_name(p->sha1))) {
                free(tmp_idx);
                return -1;
        }
@@ -1548,7 +1601,7 @@ struct http_pack_request *new_http_pack_request(
                        fprintf(stderr,
                                "Resuming fetch of pack %s at byte %ld\n",
                                sha1_to_hex(target->sha1), prev_posn);
-               sprintf(range, "Range: bytes=%ld-", prev_posn);
+               xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
                preq->range_header = curl_slist_append(NULL, range);
                curl_easy_setopt(preq->slot->curl, CURLOPT_HTTPHEADER,
                        preq->range_header);
@@ -1708,7 +1761,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
                        fprintf(stderr,
                                "Resuming fetch of object %s at byte %ld\n",
                                hex, prev_posn);
-               sprintf(range, "Range: bytes=%ld-", prev_posn);
+               xsnprintf(range, sizeof(range), "Range: bytes=%ld-", prev_posn);
                range_header = curl_slist_append(range_header, range);
                curl_easy_setopt(freq->slot->curl,
                                 CURLOPT_HTTPHEADER, range_header);
@@ -1760,7 +1813,7 @@ int finish_http_object_request(struct http_object_request *freq)
                return -1;
        }
        freq->rename =
-               move_temp_to_file(freq->tmpfile, sha1_file_name(freq->sha1));
+               finalize_object_file(freq->tmpfile, sha1_file_name(freq->sha1));
 
        return freq->rename;
 }