1use serde::{Deserialize, Serialize};
35use std::fmt;
36use thiserror::Error;
37
38const DEFAULT_CHUNK_SIZE: u64 = 256 * 1024;
40
41#[derive(Debug, Error)]
43pub enum RangeError {
44 #[error("Invalid range syntax: {0}")]
45 InvalidSyntax(String),
46
47 #[error("Range not satisfiable: {0}")]
48 NotSatisfiable(String),
49
50 #[error("Invalid range bounds: start={0}, end={1}")]
51 InvalidBounds(u64, u64),
52
53 #[error("Range exceeds content length: {0} > {1}")]
54 ExceedsContent(u64, u64),
55}
56
57#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
59pub struct ByteRange {
60 pub start: u64,
62 pub end: Option<u64>,
64}
65
66impl ByteRange {
67 #[must_use]
69 pub const fn new(start: u64, end: Option<u64>) -> Self {
70 Self { start, end }
71 }
72
73 #[must_use]
75 pub const fn from_to(start: u64, end: u64) -> Self {
76 Self {
77 start,
78 end: Some(end),
79 }
80 }
81
82 #[must_use]
84 pub const fn from_start(start: u64) -> Self {
85 Self { start, end: None }
86 }
87
88 #[must_use]
90 pub const fn suffix(count: u64) -> Self {
91 Self {
92 start: 0,
93 end: Some(count),
94 }
95 }
96
97 pub fn normalize(&self, content_length: u64) -> Result<(u64, u64), RangeError> {
99 let start = self.start;
100 let end = self.end.unwrap_or(content_length.saturating_sub(1));
101
102 if start > end {
104 return Err(RangeError::InvalidBounds(start, end));
105 }
106
107 if end >= content_length {
108 return Err(RangeError::ExceedsContent(end, content_length));
109 }
110
111 Ok((start, end))
112 }
113
114 #[must_use]
116 pub const fn length(&self) -> u64 {
117 match self.end {
118 Some(end) => end.saturating_sub(self.start) + 1,
119 None => u64::MAX, }
121 }
122}
123
124impl fmt::Display for ByteRange {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 write!(f, "bytes {}-", self.start)?;
127 if let Some(end) = self.end {
128 write!(f, "{end}")
129 } else {
130 write!(f, "*")
131 }
132 }
133}
134
135#[derive(Debug, Clone, Serialize, Deserialize)]
137pub struct RangeRequest {
138 pub ranges: Vec<ByteRange>,
140}
141
142impl RangeRequest {
143 #[must_use]
145 pub fn new(range: ByteRange) -> Self {
146 Self {
147 ranges: vec![range],
148 }
149 }
150
151 #[must_use]
153 pub fn multi(ranges: Vec<ByteRange>) -> Self {
154 Self { ranges }
155 }
156
157 pub fn parse(header: &str) -> Result<Self, RangeError> {
159 let header = header.trim();
160
161 if !header.starts_with("bytes=") {
163 return Err(RangeError::InvalidSyntax(
164 "Range must start with 'bytes='".to_string(),
165 ));
166 }
167
168 let range_str = &header[6..]; let mut ranges = Vec::new();
170
171 for part in range_str.split(',') {
173 let part = part.trim();
174
175 if part.is_empty() {
176 continue;
177 }
178
179 if let Some((start_str, end_str)) = part.split_once('-') {
181 let range = if start_str.is_empty() {
182 let count: u64 = end_str
184 .parse()
185 .map_err(|_| RangeError::InvalidSyntax(part.to_string()))?;
186 ByteRange::suffix(count)
187 } else if end_str.is_empty() {
188 let start: u64 = start_str
190 .parse()
191 .map_err(|_| RangeError::InvalidSyntax(part.to_string()))?;
192 ByteRange::from_start(start)
193 } else {
194 let start: u64 = start_str
196 .parse()
197 .map_err(|_| RangeError::InvalidSyntax(part.to_string()))?;
198 let end: u64 = end_str
199 .parse()
200 .map_err(|_| RangeError::InvalidSyntax(part.to_string()))?;
201 ByteRange::from_to(start, end)
202 };
203
204 ranges.push(range);
205 } else {
206 return Err(RangeError::InvalidSyntax(part.to_string()));
207 }
208 }
209
210 if ranges.is_empty() {
211 return Err(RangeError::InvalidSyntax(
212 "No valid ranges found".to_string(),
213 ));
214 }
215
216 Ok(Self { ranges })
217 }
218
219 #[must_use]
221 #[inline]
222 pub fn is_multi_range(&self) -> bool {
223 self.ranges.len() > 1
224 }
225
226 pub fn total_bytes(&self, content_length: u64) -> Result<u64, RangeError> {
228 let mut total = 0u64;
229 for range in &self.ranges {
230 let (start, end) = range.normalize(content_length)?;
231 total = total.saturating_add(end.saturating_sub(start) + 1);
232 }
233 Ok(total)
234 }
235}
236
237#[derive(Debug, Clone, PartialEq, Eq)]
239pub struct ChunkRange {
240 pub chunk_index: u64,
242 pub offset_in_chunk: u64,
244 pub length: u64,
246}
247
248pub struct RangeHandler {
250 content_length: u64,
252 chunk_size: u64,
254}
255
256impl RangeHandler {
257 #[must_use]
259 pub const fn new(content_length: u64, chunk_size: u64) -> Self {
260 Self {
261 content_length,
262 chunk_size,
263 }
264 }
265
266 #[must_use]
268 pub const fn with_default_chunk_size(content_length: u64) -> Self {
269 Self::new(content_length, DEFAULT_CHUNK_SIZE)
270 }
271
272 pub fn get_required_chunks(
274 &self,
275 request: &RangeRequest,
276 ) -> Result<Vec<ChunkRange>, RangeError> {
277 let mut chunk_ranges = Vec::new();
278
279 for range in &request.ranges {
280 let (start, end) = range.normalize(self.content_length)?;
281
282 let start_chunk = start / self.chunk_size;
284 let end_chunk = end / self.chunk_size;
285
286 for chunk_idx in start_chunk..=end_chunk {
287 let chunk_start = chunk_idx * self.chunk_size;
288 let chunk_end = ((chunk_idx + 1) * self.chunk_size).min(self.content_length) - 1;
289
290 let read_start = start.max(chunk_start);
292 let read_end = end.min(chunk_end);
293
294 let offset_in_chunk = read_start - chunk_start;
295 let length = read_end - read_start + 1;
296
297 chunk_ranges.push(ChunkRange {
298 chunk_index: chunk_idx,
299 offset_in_chunk,
300 length,
301 });
302 }
303 }
304
305 Ok(chunk_ranges)
306 }
307
308 #[must_use]
310 pub fn content_range_header(&self, start: u64, end: u64) -> String {
311 format!("bytes {start}-{end}/{}", self.content_length)
312 }
313
314 #[must_use]
316 #[inline]
317 pub fn is_satisfiable(&self, request: &RangeRequest) -> bool {
318 request
319 .ranges
320 .iter()
321 .all(|r| r.normalize(self.content_length).is_ok())
322 }
323
324 #[must_use]
326 #[inline]
327 pub const fn content_length(&self) -> u64 {
328 self.content_length
329 }
330
331 #[must_use]
333 #[inline]
334 pub const fn chunk_size(&self) -> u64 {
335 self.chunk_size
336 }
337}
338
339#[derive(Debug, Clone)]
341pub struct PartialResponse {
342 pub status_code: u16,
344 pub content_range: Option<String>,
346 pub content_length: u64,
348 pub data: Vec<u8>,
350}
351
352impl PartialResponse {
353 #[must_use]
355 pub fn partial_content(content_range: String, data: Vec<u8>) -> Self {
356 let content_length = data.len() as u64;
357 Self {
358 status_code: 206,
359 content_range: Some(content_range),
360 content_length,
361 data,
362 }
363 }
364
365 #[must_use]
367 pub fn not_satisfiable(total_length: u64) -> Self {
368 Self {
369 status_code: 416,
370 content_range: Some(format!("bytes */{total_length}")),
371 content_length: 0,
372 data: Vec::new(),
373 }
374 }
375
376 #[must_use]
378 pub fn full_content(data: Vec<u8>) -> Self {
379 let content_length = data.len() as u64;
380 Self {
381 status_code: 200,
382 content_range: None,
383 content_length,
384 data,
385 }
386 }
387}
388
389#[cfg(test)]
390mod tests {
391 use super::*;
392
393 #[test]
394 fn test_byte_range_new() {
395 let range = ByteRange::new(0, Some(1023));
396 assert_eq!(range.start, 0);
397 assert_eq!(range.end, Some(1023));
398 }
399
400 #[test]
401 fn test_byte_range_normalize() {
402 let range = ByteRange::from_to(0, 1023);
403 let (start, end) = range.normalize(10_000).unwrap();
404 assert_eq!(start, 0);
405 assert_eq!(end, 1023);
406
407 let range = ByteRange::from_to(0, 20_000);
409 assert!(range.normalize(10_000).is_err());
410 }
411
412 #[test]
413 fn test_byte_range_length() {
414 let range = ByteRange::from_to(0, 1023);
415 assert_eq!(range.length(), 1024);
416
417 let range = ByteRange::from_start(1000);
418 assert_eq!(range.length(), u64::MAX); }
420
421 #[test]
422 fn test_range_request_parse_simple() {
423 let request = RangeRequest::parse("bytes=0-1023").unwrap();
424 assert_eq!(request.ranges.len(), 1);
425 assert_eq!(request.ranges[0].start, 0);
426 assert_eq!(request.ranges[0].end, Some(1023));
427 }
428
429 #[test]
430 fn test_range_request_parse_open_ended() {
431 let request = RangeRequest::parse("bytes=1024-").unwrap();
432 assert_eq!(request.ranges.len(), 1);
433 assert_eq!(request.ranges[0].start, 1024);
434 assert_eq!(request.ranges[0].end, None);
435 }
436
437 #[test]
438 fn test_range_request_parse_suffix() {
439 let request = RangeRequest::parse("bytes=-500").unwrap();
440 assert_eq!(request.ranges.len(), 1);
441 assert_eq!(request.ranges[0].start, 0);
442 assert_eq!(request.ranges[0].end, Some(500));
443 }
444
445 #[test]
446 fn test_range_request_parse_multi() {
447 let request = RangeRequest::parse("bytes=0-1023,2048-3071").unwrap();
448 assert_eq!(request.ranges.len(), 2);
449 assert_eq!(request.ranges[0].start, 0);
450 assert_eq!(request.ranges[0].end, Some(1023));
451 assert_eq!(request.ranges[1].start, 2048);
452 assert_eq!(request.ranges[1].end, Some(3071));
453 }
454
455 #[test]
456 fn test_range_request_parse_invalid() {
457 assert!(RangeRequest::parse("invalid").is_err());
458 assert!(RangeRequest::parse("bytes=").is_err());
459 assert!(RangeRequest::parse("bytes=abc-def").is_err());
460 }
461
462 #[test]
463 fn test_range_handler_simple_range() {
464 let handler = RangeHandler::new(1_000_000, 256_000);
465 let request = RangeRequest::parse("bytes=0-255999").unwrap();
466 let chunks = handler.get_required_chunks(&request).unwrap();
467
468 assert_eq!(chunks.len(), 1);
469 assert_eq!(chunks[0].chunk_index, 0);
470 assert_eq!(chunks[0].offset_in_chunk, 0);
471 assert_eq!(chunks[0].length, 256_000);
472 }
473
474 #[test]
475 fn test_range_handler_multi_chunk() {
476 let handler = RangeHandler::new(1_000_000, 256_000);
477 let request = RangeRequest::parse("bytes=200000-600000").unwrap();
478 let chunks = handler.get_required_chunks(&request).unwrap();
479
480 assert_eq!(chunks.len(), 3);
482 assert_eq!(chunks[0].chunk_index, 0);
483 assert_eq!(chunks[1].chunk_index, 1);
484 assert_eq!(chunks[2].chunk_index, 2);
485 }
486
487 #[test]
488 fn test_range_handler_content_range_header() {
489 let handler = RangeHandler::new(1_000_000, 256_000);
490 let header = handler.content_range_header(0, 1023);
491 assert_eq!(header, "bytes 0-1023/1000000");
492 }
493
494 #[test]
495 fn test_range_handler_is_satisfiable() {
496 let handler = RangeHandler::new(1_000_000, 256_000);
497
498 let good_request = RangeRequest::parse("bytes=0-1023").unwrap();
499 assert!(handler.is_satisfiable(&good_request));
500
501 let bad_request = RangeRequest::parse("bytes=0-2000000").unwrap();
502 assert!(!handler.is_satisfiable(&bad_request));
503 }
504
505 #[test]
506 fn test_partial_response_partial_content() {
507 let data = vec![1u8, 2, 3, 4];
508 let response = PartialResponse::partial_content("bytes 0-3/100".to_string(), data);
509 assert_eq!(response.status_code, 206);
510 assert_eq!(response.content_length, 4);
511 assert_eq!(response.content_range.unwrap(), "bytes 0-3/100");
512 }
513
514 #[test]
515 fn test_partial_response_not_satisfiable() {
516 let response = PartialResponse::not_satisfiable(100);
517 assert_eq!(response.status_code, 416);
518 assert_eq!(response.content_range.unwrap(), "bytes */100");
519 }
520
521 #[test]
522 fn test_partial_response_full_content() {
523 let data = vec![1u8; 100];
524 let response = PartialResponse::full_content(data);
525 assert_eq!(response.status_code, 200);
526 assert_eq!(response.content_length, 100);
527 assert!(response.content_range.is_none());
528 }
529
530 #[test]
531 fn test_range_request_total_bytes() {
532 let request = RangeRequest::parse("bytes=0-1023,2048-3071").unwrap();
533 let total = request.total_bytes(10_000).unwrap();
534 assert_eq!(total, 2048); }
536}