"]
+description = "Static files support for actix web."
+readme = "README.md"
+keywords = ["actix", "http", "async", "futures"]
+homepage = "https://actix.rs"
+repository = "https://github.com/actix/actix-web.git"
+documentation = "https://docs.rs/actix-files/"
+categories = ["asynchronous", "web-programming::http-server"]
+license = "MIT/Apache-2.0"
+edition = "2018"
+workspace = ".."
+
+[lib]
+name = "actix_files"
+path = "src/lib.rs"
+
+[dependencies]
+actix-web = "1.0.0-alpha.2"
+actix-service = "0.3.4"
+bitflags = "1"
+bytes = "0.4"
+futures = "0.1.25"
+derive_more = "0.14"
+log = "0.4"
+mime = "0.3"
+mime_guess = "2.0.0-alpha"
+percent-encoding = "1.0"
+v_htmlescape = "0.4"
+
+[dev-dependencies]
+actix-web = { version = "1.0.0-alpha.2", features=["ssl"] }
diff --git a/actix-files/README.md b/actix-files/README.md
new file mode 100644
index 000000000..5b133f57e
--- /dev/null
+++ b/actix-files/README.md
@@ -0,0 +1 @@
+# Static files support for actix web [](https://travis-ci.org/actix/actix-web) [](https://codecov.io/gh/actix/actix-web) [](https://crates.io/crates/actix-files) [](https://gitter.im/actix/actix?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
diff --git a/actix-files/src/error.rs b/actix-files/src/error.rs
new file mode 100644
index 000000000..ca99fa813
--- /dev/null
+++ b/actix-files/src/error.rs
@@ -0,0 +1,41 @@
+use actix_web::{http::StatusCode, HttpResponse, ResponseError};
+use derive_more::Display;
+
+/// Errors which can occur when serving static files.
+#[derive(Display, Debug, PartialEq)]
+pub enum FilesError {
+ /// Path is not a directory
+ #[display(fmt = "Path is not a directory. Unable to serve static files")]
+ IsNotDirectory,
+
+ /// Cannot render directory
+ #[display(fmt = "Unable to render directory without index file")]
+ IsDirectory,
+}
+
+/// Return `NotFound` for `FilesError`
+impl ResponseError for FilesError {
+ fn error_response(&self) -> HttpResponse {
+ HttpResponse::new(StatusCode::NOT_FOUND)
+ }
+}
+
+#[derive(Display, Debug, PartialEq)]
+pub enum UriSegmentError {
+ /// The segment started with the wrapped invalid character.
+ #[display(fmt = "The segment started with the wrapped invalid character")]
+ BadStart(char),
+ /// The segment contained the wrapped invalid character.
+ #[display(fmt = "The segment contained the wrapped invalid character")]
+ BadChar(char),
+ /// The segment ended with the wrapped invalid character.
+ #[display(fmt = "The segment ended with the wrapped invalid character")]
+ BadEnd(char),
+}
+
+/// Return `BadRequest` for `UriSegmentError`
+impl ResponseError for UriSegmentError {
+ fn error_response(&self) -> HttpResponse {
+ HttpResponse::new(StatusCode::BAD_REQUEST)
+ }
+}
diff --git a/actix-files/src/lib.rs b/actix-files/src/lib.rs
new file mode 100644
index 000000000..8404ab319
--- /dev/null
+++ b/actix-files/src/lib.rs
@@ -0,0 +1,1211 @@
+//! Static files support
+use std::cell::RefCell;
+use std::fmt::Write;
+use std::fs::{DirEntry, File};
+use std::io::{Read, Seek};
+use std::path::{Path, PathBuf};
+use std::rc::Rc;
+use std::{cmp, io};
+
+use actix_service::boxed::{self, BoxedNewService, BoxedService};
+use actix_service::{IntoNewService, NewService, Service};
+use actix_web::dev::{
+ HttpServiceFactory, Payload, ResourceDef, ServiceConfig, ServiceFromRequest,
+ ServiceRequest, ServiceResponse,
+};
+use actix_web::error::{BlockingError, Error, ErrorInternalServerError};
+use actix_web::http::header::DispositionType;
+use actix_web::{web, FromRequest, HttpRequest, HttpResponse, Responder};
+use bytes::Bytes;
+use futures::future::{ok, Either, FutureResult};
+use futures::{Async, Future, Poll, Stream};
+use mime;
+use mime_guess::get_mime_type;
+use percent_encoding::{utf8_percent_encode, DEFAULT_ENCODE_SET};
+use v_htmlescape::escape as escape_html_entity;
+
+mod error;
+mod named;
+mod range;
+
+use self::error::{FilesError, UriSegmentError};
+pub use crate::named::NamedFile;
+pub use crate::range::HttpRange;
+
+type HttpService = BoxedService, ServiceResponse, Error>;
+type HttpNewService =
+ BoxedNewService<(), ServiceRequest
, ServiceResponse, Error, ()>;
+
+/// Return the MIME type associated with a filename extension (case-insensitive).
+/// If `ext` is empty or no associated type for the extension was found, returns
+/// the type `application/octet-stream`.
+#[inline]
+pub fn file_extension_to_mime(ext: &str) -> mime::Mime {
+ get_mime_type(ext)
+}
+
+#[doc(hidden)]
+/// A helper created from a `std::fs::File` which reads the file
+/// chunk-by-chunk on a `ThreadPool`.
+pub struct ChunkedReadFile {
+ size: u64,
+ offset: u64,
+ file: Option,
+ fut: Option>>>,
+ counter: u64,
+}
+
+fn handle_error(err: BlockingError) -> Error {
+ match err {
+ BlockingError::Error(err) => err.into(),
+ BlockingError::Canceled => ErrorInternalServerError("Unexpected error").into(),
+ }
+}
+
+impl Stream for ChunkedReadFile {
+ type Item = Bytes;
+ type Error = Error;
+
+ fn poll(&mut self) -> Poll