actori_http/header/common/
content_range.rs1use std::fmt::{self, Display, Write};
2use std::str::FromStr;
3
4use crate::error::ParseError;
5use crate::header::{
6 HeaderValue, IntoHeaderValue, InvalidHeaderValue, Writer, CONTENT_RANGE,
7};
8
9header! {
10 (ContentRange, CONTENT_RANGE) => [ContentRangeSpec]
13
14 test_content_range {
15 test_header!(test_bytes,
16 vec![b"bytes 0-499/500"],
17 Some(ContentRange(ContentRangeSpec::Bytes {
18 range: Some((0, 499)),
19 instance_length: Some(500)
20 })));
21
22 test_header!(test_bytes_unknown_len,
23 vec![b"bytes 0-499/*"],
24 Some(ContentRange(ContentRangeSpec::Bytes {
25 range: Some((0, 499)),
26 instance_length: None
27 })));
28
29 test_header!(test_bytes_unknown_range,
30 vec![b"bytes */500"],
31 Some(ContentRange(ContentRangeSpec::Bytes {
32 range: None,
33 instance_length: Some(500)
34 })));
35
36 test_header!(test_unregistered,
37 vec![b"seconds 1-2"],
38 Some(ContentRange(ContentRangeSpec::Unregistered {
39 unit: "seconds".to_owned(),
40 resp: "1-2".to_owned()
41 })));
42
43 test_header!(test_no_len,
44 vec![b"bytes 0-499"],
45 None::<ContentRange>);
46
47 test_header!(test_only_unit,
48 vec![b"bytes"],
49 None::<ContentRange>);
50
51 test_header!(test_end_less_than_start,
52 vec![b"bytes 499-0/500"],
53 None::<ContentRange>);
54
55 test_header!(test_blank,
56 vec![b""],
57 None::<ContentRange>);
58
59 test_header!(test_bytes_many_spaces,
60 vec![b"bytes 1-2/500 3"],
61 None::<ContentRange>);
62
63 test_header!(test_bytes_many_slashes,
64 vec![b"bytes 1-2/500/600"],
65 None::<ContentRange>);
66
67 test_header!(test_bytes_many_dashes,
68 vec![b"bytes 1-2-3/500"],
69 None::<ContentRange>);
70
71 }
72}
73
74#[derive(PartialEq, Clone, Debug)]
95pub enum ContentRangeSpec {
96 Bytes {
98 range: Option<(u64, u64)>,
101
102 instance_length: Option<u64>,
104 },
105
106 Unregistered {
108 unit: String,
110
111 resp: String,
113 },
114}
115
116fn split_in_two(s: &str, separator: char) -> Option<(&str, &str)> {
117 let mut iter = s.splitn(2, separator);
118 match (iter.next(), iter.next()) {
119 (Some(a), Some(b)) => Some((a, b)),
120 _ => None,
121 }
122}
123
124impl FromStr for ContentRangeSpec {
125 type Err = ParseError;
126
127 fn from_str(s: &str) -> Result<Self, ParseError> {
128 let res = match split_in_two(s, ' ') {
129 Some(("bytes", resp)) => {
130 let (range, instance_length) =
131 split_in_two(resp, '/').ok_or(ParseError::Header)?;
132
133 let instance_length = if instance_length == "*" {
134 None
135 } else {
136 Some(instance_length.parse().map_err(|_| ParseError::Header)?)
137 };
138
139 let range = if range == "*" {
140 None
141 } else {
142 let (first_byte, last_byte) =
143 split_in_two(range, '-').ok_or(ParseError::Header)?;
144 let first_byte =
145 first_byte.parse().map_err(|_| ParseError::Header)?;
146 let last_byte = last_byte.parse().map_err(|_| ParseError::Header)?;
147 if last_byte < first_byte {
148 return Err(ParseError::Header);
149 }
150 Some((first_byte, last_byte))
151 };
152
153 ContentRangeSpec::Bytes {
154 range,
155 instance_length,
156 }
157 }
158 Some((unit, resp)) => ContentRangeSpec::Unregistered {
159 unit: unit.to_owned(),
160 resp: resp.to_owned(),
161 },
162 _ => return Err(ParseError::Header),
163 };
164 Ok(res)
165 }
166}
167
168impl Display for ContentRangeSpec {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 match *self {
171 ContentRangeSpec::Bytes {
172 range,
173 instance_length,
174 } => {
175 f.write_str("bytes ")?;
176 match range {
177 Some((first_byte, last_byte)) => {
178 write!(f, "{}-{}", first_byte, last_byte)?;
179 }
180 None => {
181 f.write_str("*")?;
182 }
183 };
184 f.write_str("/")?;
185 if let Some(v) = instance_length {
186 write!(f, "{}", v)
187 } else {
188 f.write_str("*")
189 }
190 }
191 ContentRangeSpec::Unregistered { ref unit, ref resp } => {
192 f.write_str(unit)?;
193 f.write_str(" ")?;
194 f.write_str(resp)
195 }
196 }
197 }
198}
199
200impl IntoHeaderValue for ContentRangeSpec {
201 type Error = InvalidHeaderValue;
202
203 fn try_into(self) -> Result<HeaderValue, Self::Error> {
204 let mut writer = Writer::new();
205 let _ = write!(&mut writer, "{}", self);
206 HeaderValue::from_maybe_shared(writer.take())
207 }
208}