1#![warn(clippy::pedantic)]
2#![allow(unknown_lints)]
4#![allow(clippy::uninlined_format_args, clippy::single_range_in_vec_init)]
5use core::fmt::{Debug, Display, Formatter};
6use core::ops::RangeInclusive;
7use std::num::{IntErrorKind, NonZeroUsize};
8
9const UNIT_SEP: &str = "bytes=";
10pub fn parse_range_header(
135 range_header_value: &str,
136) -> Result<ParsedRanges, RangeUnsatisfiableError> {
137 const NZ_100: NonZeroUsize = match NonZeroUsize::new(100) {
139 None => {
140 unreachable!();
141 }
142 Some(nz) => nz,
143 };
144 parse_range_header_with_max_ranges(range_header_value, NZ_100)
147}
148
149pub fn parse_range_header_with_max_ranges(
154 range_header_value: &str,
155 max_ranges: NonZeroUsize,
156) -> Result<ParsedRanges, RangeUnsatisfiableError> {
157 const COMMA: char = ',';
158 let indicated_range = match range_header_value.get(..UNIT_SEP.len()) {
159 Some(r) => {
160 if !r.eq_ignore_ascii_case(UNIT_SEP) {
161 return Err(RangeUnsatisfiableError::Invalid(
162 RangeInvalid::DoesNotStartWithToken,
163 ));
164 }
165 match range_header_value.get(UNIT_SEP.len()..) {
166 Some(r) => r,
167 None => {
168 return Err(RangeUnsatisfiableError::Invalid(
170 RangeInvalid::DoesNotStartWithToken,
171 ));
172 }
173 }
174 }
175 None => {
176 return Err(RangeUnsatisfiableError::Invalid(
177 RangeInvalid::DoesNotStartWithToken,
178 ));
179 }
180 };
181 let mut last_err = None;
182 let mut num_empty = 0;
183 let mut ranges = Vec::new();
184 for range in indicated_range.split(COMMA) {
185 if num_empty >= MAX_EMPTY {
186 return Err(RangeUnsatisfiableError::Rejected(
187 RangeRejected::TooManyUnparseable,
188 ));
189 }
190 let val = if let Some(trimmed) = trim(range) {
191 if trimmed.is_empty() {
192 num_empty += 1;
193 continue;
194 }
195 match parse_inner(trimmed) {
196 Ok(parsed) => parsed,
197 Err(e) => {
198 last_err = Some(e);
199 num_empty += 1;
200 continue;
201 }
202 }
203 } else {
204 last_err = Some(RangeUnsatisfiableError::Invalid(
205 RangeInvalid::IllegalWhitespace,
206 ));
207 num_empty += 1;
208 continue;
209 };
210 ranges.push(val);
211 if ranges.len() > max_ranges.get() {
212 return Err(RangeUnsatisfiableError::Rejected(RangeRejected::TooMany));
213 }
214 }
215 if let Some(last_err) = last_err {
216 return Err(last_err);
217 }
218 if indicated_range.ends_with(space_or_tab) {
219 if !indicated_range
221 .trim_end_matches(space_or_tab)
222 .ends_with(',')
223 {
224 return Err(RangeUnsatisfiableError::Invalid(
225 RangeInvalid::IllegalWhitespace,
226 ));
227 }
228 }
229 if ranges.is_empty() {
230 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::NoNonempty))
231 } else {
232 Ok(ParsedRanges::new(ranges))
233 }
234}
235
236const MAX_EMPTY: usize = 15;
237
238fn trim(s: &str) -> Option<&str> {
239 let trimmed = s.trim_matches(space_or_tab);
240 if trimmed.starts_with(char::is_whitespace) || trimmed.ends_with(char::is_whitespace) {
241 None
242 } else {
243 Some(trimmed)
244 }
245}
246
247fn space_or_tab(ch: char) -> bool {
248 ch == ' ' || ch == '\t'
249}
250
251#[derive(Debug, Copy, Clone, Eq, PartialEq)]
252pub enum SyntacticallyCorrectRange {
253 FromStart(u64),
254 FromLast(u64),
255 Indexed(u64, u64),
257}
258
259#[inline]
260fn parse_inner(range: &str) -> Result<SyntacticallyCorrectRange, RangeUnsatisfiableError> {
261 if let Some((start, end)) = range.split_once('-') {
262 if start.is_empty() {
263 let end = strict_parse_u64(end)?;
264 return Ok(SyntacticallyCorrectRange::FromLast(end));
265 }
266 let start = strict_parse_u64(start)?;
267 if end.is_empty() {
268 return Ok(SyntacticallyCorrectRange::FromStart(start));
269 }
270 let end = strict_parse_u64(end)?;
271 if start > end {
272 return Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed));
273 }
274 return Ok(SyntacticallyCorrectRange::Indexed(start, end));
275 }
276 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable))
277}
278
279fn strict_parse_u64(s: &str) -> Result<u64, RangeUnsatisfiableError> {
280 const MAX_DIGITS: usize = 30;
281 if s.starts_with('+') {
282 return Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable));
283 }
284 if s.len() > MAX_DIGITS {
285 return Err(RangeUnsatisfiableError::Rejected(
287 RangeRejected::TooManyDigits,
288 ));
289 }
290 match s.parse::<u64>() {
291 Ok(o) => Ok(o),
292 Err(e)
293 if e.kind() == &IntErrorKind::PosOverflow
294 && s.chars().all(|ch| ch.is_ascii_digit()) =>
295 {
296 Ok(u64::MAX)
301 }
302 Err(_) => Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable)),
303 }
304}
305
306#[derive(Debug, Clone, Eq, PartialEq)]
307pub struct ParsedRanges {
308 ranges: Vec<SyntacticallyCorrectRange>,
309}
310
311impl ParsedRanges {
312 pub fn try_new(
318 ranges: Vec<SyntacticallyCorrectRange>,
319 ) -> Result<Self, RangeUnsatisfiableError> {
320 if ranges.is_empty() {
321 return Err(RangeUnsatisfiableError::Invalid(RangeInvalid::NoNonempty));
322 }
323 for range in &ranges {
324 match range {
325 SyntacticallyCorrectRange::Indexed(a, b) if a > b => {
326 return Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed));
327 }
328 SyntacticallyCorrectRange::FromStart(_)
329 | SyntacticallyCorrectRange::FromLast(_)
330 | SyntacticallyCorrectRange::Indexed(_, _) => {}
331 }
332 }
333 Ok(Self { ranges })
334 }
335
336 fn new(ranges: Vec<SyntacticallyCorrectRange>) -> Self {
337 ParsedRanges { ranges }
338 }
339
340 #[must_use]
341 #[allow(clippy::len_without_is_empty)]
342 pub fn len(&self) -> usize {
343 self.ranges.len()
344 }
345
346 #[must_use]
347 pub fn into_ranges(self) -> Vec<SyntacticallyCorrectRange> {
348 self.ranges
349 }
350
351 pub fn validate(
357 &self,
358 file_size_bytes: u64,
359 ) -> Result<Vec<RangeInclusive<u64>>, RangeUnsatisfiableError> {
360 let len = self.ranges.len();
361 if file_size_bytes == 0 {
362 return match self.zero_len_validate() {
363 Some(e) => Err(e),
364 None => Ok(vec![]),
365 };
366 }
367 let mut validated = Vec::with_capacity(len);
368 let mut bad_range = false;
369 for parsed in &self.ranges {
370 let (start, end) = match *parsed {
371 SyntacticallyCorrectRange::FromStart(i) => {
372 if i > file_size_bytes.saturating_sub(1) {
373 bad_range = true;
374 continue;
375 }
376 let end = file_size_bytes.saturating_sub(1);
377 (i, end)
378 }
379 SyntacticallyCorrectRange::FromLast(i) => {
380 if i == 0 {
381 bad_range = true;
382 continue;
383 }
384 (
386 file_size_bytes.saturating_sub(i),
387 file_size_bytes.saturating_sub(1),
388 )
389 }
390 SyntacticallyCorrectRange::Indexed(start, end) => {
391 let end = core::cmp::min(end, file_size_bytes.saturating_sub(1));
392 if start > end {
394 bad_range = true;
395 continue;
396 }
397 (start, end)
398 }
399 };
400 let valid = RangeInclusive::new(start, end);
401 validated.push(valid);
402 }
403
404 if validated.is_empty() && bad_range {
405 return Err(RangeUnsatisfiableError::Unsatisfiable);
406 }
407 match validate_ranges(validated.as_slice()) {
408 RangeValidationResult::Valid => Ok(validated),
409 RangeValidationResult::Overlapping => Err(RangeUnsatisfiableError::Rejected(
410 RangeRejected::TooManyOverlapping,
411 )),
412 }
413 }
414
415 #[inline(never)]
416 fn zero_len_validate(&self) -> Option<RangeUnsatisfiableError> {
417 let mut last_error = None;
418 let mut any_passing = false;
419 for parsed in &self.ranges {
420 match *parsed {
421 SyntacticallyCorrectRange::FromStart(_)
422 | SyntacticallyCorrectRange::Indexed(_, _) => {
423 last_error = Some(RangeUnsatisfiableError::Unsatisfiable);
424 }
425 SyntacticallyCorrectRange::FromLast(i) => {
426 if i == 0 {
427 last_error = Some(RangeUnsatisfiableError::Unsatisfiable);
435 continue;
436 }
437 any_passing = true;
438 }
439 }
440 }
441 match (any_passing, last_error) {
442 (false, Some(e)) => Some(e),
443 _ => None,
444 }
445 }
446}
447
448#[derive(Debug, Copy, Clone, Eq, PartialEq)]
451#[non_exhaustive]
452pub enum RangeUnsatisfiableError {
453 Invalid(RangeInvalid),
454 Rejected(RangeRejected),
455 Unsatisfiable,
457}
458
459#[derive(Debug, Copy, Clone, Eq, PartialEq)]
462#[non_exhaustive]
463pub enum RangeInvalid {
464 Reversed,
465 IllegalWhitespace,
466 DoesNotStartWithToken,
470 NoNonempty,
471 Unparseable,
472}
473
474#[derive(Debug, Copy, Clone, Eq, PartialEq)]
476#[non_exhaustive]
477pub enum RangeRejected {
478 TooManyOverlapping,
481 TooManyUnparseable,
482 TooManyDigits,
483 TooMany,
485}
486
487impl Display for RangeUnsatisfiableError {
488 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
489 match self {
490 RangeUnsatisfiableError::Invalid(r) => match r {
491 RangeInvalid::Reversed => f.write_str("range invalid: reversed"),
492 RangeInvalid::IllegalWhitespace => f.write_str("range invalid: illegal whitespace"),
493 RangeInvalid::DoesNotStartWithToken => f.write_fmt(format_args!(
494 "range invalid: range does not start with token '{UNIT_SEP}'"
495 )),
496 RangeInvalid::NoNonempty => f.write_str("range invalid: no nonempty ranges remain"),
497 RangeInvalid::Unparseable => {
498 f.write_str("range invalid: provided input did not make sense")
499 }
500 },
501 RangeUnsatisfiableError::Rejected(r) => match r {
502 RangeRejected::TooManyOverlapping => {
503 f.write_str("range rejected: too many overlapping ranges")
504 }
505 RangeRejected::TooManyUnparseable => {
506 f.write_str("range rejected: too many unparseable ranges")
507 }
508 RangeRejected::TooMany => f.write_str("range rejected: too many ranges"),
509 RangeRejected::TooManyDigits => {
510 f.write_str("range rejected: too many characters in the range digit-position")
511 }
512 },
513 RangeUnsatisfiableError::Unsatisfiable => f.write_str("range unsatisfiable"),
514 }
515 }
516}
517
518impl std::error::Error for RangeUnsatisfiableError {}
519
520enum RangeValidationResult {
521 Valid,
522 Overlapping,
523}
524
525fn validate_ranges(ranges: &[RangeInclusive<u64>]) -> RangeValidationResult {
526 let mut sorted = true;
527 let mut prev_start = 0;
528 for range in ranges {
529 let start = *range.start();
530 sorted &= prev_start <= start;
531 prev_start = start;
532 }
533 if ranges.len() == 1 {
534 return RangeValidationResult::Valid;
535 }
536 let bounds = ranges.iter().map(|r| (*r.start(), *r.end()));
537 let too_many = if sorted {
538 has_multiple_overlaps(bounds)
539 } else {
540 let mut by_start: Vec<_> = bounds.collect();
541 by_start.sort_unstable_by_key(|&(start, _)| start);
542 has_multiple_overlaps(by_start.into_iter())
543 };
544 if too_many {
545 RangeValidationResult::Overlapping
546 } else {
547 RangeValidationResult::Valid
548 }
549}
550
551fn has_multiple_overlaps(mut by_start: impl Iterator<Item = (u64, u64)>) -> bool {
552 #[allow(clippy::manual_let_else)]
554 let mut max_end = match by_start.next() {
555 Some((_, end)) => end,
556 None => return false,
557 };
558 let mut seen_overlap = false;
559 for (start, end) in by_start {
560 if start <= max_end {
561 if seen_overlap {
562 return true;
563 }
564 seen_overlap = true;
565 }
566 max_end = max_end.max(end);
567 }
568 false
569}
570
571#[cfg(test)]
572mod tests {
573 use crate::{
574 parse_range_header, parse_range_header_with_max_ranges, ParsedRanges, RangeInvalid,
575 RangeRejected, RangeUnsatisfiableError, SyntacticallyCorrectRange,
576 };
577 use core::ops::RangeInclusive;
578 use rand::seq::SliceRandom;
579 use std::fmt::Write;
580 use std::num::NonZeroUsize;
581
582 const TEST_FILE_LENGTH: u64 = 10_000;
583 #[test]
585 fn rfc_7233_standard_test1() {
586 let input = "bytes=0-499";
587 let expect = SyntacticallyCorrectRange::Indexed(0, 499);
588 let actual = parse_range_header(input).unwrap();
589 assert_eq!(single_range(expect), actual);
590 let expect = RangeInclusive::new(0, 499);
591 let actual = actual.validate(TEST_FILE_LENGTH).unwrap()[0].clone();
592 assert_eq!(expect, actual);
593 }
594
595 #[test]
596 fn rfc_7233_standard_test2() {
597 let input = "bytes=500-999";
598 let expect = SyntacticallyCorrectRange::Indexed(500, 999);
599 let actual = parse_range_header(input).unwrap();
600 assert_eq!(single_range(expect), actual);
601 let expect = RangeInclusive::new(500, 999);
602 let actual = actual.validate(TEST_FILE_LENGTH).unwrap()[0].clone();
603 assert_eq!(expect, actual);
604 }
605
606 #[test]
608 fn rfc_7233_suffixed_test() {
609 let input = "bytes=-500";
610 let expect = SyntacticallyCorrectRange::FromLast(500);
611 let actual = parse_range_header(input).unwrap();
612 assert_eq!(single_range(expect), actual);
613 let expect = RangeInclusive::new(9500, 9999);
614 let actual = actual.validate(10_000).unwrap()[0].clone();
615 assert_eq!(expect, actual);
616 }
617
618 #[test]
620 fn rfc_7233_open_range_test() {
621 let input = "bytes=9500-";
622 let expect = SyntacticallyCorrectRange::FromStart(9500);
623 let actual = parse_range_header(input).unwrap();
624 assert_eq!(single_range(expect), actual);
625 let expect = RangeInclusive::new(9500, 9999);
626 let actual = actual.validate(10_000).unwrap()[0].clone();
627 assert_eq!(expect, actual);
628 }
629
630 #[test]
632 fn rfc_7233_first_and_last() {
633 let input = "bytes=0-0, -1";
634 let expect = vec![
635 SyntacticallyCorrectRange::Indexed(0, 0),
636 SyntacticallyCorrectRange::FromLast(1),
637 ];
638 let actual = parse_range_header(input).unwrap();
639 assert_eq!(expect, actual.ranges);
640 let expect = vec![0..=0, 9999..=9999];
641 let actual = actual.validate(10_000).unwrap();
642 assert_eq!(expect, actual);
643 }
644
645 #[test]
646 fn parse_standard_range() {
647 let input = "bytes=0-1023";
648 let expect = SyntacticallyCorrectRange::Indexed(0, 1023);
649 let actual = parse_range_header(input).unwrap();
650 assert_eq!(single_range(expect), actual);
651 let expect = RangeInclusive::new(0, 1023);
652 let actual = actual.validate(TEST_FILE_LENGTH).unwrap()[0].clone();
653 assert_eq!(expect, actual);
654 }
655
656 #[test]
657 fn parse_open_ended_range() {
658 let input = "bytes=0-";
659 let expect = SyntacticallyCorrectRange::FromStart(0);
660 let actual = parse_range_header(input).unwrap();
661 assert_eq!(single_range(expect), actual);
662 let expect = RangeInclusive::new(0, TEST_FILE_LENGTH - 1);
663 let actual = actual.validate(TEST_FILE_LENGTH).unwrap()[0].clone();
664 assert_eq!(expect, actual);
665 }
666
667 #[test]
668 fn parse_suffix_range_edge() {
669 let input = &format!("bytes=-{}", TEST_FILE_LENGTH);
670 let expect = SyntacticallyCorrectRange::FromLast(TEST_FILE_LENGTH);
671 let actual = parse_range_header(input).unwrap();
672 assert_eq!(single_range(expect), actual);
673 let expect = RangeInclusive::new(0, TEST_FILE_LENGTH - 1);
674 let actual = actual.validate(TEST_FILE_LENGTH).unwrap()[0].clone();
675 assert_eq!(expect, actual);
676 }
677
678 #[test]
679 fn parse_empty_as_invalid() {
680 let input = "";
681 let parsed = parse_range_header(input);
682 assert_eq!(
683 parsed,
684 Err(RangeUnsatisfiableError::Invalid(
685 RangeInvalid::DoesNotStartWithToken
686 ))
687 );
688 }
689
690 #[test]
691 fn parse_empty_range_as_invalid() {
692 let input = "bytes=";
693 let parsed = parse_range_header(input);
694 assert_eq!(
695 parsed,
696 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::NoNonempty))
697 );
698 }
699
700 #[test]
701 fn parse_range_starting_with_whitespace_is_valid() {
702 let input = "bytes= 0-15";
703 let parsed = parse_range_header(input);
704 assert_eq!(Ok(vec![0..=15]), parsed.unwrap().validate(TEST_FILE_LENGTH));
705 }
706
707 #[test]
708 fn parse_range_token_starting_with_whitespace_as_invalid() {
709 let input = " bytes=0-15";
710 let parsed = parse_range_header(input);
711 assert_eq!(
712 parsed,
713 Err(RangeUnsatisfiableError::Invalid(
714 RangeInvalid::DoesNotStartWithToken
715 ))
716 );
717 }
718
719 #[test]
720 fn parse_range_strict_parse_numerical() {
721 let input = "bytes=+0-15";
722 let parsed = parse_range_header(input);
723 assert_eq!(
724 parsed,
725 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable))
726 );
727 }
728
729 #[test]
730 fn parse_bad_unit_as_invalid() {
731 let input = "abcde=0-10";
732 let parsed = parse_range_header(input);
733 assert_eq!(
734 parsed,
735 Err(RangeUnsatisfiableError::Invalid(
736 RangeInvalid::DoesNotStartWithToken
737 ))
738 );
739 }
740
741 #[test]
742 fn parse_missing_equals_as_malformed() {
743 let input = "bytes0-10";
744 let parsed = parse_range_header(input);
745 assert_eq!(
746 parsed,
747 Err(RangeUnsatisfiableError::Invalid(
748 RangeInvalid::DoesNotStartWithToken
749 ))
750 );
751 }
752
753 #[test]
754 fn parse_negative_bad_characters_in_range_as_malformed() {
755 let input = "bytes=1-10a";
756 let parsed = parse_range_header(input);
757 assert_eq!(
758 parsed,
759 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable))
760 );
761 }
762
763 #[test]
764 fn parse_negative_numbers_as_malformed() {
765 let input = "bytes=-1-10";
766 let parsed = parse_range_header(input);
767 assert_eq!(
769 parsed,
770 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable))
771 );
772 }
773
774 #[test]
775 fn parse_bad_characters_in_start_of_range() {
776 let input = "bytes=a1-10";
777 let parsed = parse_range_header(input);
778 assert_eq!(
780 parsed,
781 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable))
782 );
783 }
784
785 #[test]
786 fn parse_out_of_bounds_overrun_as_content_length() {
787 let input = &format!("bytes=0-{}", TEST_FILE_LENGTH);
788 let expect = vec![RangeInclusive::new(0, TEST_FILE_LENGTH - 1)];
789 let actual = parse_range_header(input)
790 .unwrap()
791 .validate(TEST_FILE_LENGTH)
792 .unwrap();
793 assert_eq!(expect, actual);
794 }
795
796 #[test]
797 fn parse_suffix_longer_than_file_as_whole_file() {
798 let input = &format!("bytes=-{}", TEST_FILE_LENGTH + 1);
799 let parsed = parse_range_header(input)
800 .unwrap()
801 .validate(TEST_FILE_LENGTH)
802 .unwrap();
803 assert_eq!(parsed, vec![0..=TEST_FILE_LENGTH - 1]);
804 }
805
806 #[test]
807 fn parse_suffix_of_empty_file_as_satisfiable_returns_no_ranges() {
808 let parsed = parse_range_header("bytes=-1").unwrap().validate(0);
809 assert_eq!(parsed, Ok(vec![]));
810 }
811
812 #[test]
813 fn parse_zero_length_suffix_as_unsatisfiable() {
814 let input = "bytes=-0";
815 let parsed = parse_range_header(input).unwrap();
816 assert_eq!(
817 parsed.validate(TEST_FILE_LENGTH),
818 Err(RangeUnsatisfiableError::Unsatisfiable)
819 );
820 }
821
822 #[test]
823 fn parse_zero_length_suffix_retains_satisfiable_ranges() {
824 let input = "bytes=15-20,-0";
825 let parsed = parse_range_header(input).unwrap();
826 assert_eq!(Ok(vec![15..=20]), parsed.validate(TEST_FILE_LENGTH));
827 }
828
829 #[test]
830 fn retains_satisfiable_ranges() {
831 let input = "bytes=10-20,0-0";
832 let parsed = parse_range_header(input).unwrap();
833 assert_eq!(Ok(vec![0..=0]), parsed.validate(10));
834 let parsed = parse_range_header(input).unwrap();
835 assert_eq!(Ok(vec![10..=19, 0..=0]), parsed.validate(20));
836 let parsed = parse_range_header(input).unwrap();
837 assert_eq!(Ok(vec![10..=20, 0..=0]), parsed.validate(21));
838 }
839
840 #[test]
841 fn rejects_invalid_range_even_when_oob() {
842 let input = "bytes=20-10,0-0";
843 assert_eq!(
844 parse_range_header(input),
845 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed)),
846 );
847 }
848
849 #[test]
850 fn retains_satisfiable_ranges_reordered() {
851 let input = "bytes=0-0,10-20";
852 let parsed = parse_range_header(input).unwrap();
853 assert_eq!(Ok(vec![0..=0]), parsed.validate(10));
854 let parsed = parse_range_header(input).unwrap();
855 assert_eq!(Ok(vec![0..=0, 10..=19]), parsed.validate(20));
856 let parsed = parse_range_header(input).unwrap();
857 assert_eq!(Ok(vec![0..=0, 10..=20]), parsed.validate(21));
858 }
859
860 #[test]
861 fn parse_single_reversed_as_invalid() {
862 let input = "bytes=15-0";
863 assert_eq!(
864 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed)),
865 parse_range_header(input),
866 );
867 }
868
869 #[test]
870 fn parse_zero_range_as_invalid() {
871 let input = "bytes=15-";
872 let parsed = parse_range_header(input).unwrap();
873 assert_eq!(
874 parsed.validate(0),
875 Err(RangeUnsatisfiableError::Unsatisfiable)
876 );
877 }
878
879 #[test]
880 fn empty_file_quirks() {
881 let parsed = parse_range_header("bytes=-0").unwrap();
882 assert_eq!(
883 parsed.validate(0),
884 Err(RangeUnsatisfiableError::Unsatisfiable)
885 );
886 let parsed = parse_range_header("bytes=-0,-1").unwrap();
887 assert_eq!(parsed.validate(0), Ok(vec![]));
888 }
889
890 #[test]
891 fn parse_multi_range() {
892 let input = "bytes=0-1023, 2015-3000, 4000-4500, 8000-9999";
893 let expected_ranges = vec![
894 SyntacticallyCorrectRange::Indexed(0, 1023),
895 SyntacticallyCorrectRange::Indexed(2015, 3000),
896 SyntacticallyCorrectRange::Indexed(4000, 4500),
897 SyntacticallyCorrectRange::Indexed(8000, 9999),
898 ];
899 let parsed = parse_range_header(input).unwrap();
900 assert_eq!(expected_ranges, parsed.ranges);
901 let validated = parsed.validate(TEST_FILE_LENGTH).unwrap();
902 assert_eq!(
903 vec![0..=1023, 2015..=3000, 4000..=4500, 8000..=9999],
904 validated
905 );
906 }
907
908 #[test]
909 fn parse_multi_range_with_open() {
910 let input = "bytes=0-1023, 1024-";
911 let expected_ranges = vec![
912 SyntacticallyCorrectRange::Indexed(0, 1023),
913 SyntacticallyCorrectRange::FromStart(1024),
914 ];
915 let parsed = parse_range_header(input).unwrap();
916 assert_eq!(expected_ranges, parsed.ranges);
917 let validated = parsed.validate(TEST_FILE_LENGTH).unwrap();
918 assert_eq!(vec![0..=1023, 1024..=9999], validated);
919 }
920
921 #[test]
922 fn parse_multi_range_with_suffix() {
923 let input = "bytes=0-1023, -1000";
924 let expected_ranges = vec![
925 SyntacticallyCorrectRange::Indexed(0, 1023),
926 SyntacticallyCorrectRange::FromLast(1000),
927 ];
928 let parsed = parse_range_header(input).unwrap();
929 assert_eq!(expected_ranges, parsed.ranges);
930 let validated = parsed.validate(TEST_FILE_LENGTH).unwrap();
931 assert_eq!(vec![0..=1023, 9000..=9999], validated);
932 }
933
934 #[test]
935 fn parse_overlapping_multi_range_as_unsatisfiable_standard() {
936 let prepared = parse_range_header("bytes=500-700,601-999").unwrap();
937 assert_eq!(
938 Ok(vec![500..=700, 601..=999]),
939 prepared.validate(TEST_FILE_LENGTH)
940 );
941 let prepared = parse_range_header("bytes=0-1023, 500-800").unwrap();
942 assert_eq!(
943 Ok(vec![0..=1023, 500..=800]),
944 prepared.validate(TEST_FILE_LENGTH)
945 );
946 let prepared = parse_range_header("bytes=0-0, 0-15").unwrap();
947 assert_eq!(Ok(vec![0..=0, 0..=15]), prepared.validate(TEST_FILE_LENGTH));
948 let prepared = parse_range_header("bytes=0-20, 20-35").unwrap();
949 assert_eq!(
950 Ok(vec![0..=20, 20..=35]),
951 prepared.validate(TEST_FILE_LENGTH)
952 );
953 let input = "bytes=0-1023, 500-800, 450-650";
954 assert_validation_err(
955 input,
956 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
957 );
958 let input = "bytes=0-1023, 500-800, 1000-1001";
959 assert_validation_err(
960 input,
961 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
962 );
963 let input = "bytes=0-1023, 500-800, 1000-";
964 assert_validation_err(
965 input,
966 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
967 );
968 let input = "bytes=0-, 0-0, 0-15";
969 assert_validation_err(
970 input,
971 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
972 );
973 let input = "bytes=0-20, 20-35, 35-";
974 assert_validation_err(
975 input,
976 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
977 );
978 }
979
980 #[test]
981 fn parse_overlapping_multi_range_as_unsatisfiable_open() {
982 let input = "bytes=0-, 1-, 5000-6000";
983 assert_validation_err(
984 input,
985 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
986 );
987 let parsed = parse_range_header("bytes=0-, 5000-6000").unwrap();
988 assert_eq!(
989 Ok(vec![0..=TEST_FILE_LENGTH - 1, 5000..=6000]),
990 parsed.validate(TEST_FILE_LENGTH)
991 );
992 }
993
994 #[test]
995 fn parse_overlapping_multi_range_as_unsatisfiable_suffixed() {
996 let parsed = parse_range_header("bytes=8000-9000, -1001").unwrap();
997 assert_eq!(
998 Ok(vec![8000..=9000, 8999..=TEST_FILE_LENGTH - 1]),
999 parsed.validate(TEST_FILE_LENGTH)
1000 );
1001 let parsed = parse_range_header("bytes=8000-9000, -1000").unwrap();
1002 assert_eq!(
1003 Ok(vec![8000..=9000, 9000..=TEST_FILE_LENGTH - 1]),
1004 parsed.validate(TEST_FILE_LENGTH)
1005 );
1006 let input = "bytes=8000-9000, -1001, -500";
1007 assert_validation_err(
1008 input,
1009 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
1010 );
1011 let input = "bytes=8000-9000, -1000, -400";
1012 assert_validation_err(
1013 input,
1014 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
1015 );
1016 }
1017
1018 #[test]
1019 fn parse_overlapping_multi_range_as_unsatisfiable_suffixed_open() {
1020 let parsed = parse_range_header("bytes=0-, -1").unwrap();
1021 assert_eq!(
1022 Ok(vec![
1023 0..=TEST_FILE_LENGTH - 1,
1024 TEST_FILE_LENGTH - 1..=TEST_FILE_LENGTH - 1
1025 ]),
1026 parsed.validate(TEST_FILE_LENGTH)
1027 );
1028 let input = "bytes=0-, 5-6, -1";
1029 assert_validation_err(
1030 input,
1031 RangeUnsatisfiableError::Rejected(RangeRejected::TooManyOverlapping),
1032 );
1033 }
1034
1035 #[test]
1036 fn parse_start_boundaries() {
1037 let parsed = parse_range_header("bytes=9999-").unwrap();
1038 assert_eq!(Ok(vec![9999..=9999]), parsed.validate(TEST_FILE_LENGTH));
1039 let parsed = parse_range_header("bytes=10000-").unwrap();
1040 assert_eq!(
1041 Err(RangeUnsatisfiableError::Unsatisfiable),
1042 parsed.validate(TEST_FILE_LENGTH)
1043 );
1044 }
1045
1046 #[test]
1047 fn parse_multi_range_with_a_reversed_as_invalid() {
1048 let input = "bytes=0-15, 30-20";
1049 assert_eq!(
1050 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed)),
1051 parse_range_header(input)
1052 );
1053 }
1054
1055 #[track_caller]
1056 fn assert_validation_err(input: &str, err: RangeUnsatisfiableError) {
1057 let parsed = parse_range_header(input)
1058 .unwrap()
1059 .validate(TEST_FILE_LENGTH);
1060 assert_eq!(Err(err), parsed);
1061 }
1062
1063 #[test]
1064 fn parse_multi_range_rejects_invalid() {
1065 let input = "bytes=0-15, 25, 9, ";
1066 let parsed = parse_range_header(input);
1067 assert!(parsed.is_err());
1068 }
1069
1070 #[quickcheck_macros::quickcheck]
1071 #[allow(clippy::needless_pass_by_value)]
1072 fn never_panics(input: String) -> quickcheck::TestResult {
1073 if let Ok(passed_first_pass) = parse_range_header(&input) {
1074 let _v = passed_first_pass.validate(u64::MAX);
1075 quickcheck::TestResult::passed()
1076 } else {
1077 quickcheck::TestResult::passed()
1078 }
1079 }
1080
1081 #[quickcheck_macros::quickcheck]
1082 #[allow(clippy::needless_pass_by_value)]
1083 fn never_panics_empty_validate(input: String) -> quickcheck::TestResult {
1084 if let Ok(passed_first_pass) = parse_range_header(&input) {
1085 let _v = passed_first_pass.validate(0);
1086 quickcheck::TestResult::passed()
1087 } else {
1088 quickcheck::TestResult::passed()
1089 }
1090 }
1091
1092 #[test]
1093 #[allow(clippy::cast_possible_truncation)]
1094 fn zero_length_file_does_not_return_an_unusable_range_on_suffixed() {
1095 const BYTES: &[u8; 0] = &[];
1096 let parsed = parse_range_header("bytes=-1").unwrap();
1097 let val = parsed.validate(0).unwrap();
1098 for range in val {
1099 for val in range {
1100 let value = BYTES[val as usize];
1101 assert_eq!(15, value);
1103 }
1104 }
1105 }
1106
1107 #[test]
1108 fn zero_length_file_does_not_accept_any_staring_range() {
1109 let parsed = parse_range_header("bytes=0-").unwrap();
1110 assert_eq!(
1111 Err(RangeUnsatisfiableError::Unsatisfiable),
1112 parsed.validate(0)
1113 );
1114 let parsed = parse_range_header("bytes=0-0").unwrap();
1115 assert_eq!(
1116 Err(RangeUnsatisfiableError::Unsatisfiable),
1117 parsed.validate(0)
1118 );
1119 let parsed = parse_range_header("bytes=0-100").unwrap();
1120 assert_eq!(
1121 Err(RangeUnsatisfiableError::Unsatisfiable),
1122 parsed.validate(0)
1123 );
1124 }
1125
1126 #[test]
1127 fn zero_length_file_will_not_give_an_error_if_any_range_is_satisfiable() {
1128 let parsed = parse_range_header("bytes=0-0,-1").unwrap();
1130 assert_eq!(Ok(vec![]), parsed.validate(0));
1131 let parsed = parse_range_header("bytes=1-,-1").unwrap();
1132 assert_eq!(Ok(vec![]), parsed.validate(0));
1133 }
1134
1135 #[test]
1136 fn zero_length_file_will_not_accept_reversed_ranges() {
1137 assert_eq!(
1138 parse_range_header("bytes=15-0,-1"),
1139 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed)),
1140 );
1141 }
1142
1143 #[test]
1144 fn accepts_any_case() {
1145 let _parsed = parse_range_header("bytes=0-0").unwrap();
1146 let _parsed = parse_range_header("Bytes=0-0").unwrap();
1147 let _parsed = parse_range_header("ByTeS=0-0").unwrap();
1148 }
1149
1150 #[test]
1151 fn accepts_leading_zeroes() {
1152 let parsed = parse_range_header("bytes=1-2").unwrap();
1155 assert_eq!(Ok(vec![1..=2]), parsed.validate(TEST_FILE_LENGTH));
1156 let parsed = parse_range_header("bytes=01-2").unwrap();
1157 assert_eq!(Ok(vec![1..=2]), parsed.validate(TEST_FILE_LENGTH));
1158 let parsed = parse_range_header("bytes=001-2").unwrap();
1159 assert_eq!(Ok(vec![1..=2]), parsed.validate(TEST_FILE_LENGTH));
1160 let parsed = parse_range_header("bytes=00001-2").unwrap();
1161 assert_eq!(Ok(vec![1..=2]), parsed.validate(TEST_FILE_LENGTH));
1162 }
1163
1164 #[test]
1165 fn accepts_whitespace_around_separators() {
1166 assert_eq!(
1167 Err(RangeUnsatisfiableError::Invalid(
1168 RangeInvalid::IllegalWhitespace
1169 )),
1170 parse_range_header("bytes=1-2 ")
1171 );
1172 parse_range_header("bytes= , 0-1,3-4").unwrap();
1173 parse_range_header("bytes=0-1,3-4").unwrap();
1174 parse_range_header("bytes=0-1, 3-4").unwrap();
1175 parse_range_header("bytes=0-1, 3-4").unwrap();
1176 parse_range_header("bytes=0-1 , 3-4").unwrap();
1177 parse_range_header("bytes=0-1 ,3-4").unwrap();
1178 parse_range_header("bytes=0-1,\t3-4").unwrap();
1179 parse_range_header("bytes=0-1,\t\t3-4").unwrap();
1180 parse_range_header("bytes=0-1 ,\t3-4").unwrap();
1181 parse_range_header("bytes=0-1 \t,3-4").unwrap();
1182 assert_eq!(
1183 Err(RangeUnsatisfiableError::Invalid(
1184 RangeInvalid::IllegalWhitespace
1185 )),
1186 parse_range_header("bytes=0-1,\n3-4")
1187 );
1188 assert_eq!(
1189 Err(RangeUnsatisfiableError::Invalid(
1190 RangeInvalid::IllegalWhitespace
1191 )),
1192 parse_range_header("bytes=0-1,\n 3-4")
1193 );
1194 assert_eq!(
1195 Err(RangeUnsatisfiableError::Invalid(
1196 RangeInvalid::IllegalWhitespace
1197 )),
1198 parse_range_header("bytes=0-1\n, 3-4")
1199 );
1200 assert_eq!(
1201 Err(RangeUnsatisfiableError::Invalid(
1202 RangeInvalid::IllegalWhitespace
1203 )),
1204 parse_range_header("bytes=0-1,3-4\n")
1205 );
1206 }
1207
1208 #[test]
1209 fn rejects_long_number_even_if_its_not_a_number() {
1210 let expect = ParsedRanges {
1212 ranges: vec![SyntacticallyCorrectRange::Indexed(0, 15)],
1213 };
1214 assert_eq!(
1215 Ok(expect),
1216 parse_range_header("bytes=0-000000000000000000000000000015")
1217 );
1218 assert_eq!(
1219 Err(RangeUnsatisfiableError::Rejected(
1220 RangeRejected::TooManyDigits
1221 )),
1222 parse_range_header("bytes=0-0000000000000000000000000000015")
1223 );
1224 assert_eq!(
1225 Err(RangeUnsatisfiableError::Rejected(
1226 RangeRejected::TooManyDigits
1227 )),
1228 parse_range_header("bytes=0-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")
1229 );
1230 }
1231
1232 #[test]
1233 fn accepts_max_u64_value() {
1234 let parsed = parse_range_header("bytes=0-18446744073709551615").unwrap();
1235 assert_eq!(
1236 Ok(vec![0..=TEST_FILE_LENGTH.saturating_sub(1)]),
1237 parsed.validate(TEST_FILE_LENGTH)
1238 );
1239 }
1240 #[test]
1241 fn does_not_accept_a_completely_empty_range() {
1242 assert_eq!(
1243 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::NoNonempty)),
1244 parse_range_header("bytes=")
1245 );
1246 }
1247
1248 #[test]
1249 fn accepts_a_few_empty_elements() {
1250 let parsed = parse_range_header("bytes=0-1,,3-4,").unwrap();
1251 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1252 let parsed = parse_range_header("bytes=,0-1,,3-4").unwrap();
1253 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1254 let parsed = parse_range_header("bytes=0-1,,3-4").unwrap();
1255 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1256 let parsed = parse_range_header("bytes=0-1 , , 3-4").unwrap();
1257 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1258 let parsed = parse_range_header("bytes=0-1 ,, , 3-4").unwrap();
1259 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1260 let parsed = parse_range_header("bytes=0-1 , , , 3-4").unwrap();
1261 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1262 let parsed = parse_range_header("bytes=0-1 ,, ,, 3-4").unwrap();
1263 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1264 let parsed = parse_range_header("bytes=0-1 ,,,,, 3-4").unwrap();
1265 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1266
1267 let parsed = parse_range_header("bytes=0-1,,,,,,,,,,,,,,,3-4").unwrap();
1268 assert_eq!(Ok(vec![0..=1, 3..=4]), parsed.validate(TEST_FILE_LENGTH));
1269 assert_eq!(
1270 Err(RangeUnsatisfiableError::Rejected(
1271 RangeRejected::TooManyUnparseable
1272 )),
1273 parse_range_header("bytes=0-1,,,,,,,,,,,,,,,,3-4")
1274 );
1275 }
1276
1277 #[test]
1278 fn regression_empty_err_on_only_comma() {
1279 let parsed = parse_range_header("bytes=,,");
1280 assert_eq!(
1281 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::NoNonempty)),
1282 parsed
1283 );
1284 let parsed = parse_range_header("bytes=, ,");
1285 assert_eq!(
1286 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::NoNonempty)),
1287 parsed
1288 );
1289 }
1290
1291 #[test]
1292 fn regression_disallowed_valid_white_spacing_allowed_invalid_white_spacing() {
1293 let _parsed = parse_range_header("bytes=0-1 ,").unwrap();
1294 let parsed = parse_range_header("bytes=0-1 ");
1296 assert_eq!(
1297 Err(RangeUnsatisfiableError::Invalid(
1298 RangeInvalid::IllegalWhitespace
1299 )),
1300 parsed
1301 );
1302 let _parsed = parse_range_header("bytes=0-1, ").unwrap();
1304 }
1305
1306 #[test]
1307 fn regression_u64_overflow_clamps_to_end_of_file() {
1308 let parsed = parse_range_header("bytes=0-18446744073709551615000000000").unwrap();
1309 assert_eq!(Ok(vec![0..=9999]), parsed.validate(TEST_FILE_LENGTH));
1310 let parsed = parse_range_header("bytes=-18446744073709551615000000000").unwrap();
1311 assert_eq!(Ok(vec![0..=9999]), parsed.validate(TEST_FILE_LENGTH));
1312 let parsed =
1313 parse_range_header("bytes=18446744073709551615000000000-18446744073709551615000000000")
1314 .unwrap();
1315 assert_eq!(
1316 Err(RangeUnsatisfiableError::Unsatisfiable),
1317 parsed.validate(TEST_FILE_LENGTH)
1318 );
1319 }
1320
1321 #[test]
1322 fn regression_u64_parsing_allows_garbage() {
1323 assert_eq!(
1324 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable)),
1325 parse_range_header("bytes=0-99999999999999999999abc")
1326 );
1327 assert_eq!(
1328 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable)),
1329 parse_range_header("bytes=0-99999999999999999999-5")
1330 );
1331 assert_eq!(
1332 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable)),
1333 parse_range_header("bytes=0-99999999999999999999 5")
1334 );
1335 assert_eq!(
1336 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable)),
1337 parse_range_header("bytes=-99999999999999999999abc")
1338 );
1339 assert_eq!(
1340 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable)),
1341 parse_range_header("bytes=99999999999999999999abc-,0-1")
1342 );
1343 assert_eq!(
1344 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Unparseable)),
1345 parse_range_header("bytes=0-18446744073709551615x")
1346 );
1347 }
1348
1349 #[test]
1350 fn regression_char_boundary_check() {
1351 assert_eq!(
1352 Err(RangeUnsatisfiableError::Invalid(
1353 RangeInvalid::DoesNotStartWithToken
1354 )),
1355 parse_range_header("bytesé=0-1")
1356 );
1357 }
1358
1359 #[test]
1360 fn spec_contradiction() {
1361 assert_eq!(
1368 Ok(vec![0..=999, 4500..=5499, 9000..=9999]),
1369 parse_range_header("bytes= 0-999, 4500-5499, -1000")
1370 .unwrap()
1371 .validate(TEST_FILE_LENGTH)
1372 );
1373 }
1374
1375 #[test]
1376 fn default_100_ranges() {
1377 let mut spec = "bytes=".to_string();
1378 let cases = 200;
1379 for i in (0..cases).step_by(2) {
1380 let start = i;
1381 let end = i + 1;
1382 spec.write_fmt(format_args!("{}-{},", start, end)).unwrap();
1383 }
1384 spec.pop();
1385 let parsed = parse_range_header(&spec).unwrap();
1386 parsed.validate(TEST_FILE_LENGTH).unwrap();
1387 let mut spec = "bytes=".to_string();
1388 let cases = 200;
1389 for i in (0..cases).rev().step_by(2) {
1390 let start = i;
1391 let end = i + 1;
1392 spec.write_fmt(format_args!("{}-{},", start, end)).unwrap();
1393 }
1394 spec.pop();
1395 let parsed = parse_range_header(&spec).unwrap();
1396 parsed.validate(TEST_FILE_LENGTH).unwrap();
1397 let mut spec = "bytes=".to_string();
1398 let cases = 201;
1399 for i in (0..cases).rev().step_by(2) {
1400 let start = i;
1401 let end = i + 1;
1402 spec.write_fmt(format_args!("{}-{},", start, end)).unwrap();
1403 }
1404 spec.pop();
1405
1406 assert_eq!(
1407 Err(RangeUnsatisfiableError::Rejected(RangeRejected::TooMany)),
1408 parse_range_header(&spec)
1409 );
1410 }
1411
1412 #[test]
1413 fn random_ranges_overlap_check() {
1414 let mut ranges = Vec::with_capacity(100);
1416 let cases = 200;
1417 for i in (0..cases).rev().step_by(2) {
1418 let start = i;
1419 let end = i + 1;
1420 ranges.push(format!("{}-{},", start, end));
1421 }
1422 let mut rng = rand::rng();
1423 ranges.shuffle(&mut rng);
1424 let mut spec = "bytes=".to_string();
1425 for val in ranges {
1426 spec.push_str(&val);
1427 }
1428 spec.pop();
1429 let parsed = parse_range_header(&spec).unwrap();
1430 parsed.validate(TEST_FILE_LENGTH).unwrap();
1431 }
1432
1433 #[test]
1434 fn configurable_ranges() {
1435 assert!(
1436 parse_range_header_with_max_ranges("bytes=1-2", NonZeroUsize::new(1).unwrap()).is_ok()
1437 );
1438 assert_eq!(
1439 Err(RangeUnsatisfiableError::Rejected(RangeRejected::TooMany)),
1440 parse_range_header_with_max_ranges("bytes=1-2,2-3", NonZeroUsize::new(1).unwrap())
1441 );
1442 }
1443
1444 #[test]
1445 fn try_new_rejects_empty() {
1446 assert_eq!(
1447 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::NoNonempty)),
1448 ParsedRanges::try_new(vec![])
1449 );
1450 }
1451
1452 #[test]
1453 fn try_new_rejects_reversed() {
1454 assert_eq!(
1455 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed)),
1456 ParsedRanges::try_new(vec![SyntacticallyCorrectRange::Indexed(10, 5)])
1457 );
1458 }
1459
1460 #[test]
1461 fn try_new_rejects_reversed_mixed_with_valid() {
1462 assert_eq!(
1464 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed)),
1465 ParsedRanges::try_new(vec![
1466 SyntacticallyCorrectRange::Indexed(0, 3),
1467 SyntacticallyCorrectRange::Indexed(10, 5),
1468 ])
1469 );
1470 assert_eq!(
1471 Err(RangeUnsatisfiableError::Invalid(RangeInvalid::Reversed)),
1472 ParsedRanges::try_new(vec![
1473 SyntacticallyCorrectRange::Indexed(10, 5),
1474 SyntacticallyCorrectRange::Indexed(0, 3),
1475 ])
1476 );
1477 }
1478
1479 #[test]
1480 fn try_new_accepts_same_edge_inputs_as_parser() {
1481 let cases = [
1482 (SyntacticallyCorrectRange::Indexed(5, 5), "bytes=5-5"),
1483 (SyntacticallyCorrectRange::FromLast(0), "bytes=-0"),
1484 (
1485 SyntacticallyCorrectRange::FromLast(u64::MAX),
1486 "bytes=-99999999999999999999",
1487 ),
1488 (
1489 SyntacticallyCorrectRange::FromStart(u64::MAX),
1490 "bytes=99999999999999999999-",
1491 ),
1492 (
1493 SyntacticallyCorrectRange::Indexed(0, u64::MAX),
1494 "bytes=0-99999999999999999999",
1495 ),
1496 (
1497 SyntacticallyCorrectRange::Indexed(u64::MAX, u64::MAX),
1498 "bytes=99999999999999999999-99999999999999999999",
1499 ),
1500 ];
1501 for (range, header) in cases {
1502 assert_eq!(
1503 parse_range_header(header),
1504 ParsedRanges::try_new(vec![range]),
1505 "header: {}",
1506 header
1507 );
1508 }
1509 }
1510
1511 #[test]
1512 fn try_new_matches_parsed() {
1513 let headers = [
1514 "bytes=0-15",
1515 "bytes=-0",
1516 "bytes=15-",
1517 "bytes=0-15, 10-20, 30-50",
1518 "bytes=0-15, 10-20, 30-50, 45-",
1519 "bytes=20-30, 0-15, -5",
1520 "bytes=0-99999999999999999999",
1521 ];
1522 for header in headers {
1523 let parsed = parse_range_header(header).unwrap();
1524 assert_eq!(
1525 Ok(parsed.clone()),
1526 ParsedRanges::try_new(parsed.into_ranges()),
1527 "header: {}",
1528 header
1529 );
1530 }
1531 }
1532
1533 fn single_range(syntactically_correct: SyntacticallyCorrectRange) -> ParsedRanges {
1534 ParsedRanges::new(vec![syntactically_correct])
1535 }
1536}