extern crate hyper;
extern crate iron;
extern crate mount;
extern crate percent_encoding;
extern crate router;
use self::hyper::header::ByteRangeSpec::*;
use self::hyper::mime::{Mime, SubLevel, TopLevel};
use super::not_shared;
use iron::middleware::Handler;
use iron::request::Request;
use iron::response::Response;
use iron::{headers, status, IronResult};
use std::fs::File;
use std::io::Seek;
use std::path::PathBuf;
pub struct ServeFile {
path: PathBuf,
}
impl ServeFile {
pub fn new(path: PathBuf) -> Self {
ServeFile { path }
}
fn handle_for_range(
&self,
mut file: File,
requested_from: u64,
filesize: u64,
) -> IronResult<Response> {
let error416 = Ok(Response::with((
status::RangeNotSatisfiable,
"416 Range Not Satisfiable",
)));
if filesize <= requested_from {
return error416;
}
let seekret = file.seek(std::io::SeekFrom::Start(requested_from));
match seekret {
Ok(seekretlength) if seekretlength == requested_from => {
let mut response = Response::with((status::PartialContent, file));
let range = headers::ContentRangeSpec::Bytes {
range: Some((requested_from, filesize - 1)),
instance_length: None,
};
response.headers.set(headers::ContentRange(range));
apply_default_send_file_headers(&mut response.headers);
Ok(response)
}
_ => error416,
}
}
}
fn parse_range(headers: &headers::Headers) -> Option<u64> {
match headers.get::<headers::Range>() {
Some(headers::Range::Bytes(ranges)) => {
if let [AllFrom(from)] = ranges.as_slice() {
Some(*from)
} else {
None
}
}
_ => None,
}
}
fn apply_default_send_file_headers(headers: &mut headers::Headers) {
let attachment_header = iron::headers::ContentDisposition {
disposition: iron::headers::DispositionType::Attachment,
parameters: Vec::new(),
};
headers.set(attachment_header);
let content_type =
headers::ContentType(Mime(TopLevel::Application, SubLevel::OctetStream, vec![]));
headers.set(content_type);
}
impl Handler for ServeFile {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
let error = not_shared::not_shared_handler(req);
let metadata = std::fs::metadata(&self.path);
let filesize = match metadata {
Ok(metadata) => metadata.len(),
Err(_) => {
return error;
}
};
let file = match File::open(&self.path) {
Ok(file) => file,
Err(_) => {
return error;
}
};
match parse_range(&req.headers) {
Some(from) => self.handle_for_range(file, from, filesize),
None => {
let mut response = Response::with((status::Ok, file));
apply_default_send_file_headers(&mut response.headers);
response.headers.set(headers::ContentLength(filesize));
Ok(response)
}
}
}
}