From 9796d35a8b50e15cbe3abecd8888065a1bdc888d Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Sun, 26 Feb 2023 14:59:32 -0800 Subject: [PATCH] refactor: minor optimizations and small improvements (#177) * Avoid content-type header's contents cloning * Don't wrap the file being read in a Mutex * Avoid cloning paths when possible * Simplify compressed file path handling logic --- src/compression.rs | 5 +++-- src/compression_static.rs | 21 ++++++++++++--------- src/static_files.rs | 23 +++++++---------------- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/src/compression.rs b/src/compression.rs index a85b6ff..349f567 100644 --- a/src/compression.rs +++ b/src/compression.rs @@ -9,6 +9,7 @@ use hyper::{ header::{HeaderValue, CONTENT_ENCODING, CONTENT_LENGTH}, Body, Method, Response, }; +use mime_guess::Mime; use pin_project::pin_project; use std::pin::Pin; use std::task::{Context, Poll}; @@ -70,8 +71,8 @@ pub fn auto( if let Some(encoding) = get_prefered_encoding(headers) { // Skip compression for non-text-based MIME types if let Some(content_type) = resp.headers().typed_get::() { - let content_type = &content_type.to_string(); - if !TEXT_MIME_TYPES.iter().any(|h| *h == content_type) { + let mime = Mime::from(content_type); + if !TEXT_MIME_TYPES.iter().any(|h| *h == mime) { return Ok(resp); } } diff --git a/src/compression_static.rs b/src/compression_static.rs index a569340..f776249 100644 --- a/src/compression_static.rs +++ b/src/compression_static.rs @@ -1,13 +1,17 @@ use headers::{ContentCoding, HeaderMap, HeaderValue}; -use std::{fs::Metadata, path::PathBuf}; +use std::{ + ffi::OsStr, + fs::Metadata, + path::{Path, PathBuf}, +}; use crate::{compression, static_files::file_metadata}; /// Search for the pre-compressed variant of the given file path. -pub async fn precompressed_variant( - file_path: PathBuf, - headers: &HeaderMap, -) -> Option<(PathBuf, Metadata, &str)> { +pub async fn precompressed_variant<'a>( + file_path: &Path, + headers: &'a HeaderMap, +) -> Option<(PathBuf, Metadata, &'a str)> { let mut precompressed = None; tracing::trace!( @@ -30,11 +34,10 @@ pub async fn precompressed_variant( // Try to find the pre-compressed metadata variant for the given file path if let Some(ext) = precomp_ext { - let mut filepath_precomp = file_path; - if let Some(filename) = filepath_precomp.file_name() { - let filename = filename.to_str().unwrap(); + let filename = file_path.file_name().and_then(OsStr::to_str); + if let Some(filename) = filename { let precomp_file_name = [filename, ".", ext].concat(); - filepath_precomp.set_file_name(precomp_file_name); + let filepath_precomp = file_path.with_file_name(precomp_file_name); tracing::trace!( "getting metadata for pre-compressed file variant {}", diff --git a/src/static_files.rs b/src/static_files.rs index 19f6f89..d8fbed4 100644 --- a/src/static_files.rs +++ b/src/static_files.rs @@ -18,7 +18,6 @@ use std::io::{self, BufReader, Read, Seek, SeekFrom}; use std::ops::Bound; use std::path::{Component, Path, PathBuf}; use std::pin::Pin; -use std::sync::Mutex; use std::task::{Context, Poll}; use crate::directory_listing::DirListFmt; @@ -152,7 +151,7 @@ async fn composed_file_metadata<'a>( if compression_static { tried_precompressed = true; if let Some((path, meta, ext)) = - compression_static::precompressed_variant(file_path.clone(), headers).await + compression_static::precompressed_variant(file_path, headers).await { return Ok((file_path, meta, false, Some((path, ext)))); } @@ -180,7 +179,7 @@ async fn composed_file_metadata<'a>( // Second pre-compressed variant check for the given file path if compression_static && !tried_precompressed { if let Some((path, meta, ext)) = - compression_static::precompressed_variant(file_path.clone(), headers).await + compression_static::precompressed_variant(file_path, headers).await { return Ok((file_path, meta, false, Some((path, ext)))); } @@ -220,7 +219,7 @@ fn file_reply<'a>( ) -> impl Future, StatusCode>> + Send + 'a { let conditionals = get_conditional_headers(headers); - let file_path = path_precompressed.unwrap_or_else(|| path.clone()); + let file_path = path_precompressed.as_ref().unwrap_or(path); match File::open(file_path) { Ok(file) => Either::Left(response_body(file, path, meta, conditionals)), @@ -367,23 +366,15 @@ const READ_BUF_SIZE: usize = 8_192; #[derive(Debug)] pub struct FileStream { - reader: Mutex, + reader: T, } -impl Stream for FileStream { +impl Stream for FileStream { type Item = Result; fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll> { - let mut reader = match self.reader.lock() { - Ok(reader) => reader, - Err(err) => { - tracing::error!("file stream error: {:?}", err); - return Poll::Ready(Some(Err(anyhow::anyhow!("failed to read stream file")))); - } - }; - let mut buf = BytesMut::zeroed(READ_BUF_SIZE); - match reader.read(&mut buf[..]) { + match Pin::into_inner(self).reader.read(&mut buf[..]) { Ok(n) => { if n == 0 { Poll::Ready(None) @@ -420,7 +411,7 @@ async fn response_body( }; let sub_len = end - start; - let reader = Mutex::new(BufReader::new(file).take(sub_len)); + let reader = BufReader::new(file).take(sub_len); let stream = FileStream { reader }; let body = Body::wrap_stream(stream); -- libgit2 1.7.2