@@ -62,6 +62,26 @@ static long curl_low_speed_limit = -1;
62
62
static long curl_low_speed_time = -1 ;
63
63
static int curl_ftp_no_epsv ;
64
64
static const char * curl_http_proxy ;
65
+ static const char * http_proxy_authmethod ;
66
+ static struct {
67
+ const char * name ;
68
+ long curlauth_param ;
69
+ } proxy_authmethods [] = {
70
+ { "basic" , CURLAUTH_BASIC },
71
+ { "digest" , CURLAUTH_DIGEST },
72
+ { "negotiate" , CURLAUTH_GSSNEGOTIATE },
73
+ { "ntlm" , CURLAUTH_NTLM },
74
+ #ifdef LIBCURL_CAN_HANDLE_AUTH_ANY
75
+ { "anyauth" , CURLAUTH_ANY },
76
+ #endif
77
+ /*
78
+ * CURLAUTH_DIGEST_IE has no corresponding command-line option in
79
+ * curl(1) and is not included in CURLAUTH_ANY, so we leave it out
80
+ * here, too
81
+ */
82
+ };
83
+ static struct credential proxy_auth = CREDENTIAL_INIT ;
84
+ static const char * curl_proxyuserpwd ;
65
85
static const char * curl_cookie_file ;
66
86
static int curl_save_cookies ;
67
87
struct credential http_auth = CREDENTIAL_INIT ;
@@ -159,6 +179,9 @@ static void finish_active_slot(struct active_request_slot *slot)
159
179
#else
160
180
slot -> results -> auth_avail = 0 ;
161
181
#endif
182
+
183
+ curl_easy_getinfo (slot -> curl , CURLINFO_HTTP_CONNECTCODE ,
184
+ & slot -> results -> http_connectcode );
162
185
}
163
186
164
187
/* Run callback if appropriate */
@@ -256,6 +279,9 @@ static int http_options(const char *var, const char *value, void *cb)
256
279
if (!strcmp ("http.proxy" , var ))
257
280
return git_config_string (& curl_http_proxy , var , value );
258
281
282
+ if (!strcmp ("http.proxyauthmethod" , var ))
283
+ return git_config_string (& http_proxy_authmethod , var , value );
284
+
259
285
if (!strcmp ("http.cookiefile" , var ))
260
286
return git_config_string (& curl_cookie_file , var , value );
261
287
if (!strcmp ("http.savecookies" , var )) {
@@ -304,6 +330,64 @@ static void init_curl_http_auth(CURL *result)
304
330
#endif
305
331
}
306
332
333
+ /* *var must be free-able */
334
+ static void var_override (const char * * var , char * value )
335
+ {
336
+ if (value ) {
337
+ free ((void * )* var );
338
+ * var = xstrdup (value );
339
+ }
340
+ }
341
+
342
+ static void set_proxyauth_name_password (CURL * result )
343
+ {
344
+ #if LIBCURL_VERSION_NUM >= 0x071301
345
+ curl_easy_setopt (result , CURLOPT_PROXYUSERNAME ,
346
+ proxy_auth .username );
347
+ curl_easy_setopt (result , CURLOPT_PROXYPASSWORD ,
348
+ proxy_auth .password );
349
+ #else
350
+ struct strbuf s = STRBUF_INIT ;
351
+
352
+ strbuf_addstr_urlencode (& s , proxy_auth .username , 1 );
353
+ strbuf_addch (& s , ':' );
354
+ strbuf_addstr_urlencode (& s , proxy_auth .password , 1 );
355
+ curl_proxyuserpwd = strbuf_detach (& s , NULL );
356
+ curl_easy_setopt (result , CURLOPT_PROXYUSERPWD , curl_proxyuserpwd );
357
+ #endif
358
+ }
359
+
360
+ static void init_curl_proxy_auth (CURL * result )
361
+ {
362
+ if (proxy_auth .username ) {
363
+ if (!proxy_auth .password )
364
+ credential_fill (& proxy_auth );
365
+ set_proxyauth_name_password (result );
366
+ }
367
+
368
+ var_override (& http_proxy_authmethod , getenv ("GIT_HTTP_PROXY_AUTHMETHOD" ));
369
+
370
+ #if LIBCURL_VERSION_NUM >= 0x070a07 /* CURLOPT_PROXYAUTH and CURLAUTH_ANY */
371
+ if (http_proxy_authmethod ) {
372
+ int i ;
373
+ for (i = 0 ; i < ARRAY_SIZE (proxy_authmethods ); i ++ ) {
374
+ if (!strcmp (http_proxy_authmethod , proxy_authmethods [i ].name )) {
375
+ curl_easy_setopt (result , CURLOPT_PROXYAUTH ,
376
+ proxy_authmethods [i ].curlauth_param );
377
+ break ;
378
+ }
379
+ }
380
+ if (i == ARRAY_SIZE (proxy_authmethods )) {
381
+ warning ("unsupported proxy authentication method %s: using anyauth" ,
382
+ http_proxy_authmethod );
383
+ curl_easy_setopt (result , CURLOPT_PROXYAUTH , CURLAUTH_ANY );
384
+ }
385
+ }
386
+ else
387
+ curl_easy_setopt (result , CURLOPT_PROXYAUTH , CURLAUTH_ANY );
388
+ #endif
389
+ }
390
+
307
391
static int has_cert_password (void )
308
392
{
309
393
if (ssl_cert == NULL || ssl_cert_password_required != 1 )
@@ -462,6 +546,31 @@ static CURL *get_curl_handle(void)
462
546
curl_easy_setopt (result , CURLOPT_USE_SSL , CURLUSESSL_TRY );
463
547
#endif
464
548
549
+ /*
550
+ * CURL also examines these variables as a fallback; but we need to query
551
+ * them here in order to decide whether to prompt for missing password (cf.
552
+ * init_curl_proxy_auth()).
553
+ *
554
+ * Unlike many other common environment variables, these are historically
555
+ * lowercase only. It appears that CURL did not know this and implemented
556
+ * only uppercase variants, which was later corrected to take both - with
557
+ * the exception of http_proxy, which is lowercase only also in CURL. As
558
+ * the lowercase versions are the historical quasi-standard, they take
559
+ * precedence here, as in CURL.
560
+ */
561
+ if (!curl_http_proxy ) {
562
+ if (!strcmp (http_auth .protocol , "https" )) {
563
+ var_override (& curl_http_proxy , getenv ("HTTPS_PROXY" ));
564
+ var_override (& curl_http_proxy , getenv ("https_proxy" ));
565
+ } else {
566
+ var_override (& curl_http_proxy , getenv ("http_proxy" ));
567
+ }
568
+ if (!curl_http_proxy ) {
569
+ var_override (& curl_http_proxy , getenv ("ALL_PROXY" ));
570
+ var_override (& curl_http_proxy , getenv ("all_proxy" ));
571
+ }
572
+ }
573
+
465
574
if (curl_http_proxy ) {
466
575
curl_easy_setopt (result , CURLOPT_PROXY , curl_http_proxy );
467
576
#if LIBCURL_VERSION_NUM >= 0x071800
@@ -475,10 +584,18 @@ static CURL *get_curl_handle(void)
475
584
curl_easy_setopt (result ,
476
585
CURLOPT_PROXYTYPE , CURLPROXY_SOCKS4 );
477
586
#endif
587
+ if (strstr (curl_http_proxy , "://" ))
588
+ credential_from_url (& proxy_auth , curl_http_proxy );
589
+ else {
590
+ struct strbuf url = STRBUF_INIT ;
591
+ strbuf_addf (& url , "http://%s" , curl_http_proxy );
592
+ credential_from_url (& proxy_auth , url .buf );
593
+ strbuf_release (& url );
594
+ }
595
+
596
+ curl_easy_setopt (result , CURLOPT_PROXY , proxy_auth .host );
478
597
}
479
- #if LIBCURL_VERSION_NUM >= 0x070a07
480
- curl_easy_setopt (result , CURLOPT_PROXYAUTH , CURLAUTH_ANY );
481
- #endif
598
+ init_curl_proxy_auth (result );
482
599
483
600
set_curl_keepalive (result );
484
601
@@ -519,6 +636,9 @@ void http_init(struct remote *remote, const char *url, int proactive_auth)
519
636
if (remote && remote -> http_proxy )
520
637
curl_http_proxy = xstrdup (remote -> http_proxy );
521
638
639
+ if (remote )
640
+ var_override (& http_proxy_authmethod , remote -> http_proxy_authmethod );
641
+
522
642
pragma_header = curl_slist_append (pragma_header , "Pragma: no-cache" );
523
643
no_pragma_header = curl_slist_append (no_pragma_header , "Pragma:" );
524
644
@@ -617,6 +737,18 @@ void http_cleanup(void)
617
737
curl_http_proxy = NULL ;
618
738
}
619
739
740
+ if (proxy_auth .password ) {
741
+ memset (proxy_auth .password , 0 , strlen (proxy_auth .password ));
742
+ free (proxy_auth .password );
743
+ proxy_auth .password = NULL ;
744
+ }
745
+
746
+ free ((void * )curl_proxyuserpwd );
747
+ curl_proxyuserpwd = NULL ;
748
+
749
+ free ((void * )http_proxy_authmethod );
750
+ http_proxy_authmethod = NULL ;
751
+
620
752
if (cert_auth .password != NULL ) {
621
753
memset (cert_auth .password , 0 , strlen (cert_auth .password ));
622
754
free (cert_auth .password );
@@ -946,6 +1078,8 @@ static int handle_curl_result(struct slot_results *results)
946
1078
947
1079
if (results -> curl_result == CURLE_OK ) {
948
1080
credential_approve (& http_auth );
1081
+ if (proxy_auth .password )
1082
+ credential_approve (& proxy_auth );
949
1083
return HTTP_OK ;
950
1084
} else if (missing_target (results ))
951
1085
return HTTP_MISSING_TARGET ;
@@ -960,6 +1094,8 @@ static int handle_curl_result(struct slot_results *results)
960
1094
return HTTP_REAUTH ;
961
1095
}
962
1096
} else {
1097
+ if (results -> http_connectcode == 407 )
1098
+ credential_reject (& proxy_auth );
963
1099
#if LIBCURL_VERSION_NUM >= 0x070c00
964
1100
if (!curl_errorstr [0 ])
965
1101
strlcpy (curl_errorstr ,
0 commit comments