@@ -45,7 +45,7 @@ static long curl_low_speed_time = -1;
45
45
static int curl_ftp_no_epsv ;
46
46
static const char * curl_http_proxy ;
47
47
static const char * curl_cookie_file ;
48
- static struct credential http_auth = CREDENTIAL_INIT ;
48
+ struct credential http_auth = CREDENTIAL_INIT ;
49
49
static int http_proactive_auth ;
50
50
static const char * user_agent ;
51
51
@@ -806,7 +806,6 @@ int handle_curl_result(struct slot_results *results)
806
806
credential_reject (& http_auth );
807
807
return HTTP_NOAUTH ;
808
808
} else {
809
- credential_fill (& http_auth );
810
809
return HTTP_REAUTH ;
811
810
}
812
811
} else {
@@ -820,12 +819,25 @@ int handle_curl_result(struct slot_results *results)
820
819
}
821
820
}
822
821
822
+ static CURLcode curlinfo_strbuf (CURL * curl , CURLINFO info , struct strbuf * buf )
823
+ {
824
+ char * ptr ;
825
+ CURLcode ret ;
826
+
827
+ strbuf_reset (buf );
828
+ ret = curl_easy_getinfo (curl , info , & ptr );
829
+ if (!ret && ptr )
830
+ strbuf_addstr (buf , ptr );
831
+ return ret ;
832
+ }
833
+
823
834
/* http_request() targets */
824
835
#define HTTP_REQUEST_STRBUF 0
825
836
#define HTTP_REQUEST_FILE 1
826
837
827
- static int http_request (const char * url , struct strbuf * type ,
828
- void * result , int target , int options )
838
+ static int http_request (const char * url ,
839
+ void * result , int target ,
840
+ const struct http_get_options * options )
829
841
{
830
842
struct active_request_slot * slot ;
831
843
struct slot_results results ;
@@ -858,9 +870,9 @@ static int http_request(const char *url, struct strbuf *type,
858
870
}
859
871
860
872
strbuf_addstr (& buf , "Pragma:" );
861
- if (options & HTTP_NO_CACHE )
873
+ if (options && options -> no_cache )
862
874
strbuf_addstr (& buf , " no-cache" );
863
- if (options & HTTP_KEEP_ERROR )
875
+ if (options && options -> keep_error )
864
876
curl_easy_setopt (slot -> curl , CURLOPT_FAILONERROR , 0 );
865
877
866
878
headers = curl_slist_append (headers , buf .buf );
@@ -878,26 +890,85 @@ static int http_request(const char *url, struct strbuf *type,
878
890
ret = HTTP_START_FAILED ;
879
891
}
880
892
881
- if (type ) {
882
- char * t ;
883
- strbuf_reset ( type );
884
- curl_easy_getinfo ( slot -> curl , CURLINFO_CONTENT_TYPE , & t );
885
- if (t )
886
- strbuf_addstr ( type , t );
887
- }
893
+ if (options && options -> content_type )
894
+ curlinfo_strbuf ( slot -> curl , CURLINFO_CONTENT_TYPE ,
895
+ options -> content_type );
896
+
897
+ if (options && options -> effective_url )
898
+ curlinfo_strbuf ( slot -> curl , CURLINFO_EFFECTIVE_URL ,
899
+ options -> effective_url );
888
900
889
901
curl_slist_free_all (headers );
890
902
strbuf_release (& buf );
891
903
892
904
return ret ;
893
905
}
894
906
907
+ /*
908
+ * Update the "base" url to a more appropriate value, as deduced by
909
+ * redirects seen when requesting a URL starting with "url".
910
+ *
911
+ * The "asked" parameter is a URL that we asked curl to access, and must begin
912
+ * with "base".
913
+ *
914
+ * The "got" parameter is the URL that curl reported to us as where we ended
915
+ * up.
916
+ *
917
+ * Returns 1 if we updated the base url, 0 otherwise.
918
+ *
919
+ * Our basic strategy is to compare "base" and "asked" to find the bits
920
+ * specific to our request. We then strip those bits off of "got" to yield the
921
+ * new base. So for example, if our base is "http://example.com/foo.git",
922
+ * and we ask for "http://example.com/foo.git/info/refs", we might end up
923
+ * with "https://other.example.com/foo.git/info/refs". We would want the
924
+ * new URL to become "https://other.example.com/foo.git".
925
+ *
926
+ * Note that this assumes a sane redirect scheme. It's entirely possible
927
+ * in the example above to end up at a URL that does not even end in
928
+ * "info/refs". In such a case we simply punt, as there is not much we can
929
+ * do (and such a scheme is unlikely to represent a real git repository,
930
+ * which means we are likely about to abort anyway).
931
+ */
932
+ static int update_url_from_redirect (struct strbuf * base ,
933
+ const char * asked ,
934
+ const struct strbuf * got )
935
+ {
936
+ const char * tail ;
937
+ size_t tail_len ;
938
+
939
+ if (!strcmp (asked , got -> buf ))
940
+ return 0 ;
941
+
942
+ if (prefixcmp (asked , base -> buf ))
943
+ die ("BUG: update_url_from_redirect: %s is not a superset of %s" ,
944
+ asked , base -> buf );
945
+
946
+ tail = asked + base -> len ;
947
+ tail_len = strlen (tail );
948
+
949
+ if (got -> len < tail_len ||
950
+ strcmp (tail , got -> buf + got -> len - tail_len ))
951
+ return 0 ; /* insane redirect scheme */
952
+
953
+ strbuf_reset (base );
954
+ strbuf_add (base , got -> buf , got -> len - tail_len );
955
+ return 1 ;
956
+ }
957
+
895
958
static int http_request_reauth (const char * url ,
896
- struct strbuf * type ,
897
959
void * result , int target ,
898
- int options )
960
+ struct http_get_options * options )
899
961
{
900
- int ret = http_request (url , type , result , target , options );
962
+ int ret = http_request (url , result , target , options );
963
+
964
+ if (options && options -> effective_url && options -> base_url ) {
965
+ if (update_url_from_redirect (options -> base_url ,
966
+ url , options -> effective_url )) {
967
+ credential_from_url (& http_auth , options -> base_url -> buf );
968
+ url = options -> effective_url -> buf ;
969
+ }
970
+ }
971
+
901
972
if (ret != HTTP_REAUTH )
902
973
return ret ;
903
974
@@ -907,7 +978,7 @@ static int http_request_reauth(const char *url,
907
978
* making our next request. We only know how to do this for
908
979
* the strbuf case, but that is enough to satisfy current callers.
909
980
*/
910
- if (options & HTTP_KEEP_ERROR ) {
981
+ if (options && options -> keep_error ) {
911
982
switch (target ) {
912
983
case HTTP_REQUEST_STRBUF :
913
984
strbuf_reset (result );
@@ -916,15 +987,17 @@ static int http_request_reauth(const char *url,
916
987
die ("BUG: HTTP_KEEP_ERROR is only supported with strbufs" );
917
988
}
918
989
}
919
- return http_request (url , type , result , target , options );
990
+
991
+ credential_fill (& http_auth );
992
+
993
+ return http_request (url , result , target , options );
920
994
}
921
995
922
996
int http_get_strbuf (const char * url ,
923
- struct strbuf * type ,
924
- struct strbuf * result , int options )
997
+ struct strbuf * result ,
998
+ struct http_get_options * options )
925
999
{
926
- return http_request_reauth (url , type , result ,
927
- HTTP_REQUEST_STRBUF , options );
1000
+ return http_request_reauth (url , result , HTTP_REQUEST_STRBUF , options );
928
1001
}
929
1002
930
1003
/*
@@ -933,24 +1006,25 @@ int http_get_strbuf(const char *url,
933
1006
* If a previous interrupted download is detected (i.e. a previous temporary
934
1007
* file is still around) the download is resumed.
935
1008
*/
936
- static int http_get_file (const char * url , const char * filename , int options )
1009
+ static int http_get_file (const char * url , const char * filename ,
1010
+ struct http_get_options * options )
937
1011
{
938
1012
int ret ;
939
1013
struct strbuf tmpfile = STRBUF_INIT ;
940
1014
FILE * result ;
941
1015
942
1016
strbuf_addf (& tmpfile , "%s.temp" , filename );
943
1017
result = fopen (tmpfile .buf , "a" );
944
- if (! result ) {
1018
+ if (!result ) {
945
1019
error ("Unable to open local file %s" , tmpfile .buf );
946
1020
ret = HTTP_ERROR ;
947
1021
goto cleanup ;
948
1022
}
949
1023
950
- ret = http_request_reauth (url , NULL , result , HTTP_REQUEST_FILE , options );
1024
+ ret = http_request_reauth (url , result , HTTP_REQUEST_FILE , options );
951
1025
fclose (result );
952
1026
953
- if (( ret == HTTP_OK ) && move_temp_to_file (tmpfile .buf , filename ))
1027
+ if (ret == HTTP_OK && move_temp_to_file (tmpfile .buf , filename ))
954
1028
ret = HTTP_ERROR ;
955
1029
cleanup :
956
1030
strbuf_release (& tmpfile );
@@ -959,12 +1033,15 @@ static int http_get_file(const char *url, const char *filename, int options)
959
1033
960
1034
int http_fetch_ref (const char * base , struct ref * ref )
961
1035
{
1036
+ struct http_get_options options = {0 };
962
1037
char * url ;
963
1038
struct strbuf buffer = STRBUF_INIT ;
964
1039
int ret = -1 ;
965
1040
1041
+ options .no_cache = 1 ;
1042
+
966
1043
url = quote_ref_url (base , ref -> name );
967
- if (http_get_strbuf (url , NULL , & buffer , HTTP_NO_CACHE ) == HTTP_OK ) {
1044
+ if (http_get_strbuf (url , & buffer , & options ) == HTTP_OK ) {
968
1045
strbuf_rtrim (& buffer );
969
1046
if (buffer .len == 40 )
970
1047
ret = get_sha1_hex (buffer .buf , ref -> old_sha1 );
@@ -995,7 +1072,7 @@ static char *fetch_pack_index(unsigned char *sha1, const char *base_url)
995
1072
strbuf_addf (& buf , "%s.temp" , sha1_pack_index_name (sha1 ));
996
1073
tmp = strbuf_detach (& buf , NULL );
997
1074
998
- if (http_get_file (url , tmp , 0 ) != HTTP_OK ) {
1075
+ if (http_get_file (url , tmp , NULL ) != HTTP_OK ) {
999
1076
error ("Unable to get pack index %s" , url );
1000
1077
free (tmp );
1001
1078
tmp = NULL ;
@@ -1048,6 +1125,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
1048
1125
1049
1126
int http_get_info_packs (const char * base_url , struct packed_git * * packs_head )
1050
1127
{
1128
+ struct http_get_options options = {0 };
1051
1129
int ret = 0 , i = 0 ;
1052
1130
char * url , * data ;
1053
1131
struct strbuf buf = STRBUF_INIT ;
@@ -1057,7 +1135,8 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
1057
1135
strbuf_addstr (& buf , "objects/info/packs" );
1058
1136
url = strbuf_detach (& buf , NULL );
1059
1137
1060
- ret = http_get_strbuf (url , NULL , & buf , HTTP_NO_CACHE );
1138
+ options .no_cache = 1 ;
1139
+ ret = http_get_strbuf (url , & buf , & options );
1061
1140
if (ret != HTTP_OK )
1062
1141
goto cleanup ;
1063
1142
0 commit comments