flesh out docs

This commit is contained in:
Rob Ede 2020-09-16 01:07:10 +01:00
parent c6e2319f71
commit 995f4b63e8
No known key found for this signature in database
GPG Key ID: C2A3B36E841A91E6
8 changed files with 64 additions and 20 deletions

View File

@ -18,7 +18,6 @@ path = "src/lib.rs"
[dependencies] [dependencies]
actix-web = { version = "3.0.0", default-features = false } actix-web = { version = "3.0.0", default-features = false }
actix-http = "2.0.0"
actix-service = "1.0.6" actix-service = "1.0.6"
bitflags = "1" bitflags = "1"
bytes = "0.5.3" bytes = "0.5.3"

View File

@ -1,5 +1,5 @@
use std::{ use std::{
cmp, cmp, fmt,
fs::File, fs::File,
future::Future, future::Future,
io::{self, Read, Seek}, io::{self, Read, Seek},
@ -31,6 +31,12 @@ pub struct ChunkedReadFile {
pub(crate) counter: u64, pub(crate) counter: u64,
} }
impl fmt::Debug for ChunkedReadFile {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("ChunkedReadFile")
}
}
impl Stream for ChunkedReadFile { impl Stream for ChunkedReadFile {
type Item = Result<Bytes, Error>; type Item = Result<Bytes, Error>;

View File

@ -1,4 +1,4 @@
use std::{cell::RefCell, io, path::PathBuf, rc::Rc}; use std::{cell::RefCell, fmt, io, path::PathBuf, rc::Rc};
use actix_service::{boxed, IntoServiceFactory, ServiceFactory}; use actix_service::{boxed, IntoServiceFactory, ServiceFactory};
use actix_web::{ use actix_web::{
@ -17,7 +17,7 @@ use crate::{
HttpNewService, MimeOverride, HttpNewService, MimeOverride,
}; };
/// Static files handling /// Static files handling service.
/// ///
/// `Files` service must be registered with `App::service()` method. /// `Files` service must be registered with `App::service()` method.
/// ///
@ -41,6 +41,12 @@ pub struct Files {
guards: Option<Rc<dyn Guard>>, guards: Option<Rc<dyn Guard>>,
} }
impl fmt::Debug for Files {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("Files")
}
}
impl Clone for Files { impl Clone for Files {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@ -193,11 +199,13 @@ impl HttpServiceFactory for Files {
if self.default.borrow().is_none() { if self.default.borrow().is_none() {
*self.default.borrow_mut() = Some(config.default_service()); *self.default.borrow_mut() = Some(config.default_service());
} }
let rdef = if config.is_root() { let rdef = if config.is_root() {
ResourceDef::root_prefix(&self.path) ResourceDef::root_prefix(&self.path)
} else { } else {
ResourceDef::prefix(&self.path) ResourceDef::prefix(&self.path)
}; };
config.register_service(rdef, None, self, None) config.register_service(rdef, None, self, None)
} }
} }

View File

@ -1,6 +1,22 @@
//! Static files support //! Static files support for Actix Web.
//!
//! Provides a non-blocking service for serving static files from disk.
//!
//! # Example
//! ```rust
//! use actix_web::App;
//! use actix_files::Files;
//!
//! let app = App::new()
//! .service(Files::new("/static", "."));
//! ```
//!
//! # Implementation Quirks
//! - If a filename contains non-ascii characters, that file will be served with the `charset=utf-8`
//! extension on the Content-Type header.
#![deny(rust_2018_idioms)] #![deny(rust_2018_idioms)]
#![warn(missing_docs, missing_debug_implementations)]
use std::io; use std::io;

View File

