@@ -37,6 +37,9 @@ static const char *receive_pack_service_url = "/git-receive-pack";
3737static const char * get_verb = "GET" ;
3838static const char * post_verb = "POST" ;
3939
40+ #define SERVER_TYPE_REMOTE "remote"
41+ #define SERVER_TYPE_PROXY "proxy"
42+
4043#define OWNING_SUBTRANSPORT (s ) ((http_subtransport *)(s)->parent.subtransport)
4144
4245#define PARSE_ERROR_GENERIC -1
@@ -97,6 +100,7 @@ typedef struct {
97100 /* Authentication */
98101 git_cred * cred ;
99102 git_cred * url_cred ;
103+ git_cred * proxy_cred ;
100104 git_vector auth_contexts ;
101105} http_subtransport ;
102106
@@ -353,10 +357,19 @@ static int on_header_value(http_parser *parser, const char *str, size_t len)
353357 return 0 ;
354358}
355359
360+ GIT_INLINE (void ) free_cred (git_cred * * cred )
361+ {
362+ if (* cred ) {
363+ git_cred_free (* cred );
364+ (* cred ) = NULL ;
365+ }
366+ }
367+
356368static int on_auth_required (
357369 git_cred * * creds ,
358370 http_parser * parser ,
359371 const char * url ,
372+ const char * type ,
360373 git_cred_acquire_cb callback ,
361374 void * callback_payload ,
362375 const char * username ,
@@ -367,17 +380,13 @@ static int on_auth_required(
367380 int ret ;
368381
369382 if (!allowed_types ) {
370- giterr_set (GITERR_NET , "remote did not prompt for authentication mechanisms" );
383+ giterr_set (GITERR_NET , "%s requested authentication but did not negotiate mechanisms" , type );
371384 t -> parse_error = PARSE_ERROR_GENERIC ;
372385 return t -> parse_error ;
373386 }
374387
375388 if (callback ) {
376- if (* creds ) {
377- (* creds )-> free (* creds );
378- * creds = NULL ;
379- }
380-
389+ free_cred (creds );
381390 ret = callback (creds , url , username , allowed_types , callback_payload );
382391
383392 if (ret == GIT_PASSTHROUGH ) {
@@ -390,7 +399,7 @@ static int on_auth_required(
390399 assert (* creds );
391400
392401 if (!((* creds )-> credtype & allowed_types )) {
393- giterr_set (GITERR_NET , "credential provider returned an invalid cred type" );
402+ giterr_set (GITERR_NET , "%s credential provider returned an invalid cred type" , type );
394403 t -> parse_error = PARSE_ERROR_GENERIC ;
395404 return t -> parse_error ;
396405 }
@@ -401,7 +410,8 @@ static int on_auth_required(
401410 }
402411 }
403412
404- giterr_set (GITERR_NET , "authentication required but no callback set" );
413+ giterr_set (GITERR_NET , "%s authentication required but no callback set" ,
414+ type );
405415 t -> parse_error = PARSE_ERROR_GENERIC ;
406416 return t -> parse_error ;
407417}
@@ -412,7 +422,7 @@ static int on_headers_complete(http_parser *parser)
412422 http_subtransport * t = ctx -> t ;
413423 http_stream * s = ctx -> s ;
414424 git_buf buf = GIT_BUF_INIT ;
415- int allowed_www_auth_types = 0 ;
425+ int allowed_proxy_auth_types = 0 , allowed_www_auth_types = 0 ;
416426
417427 /* Both parse_header_name and parse_header_value are populated
418428 * and ready for consumption. */
@@ -425,15 +435,29 @@ static int on_headers_complete(http_parser *parser)
425435 * these may be 407/401 (authentication is not complete) or a 200
426436 * (informing us that auth has completed).
427437 */
428- if (parse_authenticate_response (& t -> www_authenticate , t ,
438+ if (parse_authenticate_response (& t -> proxy_authenticate , t ,
439+ & allowed_proxy_auth_types ) < 0 ||
440+ parse_authenticate_response (& t -> www_authenticate , t ,
429441 & allowed_www_auth_types ) < 0 )
430442 return t -> parse_error = PARSE_ERROR_GENERIC ;
431443
444+ /* Check for a proxy authentication failure. */
445+ if (parser -> status_code == 407 && get_verb == s -> verb )
446+ return on_auth_required (& t -> proxy_cred ,
447+ parser ,
448+ t -> proxy .url ,
449+ SERVER_TYPE_PROXY ,
450+ t -> proxy .credentials ,
451+ t -> proxy .payload ,
452+ t -> proxy_data .user ,
453+ allowed_proxy_auth_types );
454+
432455 /* Check for an authentication failure. */
433456 if (parser -> status_code == 401 && get_verb == s -> verb )
434457 return on_auth_required (& t -> cred ,
435458 parser ,
436459 t -> owner -> url ,
460+ SERVER_TYPE_REMOTE ,
437461 t -> owner -> cred_acquire_cb ,
438462 t -> owner -> cred_acquire_payload ,
439463 t -> gitserver_data .user ,
@@ -1131,15 +1155,9 @@ static int http_close(git_smart_subtransport *subtransport)
11311155 t -> gitserver_stream = NULL ;
11321156 }
11331157
1134- if (t -> cred ) {
1135- t -> cred -> free (t -> cred );
1136- t -> cred = NULL ;
1137- }
1138-
1139- if (t -> url_cred ) {
1140- t -> url_cred -> free (t -> url_cred );
1141- t -> url_cred = NULL ;
1142- }
1158+ free_cred (& t -> cred );
1159+ free_cred (& t -> url_cred );
1160+ free_cred (& t -> proxy_cred );
11431161
11441162 git_vector_foreach (& t -> auth_contexts , i , context ) {
11451163 if (context -> free )
0 commit comments