From 8f3f89716f64c76500aa0de31301ae61ff4bb655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Orhun=20Parmaks=C4=B1z?= Date: Sun, 5 Dec 2021 15:03:51 +0300 Subject: [PATCH] fix(async): drop the RW guard of config before suspend points --- src/main.rs | 8 ++++---- src/paste.rs | 4 ++-- src/server.rs | 45 ++++++++++++++++++++++++++++++++------------- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/main.rs b/src/main.rs index 6577b1d..d14979f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use std::env; use std::fs; use std::io::Result as IoResult; use std::path::PathBuf; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, RwLock}; use std::time::Duration; #[actix_web::main] @@ -21,11 +21,11 @@ async fn main() -> IoResult<()> { dotenv::dotenv().ok(); let config_path = PathBuf::from(env::var("CONFIG").unwrap_or_else(|_| String::from("config.toml"))); - let config = Arc::new(Mutex::new( + let config = Arc::new(RwLock::new( Config::parse(&config_path).expect("failed to parse config"), )); let cloned_config = Arc::clone(&config); - let server_config = config.lock().expect("cannot acquire config").server.clone(); + let server_config = config.read().expect("cannot acquire config").server.clone(); // Create necessary directories. fs::create_dir_all(&server_config.upload_path)?; @@ -41,7 +41,7 @@ async fn main() -> IoResult<()> { let config_watcher = move |event: Event| { if let Event::Write(path) = event { match Config::parse(&path) { - Ok(config) => match cloned_config.lock() { + Ok(config) => match cloned_config.write() { Ok(mut cloned_config) => { *cloned_config = config; log::info!("Configuration has been updated."); diff --git a/src/paste.rs b/src/paste.rs index b78b966..f7ef182 100644 --- a/src/paste.rs +++ b/src/paste.rs @@ -158,7 +158,7 @@ impl Paste { &mut self, expiry_date: Option, client: &Client, - config: &Config, + config: Config, ) -> Result { let data = str::from_utf8(&self.data).map_err(error::ErrorBadRequest)?; let url = Url::parse(data).map_err(error::ErrorBadRequest)?; @@ -189,7 +189,7 @@ impl Paste { .to_string()); } } - Ok(self.store_file(file_name, expiry_date, config)?) + Ok(self.store_file(file_name, expiry_date, &config)?) } /// Writes an URL to a file in upload directory. diff --git a/src/server.rs b/src/server.rs index e72dd73..11b78f9 100644 --- a/src/server.rs +++ b/src/server.rs @@ -14,7 +14,7 @@ use futures_util::stream::StreamExt; use std::convert::TryFrom; use std::env; use std::fs; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, RwLock}; /// Shows the landing page. #[get("/")] @@ -29,10 +29,10 @@ async fn index() -> impl Responder { async fn serve( request: HttpRequest, file: web::Path, - config: web::Data>>, + config: web::Data>>, ) -> Result { let config = config - .lock() + .read() .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?; let path = config.server.upload_path.join(&*file); let mut path = util::glob_match_file(path)?; @@ -85,16 +85,13 @@ async fn upload( request: HttpRequest, mut payload: Multipart, client: web::Data, - config: web::Data>>, + config: web::Data>>, ) -> Result { let connection = request.connection_info().clone(); let host = connection.remote_addr().unwrap_or("unknown host"); auth::check(host, request.headers(), env::var("AUTH_TOKEN").ok())?; let expiry_date = header::parse_expiry_date(request.headers())?; let mut urls: Vec = Vec::new(); - let config = config - .lock() - .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?; while let Some(item) = payload.next().await { let mut field = item?; let content = ContentDisposition::try_from(field.content_disposition())?; @@ -102,6 +99,9 @@ async fn upload( let mut bytes = Vec::::new(); while let Some(chunk) = field.next().await { bytes.append(&mut chunk?.to_vec()); + let config = config + .read() + .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?; if bytes.len() as u128 > config.server.max_content_length.get_bytes() { log::warn!("Upload rejected for {}", host); return Err(error::ErrorPayloadTooLarge("upload limit exceeded")); @@ -114,9 +114,17 @@ async fn upload( if paste_type != PasteType::Oneshot && paste_type != PasteType::RemoteFile && expiry_date.is_none() - && !config.paste.duplicate_files.unwrap_or(true) + && !config + .read() + .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))? + .paste + .duplicate_files + .unwrap_or(true) { let bytes_checksum = util::sha256_digest(&*bytes)?; + let config = config + .read() + .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?; if let Some(file) = Directory::try_from(config.server.upload_path.as_path())? .get_file(bytes_checksum) { @@ -128,7 +136,6 @@ async fn upload( .file_name() .map(|v| v.to_string_lossy()) .unwrap_or_default() - .to_string() )); continue; } @@ -139,14 +146,26 @@ async fn upload( }; let file_name = match paste.type_ { PasteType::File | PasteType::Oneshot => { + let config = config + .read() + .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?; paste.store_file(content.get_file_name()?, expiry_date, &config)? } PasteType::RemoteFile => { - paste - .store_remote_file(expiry_date, &client, &config) - .await? + { + let config = config.read().map_err(|_| { + error::ErrorInternalServerError("cannot acquire config") + })?; + paste.store_remote_file(expiry_date, &client, config.clone()) + } + .await? + } + PasteType::Url => { + let config = config + .read() + .map_err(|_| error::ErrorInternalServerError("cannot acquire config"))?; + paste.store_url(expiry_date, &config)? } - PasteType::Url => paste.store_url(expiry_date, &config)?, }; log::info!( "{} ({}) is uploaded from {}",