@@ -6,6 +6,9 @@ extern crate url;
6
6
7
7
#[ cfg( feature = "reqwest-backend" ) ]
8
8
extern crate reqwest;
9
+ #[ cfg( feature = "reqwest-backend" ) ]
10
+ #[ macro_use]
11
+ extern crate lazy_static;
9
12
10
13
use url:: Url ;
11
14
use std:: path:: Path ;
@@ -237,56 +240,24 @@ pub mod reqwest_be {
237
240
extern crate env_proxy;
238
241
239
242
use std:: io;
243
+ use std:: time:: Duration ;
240
244
use errors:: * ;
241
245
use url:: Url ;
242
246
use super :: Event ;
243
- use reqwest:: { header, Client , Proxy } ;
247
+ use reqwest:: { header, Client , Proxy , Response } ;
244
248
245
249
pub fn download ( url : & Url ,
246
250
resume_from : u64 ,
247
251
callback : & Fn ( Event ) -> Result < ( ) > )
248
252
-> Result < ( ) > {
249
253
250
254
// Short-circuit reqwest for the "file:" URL scheme
251
- if try! ( download_from_file_url ( url, callback) ) {
255
+ if download_from_file_url ( url, resume_from , callback) ? {
252
256
return Ok ( ( ) ) ;
253
257
}
254
258
255
- let maybe_proxy = env_proxy:: for_url ( url)
256
- . map ( |( addr, port) | {
257
- String :: from ( format ! ( "{}:{}" , addr, port) )
258
- } ) ;
259
-
260
- let client = match url. scheme ( ) {
261
- "https" => match maybe_proxy {
262
- None => Client :: new ( ) ?,
263
- Some ( host_port) => {
264
- Client :: builder ( ) ?
265
- . proxy ( Proxy :: https ( & host_port) ?)
266
- . build ( ) ?
267
- }
268
- } ,
269
- "http" => match maybe_proxy {
270
- None => Client :: new ( ) ?,
271
- Some ( host_port) => {
272
- Client :: builder ( ) ?
273
- . proxy ( Proxy :: http ( & host_port) ?)
274
- . build ( ) ?
275
- }
276
- } ,
277
- _ => return Err ( format ! ( "unsupported URL scheme: '{}'" , url. scheme( ) ) . into ( ) )
278
- } ;
279
-
280
- let mut res = if resume_from > 0 {
281
- client
282
- . get ( url. clone ( ) ) ?
283
- . header ( header:: Range :: Bytes (
284
- vec ! [ header:: ByteRangeSpec :: AllFrom ( resume_from) ]
285
- ) )
286
- . send ( )
287
- } else {
288
- client. get ( url. clone ( ) ) ?. send ( )
289
- } . chain_err ( || "failed to make network request" ) ?;
259
+ let mut res = request ( url, resume_from)
260
+ . chain_err ( || "failed to make network request" ) ?;
290
261
291
262
if !res. status ( ) . is_success ( ) {
292
263
let code: u16 = res. status ( ) . into ( ) ;
@@ -296,23 +267,65 @@ pub mod reqwest_be {
296
267
let buffer_size = 0x10000 ;
297
268
let mut buffer = vec ! [ 0u8 ; buffer_size] ;
298
269
299
- if let Some ( len) = res. headers ( ) . get :: < header:: ContentLength > ( ) . cloned ( ) {
300
- try! ( callback ( Event :: DownloadContentLengthReceived ( len. 0 ) ) ) ;
270
+ if let Some ( len) = res. headers ( ) . get :: < header:: ContentLength > ( ) {
271
+ callback ( Event :: DownloadContentLengthReceived ( len. 0 + resume_from ) ) ? ;
301
272
}
302
273
303
274
loop {
304
- let bytes_read = try! ( io:: Read :: read ( & mut res, & mut buffer)
305
- . chain_err ( || "error reading from socket" ) ) ;
275
+ let bytes_read = io:: Read :: read ( & mut res, & mut buffer)
276
+ . chain_err ( || "error reading from socket" ) ? ;
306
277
307
278
if bytes_read != 0 {
308
- try! ( callback ( Event :: DownloadDataReceived ( & buffer[ 0 ..bytes_read] ) ) ) ;
279
+ callback ( Event :: DownloadDataReceived ( & buffer[ 0 ..bytes_read] ) ) ? ;
309
280
} else {
310
281
return Ok ( ( ) ) ;
311
282
}
312
283
}
313
284
}
314
285
286
+ lazy_static ! {
287
+ static ref CLIENT : Client = {
288
+ let catcher = || {
289
+ Client :: builder( ) ?
290
+ . gzip( false )
291
+ . proxy( Proxy :: custom( env_proxy) )
292
+ . timeout( Duration :: from_secs( 30 ) )
293
+ . build( )
294
+ } ;
295
+
296
+ // woah, an unwrap?!
297
+ // It's OK. This is the same as what is happening in curl.
298
+ //
299
+ // The curl::Easy::new() internally assert!s that the initialized
300
+ // Easy is not null. Inside reqwest, the errors here would be from
301
+ // the TLS library returning a null pointer as well.
302
+ catcher( ) . unwrap( )
303
+ } ;
304
+ }
305
+
306
+ fn env_proxy ( url : & Url ) -> Option < Url > {
307
+ env_proxy:: for_url ( url) . and_then ( |( host, port) | {
308
+ //TODO: update env_proxy to return full string, not just (host,port)
309
+ //Ideally: fn for_str(s: &str) -> Option<String>
310
+ let proxy_url = format ! ( "http://{}:{}" , host, port) ;
311
+ proxy_url. parse ( ) . ok ( )
312
+ } )
313
+ }
314
+
315
+ fn request ( url : & Url , resume_from : u64 ) -> :: reqwest:: Result < Response > {
316
+ let mut req = CLIENT . get ( url. clone ( ) ) ?;
317
+
318
+ if resume_from != 0 {
319
+ req. header ( header:: Range :: Bytes (
320
+ vec ! [ header:: ByteRangeSpec :: AllFrom ( resume_from) ]
321
+ ) ) ;
322
+ }
323
+
324
+ req. send ( )
325
+ }
326
+
315
327
fn download_from_file_url ( url : & Url ,
328
+ resume_from : u64 ,
316
329
callback : & Fn ( Event ) -> Result < ( ) > )
317
330
-> Result < bool > {
318
331
@@ -333,6 +346,7 @@ pub mod reqwest_be {
333
346
334
347
let ref mut f = try!( fs:: File :: open ( src)
335
348
. chain_err ( || "unable to open downloaded file" ) ) ;
349
+ io:: Seek :: seek ( f, io:: SeekFrom :: Start ( resume_from) ) ?;
336
350
337
351
let ref mut buffer = vec ! [ 0u8 ; 0x10000 ] ;
338
352
loop {
0 commit comments