@@ -36,13 +36,18 @@ use url::Url;
36
36
37
37
struct CurlTransport {
38
38
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 > > >
39
44
}
40
45
41
46
struct CurlSubtransport {
42
47
handle : Arc < Mutex < Easy > > ,
43
48
service : & ' static str ,
44
49
url_path : & ' static str ,
45
- base_url : String ,
50
+ base_url : Arc < Mutex < String > > ,
46
51
method : & ' static str ,
47
52
reader : Option < Cursor < Vec < u8 > > > ,
48
53
sent_request : bool ,
@@ -81,12 +86,15 @@ pub unsafe fn register(handle: Easy) {
81
86
82
87
fn factory ( remote : & git2:: Remote , handle : Arc < Mutex < Easy > > )
83
88
-> Result < Transport , Error > {
84
- Transport :: smart ( remote, true , CurlTransport { handle : handle } )
89
+ Transport :: smart ( remote, true , CurlTransport { handle : handle, base_url : None } )
85
90
}
86
91
87
92
impl SmartSubtransport for CurlTransport {
88
- fn action ( & self , url : & str , action : Service )
93
+ fn action ( & mut self , url : & str , action : Service )
89
94
-> Result < Box < SmartSubtransportStream > , Error > {
95
+ if self . base_url . is_none ( ) {
96
+ self . base_url = Some ( Arc :: new ( Mutex :: new ( url. to_string ( ) ) ) ) ;
97
+ }
90
98
let ( service, path, method) = match action {
91
99
Service :: UploadPackLs => {
92
100
( "upload-pack" , "/info/refs?service=git-upload-pack" , "GET" )
@@ -106,7 +114,7 @@ impl SmartSubtransport for CurlTransport {
106
114
handle : self . handle . clone ( ) ,
107
115
service : service,
108
116
url_path : path,
109
- base_url : url . to_string ( ) ,
117
+ base_url : self . base_url . as_ref ( ) . unwrap ( ) . clone ( ) ,
110
118
method : method,
111
119
reader : None ,
112
120
sent_request : false ,
@@ -130,7 +138,7 @@ impl CurlSubtransport {
130
138
let agent = format ! ( "git/1.0 (git2-curl {})" , env!( "CARGO_PKG_VERSION" ) ) ;
131
139
132
140
// 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) ;
134
142
let parsed = try!( Url :: parse ( & url) . map_err ( |_| {
135
143
self . err ( "invalid url, failed to parse" )
136
144
} ) ) ;
@@ -230,6 +238,20 @@ impl CurlSubtransport {
230
238
// Ok, time to read off some data.
231
239
let rdr = Cursor :: new ( data) ;
232
240
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
+
233
255
Ok ( ( ) )
234
256
}
235
257
}
0 commit comments