t: add tests for diff.renames (true/false/unset)
[gitweb.git] / http.c
diff --git a/http.c b/http.c
index 0da9e6639832a493f932e3ba332683d3d4ae73ae..dfc53c1e2554e76126459d6cb1f098facac28593 100644 (file)
--- a/http.c
+++ b/http.c
@@ -62,6 +62,26 @@ 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 *http_proxy_authmethod;
+static struct {
+       const char *name;
+       long curlauth_param;
+} proxy_authmethods[] = {
+       { "basic", CURLAUTH_BASIC },
+       { "digest", CURLAUTH_DIGEST },
+       { "negotiate", CURLAUTH_GSSNEGOTIATE },
+       { "ntlm", CURLAUTH_NTLM },
+#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
+       { "anyauth", CURLAUTH_ANY },
+#endif
+       /*
+        * CURLAUTH_DIGEST_IE has no corresponding command-line option in
+        * curl(1) and is not included in CURLAUTH_ANY, so we leave it out
+        * here, too
+        */
+};
+static struct credential proxy_auth = CREDENTIAL_INIT;
+static const char *curl_proxyuserpwd;
 static const char *curl_cookie_file;
 static int curl_save_cookies;
 struct credential http_auth = CREDENTIAL_INIT;
@@ -159,6 +179,9 @@ static void finish_active_slot(struct active_request_slot *slot)
 #else
                slot->results->auth_avail = 0;
 #endif
+
+               curl_easy_getinfo(slot->curl, CURLINFO_HTTP_CONNECTCODE,
+                       &slot->results->http_connectcode);
        }
 
        /* Run callback if appropriate */
@@ -256,6 +279,9 @@ static int http_options(const char *var, const char *value, void *cb)
        if (!strcmp("http.proxy", var))
                return git_config_string(&curl_http_proxy, var, value);
 
+       if (!strcmp("http.proxyauthmethod", var))
+               return git_config_string(&http_proxy_authmethod, var, value);
+
        if (!strcmp("http.cookiefile", var))
                return git_config_string(&curl_cookie_file, var, value);
        if (!strcmp("http.savecookies", var)) {
@@ -304,6 +330,64 @@ static void init_curl_http_auth(CURL *result)
 #endif
 }
 
