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