@@ -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 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 > >
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,19 @@ 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 {
90
+ handle : handle,
91
+ base_url : Arc :: new ( Mutex :: new ( String :: new ( ) ) )
92
+ } )
85
93
}
86
94
87
95
impl SmartSubtransport for CurlTransport {
88
96
fn action ( & self , url : & str , action : Service )
89
97
-> 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
+ }
90
102
let ( service, path, method) = match action {
91
103
Service :: UploadPackLs => {
92
104
( "upload-pack" , "/info/refs?service=git-upload-pack" , "GET" )
@@ -106,7 +118,7 @@ impl SmartSubtransport for CurlTransport {
106
118
handle : self . handle . clone ( ) ,
107
119
service : service,
108
120
url_path : path,
109
- base_url : url . to_string ( ) ,
121
+ base_url : self . base_url . clone ( ) ,
110
122
method : method,
111
123
reader : None ,
112
124
sent_request : false ,
@@ -130,7 +142,7 @@ impl CurlSubtransport {
130
142
let agent = format ! ( "git/1.0 (git2-curl {})" , env!( "CARGO_PKG_VERSION" ) ) ;
131
143
132
144
// 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) ;
134
146
let parsed = try!( Url :: parse ( & url) . map_err ( |_| {
135
147
self . err ( "invalid url, failed to parse" )
136
148
} ) ) ;
@@ -230,6 +242,20 @@ impl CurlSubtransport {
230
242
// Ok, time to read off some data.
231
243
let rdr = Cursor :: new ( data) ;
232
244
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
+
233
259
Ok ( ( ) )
234
260
}
235
261
}
0 commit comments