Skip to content

Commit 40a18fc

Browse files
peffgitster
authored andcommitted
http: add an "auto" mode for http.emptyauth
This variable needs to be specified to make some types of non-basic authentication work, but ideally this would just work out of the box for everyone. However, simply setting it to "1" by default introduces an extra round-trip for cases where it _isn't_ useful. We end up sending a bogus empty credential that the server rejects. Instead, let's introduce an automatic mode, that works like this: 1. We won't try to send the bogus credential on the first request. We'll wait to get an HTTP 401, as usual. 2. After seeing an HTTP 401, the empty-auth hack will kick in only when we know there is an auth method available that might make use of it (i.e., something besides "Basic" or "Digest"). That should make it work out of the box, without incurring any extra round-trips for people hitting Basic-only servers. This _does_ incur an extra round-trip if you really want to use "Basic" but your server advertises other methods (the emptyauth hack will kick in but fail, and then Git will actually ask for a password). The auto mode may incur an extra round-trip over setting http.emptyauth=true, because part of the emptyauth hack is to feed this blank password to curl even before we've made a single request. Helped-by: Johannes Schindelin <[email protected]> Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 840398f commit 40a18fc

File tree

1 file changed

+45
-5
lines changed

1 file changed

+45
-5
lines changed

http.c

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ static int curl_save_cookies;
109109
struct credential http_auth = CREDENTIAL_INIT;
110110
static int http_proactive_auth;
111111
static const char *user_agent;
112-
static int curl_empty_auth;
112+
static int curl_empty_auth = -1;
113113

114114
enum http_follow_config http_follow_config = HTTP_FOLLOW_INITIAL;
115115

@@ -125,6 +125,14 @@ static struct credential cert_auth = CREDENTIAL_INIT;
125125
static int ssl_cert_password_required;
126126
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
127127
static unsigned long http_auth_methods = CURLAUTH_ANY;
128+
static int http_auth_methods_restricted;
129+
/* Modes for which empty_auth cannot actually help us. */
130+
static unsigned long empty_auth_useless =
131+
CURLAUTH_BASIC
132+
#ifdef CURLAUTH_DIGEST_IE
133+
| CURLAUTH_DIGEST_IE
134+
#endif
135+
| CURLAUTH_DIGEST;
128136
#endif
129137

130138
static struct curl_slist *pragma_header;
@@ -333,7 +341,10 @@ static int http_options(const char *var, const char *value, void *cb)
333341
return git_config_string(&user_agent, var, value);
334342

335343
if (!strcmp("http.emptyauth", var)) {
336-
curl_empty_auth = git_config_bool(var, value);
344+
if (value && !strcmp("auto", value))
345+
curl_empty_auth = -1;
346+
else
347+
curl_empty_auth = git_config_bool(var, value);
337348
return 0;
338349
}
339350

@@ -382,10 +393,37 @@ static int http_options(const char *var, const char *value, void *cb)
382393
return git_default_config(var, value, cb);
383394
}
384395

396+
static int curl_empty_auth_enabled(void)
397+
{
398+
if (curl_empty_auth >= 0)
399+
return curl_empty_auth;
400+
401+
#ifndef LIBCURL_CAN_HANDLE_AUTH_ANY
402+
/*
403+
* Our libcurl is too old to do AUTH_ANY in the first place;
404+
* just default to turning the feature off.
405+
*/
406+
#else
407+
/*
408+
* In the automatic case, kick in the empty-auth
409+
* hack as long as we would potentially try some
410+
* method more exotic than "Basic" or "Digest".
411+
*
412+
* But only do this when this is our second or
413+
* subsequent request, as by then we know what
414+
* methods are available.
415+
*/
416+
if (http_auth_methods_restricted &&
417+
(http_auth_methods & ~empty_auth_useless))
418+
return 1;
419+
#endif
420+
return 0;
421+
}
422+
385423
static void init_curl_http_auth(CURL *result)
386424
{
387425
if (!http_auth.username || !*http_auth.username) {
388-
if (curl_empty_auth)
426+
if (curl_empty_auth_enabled())
389427
curl_easy_setopt(result, CURLOPT_USERPWD, ":");
390428
return;
391429
}
@@ -1072,7 +1110,7 @@ struct active_request_slot *get_active_slot(void)
10721110
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
10731111
curl_easy_setopt(slot->curl, CURLOPT_HTTPAUTH, http_auth_methods);
10741112
#endif
1075-
if (http_auth.password || curl_empty_auth)
1113+
if (http_auth.password || curl_empty_auth_enabled())
10761114
init_curl_http_auth(slot->curl);
10771115

10781116
return slot;
@@ -1340,8 +1378,10 @@ static int handle_curl_result(struct slot_results *results)
13401378
} else {
13411379
#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
13421380
http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE;
1343-
if (results->auth_avail)
1381+
if (results->auth_avail) {
13441382
http_auth_methods &= results->auth_avail;
1383+
http_auth_methods_restricted = 1;
1384+
}
13451385
#endif
13461386
return HTTP_REAUTH;
13471387
}

0 commit comments

Comments
 (0)