Partial response ranges are now parsed properly
This commit is contained in:
parent
db637c0889
commit
b7a3410fc4
@ -9,6 +9,7 @@ mod category;
|
|||||||
mod video;
|
mod video;
|
||||||
mod thumbnail;
|
mod thumbnail;
|
||||||
mod common;
|
mod common;
|
||||||
|
mod partial;
|
||||||
|
|
||||||
#[cfg(feature = "admin")]
|
#[cfg(feature = "admin")]
|
||||||
mod admin;
|
mod admin;
|
||||||
|
65
api/src/partial.rs
Normal file
65
api/src/partial.rs
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
use rocket::http::Status;
|
||||||
|
use rocket::request::{Outcome, Request, FromRequest};
|
||||||
|
|
||||||
|
// Only single byte ranges are supported right now
|
||||||
|
pub struct Range {
|
||||||
|
start: u32,
|
||||||
|
end: Option<u32>
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum RangeError {
|
||||||
|
Invalid,
|
||||||
|
Malformed
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[rocket::async_trait]
|
||||||
|
impl<'r> FromRequest<'r> for Range {
|
||||||
|
type Error = RangeError;
|
||||||
|
async fn from_request(req: &'r Request<'_>) -> Outcome<Self, Self::Error> {
|
||||||
|
// No range basically just means get the whole file
|
||||||
|
let range_raw = req.headers().get_one("range");
|
||||||
|
if range_raw.is_none() {
|
||||||
|
return Outcome::Success(Self { start: 0, end: None })
|
||||||
|
}
|
||||||
|
let range_raw = range_raw.unwrap();
|
||||||
|
|
||||||
|
// First make sure that we only ever handle byte ranges
|
||||||
|
const PREFIX: &'static str = "bytes=";
|
||||||
|
if !range_raw.starts_with(PREFIX) {
|
||||||
|
return Outcome::Failure((Status::BadRequest, RangeError::Invalid))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next strip the 'bytes=' out and grab the only everything until either
|
||||||
|
// ',' <whitespace> <end-of-line>
|
||||||
|
// ! Strip the comma if its there so we end up with a slice that matches
|
||||||
|
// [0-9]+-[0-9]+
|
||||||
|
let range_raw = range_raw
|
||||||
|
.strip_prefix(PREFIX).unwrap();
|
||||||
|
|
||||||
|
if let Some(ranges) = range_raw.split_once('-') {
|
||||||
|
let start = ranges.0.parse::<u32>();
|
||||||
|
let end = ranges.1.parse::<u32>().ok();
|
||||||
|
println!("Range collected {:?} -> {:?}", start, end);
|
||||||
|
match (start, end) {
|
||||||
|
(Ok(start), Some(end)) => {
|
||||||
|
if end <= start {
|
||||||
|
println!("Start end range invalid {}->{}", start, end);
|
||||||
|
return Outcome::Failure((Status::BadRequest, RangeError::Malformed))
|
||||||
|
}
|
||||||
|
return Outcome::Success(Self {
|
||||||
|
start, end: Some(end)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
(Ok(start), None) => {
|
||||||
|
return Outcome::Success(Self { start, end: None })
|
||||||
|
}
|
||||||
|
_ => Outcome::Failure((Status::BadRequest, RangeError::Invalid))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Outcome::Failure((Status::BadRequest, RangeError::Invalid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user