From: Junio C Hamano Date: Fri, 10 Mar 2017 21:24:23 +0000 (-0800) Subject: Merge branch 'jk/http-auth' X-Git-Tag: v2.13.0-rc0~141 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/92718f57c2e18e69bc7ae3ed18c7157c475e17a9?ds=inline;hp=-c Merge branch 'jk/http-auth' Reduce authentication round-trip over HTTP when the server supports just a single authentication method. * jk/http-auth: http: add an "auto" mode for http.emptyauth http: restrict auth methods to what the server advertises --- 92718f57c2e18e69bc7ae3ed18c7157c475e17a9 diff --combined http.c index 90a1c0f113,d9d73a2e60..d2d6899b99 --- a/http.c +++ b/http.c @@@ -109,7 -109,7 +109,7 @@@ static int curl_save_cookies struct credential http_auth = CREDENTIAL_INIT; static int http_proactive_auth; static const char *user_agent; - static int curl_empty_auth; + static int curl_empty_auth = -1; enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL; @@@ -125,6 -125,14 +125,14 @@@ static struct credential cert_auth = CR static int ssl_cert_password_required; #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY static unsigned long http_auth_methods = CURLAUTH_ANY; + static int http_auth_methods_restricted; + /* Modes for which empty_auth cannot actually help us. */ + static unsigned long empty_auth_useless = + CURLAUTH_BASIC + #ifdef CURLAUTH_DIGEST_IE + | CURLAUTH_DIGEST_IE + #endif + | CURLAUTH_DIGEST; #endif static struct curl_slist *pragma_header; @@@ -333,7 -341,10 +341,10 @@@ static int http_options(const char *var return git_config_string(&user_agent, var, value); if (!strcmp("http.emptyauth", var)) { - curl_empty_auth = git_config_bool(var, value); + if (value && !strcmp("auto", value)) + curl_empty_auth = -1; + else + curl_empty_auth = git_config_bool(var, value); return 0; } @@@ -382,10 -393,37 +393,37 @@@ return git_default_config(var, value, cb); } + static int curl_empty_auth_enabled(void) + { + if (curl_empty_auth >= 0) + return curl_empty_auth; + + #ifndef LIBCURL_CAN_HANDLE_AUTH_ANY + /* + * Our libcurl is too old to do AUTH_ANY in the first place; + * just default to turning the feature off. + */ + #else + /* + * In the automatic case, kick in the empty-auth + * hack as long as we would potentially try some + * method more exotic than "Basic" or "Digest". + * + * But only do this when this is our second or + * subsequent request, as by then we know what + * methods are available. + */ + if (http_auth_methods_restricted && + (http_auth_methods & ~empty_auth_useless)) + return 1; + #endif + return 0; + } + static void init_curl_http_auth(CURL *result) { if (!http_auth.username || !*http_auth.username) { - if (curl_empty_auth) + if (curl_empty_auth_enabled()) curl_easy_setopt(result, CURLOPT_USERPWD, ":"); return; } @@@ -636,25 -674,11 +674,25 @@@ void setup_curl_trace(CURL *handle curl_easy_setopt(handle, CURLOPT_DEBUGDATA, NULL); } +static long get_curl_allowed_protocols(int from_user) +{ + long allowed_protocols = 0; + + if (is_transport_allowed("http", from_user)) + allowed_protocols |= CURLPROTO_HTTP; + if (is_transport_allowed("https", from_user)) + allowed_protocols |= CURLPROTO_HTTPS; + if (is_transport_allowed("ftp", from_user)) + allowed_protocols |= CURLPROTO_FTP; + if (is_transport_allowed("ftps", from_user)) + allowed_protocols |= CURLPROTO_FTPS; + + return allowed_protocols; +} static CURL *get_curl_handle(void) { CURL *result = curl_easy_init(); - long allowed_protocols = 0; if (!result) die("curl_easy_init failed"); @@@ -750,13 -774,20 +788,13 @@@ curl_easy_setopt(result, CURLOPT_POST301, 1); #endif #if LIBCURL_VERSION_NUM >= 0x071304 - if (is_transport_allowed("http")) - allowed_protocols |= CURLPROTO_HTTP; - if (is_transport_allowed("https")) - allowed_protocols |= CURLPROTO_HTTPS; - if (is_transport_allowed("ftp")) - allowed_protocols |= CURLPROTO_FTP; - if (is_transport_allowed("ftps")) - allowed_protocols |= CURLPROTO_FTPS; - curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, allowed_protocols); - curl_easy_setopt(result, CURLOPT_PROTOCOLS, allowed_protocols); + curl_easy_setopt(result, CURLOPT_REDIR_PROTOCOLS, + get_curl_allowed_protocols(0)); + curl_easy_setopt(result, CURLOPT_PROTOCOLS, + get_curl_allowed_protocols(-1)); #else - if (transport_restrict_protocols()) - warning("protocol restrictions not applied to curl redirects because\n" - "your curl version is too old (>= 7.19.4)"); + warning("protocol restrictions not applied to curl redirects because\n" + "your curl version is too old (>= 7.19.4)"); #endif if (getenv("GIT_CURL_VERBOSE")) curl_easy_setopt(result, CURLOPT_VERBOSE, 1L); @@@ -1079,7 -1110,7 +1117,7 @@@ struct active_request_slot *get_active_ #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods); #endif - if (http_auth.password || curl_empty_auth) + if (http_auth.password || curl_empty_auth_enabled()) init_curl_http_auth(slot->curl); return slot; @@@ -1347,6 -1378,10 +1385,10 @@@ static int handle_curl_result(struct sl } else { #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE; + if (results->auth_avail) { + http_auth_methods &= results->auth_avail; + http_auth_methods_restricted = 1; + } #endif return HTTP_REAUTH; }