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