From de7c05c45efbf31139ccd7737bbc539ed273dc40 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 14 Feb 2018 23:28:35 +0100 Subject: [PATCH] #60: Basic Ranges header support --- src/error.rs | 6 ++++++ src/fs.rs | 41 +++++++++++++++++++++++++++++------------ src/httpcodes.rs | 3 +++ 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/error.rs b/src/error.rs index 084249217..f9bbca241 100644 --- a/src/error.rs +++ b/src/error.rs @@ -627,6 +627,12 @@ pub fn ErrorPreconditionFailed(err: T) -> InternalError { InternalError::new(err, StatusCode::PRECONDITION_FAILED) } +/// Helper function that creates wrapper of any error and generate *RANGE NOT SATISFIABLE* response. +#[allow(non_snake_case)] +pub fn ErrorRangeNotSatisfiable(err: T) -> InternalError { + InternalError::new(err, StatusCode::RANGE_NOT_SATISFIABLE) +} + /// Helper function that creates wrapper of any error and generate *EXPECTATION FAILED* response. #[allow(non_snake_case)] pub fn ErrorExpectationFailed(err: T) -> InternalError { diff --git a/src/fs.rs b/src/fs.rs index 7a4dd229c..02e9f0fa3 100644 --- a/src/fs.rs +++ b/src/fs.rs @@ -2,9 +2,9 @@ // //! TODO: needs to re-implement actual files handling, current impl blocks use std::io; -use std::io::Read; +use std::io::{Read,Seek,SeekFrom}; use std::fmt::Write; -use std::fs::{File, DirEntry}; +use std::fs::{File, DirEntry, metadata}; use std::path::{Path, PathBuf}; use std::ops::{Deref, DerefMut}; @@ -12,10 +12,11 @@ use mime_guess::get_mime_type; use param::FromParam; use handler::{Handler, Responder}; -use headers::ContentEncoding; +use headers::{ContentEncoding,HttpRange}; +use http::header; use httprequest::HttpRequest; use httpresponse::HttpResponse; -use httpcodes::HTTPOk; +use httpcodes::{HTTPOk,HTTPPartialContent,HTTPRangeNotSatisfiable}; /// A file with an associated name; responds with the Content-Type based on the /// file extension. @@ -83,16 +84,32 @@ impl Responder for NamedFile { type Item = HttpResponse; type Error = io::Error; - fn respond_to(mut self, _: HttpRequest) -> Result { - let mut resp = HTTPOk.build(); - resp.content_encoding(ContentEncoding::Identity); - if let Some(ext) = self.path().extension() { + fn respond_to(mut self, req: HttpRequest) -> Result { + if let Ok(rangeheader) = req.headers().get("range").unwrap().to_str() { + let file_metadata = metadata(self.0)?; + if let Ok(ranges) = HttpRange::parse(rangeheader, file_metadata.len()) { + let mut resp = HTTPPartialContent.build(); + let length: usize = ranges[0].length as usize; + let mut data: Vec = vec![0u8; length]; + let _ = &self.1.seek(SeekFrom::Start(ranges[0].start))?; + let _ = self.1.read_exact(&mut data); + Ok(resp.body(data).unwrap()) + } else { + Ok(HTTPRangeNotSatisfiable.build() + .header(header::CONTENT_RANGE, format!("0-{}", file_metadata.len()).as_str()) + .body("").unwrap()) + } + } else { + let mut resp = HTTPOk.build(); + resp.content_encoding(ContentEncoding::Identity); + if let Some(ext) = self.path().extension() { let mime = get_mime_type(&ext.to_string_lossy()); - resp.content_type(format!("{}", mime).as_str()); + resp.content_type(format!("{}", mime).as_str()); + } + let mut data = Vec::new(); + let _ = self.1.read_to_end(&mut data); + Ok(resp.body(data).unwrap()) } - let mut data = Vec::new(); - let _ = self.1.read_to_end(&mut data); - Ok(resp.body(data).unwrap()) } } diff --git a/src/httpcodes.rs b/src/httpcodes.rs index 50eb90917..edad519aa 100644 --- a/src/httpcodes.rs +++ b/src/httpcodes.rs @@ -42,6 +42,8 @@ pub const HTTPPreconditionFailed: StaticResponse = StaticResponse(StatusCode::PRECONDITION_FAILED); pub const HTTPPayloadTooLarge: StaticResponse = StaticResponse(StatusCode::PAYLOAD_TOO_LARGE); pub const HTTPUriTooLong: StaticResponse = StaticResponse(StatusCode::URI_TOO_LONG); +pub const HTTPRangeNotSatisfiable: StaticResponse = + StaticResponse(StatusCode::RANGE_NOT_SATISFIABLE); pub const HTTPExpectationFailed: StaticResponse = StaticResponse(StatusCode::EXPECTATION_FAILED); @@ -141,6 +143,7 @@ impl HttpResponse { STATIC_RESP!(PreconditionFailed, StatusCode::PRECONDITION_FAILED); STATIC_RESP!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE); STATIC_RESP!(UriTooLong, StatusCode::URI_TOO_LONG); + STATIC_RESP!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE); STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED); STATIC_RESP!(InternalServerError, StatusCode::INTERNAL_SERVER_ERROR);