1use std::{
2 cmp,
3 fmt::{self, Display, Write},
4 str::FromStr,
5};
6
7use actix_http::{error::ParseError, header, HttpMessage};
8
9use super::{Header, HeaderName, HeaderValue, InvalidHeaderValue, TryIntoHeaderValue, Writer};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
63pub enum Range {
64 Bytes(Vec<ByteRangeSpec>),
66
67 Unregistered(String, String),
71}
72
73#[derive(Debug, Clone, PartialEq, Eq)]
77pub enum ByteRangeSpec {
78 FromTo(u64, u64),
84
85 From(u64),
91
92 Last(u64),
98}
99
100impl ByteRangeSpec {
101 pub fn to_satisfiable_range(&self, full_length: u64) -> Option<(u64, u64)> {
129 if full_length == 0 {
131 return None;
132 }
133
134 match *self {
135 ByteRangeSpec::FromTo(from, to) => {
136 if from < full_length && from <= to {
137 Some((from, cmp::min(to, full_length - 1)))
138 } else {
139 None
140 }
141 }
142
143 ByteRangeSpec::From(from) => {
144 if from < full_length {
145 Some((from, full_length - 1))
146 } else {
147 None
148 }
149 }
150
151 ByteRangeSpec::Last(last) => {
152 if last > 0 {
153 if last > full_length {
156 Some((0, full_length - 1))
157 } else {
158 Some((full_length - last, full_length - 1))
159 }
160 } else {
161 None
162 }
163 }
164 }
165 }
166}
167
168impl Range {
169 pub fn bytes(from: u64, to: u64) -> Range {
173 Range::Bytes(vec![ByteRangeSpec::FromTo(from, to)])
174 }
175
176 pub fn bytes_multi(ranges: Vec<(u64, u64)>) -> Range {
180 Range::Bytes(
181 ranges
182 .into_iter()
183 .map(|(from, to)| ByteRangeSpec::FromTo(from, to))
184 .collect(),
185 )
186 }
187}
188
189impl fmt::Display for ByteRangeSpec {
190 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
191 match *self {
192 ByteRangeSpec::FromTo(from, to) => write!(f, "{}-{}", from, to),
193 ByteRangeSpec::Last(pos) => write!(f, "-{}", pos),
194 ByteRangeSpec::From(pos) => write!(f, "{}-", pos),
195 }
196 }
197}
198
199impl fmt::Display for Range {
200 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201 match self {
202 Range::Bytes(ranges) => {
203 write!(f, "bytes=")?;
204
205 for (i, range) in ranges.iter().enumerate() {
206 if i != 0 {
207 f.write_str(",")?;
208 }
209
210 Display::fmt(range, f)?;
211 }
212 Ok(())
213 }
214
215 Range::Unregistered(unit, range_str) => {
216 write!(f, "{}={}", unit, range_str)
217 }
218 }
219 }
220}
221
222impl FromStr for Range {
223 type Err = ParseError;
224
225 fn from_str(s: &str) -> Result<Range, ParseError> {
226 let (unit, val) = s.split_once('=').ok_or(ParseError::Header)?;
227
228 match (unit, val) {
229 ("bytes", ranges) => {
230 let ranges = from_comma_delimited(ranges);
231
232 if ranges.is_empty() {
233 return Err(ParseError::Header);
234 }
235
236 Ok(Range::Bytes(ranges))
237 }
238
239 (_, "") => Err(ParseError::Header),
240 ("", _) => Err(ParseError::Header),
241
242 (unit, range_str) => Ok(Range::Unregistered(unit.to_owned(), range_str.to_owned())),
243 }
244 }
245}
246
247impl FromStr for ByteRangeSpec {
248 type Err = ParseError;
249
250 fn from_str(s: &str) -> Result<ByteRangeSpec, ParseError> {
251 let (start, end) = s.split_once('-').ok_or(ParseError::Header)?;
252
253 match (start, end) {
254 ("", end) => end
255 .parse()
256 .or(Err(ParseError::Header))
257 .map(ByteRangeSpec::Last),
258
259 (start, "") => start
260 .parse()
261 .or(Err(ParseError::Header))
262 .map(ByteRangeSpec::From),
263
264 (start, end) => match (start.parse(), end.parse()) {
265 (Ok(start), Ok(end)) if start <= end => Ok(ByteRangeSpec::FromTo(start, end)),
266 _ => Err(ParseError::Header),
267 },
268 }
269 }
270}
271
272impl Header for Range {
273 fn name() -> HeaderName {
274 header::RANGE
275 }
276
277 #[inline]
278 fn parse<T: HttpMessage>(msg: &T) -> Result<Self, ParseError> {
279 header::from_one_raw_str(msg.headers().get(Self::name()))
280 }
281}
282
283impl TryIntoHeaderValue for Range {
284 type Error = InvalidHeaderValue;
285
286 fn try_into_value(self) -> Result<HeaderValue, Self::Error> {
287 let mut wrt = Writer::new();
288 let _ = write!(wrt, "{}", self);
289 HeaderValue::from_maybe_shared(wrt.take())
290 }
291}
292
293fn from_comma_delimited<T: FromStr>(s: &str) -> Vec<T> {
295 s.split(',')
296 .filter_map(|x| match x.trim() {
297 "" => None,
298 y => Some(y),
299 })
300 .filter_map(|x| x.parse().ok())
301 .collect()
302}
303
304#[cfg(test)]
305mod tests {
306 use actix_http::{test::TestRequest, Request};
307
308 use super::*;
309
310 fn req(s: &str) -> Request {
311 TestRequest::default()
312 .insert_header((header::RANGE, s))
313 .finish()
314 }
315
316 #[test]
317 fn test_parse_bytes_range_valid() {
318 let r: Range = Header::parse(&req("bytes=1-100")).unwrap();
319 let r2: Range = Header::parse(&req("bytes=1-100,-")).unwrap();
320 let r3 = Range::bytes(1, 100);
321 assert_eq!(r, r2);
322 assert_eq!(r2, r3);
323
324 let r: Range = Header::parse(&req("bytes=1-100,200-")).unwrap();
325 let r2: Range = Header::parse(&req("bytes= 1-100 , 101-xxx, 200- ")).unwrap();
326 let r3 = Range::Bytes(vec![
327 ByteRangeSpec::FromTo(1, 100),
328 ByteRangeSpec::From(200),
329 ]);
330 assert_eq!(r, r2);
331 assert_eq!(r2, r3);
332
333 let r: Range = Header::parse(&req("bytes=1-100,-100")).unwrap();
334 let r2: Range = Header::parse(&req("bytes=1-100, ,,-100")).unwrap();
335 let r3 = Range::Bytes(vec![
336 ByteRangeSpec::FromTo(1, 100),
337 ByteRangeSpec::Last(100),
338 ]);
339 assert_eq!(r, r2);
340 assert_eq!(r2, r3);
341
342 let r: Range = Header::parse(&req("custom=1-100,-100")).unwrap();
343 let r2 = Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned());
344 assert_eq!(r, r2);
345 }
346
347 #[test]
348 fn test_parse_unregistered_range_valid() {
349 let r: Range = Header::parse(&req("custom=1-100,-100")).unwrap();
350 let r2 = Range::Unregistered("custom".to_owned(), "1-100,-100".to_owned());
351 assert_eq!(r, r2);
352
353 let r: Range = Header::parse(&req("custom=abcd")).unwrap();
354 let r2 = Range::Unregistered("custom".to_owned(), "abcd".to_owned());
355 assert_eq!(r, r2);
356
357 let r: Range = Header::parse(&req("custom=xxx-yyy")).unwrap();
358 let r2 = Range::Unregistered("custom".to_owned(), "xxx-yyy".to_owned());
359 assert_eq!(r, r2);
360 }
361
362 #[test]
363 fn test_parse_invalid() {
364 let r: Result<Range, ParseError> = Header::parse(&req("bytes=1-a,-"));
365 assert_eq!(r.ok(), None);
366
367 let r: Result<Range, ParseError> = Header::parse(&req("bytes=1-2-3"));
368 assert_eq!(r.ok(), None);
369
370 let r: Result<Range, ParseError> = Header::parse(&req("abc"));
371 assert_eq!(r.ok(), None);
372
373 let r: Result<Range, ParseError> = Header::parse(&req("bytes=1-100="));
374 assert_eq!(r.ok(), None);
375
376 let r: Result<Range, ParseError> = Header::parse(&req("bytes="));
377 assert_eq!(r.ok(), None);
378
379 let r: Result<Range, ParseError> = Header::parse(&req("custom="));
380 assert_eq!(r.ok(), None);
381
382 let r: Result<Range, ParseError> = Header::parse(&req("=1-100"));
383 assert_eq!(r.ok(), None);
384 }
385
386 #[test]
387 fn test_fmt() {
388 let range = Range::Bytes(vec![
389 ByteRangeSpec::FromTo(0, 1000),
390 ByteRangeSpec::From(2000),
391 ]);
392 assert_eq!(&range.to_string(), "bytes=0-1000,2000-");
393
394 let range = Range::Bytes(vec![]);
395
396 assert_eq!(&range.to_string(), "bytes=");
397
398 let range = Range::Unregistered("custom".to_owned(), "1-xxx".to_owned());
399
400 assert_eq!(&range.to_string(), "custom=1-xxx");
401 }
402
403 #[test]
404 fn test_byte_range_spec_to_satisfiable_range() {
405 assert_eq!(
406 Some((0, 0)),
407 ByteRangeSpec::FromTo(0, 0).to_satisfiable_range(3)
408 );
409 assert_eq!(
410 Some((1, 2)),
411 ByteRangeSpec::FromTo(1, 2).to_satisfiable_range(3)
412 );
413 assert_eq!(
414 Some((1, 2)),
415 ByteRangeSpec::FromTo(1, 5).to_satisfiable_range(3)
416 );
417 assert_eq!(None, ByteRangeSpec::FromTo(3, 3).to_satisfiable_range(3));
418 assert_eq!(None, ByteRangeSpec::FromTo(2, 1).to_satisfiable_range(3));
419 assert_eq!(None, ByteRangeSpec::FromTo(0, 0).to_satisfiable_range(0));
420
421 assert_eq!(Some((0, 2)), ByteRangeSpec::From(0).to_satisfiable_range(3));
422 assert_eq!(Some((2, 2)), ByteRangeSpec::From(2).to_satisfiable_range(3));
423 assert_eq!(None, ByteRangeSpec::From(3).to_satisfiable_range(3));
424 assert_eq!(None, ByteRangeSpec::From(5).to_satisfiable_range(3));
425 assert_eq!(None, ByteRangeSpec::From(0).to_satisfiable_range(0));
426
427 assert_eq!(Some((1, 2)), ByteRangeSpec::Last(2).to_satisfiable_range(3));
428 assert_eq!(Some((2, 2)), ByteRangeSpec::Last(1).to_satisfiable_range(3));
429 assert_eq!(Some((0, 2)), ByteRangeSpec::Last(5).to_satisfiable_range(3));
430 assert_eq!(None, ByteRangeSpec::Last(0).to_satisfiable_range(3));
431 assert_eq!(None, ByteRangeSpec::Last(2).to_satisfiable_range(0));
432 }
433}