@@ -36,13 +36,18 @@ use url::Url;
3636
3737struct CurlTransport {
3838 handle : Arc < Mutex < Easy > > ,
39+ /// The URL of the remote server, e.g. "https://github.com/user/repo"
40+ ///
41+ /// This is an empty string until the first action is performed.
42+ /// If there is an HTTP redirect, this will be updated with the new URL.
43+ base_url : Arc < Mutex < String > >
3944}
4045
4146struct CurlSubtransport {
4247 handle : Arc < Mutex < Easy > > ,
4348 service : & ' static str ,
4449 url_path : & ' static str ,
45- base_url : String ,
50+ base_url : Arc < Mutex < String > > ,
4651 method : & ' static str ,
4752 reader : Option < Cursor < Vec < u8 > > > ,
4853 sent_request : bool ,
@@ -81,12 +86,19 @@ pub unsafe fn register(handle: Easy) {
8186
8287fn factory ( remote : & git2:: Remote , handle : Arc < Mutex < Easy > > )
8388 -> Result < Transport , Error > {
84- Transport :: smart ( remote, true , CurlTransport { handle : handle } )
89+ Transport :: smart ( remote, true , CurlTransport {
90+ handle : handle,
91+ base_url : Arc :: new ( Mutex :: new ( String :: new ( ) ) )
92+ } )
8593}
8694
8795impl SmartSubtransport for CurlTransport {
8896 fn action ( & self , url : & str , action : Service )
8997 -> Result < Box < SmartSubtransportStream > , Error > {
98+ let mut base_url = self . base_url . lock ( ) . unwrap ( ) ;
99+ if base_url. len ( ) == 0 {
100+ * base_url = url. to_string ( ) ;
101+ }
90102 let ( service, path, method) = match action {
91103 Service :: UploadPackLs => {
92104 ( "upload-pack" , "/info/refs?service=git-upload-pack" , "GET" )
@@ -106,7 +118,7 @@ impl SmartSubtransport for CurlTransport {
106118 handle : self . handle . clone ( ) ,
107119 service : service,
108120 url_path : path,
109- base_url : url . to_string ( ) ,
121+ base_url : self . base_url . clone ( ) ,
110122 method : method,
111123 reader : None ,
112124 sent_request : false ,
@@ -130,7 +142,7 @@ impl CurlSubtransport {
130142 let agent = format ! ( "git/1.0 (git2-curl {})" , env!( "CARGO_PKG_VERSION" ) ) ;
131143
132144 // Parse our input URL to figure out the host
133- let url = format ! ( "{}{}" , self . base_url, self . url_path) ;
145+ let url = format ! ( "{}{}" , self . base_url. lock ( ) . unwrap ( ) , self . url_path) ;
134146 let parsed = try!( Url :: parse ( & url) . map_err ( |_| {
135147 self . err ( "invalid url, failed to parse" )
136148 } ) ) ;
@@ -230,6 +242,20 @@ impl CurlSubtransport {
230242 // Ok, time to read off some data.
231243 let rdr = Cursor :: new ( data) ;
232244 self . reader = Some ( rdr) ;
245+
246+ // If there was a redirect, update the `CurlTransport` with the new base.
247+ if let Ok ( Some ( effective_url) ) = h. effective_url ( ) {
248+ let new_base = if effective_url. ends_with ( self . url_path ) {
249+ // Strip the action from the end.
250+ & effective_url[ ..effective_url. len ( ) - self . url_path . len ( ) ]
251+ } else {
252+ // I'm not sure if this code path makes sense, but it's what
253+ // libgit does.
254+ effective_url
255+ } ;
256+ * self . base_url . lock ( ) . unwrap ( ) = new_base. to_string ( ) ;
257+ }
258+
233259 Ok ( ( ) )
234260 }
235261}
0 commit comments