Move default handler to static files config

This commit is contained in:
Douman 2018-11-27 23:04:23 +03:00
parent df42fbf304
commit 91b66de6be
1 changed files with 29 additions and 26 deletions

View File

@ -20,7 +20,7 @@ use mime_guess::{get_mime_type, guess_mime_type};
use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET}; use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
use error::{Error, StaticFileError}; use error::{Error, StaticFileError};
use handler::{AsyncResult, Handler, Responder, RouteHandler, WrapHandler}; use handler::{AsyncResult, Handler, Responder};
use header; use header;
use header::{ContentDisposition, DispositionParam, DispositionType}; use header::{ContentDisposition, DispositionParam, DispositionType};
use http::{ContentEncoding, Method, StatusCode}; use http::{ContentEncoding, Method, StatusCode};
@ -112,6 +112,13 @@ pub trait StaticFileConfig: Default {
fn directory_listing<S>(dir: &Directory, req: &HttpRequest<S>) -> Result<HttpResponse, io::Error> { fn directory_listing<S>(dir: &Directory, req: &HttpRequest<S>) -> Result<HttpResponse, io::Error> {
directory_listing(dir, req) directory_listing(dir, req)
} }
/// Default handler for StaticFiles.
///
/// Responses with NotFound by default
fn default_handler<S>(_req: &HttpRequest<S>) -> AsyncResult<HttpResponse> {
HttpResponse::new(StatusCode::NOT_FOUND).into()
}
} }
///Default content disposition as described in ///Default content disposition as described in
@ -665,22 +672,21 @@ fn directory_listing<S>(
/// .finish(); /// .finish();
/// } /// }
/// ``` /// ```
pub struct StaticFiles<S, C = DefaultConfig> { pub struct StaticFiles<C = DefaultConfig> {
directory: PathBuf, directory: PathBuf,
cpu_pool: CpuPool, cpu_pool: CpuPool,
default: Box<RouteHandler<S>>,
_chunk_size: usize, _chunk_size: usize,
_follow_symlinks: bool, _follow_symlinks: bool,
_cd_map: PhantomData<C>, _cd_map: PhantomData<C>,
} }
impl<S: 'static> StaticFiles<S> { impl StaticFiles {
/// Create new `StaticFiles` instance for specified base directory. /// Create new `StaticFiles` instance for specified base directory.
/// ///
/// `StaticFile` uses `CpuPool` for blocking filesystem operations. /// `StaticFile` uses `CpuPool` for blocking filesystem operations.
/// By default pool with 20 threads is used. /// By default pool with 20 threads is used.
/// Pool size can be changed by setting ACTIX_CPU_POOL environment variable. /// Pool size can be changed by setting ACTIX_CPU_POOL environment variable.
pub fn new<T: Into<PathBuf>>(dir: T) -> Result<StaticFiles<S>, Error> { pub fn new<T: Into<PathBuf>>(dir: T) -> Result<StaticFiles, Error> {
Self::with_config(dir, DefaultConfig) Self::with_config(dir, DefaultConfig)
} }
@ -689,19 +695,19 @@ impl<S: 'static> StaticFiles<S> {
pub fn with_pool<T: Into<PathBuf>>( pub fn with_pool<T: Into<PathBuf>>(
dir: T, dir: T,
pool: CpuPool, pool: CpuPool,
) -> Result<StaticFiles<S>, Error> { ) -> Result<StaticFiles, Error> {
Self::with_config_pool(dir, pool, DefaultConfig) Self::with_config_pool(dir, pool, DefaultConfig)
} }
} }
impl<S: 'static, C: StaticFileConfig> StaticFiles<S, C> { impl<C: StaticFileConfig> StaticFiles<C> {
/// Create new `StaticFiles` instance for specified base directory. /// Create new `StaticFiles` instance for specified base directory.
/// ///
/// Identical with `new` but allows to specify configiration to use. /// Identical with `new` but allows to specify configiration to use.
pub fn with_config<T: Into<PathBuf>>( pub fn with_config<T: Into<PathBuf>>(
dir: T, dir: T,
config: C, config: C,
) -> Result<StaticFiles<S, C>, Error> { ) -> Result<StaticFiles<C>, Error> {
// use default CpuPool // use default CpuPool
let pool = { DEFAULT_CPUPOOL.lock().clone() }; let pool = { DEFAULT_CPUPOOL.lock().clone() };
@ -714,7 +720,7 @@ impl<S: 'static, C: StaticFileConfig> StaticFiles<S, C> {
dir: T, dir: T,
pool: CpuPool, pool: CpuPool,
_: C, _: C,
) -> Result<StaticFiles<S, C>, Error> { ) -> Result<StaticFiles<C>, Error> {
let dir = dir.into().canonicalize()?; let dir = dir.into().canonicalize()?;
if !dir.is_dir() { if !dir.is_dir() {
@ -724,22 +730,13 @@ impl<S: 'static, C: StaticFileConfig> StaticFiles<S, C> {
Ok(StaticFiles { Ok(StaticFiles {
directory: dir, directory: dir,
cpu_pool: pool, cpu_pool: pool,
default: Box::new(WrapHandler::new(|_: &_| {
HttpResponse::new(StatusCode::NOT_FOUND)
})),
_chunk_size: 0, _chunk_size: 0,
_follow_symlinks: false, _follow_symlinks: false,
_cd_map: PhantomData, _cd_map: PhantomData,
}) })
} }
/// Sets default handler which is used when no matched file could be found. fn try_handle<S: 'static>(
pub fn default_handler<H: Handler<S>>(mut self, handler: H) -> StaticFiles<S, C> {
self.default = Box::new(WrapHandler::new(handler));
self
}
fn try_handle(
&self, &self,
req: &HttpRequest<S>, req: &HttpRequest<S>,
) -> Result<AsyncResult<HttpResponse>, Error> { ) -> Result<AsyncResult<HttpResponse>, Error> {
@ -767,13 +764,13 @@ impl<S: 'static, C: StaticFileConfig> StaticFiles<S, C> {
} }
} }
impl<S: 'static, C: 'static + StaticFileConfig> Handler<S> for StaticFiles<S, C> { impl<S: 'static, C: 'static + StaticFileConfig> Handler<S> for StaticFiles<C> {
type Result = Result<AsyncResult<HttpResponse>, Error>; type Result = Result<AsyncResult<HttpResponse>, Error>;
fn handle(&self, req: &HttpRequest<S>) -> Self::Result { fn handle(&self, req: &HttpRequest<S>) -> Self::Result {
self.try_handle(req).or_else(|e| { self.try_handle(req).or_else(|e| {
debug!("StaticFiles: Failed to handle {}: {}", req.path(), e); debug!("StaticFiles: Failed to handle {}: {}", req.path(), e);
Ok(self.default.handle(req)) Ok(C::default_handler(req))
}) })
} }
} }
@ -1392,18 +1389,24 @@ mod tests {
#[test] #[test]
fn test_static_files_bad_directory() { fn test_static_files_bad_directory() {
let st: Result<StaticFiles<()>, Error> = StaticFiles::new("missing"); let st: Result<StaticFiles, Error> = StaticFiles::new("missing");
assert!(st.is_err()); assert!(st.is_err());
let st: Result<StaticFiles<()>, Error> = StaticFiles::new("Cargo.toml"); let st: Result<StaticFiles, Error> = StaticFiles::new("Cargo.toml");
assert!(st.is_err()); assert!(st.is_err());
} }
#[test] #[test]
fn test_default_handler_file_missing() { fn test_default_handler_file_missing() {
let st = StaticFiles::new(".") #[derive(Default)]
.unwrap() struct DefaultHandler;
.default_handler(|_: &_| "default content"); impl StaticFileConfig for DefaultHandler {
fn default_handler<S>(_: &HttpRequest<S>) -> AsyncResult<HttpResponse> {
AsyncResult::ok("default content")
}
}
let st = StaticFiles::with_config(".", DefaultHandler)
.unwrap();
let req = TestRequest::with_uri("/missing") let req = TestRequest::with_uri("/missing")
.param("tail", "missing") .param("tail", "missing")
.finish(); .finish();