@ -7,17 +7,20 @@ use std::time::{SystemTime, UNIX_EPOCH};
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::fs::MetadataExt; use std::os::unix::fs::MetadataExt;
use bitflags::bitflags; use actix_web::{
use mime_guess::from_path; dev::{BodyEncoding, SizedStream},
http::{
use actix_http::body::SizedStream; header::{
use actix_web::dev::BodyEncoding; self, Charset, ContentDisposition, DispositionParam, DispositionType,
use actix_web::http::header::{ ExtendedValue,
self, Charset, ContentDisposition, DispositionParam, DispositionType, ExtendedValue, },
ContentEncoding, StatusCode,
},
Error, HttpMessage, HttpRequest, HttpResponse, Responder,
}; };
use actix_web::http::{ContentEncoding, StatusCode}; use bitflags::bitflags;
use actix_web::{Error, HttpMessage, HttpRequest, HttpResponse, Responder};
use futures_util::future::{ready, Ready}; use futures_util::future::{ready, Ready};
use mime_guess::from_path;
use crate::range::HttpRange; use crate::range::HttpRange;
use crate::ChunkedReadFile; use crate::ChunkedReadFile;
@ -247,6 +250,7 @@ impl NamedFile {
let dur = mtime let dur = mtime
.duration_since(UNIX_EPOCH) .duration_since(UNIX_EPOCH)
.expect("modification time must be after epoch"); .expect("modification time must be after epoch");
header::EntityTag::strong(format!( header::EntityTag::strong(format!(
"{:x}:{:x}:{:x}:{:x}", "{:x}:{:x}:{:x}:{:x}",
ino, ino,
@ -261,6 +265,7 @@ impl NamedFile {
self.modified.map(|mtime| mtime.into()) self.modified.map(|mtime| mtime.into())
} }
/// Creates an `HttpResponse` with file as a streaming body.
pub fn into_response(self, req: &HttpRequest) -> Result<HttpResponse, Error> { pub fn into_response(self, req: &HttpRequest) -> Result<HttpResponse, Error> {
if self.status_code != StatusCode::OK { if self.status_code != StatusCode::OK {
let mut resp = HttpResponse::build(self.status_code); let mut resp = HttpResponse::build(self.status_code);
@ -364,10 +369,10 @@ impl NamedFile {
// check for range header // check for range header
if let Some(ranges) = req.headers().get(header::RANGE) { if let Some(ranges) = req.headers().get(header::RANGE) {
if let Ok(rangesheader) = ranges.to_str() { if let Ok(ranges_header) = ranges.to_str() {
if let Ok(rangesvec) = HttpRange::parse(rangesheader, length) { if let Ok(ranges) = HttpRange::parse(ranges_header, length) {
length = rangesvec[0].length; length = ranges[0].length;
offset = rangesvec[0].start; offset = ranges[0].start;
resp.encoding(ContentEncoding::Identity); resp.encoding(ContentEncoding::Identity);
resp.header( resp.header(

View File

@ -16,7 +16,7 @@ impl FromStr for PathBufWrap {
fn from_str(path: &str) -> Result<Self, Self::Err> { fn from_str(path: &str) -> Result<Self, Self::Err> {
let mut buf = PathBuf::new(); let mut buf = PathBuf::new();
for segment in path.split('/') { for segment in path.split('/') {
if segment == ".." { if segment == ".." {
buf.pop(); buf.pop();

View File

@ -1,7 +1,10 @@
/// HTTP Range header representation. /// HTTP Range header representation.
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct HttpRange { pub struct HttpRange {
/// Start of range.
pub start: u64, pub start: u64,
/// Length of range.
pub length: u64, pub length: u64,
} }

View File

@ -1,5 +1,5 @@
use std::{ use std::{
io, fmt, io,
path::PathBuf, path::PathBuf,
rc::Rc, rc::Rc,
task::{Context, Poll}, task::{Context, Poll},
@ -20,6 +20,7 @@ use crate::{
NamedFile, PathBufWrap, NamedFile, PathBufWrap,
}; };
/// Assembled file serving service.
pub struct FilesService { pub struct FilesService {
pub(crate) directory: PathBuf, pub(crate) directory: PathBuf,
pub(crate) index: Option<String>, pub(crate) index: Option<String>,
@ -49,6 +50,12 @@ impl FilesService {
} }
} }
impl fmt::Debug for FilesService {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("FilesService")
}
}
impl Service for FilesService { impl Service for FilesService {
type Request = ServiceRequest; type Request = ServiceRequest;
type Response = ServiceResponse; type Response = ServiceResponse;