range_requests/headers/
mod.rs1use std::{
2 fmt::{self, Display},
3 num::ParseIntError,
4 ops::RangeInclusive,
5};
6
7pub mod content_range;
8pub mod if_range;
9pub mod range;
10#[cfg(test)]
11mod tests;
12
13const UNIT: &str = "bytes";
14
15#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
20pub enum ParseHttpRangeOrContentRangeError {
21 #[error("The header value is malformed")]
22 Malformed,
23 #[error("Contains nonvisible ASCII")]
24 ContainsNonVisibleASCII,
25 #[error("Empty header value")]
26 Empty,
27 #[error("Invalid unit")]
28 InvalidUnit,
29 #[error("Invalid range value")]
30 MalformedRange,
31 #[error(transparent)]
32 UnorderedRange(#[from] InvalidOrderedRange),
33 #[error("Invalid range piece")]
34 InvalidRangePiece(#[source] InvalidHttpU64),
35 #[error("Invalid size value")]
36 InvalidSize(#[source] InvalidHttpU64),
37}
38
39#[cfg(feature = "axum")]
40impl axum_core::response::IntoResponse for ParseHttpRangeOrContentRangeError {
41 fn into_response(self) -> axum_core::response::Response {
42 http::StatusCode::BAD_REQUEST.into_response()
43 }
44}
45
46#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
48pub enum InvalidHttpU64 {
49 #[error("{0} has a sign as prefix, so it can't be parsed as an unprefixed int")]
50 HasSignPrefix(String),
51 #[error(transparent)]
52 InvalidInt(#[from] ParseIntError),
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
57#[error("The provided `start`: {start} is greater than `end`: {end}")]
58pub struct InvalidOrderedRange {
59 start: u64,
60 end: u64,
61}
62
63#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub struct OrderedRange {
66 start: u64,
67 end: u64,
68}
69
70impl OrderedRange {
71 pub fn new(range: RangeInclusive<u64>) -> Result<Self, InvalidOrderedRange> {
72 let start = *range.start();
73 let end = *range.end();
74
75 if start > end {
76 return Err(InvalidOrderedRange { start, end });
77 }
78
79 Ok(Self { start, end })
80 }
81
82 pub fn start(&self) -> u64 {
84 self.start
85 }
86
87 pub fn end(&self) -> u64 {
89 self.end
90 }
91}
92
93impl Display for OrderedRange {
94 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95 write!(f, "{}-{}", self.start(), self.end())
96 }
97}
98
99pub(crate) fn u64_unprefixed_parse(s: &str) -> Result<u64, InvalidHttpU64> {
100 if s.starts_with("+") {
101 Err(InvalidHttpU64::HasSignPrefix(s.to_owned()))
102 } else {
103 Ok(s.parse::<u64>()?)
104 }
105}