60 Ranges Header support

This commit is contained in:
Your Name 2018-01-24 22:54:08 +01:00
parent c5341017cd
commit 962d8acd2f
2 changed files with 39 additions and 13 deletions

View File

@ -2,9 +2,9 @@
// //! TODO: needs to re-implement actual files handling, current impl blocks // //! TODO: needs to re-implement actual files handling, current impl blocks
use std::io; use std::io;
use std::io::Read; use std::io::{Read,Seek,SeekFrom};
use std::fmt::Write; use std::fmt::Write;
use std::fs::{File, DirEntry}; use std::fs::{File, DirEntry, metadata};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
@ -12,10 +12,11 @@ use mime_guess::get_mime_type;
use param::FromParam; use param::FromParam;
use handler::{Handler, Responder}; use handler::{Handler, Responder};
use headers::ContentEncoding; use headers::{ContentEncoding,HttpRange};
use http::header;
use httprequest::HttpRequest; use httprequest::HttpRequest;
use httpresponse::HttpResponse; 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 /// A file with an associated name; responds with the Content-Type based on the
/// file extension. /// file extension.
@ -83,16 +84,36 @@ impl Responder for NamedFile {
type Item = HttpResponse; type Item = HttpResponse;
type Error = io::Error; type Error = io::Error;
fn respond_to(mut self, _: HttpRequest) -> Result<HttpResponse, io::Error> { fn respond_to(mut self, req: HttpRequest) -> Result<HttpResponse, io::Error> {
let mut resp = HTTPOk.build(); if let Some(rangeheader) = req.headers().get(header::RANGE) {
resp.content_encoding(ContentEncoding::Identity); let file_metadata = metadata(self.0)?;
if let Some(ext) = self.path().extension() { if let Ok(ranges) = HttpRange::parse(try!(rangeheader.to_str()), file_metadata.len()) {
let mime = get_mime_type(&ext.to_string_lossy()); let mut resp = HTTPPartialContent.build();
resp.content_type(format!("{}", mime).as_str()); let length: usize = ranges[0].length as usize;
let mut data: Vec<u8> = vec![0u8; length];
let _ = &self.1.seek(SeekFrom::Start(ranges[0].start))?;
let _ = self.1.read_exact(&mut data)?;
Ok(resp
.header(header::CONTENT_RANGE, format!("bytes {}-{}/{}", ranges[0].start, ranges[0].start + ranges[0].length, file_metadata.len()).as_str())
.body(data).unwrap())
} else {
Ok(HTTPRangeNotSatisfiable.build()
.header(header::CONTENT_RANGE, format!("bytes */{}", file_metadata.len()).as_str())
.header(header::ACCEPT_RANGES, "bytes")
.finish().unwrap())
}
} else {
let mut resp = HTTPOk.build();
resp.header(header::ACCEPT_RANGES, "bytes");
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());
}
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())
} }
} }

View File

@ -10,6 +10,7 @@ use httpresponse::{HttpResponse, HttpResponseBuilder};
pub const HTTPOk: StaticResponse = StaticResponse(StatusCode::OK); pub const HTTPOk: StaticResponse = StaticResponse(StatusCode::OK);
pub const HTTPCreated: StaticResponse = StaticResponse(StatusCode::CREATED); pub const HTTPCreated: StaticResponse = StaticResponse(StatusCode::CREATED);
pub const HTTPNoContent: StaticResponse = StaticResponse(StatusCode::NO_CONTENT); pub const HTTPNoContent: StaticResponse = StaticResponse(StatusCode::NO_CONTENT);
pub const HTTPPartialContent: StaticResponse = StaticResponse(StatusCode::PARTIAL_CONTENT);
pub const HTTPMultipleChoices: StaticResponse = StaticResponse(StatusCode::MULTIPLE_CHOICES); pub const HTTPMultipleChoices: StaticResponse = StaticResponse(StatusCode::MULTIPLE_CHOICES);
pub const HTTPMovedPermanenty: StaticResponse = StaticResponse(StatusCode::MOVED_PERMANENTLY); pub const HTTPMovedPermanenty: StaticResponse = StaticResponse(StatusCode::MOVED_PERMANENTLY);
@ -41,6 +42,8 @@ pub const HTTPPreconditionFailed: StaticResponse =
StaticResponse(StatusCode::PRECONDITION_FAILED); StaticResponse(StatusCode::PRECONDITION_FAILED);
pub const HTTPPayloadTooLarge: StaticResponse = StaticResponse(StatusCode::PAYLOAD_TOO_LARGE); pub const HTTPPayloadTooLarge: StaticResponse = StaticResponse(StatusCode::PAYLOAD_TOO_LARGE);
pub const HTTPUriTooLong: StaticResponse = StaticResponse(StatusCode::URI_TOO_LONG); pub const HTTPUriTooLong: StaticResponse = StaticResponse(StatusCode::URI_TOO_LONG);
pub const HTTPRangeNotSatisfiable: StaticResponse =
StaticResponse(StatusCode::RANGE_NOT_SATISFIABLE);
pub const HTTPExpectationFailed: StaticResponse = pub const HTTPExpectationFailed: StaticResponse =
StaticResponse(StatusCode::EXPECTATION_FAILED); StaticResponse(StatusCode::EXPECTATION_FAILED);
@ -113,6 +116,7 @@ impl HttpResponse {
STATIC_RESP!(Ok, StatusCode::OK); STATIC_RESP!(Ok, StatusCode::OK);
STATIC_RESP!(Created, StatusCode::CREATED); STATIC_RESP!(Created, StatusCode::CREATED);
STATIC_RESP!(NoContent, StatusCode::NO_CONTENT); STATIC_RESP!(NoContent, StatusCode::NO_CONTENT);
STATIC_RESP!(PartialContent, StatusCode::PARTIAL_CONTENT);
STATIC_RESP!(MultipleChoices, StatusCode::MULTIPLE_CHOICES); STATIC_RESP!(MultipleChoices, StatusCode::MULTIPLE_CHOICES);
STATIC_RESP!(MovedPermanenty, StatusCode::MOVED_PERMANENTLY); STATIC_RESP!(MovedPermanenty, StatusCode::MOVED_PERMANENTLY);
@ -139,6 +143,7 @@ impl HttpResponse {
STATIC_RESP!(PreconditionFailed, StatusCode::PRECONDITION_FAILED); STATIC_RESP!(PreconditionFailed, StatusCode::PRECONDITION_FAILED);
STATIC_RESP!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE); STATIC_RESP!(PayloadTooLarge, StatusCode::PAYLOAD_TOO_LARGE);
STATIC_RESP!(UriTooLong, StatusCode::URI_TOO_LONG); STATIC_RESP!(UriTooLong, StatusCode::URI_TOO_LONG);
STATIC_RESP!(RangeNotSatisfiable, StatusCode::RANGE_NOT_SATISFIABLE);
STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED); STATIC_RESP!(ExpectationFailed, StatusCode::EXPECTATION_FAILED);
STATIC_RESP!(InternalServerError, StatusCode::INTERNAL_SERVER_ERROR); STATIC_RESP!(InternalServerError, StatusCode::INTERNAL_SERVER_ERROR);