derive deref for namedfile

This commit is contained in:
Rob Ede 2021-12-13 05:07:53 +00:00
parent 551a0d973c
commit 172321d19d
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
1 changed files with 26 additions and 36 deletions

View File

@ -2,14 +2,10 @@ use std::{
fmt, fmt,
fs::Metadata, fs::Metadata,
io, io,
ops::{Deref, DerefMut},
path::{Path, PathBuf}, path::{Path, PathBuf},
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
use actix_service::{Service, ServiceFactory}; use actix_service::{Service, ServiceFactory};
use actix_web::{ use actix_web::{
body::{self, BoxBody, SizedStream}, body::{self, BoxBody, SizedStream},
@ -27,6 +23,7 @@ use actix_web::{
Error, HttpMessage, HttpRequest, HttpResponse, Responder, Error, HttpMessage, HttpRequest, HttpResponse, Responder,
}; };
use bitflags::bitflags; use bitflags::bitflags;
use derive_more::{Deref, DerefMut};
use futures_core::future::LocalBoxFuture; use futures_core::future::LocalBoxFuture;
use mime_guess::from_path; use mime_guess::from_path;
@ -71,8 +68,11 @@ impl Default for Flags {
/// NamedFile::open_async("./static/index.html").await /// NamedFile::open_async("./static/index.html").await
/// } /// }
/// ``` /// ```
#[derive(Deref, DerefMut)]
pub struct NamedFile { pub struct NamedFile {
path: PathBuf, path: PathBuf,
#[deref]
#[deref_mut]
file: File, file: File,
modified: Option<SystemTime>, modified: Option<SystemTime>,
pub(crate) md: Metadata, pub(crate) md: Metadata,
@ -364,14 +364,18 @@ impl NamedFile {
self self
} }
/// Creates a etag in a format is similar to Apache's.
pub(crate) fn etag(&self) -> Option<header::EntityTag> { pub(crate) fn etag(&self) -> Option<header::EntityTag> {
// This etag format is similar to Apache's.
self.modified.as_ref().map(|mtime| { self.modified.as_ref().map(|mtime| {
let ino = { let ino = {
#[cfg(unix)] #[cfg(unix)]
{ {
#[cfg(unix)]
use std::os::unix::fs::MetadataExt as _;
self.md.ino() self.md.ino()
} }
#[cfg(not(unix))] #[cfg(not(unix))]
{ {
0 0
@ -472,17 +476,17 @@ impl NamedFile {
false false
}; };
let mut resp = HttpResponse::build(self.status_code); let mut res = HttpResponse::build(self.status_code);
if self.flags.contains(Flags::PREFER_UTF8) { if self.flags.contains(Flags::PREFER_UTF8) {
let ct = equiv_utf8_text(self.content_type.clone()); let ct = equiv_utf8_text(self.content_type.clone());
resp.insert_header((header::CONTENT_TYPE, ct.to_string())); res.insert_header((header::CONTENT_TYPE, ct.to_string()));
} else { } else {
resp.insert_header((header::CONTENT_TYPE, self.content_type.to_string())); res.insert_header((header::CONTENT_TYPE, self.content_type.to_string()));
} }
if self.flags.contains(Flags::CONTENT_DISPOSITION) { if self.flags.contains(Flags::CONTENT_DISPOSITION) {
resp.insert_header(( res.insert_header((
header::CONTENT_DISPOSITION, header::CONTENT_DISPOSITION,
self.content_disposition.to_string(), self.content_disposition.to_string(),
)); ));
@ -490,18 +494,18 @@ impl NamedFile {
// default compressing // default compressing
if let Some(current_encoding) = self.encoding { if let Some(current_encoding) = self.encoding {
resp.encoding(current_encoding); res.encoding(current_encoding);
} }
if let Some(lm) = last_modified { if let Some(lm) = last_modified {
resp.insert_header((header::LAST_MODIFIED, lm.to_string())); res.insert_header((header::LAST_MODIFIED, lm.to_string()));
} }
if let Some(etag) = etag { if let Some(etag) = etag {
resp.insert_header((header::ETAG, etag.to_string())); res.insert_header((header::ETAG, etag.to_string()));
} }
resp.insert_header((header::ACCEPT_RANGES, "bytes")); res.insert_header((header::ACCEPT_RANGES, "bytes"));
let mut length = self.md.len(); let mut length = self.md.len();
let mut offset = 0; let mut offset = 0;
@ -513,24 +517,24 @@ impl NamedFile {
length = ranges[0].length; length = ranges[0].length;
offset = ranges[0].start; offset = ranges[0].start;
resp.encoding(ContentEncoding::Identity); res.encoding(ContentEncoding::Identity);
resp.insert_header(( res.insert_header((
header::CONTENT_RANGE, header::CONTENT_RANGE,
format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()), format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()),
)); ));
} else { } else {
resp.insert_header((header::CONTENT_RANGE, format!("bytes */{}", length))); res.insert_header((header::CONTENT_RANGE, format!("bytes */{}", length)));
return resp.status(StatusCode::RANGE_NOT_SATISFIABLE).finish(); return res.status(StatusCode::RANGE_NOT_SATISFIABLE).finish();
}; };
} else { } else {
return resp.status(StatusCode::BAD_REQUEST).finish(); return res.status(StatusCode::BAD_REQUEST).finish();
}; };
}; };
if precondition_failed { if precondition_failed {
return resp.status(StatusCode::PRECONDITION_FAILED).finish(); return res.status(StatusCode::PRECONDITION_FAILED).finish();
} else if not_modified { } else if not_modified {
return resp return res
.status(StatusCode::NOT_MODIFIED) .status(StatusCode::NOT_MODIFIED)
.body(body::None::new()) .body(body::None::new())
.map_into_boxed_body(); .map_into_boxed_body();
@ -539,10 +543,10 @@ impl NamedFile {
let reader = chunked::new_chunked_read(length, offset, self.file); let reader = chunked::new_chunked_read(length, offset, self.file);
if offset != 0 || length != self.md.len() { if offset != 0 || length != self.md.len() {
resp.status(StatusCode::PARTIAL_CONTENT); res.status(StatusCode::PARTIAL_CONTENT);
} }
resp.body(SizedStream::new(length, reader)) res.body(SizedStream::new(length, reader))
} }
} }
@ -586,20 +590,6 @@ fn none_match(etag: Option<&header::EntityTag>, req: &HttpRequest) -> bool {
} }
} }
impl Deref for NamedFile {
type Target = File;
fn deref(&self) -> &Self::Target {
&self.file
}
}
impl DerefMut for NamedFile {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.file
}
}
impl Responder for NamedFile { impl Responder for NamedFile {
type Body = BoxBody; type Body = BoxBody;