1#[cfg(all(not(feature = "std"), feature = "alloc"))]
28use alloc::{
29 string::{String, ToString},
30 vec::Vec,
31};
32use core::{fmt, str::FromStr};
33#[cfg(feature = "serde")]
34use serde::{Deserialize, Serialize};
35
36#[derive(Debug, Clone, PartialEq, Eq)]
46#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
47#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
48#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
49pub enum ByteRange {
50 FromTo(u64, u64),
52 From(u64),
54 Suffix(u64),
56}
57
58impl ByteRange {
59 #[must_use]
76 pub fn is_valid(&self, length: u64) -> bool {
77 match self {
78 Self::FromTo(first, last) => first <= last && *first < length,
79 Self::From(first) => *first < length,
80 Self::Suffix(n) => *n > 0,
81 }
82 }
83
84 #[must_use]
97 pub fn resolve(&self, length: u64) -> Option<(u64, u64)> {
98 if length == 0 {
99 return None;
100 }
101 match self {
102 Self::FromTo(first, last) => {
103 if first > last || *first >= length {
104 None
105 } else {
106 Some((*first, (*last).min(length - 1)))
107 }
108 }
109 Self::From(first) => {
110 if *first >= length {
111 None
112 } else {
113 Some((*first, length - 1))
114 }
115 }
116 Self::Suffix(n) => {
117 if *n == 0 {
118 None
119 } else {
120 let first = length.saturating_sub(*n);
121 Some((first, length - 1))
122 }
123 }
124 }
125 }
126}
127
128impl fmt::Display for ByteRange {
129 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
130 match self {
131 Self::FromTo(first, last) => write!(f, "{first}-{last}"),
132 Self::From(first) => write!(f, "{first}-"),
133 Self::Suffix(n) => write!(f, "-{n}"),
134 }
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq)]
147#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
148#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
149#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
150pub enum RangeHeader {
151 Bytes(Vec<ByteRange>),
153 Other(String),
155}
156
157impl fmt::Display for RangeHeader {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 match self {
160 Self::Bytes(ranges) => {
161 f.write_str("bytes=")?;
162 for (i, r) in ranges.iter().enumerate() {
163 if i > 0 {
164 f.write_str(", ")?;
165 }
166 fmt::Display::fmt(r, f)?;
167 }
168 Ok(())
169 }
170 Self::Other(s) => f.write_str(s),
171 }
172 }
173}
174
175#[derive(Debug, Clone, PartialEq, Eq)]
181pub enum ParseRangeError {
182 Empty,
184 Malformed,
186}
187
188impl fmt::Display for ParseRangeError {
189 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
190 match self {
191 Self::Empty => f.write_str("range header is empty"),
192 Self::Malformed => f.write_str("range header is malformed"),
193 }
194 }
195}
196
197#[cfg(feature = "std")]
198impl std::error::Error for ParseRangeError {}
199
200impl FromStr for ByteRange {
205 type Err = ParseRangeError;
206
207 fn from_str(s: &str) -> Result<Self, Self::Err> {
208 let s = s.trim();
209 if s.is_empty() {
210 return Err(ParseRangeError::Empty);
211 }
212 if let Some(n) = s.strip_prefix('-') {
213 let n: u64 = n.parse().map_err(|_| ParseRangeError::Malformed)?;
215 return Ok(Self::Suffix(n));
216 }
217 if let Some(pos) = s.find('-') {
218 let first: u64 = s[..pos].parse().map_err(|_| ParseRangeError::Malformed)?;
219 let rest = &s[pos + 1..];
220 if rest.trim().is_empty() {
221 return Ok(Self::From(first));
222 }
223 let last: u64 = rest.parse().map_err(|_| ParseRangeError::Malformed)?;
224 return Ok(Self::FromTo(first, last));
225 }
226 Err(ParseRangeError::Malformed)
227 }
228}
229
230impl FromStr for RangeHeader {
235 type Err = ParseRangeError;
236
237 fn from_str(s: &str) -> Result<Self, Self::Err> {
253 let s = s.trim();
254 if s.is_empty() {
255 return Err(ParseRangeError::Empty);
256 }
257
258 if let Some(rest) = s.strip_prefix("bytes=") {
259 let ranges: Result<Vec<ByteRange>, _> = rest
260 .split(',')
261 .filter(|p| !p.trim().is_empty())
262 .map(|p| p.trim().parse::<ByteRange>())
263 .collect();
264 let ranges = ranges?;
265 if ranges.is_empty() {
266 return Err(ParseRangeError::Malformed);
267 }
268 return Ok(Self::Bytes(ranges));
269 }
270
271 Ok(Self::Other(s.to_string()))
272 }
273}
274
275#[derive(Debug, Clone, PartialEq, Eq)]
297#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
298#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
299#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
300pub enum ContentRange {
301 Bytes {
303 first: u64,
305 last: u64,
307 complete_length: Option<u64>,
309 },
310 Unsatisfiable {
312 complete_length: u64,
314 },
315}
316
317impl ContentRange {
318 #[must_use]
320 pub fn bytes(first: u64, last: u64, complete_length: Option<u64>) -> Self {
321 Self::Bytes {
322 first,
323 last,
324 complete_length,
325 }
326 }
327
328 #[must_use]
330 pub fn bytes_unknown_length(first: u64, last: u64) -> Self {
331 Self::Bytes {
332 first,
333 last,
334 complete_length: None,
335 }
336 }
337
338 #[must_use]
343 pub fn unsatisfiable(complete_length: u64) -> Self {
344 Self::Unsatisfiable { complete_length }
345 }
346}
347
348impl fmt::Display for ContentRange {
349 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
350 match self {
351 Self::Bytes {
352 first,
353 last,
354 complete_length,
355 } => {
356 write!(f, "bytes {first}-{last}/")?;
357 match complete_length {
358 Some(len) => write!(f, "{len}"),
359 None => f.write_str("*"),
360 }
361 }
362 Self::Unsatisfiable { complete_length } => {
363 write!(f, "bytes */{complete_length}")
364 }
365 }
366 }
367}
368
369impl FromStr for ContentRange {
370 type Err = ParseRangeError;
371
372 fn from_str(s: &str) -> Result<Self, Self::Err> {
387 let s = s.trim();
388 let rest = s.strip_prefix("bytes ").ok_or(ParseRangeError::Malformed)?;
389
390 if let Some(len_str) = rest.strip_prefix("*/") {
391 let complete_length: u64 = len_str.parse().map_err(|_| ParseRangeError::Malformed)?;
392 return Ok(Self::Unsatisfiable { complete_length });
393 }
394
395 let slash = rest.find('/').ok_or(ParseRangeError::Malformed)?;
396 let range_part = &rest[..slash];
397 let len_part = &rest[slash + 1..];
398
399 let dash = range_part.find('-').ok_or(ParseRangeError::Malformed)?;
400 let first: u64 = range_part[..dash]
401 .parse()
402 .map_err(|_| ParseRangeError::Malformed)?;
403 let last: u64 = range_part[dash + 1..]
404 .parse()
405 .map_err(|_| ParseRangeError::Malformed)?;
406
407 let complete_length = if len_part == "*" {
408 None
409 } else {
410 Some(
411 len_part
412 .parse::<u64>()
413 .map_err(|_| ParseRangeError::Malformed)?,
414 )
415 };
416
417 Ok(Self::Bytes {
418 first,
419 last,
420 complete_length,
421 })
422 }
423}
424
425#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[test]
438 fn byte_range_from_to_display() {
439 assert_eq!(ByteRange::FromTo(0, 499).to_string(), "0-499");
440 }
441
442 #[test]
443 fn byte_range_from_display() {
444 assert_eq!(ByteRange::From(100).to_string(), "100-");
445 }
446
447 #[test]
448 fn byte_range_suffix_display() {
449 assert_eq!(ByteRange::Suffix(50).to_string(), "-50");
450 }
451
452 #[test]
453 fn byte_range_parse_from_to() {
454 let r: ByteRange = "0-499".parse().unwrap();
455 assert_eq!(r, ByteRange::FromTo(0, 499));
456 }
457
458 #[test]
459 fn byte_range_parse_from() {
460 let r: ByteRange = "100-".parse().unwrap();
461 assert_eq!(r, ByteRange::From(100));
462 }
463
464 #[test]
465 fn byte_range_parse_suffix() {
466 let r: ByteRange = "-50".parse().unwrap();
467 assert_eq!(r, ByteRange::Suffix(50));
468 }
469
470 #[test]
471 fn byte_range_roundtrip() {
472 let ranges = [
473 ByteRange::FromTo(0, 99),
474 ByteRange::From(500),
475 ByteRange::Suffix(200),
476 ];
477 for r in &ranges {
478 let s = r.to_string();
479 let parsed: ByteRange = s.parse().unwrap();
480 assert_eq!(&parsed, r);
481 }
482 }
483
484 #[test]
485 fn byte_range_is_valid() {
486 assert!(ByteRange::FromTo(0, 499).is_valid(1000));
487 assert!(!ByteRange::FromTo(500, 200).is_valid(1000));
488 assert!(!ByteRange::FromTo(1000, 1999).is_valid(1000));
489 assert!(ByteRange::From(0).is_valid(1));
490 assert!(!ByteRange::From(1000).is_valid(1000));
491 assert!(ByteRange::Suffix(1).is_valid(1));
492 assert!(!ByteRange::Suffix(0).is_valid(1000));
493 }
494
495 #[test]
496 fn byte_range_resolve_from_to() {
497 assert_eq!(ByteRange::FromTo(0, 99).resolve(500), Some((0, 99)));
498 assert_eq!(ByteRange::FromTo(0, 999).resolve(500), Some((0, 499)));
500 assert_eq!(ByteRange::FromTo(500, 999).resolve(500), None);
502 assert_eq!(ByteRange::FromTo(0, 99).resolve(0), None);
503 }
504
505 #[test]
506 fn byte_range_resolve_from() {
507 assert_eq!(ByteRange::From(400).resolve(500), Some((400, 499)));
508 assert_eq!(ByteRange::From(500).resolve(500), None);
509 }
510
511 #[test]
512 fn byte_range_resolve_suffix() {
513 assert_eq!(ByteRange::Suffix(100).resolve(500), Some((400, 499)));
514 assert_eq!(ByteRange::Suffix(600).resolve(500), Some((0, 499)));
516 assert_eq!(ByteRange::Suffix(0).resolve(500), None);
517 }
518
519 #[test]
524 fn range_header_parse_single() {
525 let h: RangeHeader = "bytes=0-499".parse().unwrap();
526 assert_eq!(h, RangeHeader::Bytes(vec![ByteRange::FromTo(0, 499)]));
527 }
528
529 #[test]
530 fn range_header_parse_multi() {
531 let h: RangeHeader = "bytes=0-99, 200-299".parse().unwrap();
532 assert_eq!(
533 h,
534 RangeHeader::Bytes(vec![ByteRange::FromTo(0, 99), ByteRange::FromTo(200, 299)])
535 );
536 }
537
538 #[test]
539 fn range_header_parse_suffix() {
540 let h: RangeHeader = "bytes=-500".parse().unwrap();
541 assert_eq!(h, RangeHeader::Bytes(vec![ByteRange::Suffix(500)]));
542 }
543
544 #[test]
545 fn range_header_parse_open() {
546 let h: RangeHeader = "bytes=9500-".parse().unwrap();
547 assert_eq!(h, RangeHeader::Bytes(vec![ByteRange::From(9500)]));
548 }
549
550 #[test]
551 fn range_header_roundtrip() {
552 let h = RangeHeader::Bytes(vec![ByteRange::FromTo(0, 499), ByteRange::Suffix(50)]);
553 let s = h.to_string();
554 let parsed: RangeHeader = s.parse().unwrap();
555 assert_eq!(parsed, h);
556 }
557
558 #[test]
559 fn range_header_other() {
560 let h: RangeHeader = "items=0-9".parse().unwrap();
561 assert_eq!(h, RangeHeader::Other("items=0-9".to_string()));
562 }
563
564 #[test]
565 fn range_header_empty_errors() {
566 assert_eq!("".parse::<RangeHeader>(), Err(ParseRangeError::Empty));
567 }
568
569 #[test]
574 fn content_range_bytes_display() {
575 let cr = ContentRange::bytes(0, 999, Some(5000));
576 assert_eq!(cr.to_string(), "bytes 0-999/5000");
577 }
578
579 #[test]
580 fn content_range_bytes_unknown_length_display() {
581 let cr = ContentRange::bytes_unknown_length(200, 299);
582 assert_eq!(cr.to_string(), "bytes 200-299/*");
583 }
584
585 #[test]
586 fn content_range_unsatisfiable_display() {
587 let cr = ContentRange::unsatisfiable(5000);
588 assert_eq!(cr.to_string(), "bytes */5000");
589 }
590
591 #[test]
592 fn content_range_parse_known_length() {
593 let cr: ContentRange = "bytes 0-999/5000".parse().unwrap();
594 assert_eq!(cr, ContentRange::bytes(0, 999, Some(5000)));
595 }
596
597 #[test]
598 fn content_range_parse_unknown_length() {
599 let cr: ContentRange = "bytes 0-999/*".parse().unwrap();
600 assert_eq!(cr, ContentRange::bytes_unknown_length(0, 999));
601 }
602
603 #[test]
604 fn content_range_parse_unsatisfiable() {
605 let cr: ContentRange = "bytes */5000".parse().unwrap();
606 assert_eq!(cr, ContentRange::unsatisfiable(5000));
607 }
608
609 #[test]
610 fn content_range_roundtrip() {
611 let cases = [
612 ContentRange::bytes(0, 499, Some(1000)),
613 ContentRange::bytes_unknown_length(100, 199),
614 ContentRange::unsatisfiable(9999),
615 ];
616 for cr in &cases {
617 let s = cr.to_string();
618 let parsed: ContentRange = s.parse().unwrap();
619 assert_eq!(&parsed, cr);
620 }
621 }
622
623 #[test]
628 fn byte_range_parse_empty_is_error() {
629 assert_eq!("".parse::<ByteRange>(), Err(ParseRangeError::Empty));
630 }
631
632 #[test]
634 fn parse_range_error_display() {
635 assert!(!ParseRangeError::Empty.to_string().is_empty());
636 assert!(!ParseRangeError::Malformed.to_string().is_empty());
637 }
638
639 #[test]
641 fn byte_range_parse_malformed_no_dash() {
642 assert_eq!("abc".parse::<ByteRange>(), Err(ParseRangeError::Malformed));
643 }
644}