@@ -3,7 +3,7 @@ use axum::{
3
3
body:: { self , Body , HttpBody } ,
4
4
error_handling:: HandleErrorLayer ,
5
5
extract:: { Extension , Path , Query } ,
6
- http:: { header:: * , StatusCode } ,
6
+ http:: { header:: * , Request as HttpRequest , StatusCode } ,
7
7
response:: IntoResponse ,
8
8
routing:: get,
9
9
BoxError , Router ,
@@ -28,6 +28,7 @@ use std::{
28
28
collections:: HashMap ,
29
29
error:: Error ,
30
30
fmt:: Write ,
31
+ ops:: Range ,
31
32
sync:: Arc ,
32
33
time:: { self , Duration } ,
33
34
} ;
@@ -121,6 +122,7 @@ pub async fn get_handler<T: ContentLoader + std::marker::Unpin>(
121
122
Path ( params) : Path < HashMap < String , String > > ,
122
123
Query ( query_params) : Query < GetParams > ,
123
124
method : http:: Method ,
125
+ http_req : HttpRequest < Body > ,
124
126
request_headers : HeaderMap ,
125
127
) -> Result < GatewayResponse , GatewayError > {
126
128
inc ! ( GatewayMetrics :: Requests ) ;
@@ -159,6 +161,7 @@ pub async fn get_handler<T: ContentLoader + std::marker::Unpin>(
159
161
. parse ( )
160
162
. map_err ( |e : anyhow:: Error | e. to_string ( ) )
161
163
. map_err ( |e| error ( StatusCode :: BAD_REQUEST , & e, & state) ) ?;
164
+ // TODO: handle 404 or error
162
165
let resolved_cid = resolved_path. root ( ) ;
163
166
164
167
if handle_only_if_cached ( & request_headers, & state, resolved_cid) . await ? {
@@ -220,9 +223,9 @@ pub async fn get_handler<T: ContentLoader + std::marker::Unpin>(
220
223
serve_car_recursive ( & req, state, headers, start_time) . await
221
224
} else {
222
225
match req. format {
223
- ResponseFormat :: Raw => serve_raw ( & req, state, headers, start_time) . await ,
226
+ ResponseFormat :: Raw => serve_raw ( & req, state, headers, & http_req , start_time) . await ,
224
227
ResponseFormat :: Car => serve_car ( & req, state, headers, start_time) . await ,
225
- ResponseFormat :: Fs ( _) => serve_fs ( & req, state, headers, start_time) . await ,
228
+ ResponseFormat :: Fs ( _) => serve_fs ( & req, state, headers, & http_req , start_time) . await ,
226
229
}
227
230
}
228
231
}
@@ -404,12 +407,18 @@ async fn serve_raw<T: ContentLoader + std::marker::Unpin>(
404
407
req : & Request ,
405
408
state : Arc < State < T > > ,
406
409
mut headers : HeaderMap ,
410
+ http_req : & HttpRequest < Body > ,
407
411
start_time : std:: time:: Instant ,
408
412
) -> Result < GatewayResponse , GatewayError > {
413
+ let range: Option < Range < u64 > > = if http_req. headers ( ) . contains_key ( RANGE ) {
414
+ parse_range_header ( http_req. headers ( ) . get ( RANGE ) . unwrap ( ) )
415
+ } else {
416
+ None
417
+ } ;
409
418
// FIXME: we currently only retrieve full cids
410
419
let ( body, metadata) = state
411
420
. client
412
- . get_file ( req. resolved_path . clone ( ) , start_time)
421
+ . get_file ( req. resolved_path . clone ( ) , start_time, range . clone ( ) )
413
422
. await
414
423
. map_err ( |e| error ( StatusCode :: INTERNAL_SERVER_ERROR , & e, & state) ) ?;
415
424
@@ -423,8 +432,18 @@ async fn serve_raw<T: ContentLoader + std::marker::Unpin>(
423
432
set_content_disposition_headers ( & mut headers, & file_name, DISPOSITION_ATTACHMENT ) ;
424
433
set_etag_headers ( & mut headers, get_etag ( & req. cid , Some ( req. format . clone ( ) ) ) ) ;
425
434
add_cache_control_headers ( & mut headers, metadata. clone ( ) ) ;
426
- add_ipfs_roots_headers ( & mut headers, metadata) ;
427
- response ( StatusCode :: OK , body, headers)
435
+ add_ipfs_roots_headers ( & mut headers, metadata. clone ( ) ) ;
436
+
437
+ if let Some ( mut capped_range) = range {
438
+ if let Some ( size) = metadata. size {
439
+ capped_range. end = std:: cmp:: min ( capped_range. end , size) ;
440
+ }
441
+ add_etag_range ( & mut headers, capped_range. clone ( ) ) ;
442
+ add_content_range_headers ( & mut headers, capped_range, metadata. size ) ;
443
+ response ( StatusCode :: PARTIAL_CONTENT , body, headers)
444
+ } else {
445
+ response ( StatusCode :: OK , body, headers)
446
+ }
428
447
}
429
448
FileResult :: Directory ( _) => Err ( error (
430
449
StatusCode :: INTERNAL_SERVER_ERROR ,
@@ -445,7 +464,7 @@ async fn serve_car<T: ContentLoader + std::marker::Unpin>(
445
464
// FIXME: we currently only retrieve full cids
446
465
let ( body, metadata) = state
447
466
. client
448
- . get_file ( req. resolved_path . clone ( ) , start_time)
467
+ . get_file ( req. resolved_path . clone ( ) , start_time, None )
449
468
. await
450
469
. map_err ( |e| error ( StatusCode :: INTERNAL_SERVER_ERROR , & e, & state) ) ?;
451
470
@@ -509,12 +528,19 @@ async fn serve_fs<T: ContentLoader + std::marker::Unpin>(
509
528
req : & Request ,
510
529
state : Arc < State < T > > ,
511
530
mut headers : HeaderMap ,
531
+ http_req : & HttpRequest < Body > ,
512
532
start_time : std:: time:: Instant ,
513
533
) -> Result < GatewayResponse , GatewayError > {
534
+ let range: Option < Range < u64 > > = if http_req. headers ( ) . contains_key ( RANGE ) {
535
+ parse_range_header ( http_req. headers ( ) . get ( RANGE ) . unwrap ( ) )
536
+ } else {
537
+ None
538
+ } ;
539
+
514
540
// FIXME: we currently only retrieve full cids
515
541
let ( body, metadata) = state
516
542
. client
517
- . get_file ( req. resolved_path . clone ( ) , start_time)
543
+ . get_file ( req. resolved_path . clone ( ) , start_time, range . clone ( ) )
518
544
. await
519
545
. map_err ( |e| error ( StatusCode :: INTERNAL_SERVER_ERROR , & e, & state) ) ?;
520
546
@@ -528,7 +554,9 @@ async fn serve_fs<T: ContentLoader + std::marker::Unpin>(
528
554
. try_collect ( )
529
555
. await ;
530
556
match dir_list {
531
- Ok ( dir_list) => serve_fs_dir ( & dir_list, req, state, headers, start_time) . await ,
557
+ Ok ( dir_list) => {
558
+ serve_fs_dir ( & dir_list, req, state, headers, http_req, start_time) . await
559
+ }
532
560
Err ( e) => {
533
561
tracing:: warn!( "failed to read dir: {:?}" , e) ;
534
562
Err ( error (
@@ -561,7 +589,17 @@ async fn serve_fs<T: ContentLoader + std::marker::Unpin>(
561
589
let content_sniffed_mime = body. get_mime ( ) ;
562
590
add_content_type_headers ( & mut headers, & name, content_sniffed_mime) ;
563
591
}
564
- response ( StatusCode :: OK , body, headers)
592
+
593
+ if let Some ( mut capped_range) = range {
594
+ if let Some ( size) = metadata. size {
595
+ capped_range. end = std:: cmp:: min ( capped_range. end , size) ;
596
+ }
597
+ add_etag_range ( & mut headers, capped_range. clone ( ) ) ;
598
+ add_content_range_headers ( & mut headers, capped_range, metadata. size ) ;
599
+ response ( StatusCode :: PARTIAL_CONTENT , body, headers)
600
+ } else {
601
+ response ( StatusCode :: OK , body, headers)
602
+ }
565
603
}
566
604
None => Err ( error (
567
605
StatusCode :: BAD_REQUEST ,
@@ -594,6 +632,7 @@ async fn serve_fs_dir<T: ContentLoader + std::marker::Unpin>(
594
632
req : & Request ,
595
633
state : Arc < State < T > > ,
596
634
mut headers : HeaderMap ,
635
+ http_req : & HttpRequest < Body > ,
597
636
start_time : std:: time:: Instant ,
598
637
) -> Result < GatewayResponse , GatewayError > {
599
638
let force_dir = req. query_params . force_dir . unwrap_or ( false ) ;
@@ -614,7 +653,7 @@ async fn serve_fs_dir<T: ContentLoader + std::marker::Unpin>(
614
653
}
615
654
let mut new_req = req. clone ( ) ;
616
655
new_req. resolved_path . push ( "index.html" ) ;
617
- return serve_fs ( & new_req, state, headers, start_time) . await ;
656
+ return serve_fs ( & new_req, state, headers, http_req , start_time) . await ;
618
657
}
619
658
620
659
headers. insert ( CONTENT_TYPE , HeaderValue :: from_str ( "text/html" ) . unwrap ( ) ) ;
0 commit comments