From 727f83098830c9779bf0965b9c051d11df0fbc28 Mon Sep 17 00:00:00 2001 From: Antoine Gersant Date: Tue, 19 Feb 2019 21:07:25 -0800 Subject: [PATCH] Added logging around HTTP range handling --- src/serve.rs | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) diff --git a/src/serve.rs b/src/serve.rs index 780b391..5455313 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -1,5 +1,7 @@ use rocket; use rocket::http::hyper::header::*; +use rocket::http::Status; +use rocket::Response; use rocket::response::{self, Responder}; use std::cmp; use std::convert::From; @@ -7,6 +9,7 @@ use std::fs::File; use std::io::{Read, Seek, SeekFrom}; use std::str::FromStr; +#[derive(Debug)] pub enum PartialFileRange { AllFrom(u64), FromTo(u64, u64), @@ -41,9 +44,27 @@ impl<'r, R: Responder<'r>> RangeResponder { RangeResponder { original } } - fn ignore_range(self, request: &rocket::request::Request) -> response::Result<'r> { + fn ignore_range(self, request: &rocket::request::Request, file_length: Option) -> response::Result<'r> { let mut response = self.original.respond_to(request)?; - response.set_status(rocket::http::Status::RangeNotSatisfiable); + if let Some(content_length) = file_length { + response.set_header(ContentLength(content_length)); + } + response.set_status(Status::Ok); + Ok(response) + } + + fn reject_range(self, file_length: Option) -> response::Result<'r> { + let mut response = Response::build() + .status(Status::RangeNotSatisfiable) + .finalize(); + if file_length.is_some() { + let content_range = ContentRange(ContentRangeSpec::Bytes { + range: None, + instance_length: file_length, + }); + response.set_header(content_range); + } + response.set_status(Status::RangeNotSatisfiable); Ok(response) } } @@ -79,15 +100,22 @@ fn truncate_range(range: &PartialFileRange, file_length: &Option) -> Option impl<'r> Responder<'r> for RangeResponder { fn respond_to(mut self, request: &rocket::request::Request) -> response::Result<'r> { + + let metadata: Option<_> = self.original.metadata().ok(); + let file_length: Option = metadata.map(|m| m.len()); + let range_header = request.headers().get_one("Range"); let range_header = match range_header { - None => return Ok(self.original.respond_to(request)?), + None => return self.ignore_range(request, file_length), Some(h) => h, }; let vec_range = match Range::from_str(range_header) { Ok(Range::Bytes(v)) => v, - _ => return self.ignore_range(request), + _ => { + warn!("Ignoring range header that could not be parse {:?}, file length is {:?}", range_header, file_length); + return self.ignore_range(request, file_length); + }, }; let partial_file_range = match vec_range.into_iter().next() { @@ -95,8 +123,6 @@ impl<'r> Responder<'r> for RangeResponder { Some(byte_range) => PartialFileRange::from(byte_range), }; - let metadata: Option<_> = self.original.metadata().ok(); - let file_length: Option = metadata.map(|m| m.len()); let range: Option<(u64, u64)> = truncate_range(&partial_file_range, &file_length); if let Some((from, to)) = range { @@ -118,7 +144,8 @@ impl<'r> Responder<'r> for RangeResponder { Ok(response) } else { - self.ignore_range(request) + warn!("Rejecting unsatisfiable range header {:?}, file length is {:?}", &partial_file_range, &file_length); + self.reject_range(file_length) } } }