rama_http_headers/common/
accept_ranges.rs1use rama_core::telemetry::tracing;
2use rama_http_types::HeaderValue;
3
4use crate::util::TryFromValues;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub struct AcceptRanges(Unit);
37
38derive_header! {
39 AcceptRanges(_),
40 name: ACCEPT_RANGES
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44enum Unit {
45 None,
46 Bytes,
47}
48
49impl From<Unit> for HeaderValue {
50 fn from(value: Unit) -> Self {
51 match value {
52 Unit::None => ACCEPT_RANGES_NONE,
53 Unit::Bytes => ACCEPT_RANGES_BYTES,
54 }
55 }
56}
57
58impl From<&Unit> for HeaderValue {
59 fn from(value: &Unit) -> Self {
60 match value {
61 Unit::None => ACCEPT_RANGES_NONE,
62 Unit::Bytes => ACCEPT_RANGES_BYTES,
63 }
64 }
65}
66
67impl TryFromValues for Unit {
68 fn try_from_values<'i, I>(values: &mut I) -> Result<Self, crate::Error>
69 where
70 Self: Sized,
71 I: Iterator<Item = &'i HeaderValue>,
72 {
73 values
74 .next()
75 .and_then(|val| {
76 let s = val
77 .to_str()
78 .inspect_err(|err| {
79 tracing::trace!("invalid accept-ranges header (unit) value: {err}")
80 })
81 .ok()?
82 .trim();
83 if s.eq_ignore_ascii_case("bytes") {
84 Some(Self::Bytes)
85 } else if s.eq_ignore_ascii_case("none") {
86 Some(Self::None)
87 } else {
88 tracing::trace!("unknown accept-ranges unit value: '{s}'");
89 None
90 }
91 })
92 .ok_or_else(crate::Error::invalid)
93 }
94}
95
96const ACCEPT_RANGES_NONE: HeaderValue = HeaderValue::from_static("none");
97const ACCEPT_RANGES_BYTES: HeaderValue = HeaderValue::from_static("bytes");
98
99impl AcceptRanges {
100 #[must_use]
102 pub fn bytes() -> Self {
103 Self(Unit::Bytes)
104 }
105
106 #[must_use]
108 pub fn is_bytes(&self) -> bool {
109 self.0 == Unit::Bytes
110 }
111
112 #[must_use]
114 pub fn none() -> Self {
115 Self(Unit::None)
116 }
117
118 #[must_use]
120 pub fn is_none(&self) -> bool {
121 self.0 == Unit::None
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::super::test_decode;
128 use super::*;
129
130 fn accept_ranges(s: &str) -> AcceptRanges {
131 test_decode(&[s]).unwrap()
132 }
133
134 #[test]
136 fn bytes_constructor() {
137 assert_eq!(accept_ranges("bytes"), AcceptRanges::bytes());
138 assert_eq!(accept_ranges("Bytes"), AcceptRanges::bytes());
139 assert_eq!(accept_ranges("BYTES"), AcceptRanges::bytes());
140 }
141
142 #[test]
143 fn is_bytes_method_successful_with_bytes_ranges() {
144 assert!(accept_ranges("bytes").is_bytes());
145 }
146
147 #[test]
148 fn is_bytes_method_successful_with_bytes_ranges_by_constructor() {
149 assert!(AcceptRanges::bytes().is_bytes());
150 }
151
152 #[test]
153 fn unknown_range_unit_value_failed() {
154 assert!(test_decode::<AcceptRanges>(&["dummy"]).is_none());
155 }
156
157 #[test]
159 fn none_constructor() {
160 assert_eq!(accept_ranges("none"), AcceptRanges::none());
161 assert_eq!(accept_ranges("None"), AcceptRanges::none());
162 assert_eq!(accept_ranges("NONE"), AcceptRanges::none());
163 }
164
165 #[test]
166 fn is_none_method_successful_with_none_ranges() {
167 assert!(accept_ranges("none").is_none());
168 }
169
170 #[test]
171 fn is_none_method_successful_with_none_ranges_by_constructor() {
172 assert!(AcceptRanges::none().is_none());
173 }
174}