+/* *var must be free-able */
+static void var_override(const char **var, char *value)
+{
+       if (value) {
+               free((void *)*var);
+               *var = xstrdup(value);
+       }
+}
+
+static void set_proxyauth_name_password(CURL *result)
+{
+#if LIBCURL_VERSION_NUM >= 0x071301
+               curl_easy_setopt(result, CURLOPT_PROXYUSERNAME,
+                       proxy_auth.username);
+               curl_easy_setopt(result, CURLOPT_PROXYPASSWORD,
+                       proxy_auth.password);
+#else
+               struct strbuf s = STRBUF_INIT;
+
+               strbuf_addstr_urlencode(&s, proxy_auth.username, 1);
+               strbuf_addch(&s, ':');
+               strbuf_addstr_urlencode(&s, proxy_auth.password, 1);
+               curl_proxyuserpwd = strbuf_detach(&s, NULL);
+               curl_easy_setopt(result, CURLOPT_PROXYUSERPWD, curl_proxyuserpwd);
+#endif
+}
+
+static void init_curl_proxy_auth(CURL *result)
+{
+       if (proxy_auth.username) {
+               if (!proxy_auth.password)
+                       credential_fill(&proxy_auth);
+               set_proxyauth_name_password(result);
+       }
+
+       var_override(&http_proxy_authmethod, getenv("GIT_HTTP_PROXY_AUTHMETHOD"));
+
+#if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */
+       if (http_proxy_authmethod) {
+               int i;
+               for (i = 0; i < ARRAY_SIZE(proxy_authmethods); i++) {
+                       if (!strcmp(http_proxy_authmethod, proxy_authmethods[i].name)) {
+                               curl_easy_setopt(result, CURLOPT_PROXYAUTH,
+                                               proxy_authmethods[i].curlauth_param);
+                               break;
+                       }
+               }
+               if (i == ARRAY_SIZE(proxy_authmethods)) {
+                       warning("unsupported proxy authentication method %s: using anyauth",
+                                       http_proxy_authmethod);
+                       curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+               }
+       }
+       else
+               curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
+#endif
+}
+
 static int has_cert_password(void)
 {
        if (ssl_cert == NULL || ssl_cert_password_required != 1)
@@ -462,6 +546,31 @@ static CURL *get_curl_handle(void)
                curl_easy_setopt(result, CURLOPT_USE_SSL, CURLUSESSL_TRY);
 #endif
 
+       /*
+        * CURL also examines these variables as a fallback; but we need to query
+        * them here in order to decide whether to prompt for missing password (cf.
+        * init_curl_proxy_auth()).
+        *
+        * Unlike many other common environment variables, these are historically
+        * lowercase only. It appears that CURL did not know this and implemented
+        * only uppercase variants, which was later corrected to take both - with
+        * the exception of http_proxy, which is lowercase only also in CURL. As
+        * the lowercase versions are the historical quasi-standard, they take
+        * precedence here, as in CURL.
+        */
+       if (!curl_http_proxy) {
+               if (!strcmp(http_auth.protocol, "https")) {
+                       var_override(&curl_http_proxy, getenv("HTTPS_PROXY"));
+                       var_override(&curl_http_proxy, getenv("https_proxy"));
+               } else {
+                       var_override(&curl_http_proxy, getenv("http_proxy"));
+               }
+               if (!curl_http_proxy) {
+                       var_override(&curl_http_proxy, getenv("ALL_PROXY"));
+                       var_override(&curl_http_proxy, getenv("all_proxy"));
+               }
+       }
+
        if (curl_http_proxy) {
                curl_easy_setopt(result, CURLOPT_PROXY, curl_http_proxy);
 #if LIBCURL_VERSION_NUM >= 0x071800
@@ -475,10 +584,18 @@ static CURL *get_curl_handle(void)
                        curl_easy_setopt(result,
                                CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
 #endif
+               if (strstr(curl_http_proxy, "://"))
+                       credential_from_url(&proxy_auth, curl_http_proxy);
+               else {
+                       struct strbuf url = STRBUF_INIT;
+                       strbuf_addf(&url, "http://%s", curl_http_proxy);
+                       credential_from_url(&proxy_auth, url.buf);
+                       strbuf_release(&url);
+               }
+
+               curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host);
        }
-#if LIBCURL_VERSION_NUM >= 0x070a07
-       curl_easy_setopt(result, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
-#endif
+       init_curl_proxy_auth(result);
 
        set_curl_keepalive(result);
 
@@ -519,6 +636,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
        if (remote && remote->http_proxy)
                curl_http_proxy = xstrdup(remote->http_proxy);
 
+       if (remote)
+               var_override(&http_proxy_authmethod, remote->http_proxy_authmethod);
+
        pragma_header = curl_slist_append(pragma_header, "Pragma: no-cache");
        no_pragma_header = curl_slist_append(no_pragma_header, "Pragma:");
 
@@ -617,6 +737,18 @@ void http_cleanup(void)
                curl_http_proxy = NULL;
        }
 
+       if (proxy_auth.password) {
+               memset(proxy_auth.password, 0, strlen(proxy_auth.password));
+               free(proxy_auth.password);
+               proxy_auth.password = NULL;
+       }
+
+       free((void *)curl_proxyuserpwd);
+       curl_proxyuserpwd = NULL;
+
+       free((void *)http_proxy_authmethod);
+       http_proxy_authmethod = NULL;
+
        if (cert_auth.password != NULL) {
                memset(cert_auth.password, 0, strlen(cert_auth.password));
                free(cert_auth.password);
@@ -946,6 +1078,8 @@ static int handle_curl_result(struct slot_results *results)
 
        if (results->curl_result == CURLE_OK) {
                credential_approve(&http_auth);
+               if (proxy_auth.password)
+                       credential_approve(&proxy_auth);
                return HTTP_OK;
        } else if (missing_target(results))
                return HTTP_MISSING_TARGET;
@@ -960,6 +1094,8 @@ static int handle_curl_result(struct slot_results *results)
                        return HTTP_REAUTH;
                }
        } else {
+               if (results->http_connectcode == 407)
+                       credential_reject(&proxy_auth);
 #if LIBCURL_VERSION_NUM >= 0x070c00
                if (!curl_errorstr[0])
                        strlcpy(curl_errorstr,