@@ -541,23 +541,39 @@ impl<R: Runtime> WindowManager<R> {
541
541
. get ( "range" )
542
542
. and_then ( |r| r. to_str ( ) . map ( |r| r. to_string ( ) ) . ok ( ) )
543
543
{
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 ( ) ;
547
556
// open the file
548
557
let mut file = match tokio:: fs:: File :: open ( path_. clone ( ) ) . await {
549
558
Ok ( file) => file,
550
559
Err ( e) => {
551
560
debug_eprintln ! ( "Failed to open asset: {}" , e) ;
552
- return ( headers, 404 , buf) ;
561
+ data. status_code = 404 ;
562
+ return data;
553
563
}
554
564
} ;
555
565
// Get the file size
556
566
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
+ }
558
572
Err ( e) => {
559
573
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;
561
577
}
562
578
} ;
563
579
// parse the range
@@ -572,13 +588,16 @@ impl<R: Runtime> WindowManager<R> {
572
588
Ok ( r) => r,
573
589
Err ( e) => {
574
590
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;
576
594
}
577
595
} ;
578
596
579
597
// FIXME: Support multiple ranges
580
598
// 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) ;
582
601
let mut real_length = range. length ;
583
602
// prevent max_length;
584
603
// specially on webview2
@@ -592,38 +611,84 @@ impl<R: Runtime> WindowManager<R> {
592
611
// who should be skipped on the header
593
612
let last_byte = range. start + real_length - 1 ;
594
613
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 (
599
620
"Content-Range" ,
600
621
format ! ( "bytes {}-{}/{}" , range. start, last_byte, file_size) ,
601
622
) ;
602
623
603
624
if let Err ( e) = file. seek ( std:: io:: SeekFrom :: Start ( range. start ) ) . await {
604
625
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;
606
629
}
607
630
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 {
609
637
debug_eprintln ! ( "Failed read file: {}" , e) ;
610
- return ( headers, 422 , buf) ;
638
+ data. status_code = 422 ;
639
+ return data;
611
640
}
612
641
// partial content
613
- 206
642
+ data . status_code = 206 ;
614
643
} else {
615
- 200
616
- } ;
644
+ data . status_code = 200 ;
645
+ }
617
646
618
- ( headers , status_code , buf )
647
+ data
619
648
} ) ;
620
649
621
- for ( k, v) in headers {
650
+ for ( k, v) in range_metadata . headers {
622
651
response = response. header ( k, v) ;
623
652
}
624
653
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 )
627
692
} else {
628
693
match crate :: async_runtime:: safe_block_on ( async move { tokio:: fs:: read ( path_) . await } ) {
629
694
Ok ( data) => {
0 commit comments