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:
parent
117025a96b
commit
2cc6b47fcf
2 changed files with 10 additions and 78 deletions
|
@ -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"
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue