@@ -59,6 +59,11 @@ type PooledStream = TlsStream<TcpStream>;
5959const POOL_TTL_SECS : u64 = 45 ;
6060const POOL_MAX : usize = 80 ;
6161const REQUEST_TIMEOUT_SECS : u64 = 25 ;
62+ const RANGE_PARALLEL_CHUNK_BYTES : u64 = 256 * 1024 ;
63+ // Keep synthetic range stitching bounded. Without this, a buggy or hostile
64+ // origin can advertise `Content-Range: bytes 0-1/<huge>` and make us build a
65+ // massive range plan or preallocate an enormous response buffer.
66+ const MAX_STITCHED_RANGE_BYTES : u64 = 64 * 1024 * 1024 ;
6267
6368struct PoolEntry {
6469 stream : PooledStream ,
@@ -648,8 +653,8 @@ impl DomainFronter {
648653 headers : & [ ( String , String ) ] ,
649654 body : & [ u8 ] ,
650655 ) -> Vec < u8 > {
651- const CHUNK : u64 = 256 * 1024 ;
652656 const MAX_PARALLEL : usize = 16 ;
657+ let chunk = RANGE_PARALLEL_CHUNK_BYTES ;
653658
654659 if method != "GET" || !body. is_empty ( ) {
655660 return self . relay ( method, url, headers, body) . await ;
@@ -662,7 +667,7 @@ impl DomainFronter {
662667
663668 // Probe with the first chunk.
664669 let mut probe_headers: Vec < ( String , String ) > = headers. to_vec ( ) ;
665- probe_headers. push ( ( "Range" . into ( ) , format ! ( "bytes=0-{}" , CHUNK - 1 ) ) ) ;
670+ probe_headers. push ( ( "Range" . into ( ) , format ! ( "bytes=0-{}" , chunk - 1 ) ) ) ;
666671 let first = self . relay ( method, url, & probe_headers, body) . await ;
667672
668673 let ( status, resp_headers, resp_body) = match split_response ( & first) {
@@ -676,7 +681,7 @@ impl DomainFronter {
676681 return first;
677682 }
678683
679- let probe_range = match validate_probe_range ( status, & resp_headers, resp_body, CHUNK - 1 )
684+ let probe_range = match validate_probe_range ( status, & resp_headers, resp_body, chunk - 1 )
680685 {
681686 Some ( r) => r,
682687 None => {
@@ -689,15 +694,27 @@ impl DomainFronter {
689694 } ;
690695 let total = probe_range. total ;
691696
692- if total <= CHUNK || ( probe_range. end + 1 ) >= total {
697+ if total <= chunk || ( probe_range. end + 1 ) >= total {
693698 return rewrite_206_to_200 ( & first) ;
694699 }
695700
701+ let total_usize = match checked_stitched_range_capacity ( total) {
702+ Some ( v) => v,
703+ None => {
704+ tracing:: warn!(
705+ "range-parallel: Content-Range total {} for {} is too large; falling back to single GET" ,
706+ total,
707+ url,
708+ ) ;
709+ return self . relay ( method, url, headers, body) . await ;
710+ }
711+ } ;
712+
696713 // Plan remaining ranges after what the probe already returned.
697714 let mut ranges: Vec < ( u64 , u64 ) > = Vec :: new ( ) ;
698715 let mut start = probe_range. end + 1 ;
699716 while start < total {
700- let end = ( start + CHUNK - 1 ) . min ( total - 1 ) ;
717+ let end = ( start + chunk - 1 ) . min ( total - 1 ) ;
701718 ranges. push ( ( start, end) ) ;
702719 start = end + 1 ;
703720 }
@@ -734,7 +751,7 @@ impl DomainFronter {
734751 . await ;
735752
736753 // Stitch: probe body first, then the chunks in order.
737- let mut full = Vec :: with_capacity ( total as usize ) ;
754+ let mut full = Vec :: with_capacity ( total_usize ) ;
738755 full. extend_from_slice ( resp_body) ;
739756 for ( start, end, chunk) in fetches {
740757 match chunk {
@@ -1374,6 +1391,13 @@ fn validate_probe_range(
13741391 Some ( range)
13751392}
13761393
1394+ fn checked_stitched_range_capacity ( total : u64 ) -> Option < usize > {
1395+ if total > MAX_STITCHED_RANGE_BYTES {
1396+ return None ;
1397+ }
1398+ usize:: try_from ( total) . ok ( )
1399+ }
1400+
13771401fn extract_exact_range_body (
13781402 raw : & [ u8 ] ,
13791403 start : u64 ,
@@ -2402,6 +2426,16 @@ mod tests {
24022426 assert ! ( validate_probe_range( 206 , & headers, b"hey" , 4 ) . is_none( ) ) ;
24032427 }
24042428
2429+ #[ test]
2430+ fn stitched_range_capacity_rejects_absurd_total ( ) {
2431+ assert_eq ! (
2432+ checked_stitched_range_capacity( MAX_STITCHED_RANGE_BYTES ) ,
2433+ Some ( MAX_STITCHED_RANGE_BYTES as usize ) ,
2434+ ) ;
2435+ assert_eq ! ( checked_stitched_range_capacity( MAX_STITCHED_RANGE_BYTES + 1 ) , None ) ;
2436+ assert_eq ! ( checked_stitched_range_capacity( u64 :: MAX ) , None ) ;
2437+ }
2438+
24052439 #[ test]
24062440 fn extract_exact_range_body_rejects_mismatched_content_range ( ) {
24072441 let raw = b"HTTP/1.1 206 Partial Content\r \n \
0 commit comments