@@ -47,7 +47,7 @@ static int curl_ftp_no_epsv;
47
47
static const char * curl_http_proxy ;
48
48
static const char * curl_cookie_file ;
49
49
static int curl_save_cookies ;
50
- static struct credential http_auth = CREDENTIAL_INIT ;
50
+ struct credential http_auth = CREDENTIAL_INIT ;
51
51
static int http_proactive_auth ;
52
52
static const char * user_agent ;
53
53
@@ -861,7 +861,6 @@ int handle_curl_result(struct slot_results *results)
861
861
credential_reject (& http_auth );
862
862
return HTTP_NOAUTH ;
863
863
} else {
864
- credential_fill (& http_auth );
865
864
return HTTP_REAUTH ;
866
865
}
867
866
} else {
@@ -875,12 +874,25 @@ int handle_curl_result(struct slot_results *results)
875
874
}
876
875
}
877
876
877
+ static CURLcode curlinfo_strbuf (CURL * curl , CURLINFO info , struct strbuf * buf )
878
+ {
879
+ char * ptr ;
880
+ CURLcode ret ;
881
+
882
+ strbuf_reset (buf );
883
+ ret = curl_easy_getinfo (curl , info , & ptr );
884
+ if (!ret && ptr )
885
+ strbuf_addstr (buf , ptr );
886
+ return ret ;
887
+ }
888
+
878
889
/* http_request() targets */
879
890
#define HTTP_REQUEST_STRBUF 0
880
891
#define HTTP_REQUEST_FILE 1
881
892
882
- static int http_request (const char * url , struct strbuf * type ,
883
- void * result , int target , int options )
893
+ static int http_request (const char * url ,
894
+ void * result , int target ,
895
+ const struct http_get_options * options )
884
896
{
885
897
struct active_request_slot * slot ;
886
898
struct slot_results results ;
@@ -913,9 +925,9 @@ static int http_request(const char *url, struct strbuf *type,
913
925
}
914
926
915
927
strbuf_addstr (& buf , "Pragma:" );
916
- if (options & HTTP_NO_CACHE )
928
+ if (options && options -> no_cache )
917
929
strbuf_addstr (& buf , " no-cache" );
918
- if (options & HTTP_KEEP_ERROR )
930
+ if (options && options -> keep_error )
919
931
curl_easy_setopt (slot -> curl , CURLOPT_FAILONERROR , 0 );
920
932
921
933
headers = curl_slist_append (headers , buf .buf );
@@ -933,26 +945,85 @@ static int http_request(const char *url, struct strbuf *type,
933
945
ret = HTTP_START_FAILED ;
934
946
}
935
947
936
- if (type ) {
937
- char * t ;
938
- strbuf_reset ( type );
939
- curl_easy_getinfo ( slot -> curl , CURLINFO_CONTENT_TYPE , & t );
940
- if (t )
941
- strbuf_addstr ( type , t );
942
- }
948
+ if (options && options -> content_type )
949
+ curlinfo_strbuf ( slot -> curl , CURLINFO_CONTENT_TYPE ,
950
+ options -> content_type );
951
+
952
+ if (options && options -> effective_url )
953
+ curlinfo_strbuf ( slot -> curl , CURLINFO_EFFECTIVE_URL ,
954
+ options -> effective_url );
943
955
944
956
curl_slist_free_all (headers );
945
957
strbuf_release (& buf );
946
958
947
959
return ret ;
948
960
}
949
961
962
+ /*
963
+ * Update the "base" url to a more appropriate value, as deduced by
964
+ * redirects seen when requesting a URL starting with "url".
965
+ *
966
+ * The "asked" parameter is a URL that we asked curl to access, and must begin
967
+ * with "base".
968
+ *
969
+ * The "got" parameter is the URL that curl reported to us as where we ended
970
+ * up.
971
+ *
972
+ * Returns 1 if we updated the base url, 0 otherwise.
973
+ *
974
+ * Our basic strategy is to compare "base" and "asked" to find the bits
975
+ * specific to our request. We then strip those bits off of "got" to yield the
976
+ * new base. So for example, if our base is "http://example.com/foo.git",
977
+ * and we ask for "http://example.com/foo.git/info/refs", we might end up
978
+ * with "https://other.example.com/foo.git/info/refs". We would want the
979
+ * new URL to become "https://other.example.com/foo.git".
980
+ *
981
+ * Note that this assumes a sane redirect scheme. It's entirely possible
982
+ * in the example above to end up at a URL that does not even end in
983
+ * "info/refs". In such a case we simply punt, as there is not much we can
984
+ * do (and such a scheme is unlikely to represent a real git repository,
985
+ * which means we are likely about to abort anyway).
986
+ */
987
+ static int update_url_from_redirect (struct strbuf * base ,
988
+ const char * asked ,
989
+ const struct strbuf * got )
990
+ {
991
+ const char * tail ;
992
+ size_t tail_len ;
993
+
994
+ if (!strcmp (asked , got -> buf ))
995
+ return 0 ;
996
+
997
+ if (prefixcmp (asked , base -> buf ))
998
+ die ("BUG: update_url_from_redirect: %s is not a superset of %s" ,
999
+ asked , base -> buf );
1000
+
1001
+ tail = asked + base -> len ;
1002
+ tail_len = strlen (tail );
1003
+
1004
+ if (got -> len < tail_len ||
1005
+ strcmp (tail , got -> buf + got -> len - tail_len ))
1006
+ return 0 ; /* insane redirect scheme */
1007
+
1008
+ strbuf_reset (base );
1009
+ strbuf_add (base , got -> buf , got -> len - tail_len );
1010
+ return 1 ;
1011
+ }
1012
+
950
1013
static int http_request_reauth (const char * url ,
951
- struct strbuf * type ,
952
1014
void * result , int target ,
953
- int options )
1015
+ struct http_get_options * options )
954
1016
{
955
- int ret = http_request (url , type , result , target , options );
1017
+ int ret = http_request (url , result , target , options );
1018
+
1019
+ if (options && options -> effective_url && options -> base_url ) {
1020
+ if (update_url_from_redirect (options -> base_url ,
1021
+ url , options -> effective_url )) {
1022
+ credential_from_url (& http_auth , options -> base_url -> buf );
1023
+ url = options -> effective_url -> buf ;
1024
+ }
1025
+ }
1026
+
956
1027
if (ret != HTTP_REAUTH )
957
1028
return ret ;
958
1029
@@ -962,7 +1033,7 @@ static int http_request_reauth(const char *url,
962
1033
* making our next request. We only know how to do this for
963
1034
* the strbuf case, but that is enough to satisfy current callers.
964
1035
*/
965
- if (options & HTTP_KEEP_ERROR ) {
1036
+ if (options && options -> keep_error ) {
966
1037
switch (target ) {
967
1038
case HTTP_REQUEST_STRBUF :
968
1039
strbuf_reset (result );
@@ -971,15 +1042,17 @@ static int http_request_reauth(const char *url,
971
1042
die ("BUG: HTTP_KEEP_ERROR is only supported with strbufs" );
972
1043
}
973
1044
}
974
- return http_request (url , type , result , target , options );
1045
+
1046
+ credential_fill (& http_auth );
1047
+
1048
+ return http_request (url , result , target , options );
975
1049
}
976
1050
977
1051
int http_get_strbuf (const char * url ,
978
- struct strbuf * type ,
979
- struct strbuf * result , int options )
1052
+ struct strbuf * result ,
1053
+ struct http_get_options * options )
980
1054
{
981
- return http_request_reauth (url , type , result ,
982
- HTTP_REQUEST_STRBUF , options );
1055
+ return http_request_reauth (url , result , HTTP_REQUEST_STRBUF , options );
983
1056
}
984
1057
985
1058
/*
@@ -988,24 +1061,25 @@ int http_get_strbuf(const char *url,
988
1061
* If a previous interrupted download is detected (i.e. a previous temporary
989
1062
* file is still around) the download is resumed.
990
1063
*/
991
- static int http_get_file (const char * url , const char * filename , int options )
1064
+ static int http_get_file (const char * url , const char * filename ,
1065
+ struct http_get_options * options )
992
1066
{
993
1067
int ret ;
994
1068
struct strbuf tmpfile = STRBUF_INIT ;
995
1069
FILE * result ;
996
1070
997
1071
strbuf_addf (& tmpfile , "%s.temp" , filename );
998
1072
result = fopen (tmpfile .buf , "a" );
999
- if (! result ) {
1073
+ if (!result ) {
1000
1074
error ("Unable to open local file %s" , tmpfile .buf );
1001
1075
ret = HTTP_ERROR ;
1002
1076
goto cleanup ;
1003
1077
}
1004
1078
1005
- ret = http_request_reauth (url , NULL , result , HTTP_REQUEST_FILE , options );
1079
+ ret = http_request_reauth (url , result , HTTP_REQUEST_FILE , options );
1006
1080
fclose (result );
1007
1081
1008
- if (( ret == HTTP_OK ) && move_temp_to_file (tmpfile .buf , filename ))
1082
+ if (ret == HTTP_OK && move_temp_to_file (tmpfile .buf , filename ))
1009
1083
ret = HTTP_ERROR ;
1010
1084
cleanup :
1011
1085
strbuf_release (& tmpfile );
@@ -1014,12 +1088,15 @@ static int http_get_file(const char *url, const char *filename, int options)
1014
1088
1015
1089
int http_fetch_ref (const char * base , struct ref * ref )
1016
1090
{
1091
+ struct http_get_options options = {0 };
1017
1092
char * url ;
1018
1093
struct strbuf buffer = STRBUF_INIT ;
1019
1094
int ret = -1 ;
1020
1095
1096
+ options .no_cache = 1 ;
1097
+
1021
1098
url = quote_ref_url (base , ref -> name );
1022
- if (http_get_strbuf (url , NULL , & buffer , HTTP_NO_CACHE ) == HTTP_OK ) {
1099
+ if (http_get_strbuf (url , & buffer , & options ) == HTTP_OK ) {
1023
1100
strbuf_rtrim (& buffer );
1024
1101
if (buffer .len == 40 )
1025
1102
ret = get_sha1_hex (buffer .buf , ref -> old_sha1 );
@@ -1050,7 +1127,7 @@ static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
1050
1127
strbuf_addf (& buf , "%s.temp" , sha1_pack_index_name (sha1 ));
1051
1128
tmp = strbuf_detach (& buf , NULL );
1052
1129
1053
- if (http_get_file (url , tmp , 0 ) != HTTP_OK ) {
1130
+ if (http_get_file (url , tmp , NULL ) != HTTP_OK ) {
1054
1131
error ("Unable to get pack index %s" , url );
1055
1132
free (tmp );
1056
1133
tmp = NULL ;
@@ -1103,6 +1180,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
1103
1180
1104
1181
int http_get_info_packs (const char * base_url , struct packed_git * * packs_head )
1105
1182
{
1183
+ struct http_get_options options = {0 };
1106
1184
int ret = 0 , i = 0 ;
1107
1185
char * url , * data ;
1108
1186
struct strbuf buf = STRBUF_INIT ;
@@ -1112,7 +1190,8 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
1112
1190
strbuf_addstr (& buf , "objects/info/packs" );
1113
1191
url = strbuf_detach (& buf , NULL );
1114
1192
1115
- ret = http_get_strbuf (url , NULL , & buf , HTTP_NO_CACHE );
1193
+ options .no_cache = 1 ;
1194
+ ret = http_get_strbuf (url , & buf , & options );
1116
1195
if (ret != HTTP_OK )
1117
1196
goto cleanup ;
1118
1197
0 commit comments