@@ -541,23 +541,39 @@ impl<R: Runtime> WindowManager<R> {
541541 . get ( "range" )
542542 . and_then ( |r| r. to_str ( ) . map ( |r| r. to_string ( ) ) . ok ( ) )
543543 {
544- let ( headers, status_code, data) = crate :: async_runtime:: safe_block_on ( async move {
545- let mut headers = HashMap :: new ( ) ;
546- let mut buf = Vec :: new ( ) ;
544+ #[ derive( Default ) ]
545+ struct RangeMetadata {
546+ file : Option < tokio:: fs:: File > ,
547+ range : Option < crate :: runtime:: http:: HttpRange > ,
548+ metadata : Option < std:: fs:: Metadata > ,
549+ headers : HashMap < & ' static str , String > ,
550+ status_code : u16 ,
551+ body : Vec < u8 > ,
552+ }
553+
554+ let mut range_metadata = crate :: async_runtime:: safe_block_on ( async move {
555+ let mut data = RangeMetadata :: default ( ) ;
547556 // open the file
548557 let mut file = match tokio:: fs:: File :: open ( path_. clone ( ) ) . await {
549558 Ok ( file) => file,
550559 Err ( e) => {
551560 debug_eprintln ! ( "Failed to open asset: {}" , e) ;
552- return ( headers, 404 , buf) ;
561+ data. status_code = 404 ;
562+ return data;
553563 }
554564 } ;
555565 // Get the file size
556566 let file_size = match file. metadata ( ) . await {
557- Ok ( metadata) => metadata. len ( ) ,
567+ Ok ( metadata) => {
568+ let len = metadata. len ( ) ;
569+ data. metadata . replace ( metadata) ;
570+ len
571+ }
558572 Err ( e) => {
559573 debug_eprintln ! ( "Failed to read asset metadata: {}" , e) ;
560- return ( headers, 404 , buf) ;
574+ data. file . replace ( file) ;
575+ data. status_code = 404 ;
576+ return data;
561577 }
562578 } ;
563579 // parse the range
@@ -572,13 +588,16 @@ impl<R: Runtime> WindowManager<R> {
572588 Ok ( r) => r,
573589 Err ( e) => {
574590 debug_eprintln ! ( "Failed to parse range {}: {:?}" , range, e) ;
575- return ( headers, 400 , buf) ;
591+ data. file . replace ( file) ;
592+ data. status_code = 400 ;
593+ return data;
576594 }
577595 } ;
578596
579597 // FIXME: Support multiple ranges
580598 // let support only 1 range for now
581- let status_code = if let Some ( range) = range. first ( ) {
599+ if let Some ( range) = range. first ( ) {
600+ data. range . replace ( * range) ;
582601 let mut real_length = range. length ;
583602 // prevent max_length;
584603 // specially on webview2
@@ -592,38 +611,84 @@ impl<R: Runtime> WindowManager<R> {
592611 // who should be skipped on the header
593612 let last_byte = range. start + real_length - 1 ;
594613
595- headers. insert ( "Connection" , "Keep-Alive" . into ( ) ) ;
596- headers. insert ( "Accept-Ranges" , "bytes" . into ( ) ) ;
597- headers. insert ( "Content-Length" , real_length. to_string ( ) ) ;
598- headers. insert (
614+ data. headers . insert ( "Connection" , "Keep-Alive" . into ( ) ) ;
615+ data. headers . insert ( "Accept-Ranges" , "bytes" . into ( ) ) ;
616+ data
617+ . headers
618+ . insert ( "Content-Length" , real_length. to_string ( ) ) ;
619+ data. headers . insert (
599620 "Content-Range" ,
600621 format ! ( "bytes {}-{}/{}" , range. start, last_byte, file_size) ,
601622 ) ;
602623
603624 if let Err ( e) = file. seek ( std:: io:: SeekFrom :: Start ( range. start ) ) . await {
604625 debug_eprintln ! ( "Failed to seek file to {}: {}" , range. start, e) ;
605- return ( headers, 422 , buf) ;
626+ data. file . replace ( file) ;
627+ data. status_code = 422 ;
628+ return data;
606629 }
607630
608- if let Err ( e) = file. take ( real_length) . read_to_end ( & mut buf) . await {
631+ let mut f = file. take ( real_length) ;
632+ let r = f. read_to_end ( & mut data. body ) . await ;
633+ file = f. into_inner ( ) ;
634+ data. file . replace ( file) ;
635+
636+ if let Err ( e) = r {
609637 debug_eprintln ! ( "Failed read file: {}" , e) ;
610- return ( headers, 422 , buf) ;
638+ data. status_code = 422 ;
639+ return data;
611640 }
612641 // partial content
613- 206
642+ data . status_code = 206 ;
614643 } else {
615- 200
616- } ;
644+ data . status_code = 200 ;
645+ }
617646
618- ( headers , status_code , buf )
647+ data
619648 } ) ;
620649
621- for ( k, v) in headers {
650+ for ( k, v) in range_metadata . headers {
622651 response = response. header ( k, v) ;
623652 }
624653
625- let mime_type = MimeType :: parse ( & data, & path) ;
626- response. mimetype ( & mime_type) . status ( status_code) . body ( data)
654+ let mime_type = if let ( Some ( mut file) , Some ( metadata) , Some ( range) ) = (
655+ range_metadata. file ,
656+ range_metadata. metadata ,
657+ range_metadata. range ,
658+ ) {
659+ // if we're already reading the beginning of the file, we do not need to re-read it
660+ if range. start == 0 {
661+ MimeType :: parse ( & range_metadata. body , & path)
662+ } else {
663+ let ( status, bytes) = crate :: async_runtime:: safe_block_on ( async move {
664+ let mut status = None ;
665+ if let Err ( e) = file. rewind ( ) . await {
666+ debug_eprintln ! ( "Failed to rewind file: {}" , e) ;
667+ status. replace ( 422 ) ;
668+ ( status, Vec :: with_capacity ( 0 ) )
669+ } else {
670+ // taken from https://docs.rs/infer/0.9.0/src/infer/lib.rs.html#240-251
671+ let limit = std:: cmp:: min ( metadata. len ( ) , 8192 ) as usize + 1 ;
672+ let mut bytes = Vec :: with_capacity ( limit) ;
673+ if let Err ( e) = file. take ( 8192 ) . read_to_end ( & mut bytes) . await {
674+ debug_eprintln ! ( "Failed read file: {}" , e) ;
675+ status. replace ( 422 ) ;
676+ }
677+ ( status, bytes)
678+ }
679+ } ) ;
680+ if let Some ( s) = status {
681+ range_metadata. status_code = s;
682+ }
683+ MimeType :: parse ( & bytes, & path)
684+ }
685+ } else {
686+ MimeType :: parse ( & range_metadata. body , & path)
687+ } ;
688+ response
689+ . mimetype ( & mime_type)
690+ . status ( range_metadata. status_code )
691+ . body ( range_metadata. body )
627692 } else {
628693 match crate :: async_runtime:: safe_block_on ( async move { tokio:: fs:: read ( path_) . await } ) {
629694 Ok ( data) => {
0 commit comments