@@ -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 ,
@@ -27,6 +27,7 @@ use std::{
27
27
collections:: HashMap ,
28
28
error:: Error ,
29
29
fmt:: Write ,
30
+ ops:: Range ,
30
31
sync:: Arc ,
31
32
time:: { self , Duration } ,
32
33
} ;
@@ -117,6 +118,7 @@ pub async fn get_handler<T: ContentLoader + std::marker::Unpin>(
117
118
Path ( params) : Path < HashMap < String , String > > ,
118
119
Query ( query_params) : Query < GetParams > ,
119
120
method : http:: Method ,
121
+ http_req : HttpRequest < Body > ,
120
122
request_headers : HeaderMap ,
121
123
) -> Result < GatewayResponse , GatewayError > {
122
124
inc ! ( GatewayMetrics :: Requests ) ;
@@ -155,6 +157,7 @@ pub async fn get_handler<T: ContentLoader + std::marker::Unpin>(
155
157
. parse ( )
156
158
. map_err ( |e : anyhow:: Error | e. to_string ( ) )
157
159
. map_err ( |e| error ( StatusCode :: BAD_REQUEST , & e, & state) ) ?;
160
+ // TODO: handle 404 or error
158
161
let resolved_cid = resolved_path. root ( ) ;
159
162
160
163
if handle_only_if_cached ( & request_headers, & state, resolved_cid) . await ? {
@@ -216,9 +219,9 @@ pub async fn get_handler<T: ContentLoader + std::marker::Unpin>(
216
219
serve_car_recursive ( & req, state, headers, start_time) . await
217
220
} else {
218
221
match req. format {
219
- ResponseFormat :: Raw => serve_raw ( & req, state, headers, start_time) . await ,
222
+ ResponseFormat :: Raw => serve_raw ( & req, state, headers, & http_req , start_time) . await ,
220
223
ResponseFormat :: Car => serve_car ( & req, state, headers, start_time) . await ,
221
- ResponseFormat :: Fs ( _) => serve_fs ( & req, state, headers, start_time) . await ,
224
+ ResponseFormat :: Fs ( _) => serve_fs ( & req, state, headers, & http_req , start_time) . await ,
222
225
}
223
226
}
224
227
}
@@ -382,12 +385,18 @@ async fn serve_raw<T: ContentLoader + std::marker::Unpin>(
382
385
req : & Request ,
383
386
state : Arc < State < T > > ,
384
387
mut headers : HeaderMap ,
388
+ http_req : & HttpRequest < Body > ,
385
389
start_time : std:: time:: Instant ,
386
390
) -> Result < GatewayResponse , GatewayError > {
391
+ let range: Option < Range < u64 > > = if http_req. headers ( ) . contains_key ( RANGE ) {
392
+ parse_range_header ( http_req. headers ( ) . get ( RANGE ) . unwrap ( ) )
393
+ } else {
394
+ None
395
+ } ;
387
396
// FIXME: we currently only retrieve full cids
388
397
let ( body, metadata) = state
389
398
. client
390
- . get_file ( req. resolved_path . clone ( ) , start_time)
399
+ . get_file ( req. resolved_path . clone ( ) , start_time, None )
391
400
. await
392
401
. map_err ( |e| error ( StatusCode :: INTERNAL_SERVER_ERROR , & e, & state) ) ?;
393
402
@@ -401,8 +410,18 @@ async fn serve_raw<T: ContentLoader + std::marker::Unpin>(
401
410
set_content_disposition_headers ( & mut headers, & file_name, DISPOSITION_ATTACHMENT ) ;
402
411
set_etag_headers ( & mut headers, get_etag ( & req. cid , Some ( req. format . clone ( ) ) ) ) ;
403
412
add_cache_control_headers ( & mut headers, metadata. clone ( ) ) ;
404
- add_ipfs_roots_headers ( & mut headers, metadata) ;
405
- response ( StatusCode :: OK , body, headers)
413
+ add_ipfs_roots_headers ( & mut headers, metadata. clone ( ) ) ;
414
+
415
+ if let Some ( mut capped_range) = range {
416
+ if let Some ( size) = metadata. size {
417
+ capped_range. end = std:: cmp:: min ( capped_range. end , size) ;
418
+ }
419
+ add_etag_range ( & mut headers, capped_range. clone ( ) ) ;
420
+ add_content_range_headers ( & mut headers, capped_range, metadata. size ) ;
421
+ response ( StatusCode :: PARTIAL_CONTENT , body, headers)
422
+ } else {
423
+ response ( StatusCode :: OK , body, headers)
424
+ }
406
425
}
407
426
FileResult :: Directory ( _) => Err ( error (
408
427
StatusCode :: INTERNAL_SERVER_ERROR ,
@@ -423,7 +442,7 @@ async fn serve_car<T: ContentLoader + std::marker::Unpin>(
423
442
// FIXME: we currently only retrieve full cids
424
443
let ( body, metadata) = state
425
444
. client
426
- . get_file ( req. resolved_path . clone ( ) , start_time)
445
+ . get_file ( req. resolved_path . clone ( ) , start_time, None )
427
446
. await
428
447
. map_err ( |e| error ( StatusCode :: INTERNAL_SERVER_ERROR , & e, & state) ) ?;
429
448
@@ -487,12 +506,19 @@ async fn serve_fs<T: ContentLoader + std::marker::Unpin>(
487
506
req : & Request ,
488
507
state : Arc < State < T > > ,
489
508
mut headers : HeaderMap ,
509
+ http_req : & HttpRequest < Body > ,
490
510
start_time : std:: time:: Instant ,
491
511
) -> Result < GatewayResponse , GatewayError > {
512
+ let range: Option < Range < u64 > > = if http_req. headers ( ) . contains_key ( RANGE ) {
513
+ parse_range_header ( http_req. headers ( ) . get ( RANGE ) . unwrap ( ) )
514
+ } else {
515
+ None
516
+ } ;
517
+
492
518
// FIXME: we currently only retrieve full cids
493
519
let ( body, metadata) = state
494
520
. client
495
- . get_file ( req. resolved_path . clone ( ) , start_time)
521
+ . get_file ( req. resolved_path . clone ( ) , start_time, range . clone ( ) )
496
522
. await
497
523
. map_err ( |e| error ( StatusCode :: INTERNAL_SERVER_ERROR , & e, & state) ) ?;
498
524
@@ -506,7 +532,9 @@ async fn serve_fs<T: ContentLoader + std::marker::Unpin>(
506
532
. try_collect ( )
507
533
. await ;
508
534
match dir_list {
509
- Ok ( dir_list) => serve_fs_dir ( & dir_list, req, state, headers, start_time) . await ,
535
+ Ok ( dir_list) => {
536
+ serve_fs_dir ( & dir_list, req, state, headers, http_req, start_time) . await
537
+ }
510
538
Err ( e) => {
511
539
tracing:: warn!( "failed to read dir: {:?}" , e) ;
512
540
Err ( error (
@@ -539,7 +567,17 @@ async fn serve_fs<T: ContentLoader + std::marker::Unpin>(
539
567
let body_sample = body. get_sample ( ) ;
540
568
add_content_type_headers ( & mut headers, & name, body_sample. as_slice ( ) ) ;
541
569
}
542
- response ( StatusCode :: OK , body, headers)
570
+
571
+ if let Some ( mut capped_range) = range {
572
+ if let Some ( size) = metadata. size {
573
+ capped_range. end = std:: cmp:: min ( capped_range. end , size) ;
574
+ }
575
+ add_etag_range ( & mut headers, capped_range. clone ( ) ) ;
576
+ add_content_range_headers ( & mut headers, capped_range, metadata. size ) ;
577
+ response ( StatusCode :: PARTIAL_CONTENT , body, headers)
578
+ } else {
579
+ response ( StatusCode :: OK , body, headers)
580
+ }
543
581
}
544
582
None => Err ( error (
545
583
StatusCode :: BAD_REQUEST ,
@@ -557,6 +595,7 @@ async fn serve_fs_dir<T: ContentLoader + std::marker::Unpin>(
557
595
req : & Request ,
558
596
state : Arc < State < T > > ,
559
597
mut headers : HeaderMap ,
598
+ http_req : & HttpRequest < Body > ,
560
599
start_time : std:: time:: Instant ,
561
600
) -> Result < GatewayResponse , GatewayError > {
562
601
let force_dir = req. query_params . force_dir . unwrap_or ( false ) ;
@@ -577,7 +616,7 @@ async fn serve_fs_dir<T: ContentLoader + std::marker::Unpin>(
577
616
}
578
617
let mut new_req = req. clone ( ) ;
579
618
new_req. resolved_path . push ( "index.html" ) ;
580
- return serve_fs ( & new_req, state, headers, start_time) . await ;
619
+ return serve_fs ( & new_req, state, headers, http_req , start_time) . await ;
581
620
}
582
621
583
622
headers. insert ( CONTENT_TYPE , HeaderValue :: from_str ( "text/html" ) . unwrap ( ) ) ;
0 commit comments