@@ -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 `None` until the first action is performed.
42+ /// If there is an HTTP redirect, this will be updated with the new URL.
43+ base_url : Option < 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,15 @@ 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 { handle : handle, base_url : None } )
8590}
8691
8792impl SmartSubtransport for CurlTransport {
88- fn action ( & self , url : & str , action : Service )
93+ fn action ( & mut self , url : & str , action : Service )
8994 -> Result < Box < SmartSubtransportStream > , Error > {
95+ if self . base_url . is_none ( ) {
96+ self . base_url = Some ( Arc :: new ( Mutex :: new ( url. to_string ( ) ) ) ) ;
97+ }
9098 let ( service, path, method) = match action {
9199 Service :: UploadPackLs => {
92100 ( "upload-pack" , "/info/refs?service=git-upload-pack" , "GET" )
@@ -106,7 +114,7 @@ impl SmartSubtransport for CurlTransport {
106114 handle : self . handle . clone ( ) ,
107115 service : service,
108116 url_path : path,
109- base_url : url . to_string ( ) ,
117+ base_url : self . base_url . as_ref ( ) . unwrap ( ) . clone ( ) ,
110118 method : method,
111119 reader : None ,
112120 sent_request : false ,
@@ -130,7 +138,7 @@ impl CurlSubtransport {
130138 let agent = format ! ( "git/1.0 (git2-curl {})" , env!( "CARGO_PKG_VERSION" ) ) ;
131139
132140 // Parse our input URL to figure out the host
133- let url = format ! ( "{}{}" , self . base_url, self . url_path) ;
141+ let url = format ! ( "{}{}" , self . base_url. lock ( ) . unwrap ( ) , self . url_path) ;
134142 let parsed = try!( Url :: parse ( & url) . map_err ( |_| {
135143 self . err ( "invalid url, failed to parse" )
136144 } ) ) ;
@@ -230,6 +238,20 @@ impl CurlSubtransport {
230238 // Ok, time to read off some data.
231239 let rdr = Cursor :: new ( data) ;
232240 self . reader = Some ( rdr) ;
241+
242+ // If there was a redirect, update the `CurlTransport` with the new base.
243+ if let Ok ( Some ( effective_url) ) = h. effective_url ( ) {
244+ let new_base = if effective_url. ends_with ( self . url_path ) {
245+ // Strip the action from the end.
246+ & effective_url[ ..effective_url. len ( ) - self . url_path . len ( ) ]
247+ } else {
248+ // I'm not sure if this code path makes sense, but it's what
249+ // libgit does.
250+ effective_url
251+ } ;
252+ * self . base_url . lock ( ) . unwrap ( ) = new_base. to_string ( ) ;
253+ }
254+
233255 Ok ( ( ) )
234256 }
235257}
0 commit comments