1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-11-26 03:21:08 +00:00

Use http-range library for HttpRange (#2003)

This commit is contained in:
Luka Zakrajšek 2021-02-16 19:48:16 +01:00 committed by GitHub
parent 117025a96b
commit 2cc6b47fcf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 10 additions and 78 deletions

View file

@ -25,6 +25,7 @@ bitflags = "1"
bytes = "1" bytes = "1"
futures-core = { version = "0.3.7", default-features = false } futures-core = { version = "0.3.7", default-features = false }
futures-util = { version = "0.3.7", default-features = false } futures-util = { version = "0.3.7", default-features = false }
http-range = "0.1.4"
derive_more = "0.99.5" derive_more = "0.99.5"
log = "0.4" log = "0.4"
mime = "0.3" mime = "0.3"

View file

@ -10,9 +10,6 @@ pub struct HttpRange {
pub length: u64, pub length: u64,
} }
const PREFIX: &str = "bytes=";
const PREFIX_LEN: usize = 6;
#[derive(Debug, Clone, Display, Error)] #[derive(Debug, Clone, Display, Error)]
#[display(fmt = "Parse HTTP Range failed")] #[display(fmt = "Parse HTTP Range failed")]
pub struct ParseRangeErr(#[error(not(source))] ()); pub struct ParseRangeErr(#[error(not(source))] ());
@ -23,82 +20,16 @@ impl HttpRange {
/// `header` is HTTP Range header (e.g. `bytes=bytes=0-9`). /// `header` is HTTP Range header (e.g. `bytes=bytes=0-9`).
/// `size` is full size of response (file). /// `size` is full size of response (file).
pub fn parse(header: &str, size: u64) -> Result<Vec<HttpRange>, ParseRangeErr> { pub fn parse(header: &str, size: u64) -> Result<Vec<HttpRange>, ParseRangeErr> {
if header.is_empty() { match http_range::HttpRange::parse(header, size) {
return Ok(Vec::new()); Ok(ranges) => Ok(ranges
.iter()
.map(|range| HttpRange {
start: range.start,
length: range.length,
})
.collect()),
Err(_) => Err(ParseRangeErr(())),
} }
if !header.starts_with(PREFIX) {
return Err(ParseRangeErr(()));
}
let size_sig = size as i64;
let mut no_overlap = false;
let all_ranges: Vec<Option<HttpRange>> = header[PREFIX_LEN..]
.split(',')
.map(|x| x.trim())
.filter(|x| !x.is_empty())
.map(|ra| {
let mut start_end_iter = ra.split('-');
let start_str = start_end_iter.next().ok_or(ParseRangeErr(()))?.trim();
let end_str = start_end_iter.next().ok_or(ParseRangeErr(()))?.trim();
if start_str.is_empty() {
// If no start is specified, end specifies the
// range start relative to the end of the file.
let mut length: i64 = end_str.parse().map_err(|_| ParseRangeErr(()))?;
if length > size_sig {
length = size_sig;
}
Ok(Some(HttpRange {
start: (size_sig - length) as u64,
length: length as u64,
}))
} else {
let start: i64 = start_str.parse().map_err(|_| ParseRangeErr(()))?;
if start < 0 {
return Err(ParseRangeErr(()));
}
if start >= size_sig {
no_overlap = true;
return Ok(None);
}
let length = if end_str.is_empty() {
// If no end is specified, range extends to end of the file.
size_sig - start
} else {
let mut end: i64 = end_str.parse().map_err(|_| ParseRangeErr(()))?;
if start > end {
return Err(ParseRangeErr(()));
}
if end >= size_sig {
end = size_sig - 1;
}
end - start + 1
};
Ok(Some(HttpRange {
start: start as u64,
length: length as u64,
}))
}
})
.collect::<Result<_, _>>()?;
let ranges: Vec<HttpRange> = all_ranges.into_iter().filter_map(|x| x).collect();
if no_overlap && ranges.is_empty() {
return Err(ParseRangeErr(()));
}
Ok(ranges)
} }
} }