use std::fs::File; use std::path::{Path, PathBuf}; use std::io; use std::ops::{Deref, DerefMut}; use response::{Responder, ResponseOutcome}; use http::hyper::{header, FreshHyperResponse}; use http::ContentType; #[derive(Debug)] pub struct NamedFile(PathBuf, File); impl NamedFile { pub fn open>(path: P) -> io::Result { let file = File::open(path.as_ref())?; Ok(NamedFile(path.as_ref().to_path_buf(), file)) } #[inline(always)] pub fn file(&self) -> &File { &self.1 } #[inline(always)] pub fn file_mut(&mut self) -> &mut File { &mut self.1 } #[inline(always)] pub fn path(&self) -> &Path { self.0.as_path() } } impl Responder for NamedFile { fn respond<'a>(&mut self, mut res: FreshHyperResponse<'a>) -> ResponseOutcome<'a> { if let Some(ext) = self.path().extension() { let ext_string = ext.to_string_lossy().to_lowercase(); let content_type = ContentType::from_extension(&ext_string); if !content_type.is_any() { res.headers_mut().set(header::ContentType(content_type.into())); } } self.file_mut().respond(res) } } impl Deref for NamedFile { type Target = File; fn deref(&self) -> &File { &self.1 } } impl DerefMut for NamedFile { fn deref_mut(&mut self) -> &mut File { &mut self.1 } } impl io::Read for NamedFile { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.file().read(buf) } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.file().read_to_end(buf) } } impl io::Write for NamedFile { fn write(&mut self, buf: &[u8]) -> io::Result { self.file().write(buf) } fn flush(&mut self) -> io::Result<()> { self.file().flush() } } impl io::Seek for NamedFile { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { self.file().seek(pos) } } impl<'a> io::Read for &'a NamedFile { fn read(&mut self, buf: &mut [u8]) -> io::Result { self.file().read(buf) } fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { self.file().read_to_end(buf) } } impl<'a> io::Write for &'a NamedFile { fn write(&mut self, buf: &[u8]) -> io::Result { self.file().write(buf) } fn flush(&mut self) -> io::Result<()> { self.file().flush() } } impl<'a> io::Seek for &'a NamedFile { fn seek(&mut self, pos: io::SeekFrom) -> io::Result { self.file().seek(pos) } }