@@ -45,7 +45,7 @@ static long curl_low_speed_time = -1;
4545static int curl_ftp_no_epsv ;
4646static const char * curl_http_proxy ;
4747static const char * curl_cookie_file ;
48- static struct credential http_auth = CREDENTIAL_INIT ;
48+ struct credential http_auth = CREDENTIAL_INIT ;
4949static int http_proactive_auth ;
5050static const char * user_agent ;
5151
@@ -806,7 +806,6 @@ int handle_curl_result(struct slot_results *results)
806806 credential_reject (& http_auth );
807807 return HTTP_NOAUTH ;
808808 } else {
809- credential_fill (& http_auth );
810809 return HTTP_REAUTH ;
811810 }
812811 } else {
@@ -820,12 +819,25 @@ int handle_curl_result(struct slot_results *results)
820819 }
821820}
822821
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+
823834/* http_request() targets */
824835#define HTTP_REQUEST_STRBUF 0
825836#define HTTP_REQUEST_FILE 1
826837
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 )
829841{
830842 struct active_request_slot * slot ;
831843 struct slot_results results ;
@@ -858,9 +870,9 @@ static int http_request(const char *url, struct strbuf *type,
858870 }
859871
860872 strbuf_addstr (& buf , "Pragma:" );
861- if (options & HTTP_NO_CACHE )
873+ if (options && options -> no_cache )
862874 strbuf_addstr (& buf , " no-cache" );
863- if (options & HTTP_KEEP_ERROR )
875+ if (options && options -> keep_error )
864876 curl_easy_setopt (slot -> curl , CURLOPT_FAILONERROR , 0 );
865877
866878 headers = curl_slist_append (headers , buf .buf );
@@ -878,26 +890,85 @@ static int http_request(const char *url, struct strbuf *type,
878890 ret = HTTP_START_FAILED ;
879891 }
880892
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 );
888900
889901 curl_slist_free_all (headers );
890902 strbuf_release (& buf );
891903
892904 return ret ;
893905}
894906
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+
895958static int http_request_reauth (const char * url ,
896- struct strbuf * type ,
897959 void * result , int target ,
898- int options )
960+ struct http_get_options * options )
899961{
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+
901972 if (ret != HTTP_REAUTH )
902973 return ret ;
903974
@@ -907,7 +978,7 @@ static int http_request_reauth(const char *url,
907978 * making our next request. We only know how to do this for
908979 * the strbuf case, but that is enough to satisfy current callers.
909980 */
910- if (options & HTTP_KEEP_ERROR ) {
981+ if (options && options -> keep_error ) {
911982 switch (target ) {
912983 case HTTP_REQUEST_STRBUF :
913984 strbuf_reset (result );
@@ -916,15 +987,17 @@ static int http_request_reauth(const char *url,
916987 die ("BUG: HTTP_KEEP_ERROR is only supported with strbufs" );
917988 }
918989 }
919- return http_request (url , type , result , target , options );
990+
991+ credential_fill (& http_auth );
992+
993+ return http_request (url , result , target , options );
920994}
921995
922996int 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 )
925999{
926- return http_request_reauth (url , type , result ,
927- HTTP_REQUEST_STRBUF , options );
1000+ return http_request_reauth (url , result , HTTP_REQUEST_STRBUF , options );
9281001}
9291002
9301003/*
@@ -933,24 +1006,25 @@ int http_get_strbuf(const char *url,
9331006 * If a previous interrupted download is detected (i.e. a previous temporary
9341007 * file is still around) the download is resumed.
9351008 */
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 )
9371011{
9381012 int ret ;
9391013 struct strbuf tmpfile = STRBUF_INIT ;
9401014 FILE * result ;
9411015
9421016 strbuf_addf (& tmpfile , "%s.temp" , filename );
9431017 result = fopen (tmpfile .buf , "a" );
944- if (! result ) {
1018+ if (!result ) {
9451019 error ("Unable to open local file %s" , tmpfile .buf );
9461020 ret = HTTP_ERROR ;
9471021 goto cleanup ;
9481022 }
9491023
950- ret = http_request_reauth (url , NULL , result , HTTP_REQUEST_FILE , options );
1024+ ret = http_request_reauth (url , result , HTTP_REQUEST_FILE , options );
9511025 fclose (result );
9521026
953- if (( ret == HTTP_OK ) && move_temp_to_file (tmpfile .buf , filename ))
1027+ if (ret == HTTP_OK && move_temp_to_file (tmpfile .buf , filename ))
9541028 ret = HTTP_ERROR ;
9551029cleanup :
9561030 strbuf_release (& tmpfile );
@@ -959,12 +1033,15 @@ static int http_get_file(const char *url, const char *filename, int options)
9591033
9601034int http_fetch_ref (const char * base , struct ref * ref )
9611035{
1036+ struct http_get_options options = {0 };
9621037 char * url ;
9631038 struct strbuf buffer = STRBUF_INIT ;
9641039 int ret = -1 ;
9651040
1041+ options .no_cache = 1 ;
1042+
9661043 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 ) {
9681045 strbuf_rtrim (& buffer );
9691046 if (buffer .len == 40 )
9701047 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)
9951072 strbuf_addf (& buf , "%s.temp" , sha1_pack_index_name (sha1 ));
9961073 tmp = strbuf_detach (& buf , NULL );
9971074
998- if (http_get_file (url , tmp , 0 ) != HTTP_OK ) {
1075+ if (http_get_file (url , tmp , NULL ) != HTTP_OK ) {
9991076 error ("Unable to get pack index %s" , url );
10001077 free (tmp );
10011078 tmp = NULL ;
@@ -1048,6 +1125,7 @@ static int fetch_and_setup_pack_index(struct packed_git **packs_head,
10481125
10491126int http_get_info_packs (const char * base_url , struct packed_git * * packs_head )
10501127{
1128+ struct http_get_options options = {0 };
10511129 int ret = 0 , i = 0 ;
10521130 char * url , * data ;
10531131 struct strbuf buf = STRBUF_INIT ;
@@ -1057,7 +1135,8 @@ int http_get_info_packs(const char *base_url, struct packed_git **packs_head)
10571135 strbuf_addstr (& buf , "objects/info/packs" );
10581136 url = strbuf_detach (& buf , NULL );
10591137
1060- ret = http_get_strbuf (url , NULL , & buf , HTTP_NO_CACHE );
1138+ options .no_cache = 1 ;
1139+ ret = http_get_strbuf (url , & buf , & options );
10611140 if (ret != HTTP_OK )
10621141 goto cleanup ;
10631142
0 commit comments