From d6430e39a927b8bcd4f07ab21b956cecca7b1082 Mon Sep 17 00:00:00 2001 From: _ <> Date: Sun, 29 Nov 2020 21:38:23 +0000 Subject: [PATCH] :recycle: Get rid of more unwraps and panics --- README.md | 7 +- crates/ptth_relay/src/tests.rs | 4 +- crates/ptth_server/Cargo.toml | 1 + .../ptth_server/src/bin/ptth_file_server.rs | 5 +- crates/ptth_server/src/bin/ptth_server.rs | 5 +- crates/ptth_server/src/errors.rs | 58 +++++- crates/ptth_server/src/file_server/errors.rs | 3 + crates/ptth_server/src/file_server/mod.rs | 195 ++++++++++-------- crates/ptth_server/src/file_server/tests.rs | 31 ++- crates/ptth_server/src/lib.rs | 28 +-- crates/ptth_server/src/load_toml.rs | 24 ++- src/tests.rs | 28 +-- 12 files changed, 251 insertions(+), 138 deletions(-) diff --git a/README.md b/README.md index 3b51c2f..c83c949 100644 --- a/README.md +++ b/README.md @@ -121,10 +121,11 @@ Client Relay Server O <----- O | P5 O <------ O - P6/H3 + P6/H3 | P7 + O -----> O ``` -We'll call these steps "P1" through "P6". +We'll call these steps "P1" through "P7". 1. The server makes a "listen" request to the relay, punching out through the server's firewall. @@ -138,6 +139,8 @@ to respond. 4. The server processes the request. (P4 == H2) 5. The server packages its response in another request to the relay. 6. The relay unwraps the request and forwards it to the client. (P6 == H3) +7. When the full response body has been streamed through the relay and to the +client, the relay will respond to the server. Every step of the normal HTTP process is inverted for the server: diff --git a/crates/ptth_relay/src/tests.rs b/crates/ptth_relay/src/tests.rs index c1e7b74..6b80c37 100644 --- a/crates/ptth_relay/src/tests.rs +++ b/crates/ptth_relay/src/tests.rs @@ -4,7 +4,7 @@ use super::*; fn test_pretty_print_last_seen () { use LastSeen::*; - let last_seen = DateTime::parse_from_rfc3339 ("2019-05-29T00:00:00+00:00").unwrap ().with_timezone (&Utc); + let last_seen = DateTime::parse_from_rfc3339 ("2019-05-29T00:00:00+00:00").expect ("Test case should be RFC3339").with_timezone (&Utc); for (input, expected) in vec! [ ("2019-05-28T23:59:59+00:00", Negative), @@ -18,7 +18,7 @@ fn test_pretty_print_last_seen () { ("2019-05-30T10:00:00+00:00", Description ("2019-05-29T00:00:00Z".into ())), ("2019-05-31T00:00:00+00:00", Description ("2019-05-29T00:00:00Z".into ())), ].into_iter () { - let now = DateTime::parse_from_rfc3339 (input).unwrap ().with_timezone (&Utc); + let now = DateTime::parse_from_rfc3339 (input).expect ("Test case should be RFC3339").with_timezone (&Utc); let actual = pretty_print_last_seen (now, last_seen); assert_eq! (actual, expected); } diff --git a/crates/ptth_server/Cargo.toml b/crates/ptth_server/Cargo.toml index 7fc1b84..bb8ed1b 100644 --- a/crates/ptth_server/Cargo.toml +++ b/crates/ptth_server/Cargo.toml @@ -9,6 +9,7 @@ license = "AGPL-3.0" [dependencies] aho-corasick = "0.7.14" +anyhow = "1.0.34" base64 = "0.12.3" blake3 = "0.3.7" futures = "0.3.7" diff --git a/crates/ptth_server/src/bin/ptth_file_server.rs b/crates/ptth_server/src/bin/ptth_file_server.rs index 1080286..11482a0 100644 --- a/crates/ptth_server/src/bin/ptth_file_server.rs +++ b/crates/ptth_server/src/bin/ptth_file_server.rs @@ -1,7 +1,6 @@ #![warn (clippy::pedantic)] use std::{ - error::Error, net::SocketAddr, path::PathBuf, sync::Arc, @@ -91,11 +90,11 @@ pub struct ConfigFile { } #[tokio::main] -async fn main () -> Result <(), Box > { +async fn main () -> Result <(), anyhow::Error> { tracing_subscriber::fmt::init (); let path = PathBuf::from ("./config/ptth_server.toml"); - let config_file: ConfigFile = load_toml::load (&path); + let config_file: ConfigFile = load_toml::load (&path)?; info! ("file_server_root: {:?}", config_file.file_server_root); let addr = SocketAddr::from(([0, 0, 0, 0], 4000)); diff --git a/crates/ptth_server/src/bin/ptth_server.rs b/crates/ptth_server/src/bin/ptth_server.rs index f08361e..321d3dd 100644 --- a/crates/ptth_server/src/bin/ptth_server.rs +++ b/crates/ptth_server/src/bin/ptth_server.rs @@ -1,7 +1,6 @@ #![warn (clippy::pedantic)] use std::{ - error::Error, path::PathBuf, }; @@ -29,12 +28,12 @@ struct Opt { print_tripcode: bool, } -fn main () -> Result <(), Box > { +fn main () -> Result <(), anyhow::Error> { let opt = Opt::from_args (); tracing_subscriber::fmt::init (); let path = opt.config_path.clone ().unwrap_or_else (|| PathBuf::from ("./config/ptth_server.toml")); - let config_file: ConfigFile = load_toml::load (&path); + let config_file: ConfigFile = load_toml::load (&path)?; if opt.print_tripcode { println! (r#""{}" = "{}""#, config_file.name, config_file.tripcode ()); diff --git a/crates/ptth_server/src/errors.rs b/crates/ptth_server/src/errors.rs index c8c2d4b..a2bb0c9 100644 --- a/crates/ptth_server/src/errors.rs +++ b/crates/ptth_server/src/errors.rs @@ -1,19 +1,75 @@ use thiserror::Error; +#[derive (Debug, Error)] +pub enum LoadTomlError { + #[error ("Config file has bad permissions mode, it should be octal 0600")] + ConfigBadPermissions, + + #[error ("I/O")] + Io (#[from] std::io::Error), + + #[error ("UTF-8")] + Utf8 (#[from] std::string::FromUtf8Error), + + #[error ("TOML")] + Toml (#[from] toml::de::Error), +} + #[derive (Debug, Error)] pub enum ServerError { + #[error ("Loading TOML")] + LoadToml (#[from] LoadTomlError), + + #[error ("Loading Handlebars template file")] + LoadHandlebars (#[from] handlebars::TemplateFileError), + + #[error ("API key is too weak, server can't use it")] + WeakApiKey, + #[error ("File server error")] FileServer (#[from] super::file_server::errors::FileServerError), + // Hyper stuff + #[error ("Hyper HTTP error")] Http (#[from] hyper::http::Error), #[error ("Hyper invalid header name")] InvalidHeaderName (#[from] hyper::header::InvalidHeaderName), - #[error ("Can't parse wrapped requests")] + #[error ("API key invalid")] + ApiKeyInvalid (hyper::header::InvalidHeaderValue), + + // MessagePack stuff + + #[error ("Can't parse wrapped requests in Step 3")] CantParseWrappedRequests (rmp_serde::decode::Error), + #[error ("Can't encode PTTH response as MsgPack in Step 5")] + MessagePackEncodeResponse (rmp_serde::encode::Error), + #[error ("Can't convert Hyper request to PTTH request")] CantConvertHyperToPtth (#[from] ptth_core::http_serde::Error), + + // Reqwest stuff + + #[error ("Can't build HTTP client")] + CantBuildHttpClient (reqwest::Error), + + #[error ("Can't collect non-200 error response body in Step 3")] + Step3CollectBody (reqwest::Error), + + #[error ("Can't collect wrapped requests in Step 3")] + CantCollectWrappedRequests (reqwest::Error), + + #[error ("Error in Step 5, sending response to client through relay")] + Step5Responding (reqwest::Error), + + #[error ("Error in Step 7, getting response from relay after sending response to client")] + Step7AfterResponse (reqwest::Error), + + // UTF-8 + + #[error ("Step 3 relay response (non-200 OK) was not valid UTF-8")] + Step3ErrorResponseNotUtf8 (std::string::FromUtf8Error), } diff --git a/crates/ptth_server/src/file_server/errors.rs b/crates/ptth_server/src/file_server/errors.rs index a4ae14b..e5b7cc5 100644 --- a/crates/ptth_server/src/file_server/errors.rs +++ b/crates/ptth_server/src/file_server/errors.rs @@ -31,4 +31,7 @@ pub enum FileServerError { #[error ("Markdown error")] Markdown (#[from] MarkdownError), + + #[error ("Invalid URI")] + InvalidUri (#[from] hyper::http::uri::InvalidUri), } diff --git a/crates/ptth_server/src/file_server/mod.rs b/crates/ptth_server/src/file_server/mod.rs index b27b95b..7ef6b66 100644 --- a/crates/ptth_server/src/file_server/mod.rs +++ b/crates/ptth_server/src/file_server/mod.rs @@ -8,7 +8,6 @@ use std::{ cmp::min, collections::HashMap, convert::{Infallible, TryFrom, TryInto}, - error::Error, fmt::Debug, io::SeekFrom, path::{Path, PathBuf}, @@ -451,7 +450,6 @@ struct ServeFileParams { enum InternalResponse { Favicon, Forbidden, - InvalidUri, InvalidQuery, MethodNotAllowed, NotFound, @@ -465,6 +463,100 @@ enum InternalResponse { MarkdownPreview (String), } +fn internal_serve_dir ( + path_s: &str, + path: &Path, + dir: tokio::fs::ReadDir, + full_path: PathBuf, + uri: &hyper::Uri +) +-> Result +{ + let has_trailing_slash = path_s.is_empty () || path_s.ends_with ('/'); + + if ! has_trailing_slash { + let file_name = path.file_name ().ok_or (FileServerError::NoFileNameRequested)?; + let file_name = file_name.to_str ().ok_or (FileServerError::FilePathNotUtf8)?; + return Ok (InternalResponse::Redirect (format! ("{}/", file_name))); + } + + if uri.query ().is_some () { + return Ok (InternalResponse::InvalidQuery); + } + + let dir = dir.into (); + + Ok (InternalResponse::ServeDir (ServeDirParams { + dir, + path: full_path, + })) +} + +async fn internal_serve_file ( + mut file: tokio::fs::File, + uri: &hyper::Uri, + send_body: bool, + headers: &HashMap > +) +-> Result +{ + use std::os::unix::fs::PermissionsExt; + + let file_md = file.metadata ().await.map_err (FileServerError::CantGetFileMetadata)?; + if file_md.permissions ().mode () == super::load_toml::CONFIG_PERMISSIONS_MODE + { + return Ok (InternalResponse::Forbidden); + } + + let file_len = file_md.len (); + + let range_header = headers.get ("range").and_then (|v| std::str::from_utf8 (v).ok ()); + + Ok (match check_range (range_header, file_len) { + ParsedRange::RangeNotSatisfiable (file_len) => InternalResponse::RangeNotSatisfiable (file_len), + ParsedRange::Ok (range) => { + if uri.query () == Some ("as_markdown") { + const MAX_BUF_SIZE: u32 = 1_000_000; + if file_len > MAX_BUF_SIZE.into () { + InternalResponse::MarkdownErr (MarkdownError::TooBig) + } + else { + let mut buffer = vec! [0_u8; MAX_BUF_SIZE.try_into ().expect ("Couldn't fit u32 into usize")]; + let bytes_read = file.read (&mut buffer).await?; + buffer.truncate (bytes_read); + + InternalResponse::MarkdownPreview (render_markdown_styled (&buffer)?) + } + } + else { + let file = file.into (); + + InternalResponse::ServeFile (ServeFileParams { + file, + send_body, + range, + range_requested: false, + }) + } + }, + ParsedRange::PartialContent (range) => { + if uri.query ().is_some () { + InternalResponse::InvalidQuery + } + else { + let file = file.into (); + + InternalResponse::ServeFile (ServeFileParams { + file, + send_body, + range, + range_requested: true, + }) + } + }, + }) +} + async fn internal_serve_all ( root: &Path, method: Method, @@ -479,10 +571,7 @@ async fn internal_serve_all ( info! ("Client requested {}", uri); - let uri = match hyper::Uri::from_str (uri) { - Err (_) => return Ok (InvalidUri), - Ok (x) => x, - }; + let uri = hyper::Uri::from_str (uri).map_err (FileServerError::InvalidUri)?; let send_body = match &method { Method::Get => true, @@ -523,85 +612,26 @@ async fn internal_serve_all ( } } - let has_trailing_slash = path_s.is_empty () || path_s.ends_with ('/'); - - Ok (if let Ok (dir) = read_dir (&full_path).await { - if ! has_trailing_slash { - let file_name = path.file_name ().ok_or (FileServerError::NoFileNameRequested)?; - return Ok (Redirect (format! ("{}/", file_name.to_str ().ok_or (FileServerError::FilePathNotUtf8)?))); - } - - if uri.query ().is_some () { - return Ok (InvalidQuery); - } - - let dir = dir.into (); - - ServeDir (ServeDirParams { + if let Ok (dir) = read_dir (&full_path).await { + internal_serve_dir ( + &path_s, + path, dir, - path: full_path, - }) + full_path, + &uri + ) } - else if let Ok (mut file) = File::open (&full_path).await { - use std::os::unix::fs::PermissionsExt; - - let file_md = file.metadata ().await.map_err (FileServerError::CantGetFileMetadata)?; - if file_md.permissions ().mode () == super::load_toml::CONFIG_PERMISSIONS_MODE - { - return Ok (Forbidden); - } - - let file_len = file_md.len (); - - let range_header = headers.get ("range").and_then (|v| std::str::from_utf8 (v).ok ()); - - match check_range (range_header, file_len) { - ParsedRange::RangeNotSatisfiable (file_len) => RangeNotSatisfiable (file_len), - ParsedRange::Ok (range) => { - if uri.query () == Some ("as_markdown") { - const MAX_BUF_SIZE: u32 = 1_000_000; - if file_len > MAX_BUF_SIZE.into () { - MarkdownErr (MarkdownError::TooBig) - } - else { - let mut buffer = vec! [0_u8; MAX_BUF_SIZE.try_into ().expect ("Couldn't fit u32 into usize")]; - let bytes_read = file.read (&mut buffer).await?; - buffer.truncate (bytes_read); - - MarkdownPreview (render_markdown_styled (&buffer)?) - } - } - else { - let file = file.into (); - - ServeFile (ServeFileParams { - file, - send_body, - range, - range_requested: false, - }) - } - }, - ParsedRange::PartialContent (range) => { - if uri.query ().is_some () { - InvalidQuery - } - else { - let file = file.into (); - - ServeFile (ServeFileParams { - file, - send_body, - range, - range_requested: true, - }) - } - }, - } + else if let Ok (file) = File::open (&full_path).await { + internal_serve_file ( + file, + &uri, + send_body, + headers + ).await } else { - NotFound - }) + Ok (NotFound) + } } #[instrument (level = "debug", skip (handlebars, headers))] @@ -621,7 +651,6 @@ pub async fn serve_all ( Ok (match internal_serve_all (root, method, uri, headers, hidden_path).await? { Favicon => serve_error (StatusCode::NotFound, ""), Forbidden => serve_error (StatusCode::Forbidden, "403 Forbidden"), - InvalidUri => serve_error (StatusCode::BadRequest, "Invalid URI"), InvalidQuery => serve_error (StatusCode::BadRequest, "Query is invalid for this object"), MethodNotAllowed => serve_error (StatusCode::MethodNotAllowed, "Unsupported method"), NotFound => serve_error (StatusCode::NotFound, "404 Not Found"), @@ -656,7 +685,7 @@ pub async fn serve_all ( pub fn load_templates ( asset_root: &Path ) --> Result , Box > +-> Result , handlebars::TemplateFileError> { let mut handlebars = Handlebars::new (); handlebars.set_strict_mode (true); diff --git a/crates/ptth_server/src/file_server/tests.rs b/crates/ptth_server/src/file_server/tests.rs index d81407d..cbb527f 100644 --- a/crates/ptth_server/src/file_server/tests.rs +++ b/crates/ptth_server/src/file_server/tests.rs @@ -119,7 +119,7 @@ fn file_server () { use super::*; tracing_subscriber::fmt ().try_init ().ok (); - let mut rt = Runtime::new ().unwrap (); + let mut rt = Runtime::new ().expect ("Can't create runtime"); rt.block_on (async { let file_server_root = PathBuf::from ("./"); @@ -127,6 +127,7 @@ fn file_server () { { use InternalResponse::*; + use crate::file_server::FileServerError; let bad_passwords_path = "/files/src/bad_passwords.txt"; @@ -148,8 +149,7 @@ fn file_server () { range_requested: false, file: AlwaysEqual::testing_blank (), })), - ("/ ", InvalidUri), - ].into_iter () { + ] { let resp = internal_serve_all ( &file_server_root, Method::Get, @@ -158,7 +158,24 @@ fn file_server () { None ).await; - assert_eq! (resp.unwrap (), expected); + assert_eq! (resp.expect ("This block only tests Ok (_) responses"), expected); + } + + for (uri_path, checker) in vec! [ + ("/ ", |e| match e { + FileServerError::InvalidUri (_) => (), + e => panic! ("Expected InvalidUri, got {:?}", e), + }), + ] { + let resp = internal_serve_all ( + &file_server_root, + Method::Get, + uri_path, + &headers, + None + ).await; + + checker (resp.unwrap_err ()); } let resp = internal_serve_all ( @@ -171,7 +188,7 @@ fn file_server () { None ).await; - assert_eq! (resp.unwrap (), RangeNotSatisfiable (1_048_576)); + assert_eq! (resp.expect ("Should be Ok (_)"), RangeNotSatisfiable (1_048_576)); let resp = internal_serve_all ( &file_server_root, @@ -181,7 +198,7 @@ fn file_server () { None ).await; - assert_eq! (resp.unwrap (), ServeFile (ServeFileParams { + assert_eq! (resp.expect ("Should be Ok (_)"), ServeFile (ServeFileParams { send_body: false, range: 0..1_048_576, range_requested: false, @@ -210,7 +227,7 @@ fn markdown () { ), ].into_iter () { let mut out = String::default (); - render_markdown (input.as_bytes (), &mut out).unwrap (); + render_markdown (input.as_bytes (), &mut out).expect ("Markdown sample failed"); assert_eq! (expected, &out); } } diff --git a/crates/ptth_server/src/lib.rs b/crates/ptth_server/src/lib.rs index d764a75..203af47 100644 --- a/crates/ptth_server/src/lib.rs +++ b/crates/ptth_server/src/lib.rs @@ -8,7 +8,6 @@ #![allow (clippy::mut_mut)] use std::{ - error::Error, path::PathBuf, sync::Arc, time::Duration, @@ -66,7 +65,7 @@ async fn handle_req_resp <'a> ( ) -> Result <(), ServerError> { //println! ("Step 1"); - let body = req_resp.bytes ().await.unwrap (); + let body = req_resp.bytes ().await.map_err (ServerError::CantCollectWrappedRequests)?; let wrapped_reqs: Vec = match rmp_serde::from_read_ref (&body) { Ok (x) => x, @@ -81,6 +80,8 @@ async fn handle_req_resp <'a> ( for wrapped_req in wrapped_reqs { let state = state.clone (); + // These have to detach, so we won't be able to catch the join errors. + tokio::spawn (async move { let (req_id, parts) = (wrapped_req.id, wrapped_req.req); @@ -99,11 +100,11 @@ async fn handle_req_resp <'a> ( &parts.uri, &parts.headers, state.hidden_path.as_deref () - ).await.unwrap (); + ).await?; let mut resp_req = state.client .post (&format! ("{}/http_response/{}", state.config.relay_url, req_id)) - .header (ptth_core::PTTH_MAGIC_HEADER, base64::encode (rmp_serde::to_vec (&response.parts).unwrap ())); + .header (ptth_core::PTTH_MAGIC_HEADER, base64::encode (rmp_serde::to_vec (&response.parts).map_err (ServerError::MessagePackEncodeResponse)?)); if let Some (length) = response.content_length { resp_req = resp_req.header ("Content-Length", length.to_string ()); @@ -112,7 +113,7 @@ async fn handle_req_resp <'a> ( resp_req = resp_req.body (reqwest::Body::wrap_stream (body)); } - let req = resp_req.build ().unwrap (); + let req = resp_req.build ().map_err (ServerError::Step5Responding)?; debug! ("{:?}", req.headers ()); @@ -120,7 +121,7 @@ async fn handle_req_resp <'a> ( match state.client.execute (req).await { Ok (r) => { let status = r.status (); - let text = r.text ().await.unwrap (); + let text = r.text ().await.map_err (ServerError::Step7AfterResponse)?; debug! ("{:?} {:?}", status, text); }, Err (e) => { @@ -133,6 +134,7 @@ async fn handle_req_resp <'a> ( }, } + Ok::<(), ServerError> (()) }); } @@ -166,14 +168,14 @@ pub async fn run_server ( hidden_path: Option , asset_root: Option ) --> Result <(), Box > +-> Result <(), ServerError> { use std::convert::TryInto; let asset_root = asset_root.unwrap_or_else (PathBuf::new); if password_is_bad (config_file.api_key.clone ()) { - panic! ("API key is too weak, server can't use it"); + return Err (ServerError::WeakApiKey); } let server_info = file_server::ServerInfo { @@ -184,13 +186,13 @@ pub async fn run_server ( info! ("Tripcode is {}", config_file.tripcode ()); let mut headers = reqwest::header::HeaderMap::new (); - headers.insert ("X-ApiKey", config_file.api_key.try_into ().unwrap ()); + headers.insert ("X-ApiKey", config_file.api_key.try_into ().map_err (ServerError::ApiKeyInvalid)?); let client = Client::builder () .default_headers (headers) .timeout (Duration::from_secs (40)) - .build ().unwrap (); - let handlebars = file_server::load_templates (&asset_root).expect ("Can't load Handlebars templates"); + .build ().map_err (ServerError::CantBuildHttpClient)?; + let handlebars = file_server::load_templates (&asset_root)?; let state = Arc::new (ServerState { config: Config { @@ -260,8 +262,8 @@ pub async fn run_server ( } else if req_resp.status () != StatusCode::OK { error! ("{}", req_resp.status ()); - let body = req_resp.bytes ().await.unwrap (); - let body = String::from_utf8 (body.to_vec ()).unwrap (); + let body = req_resp.bytes ().await.map_err (ServerError::Step3CollectBody)?; + let body = String::from_utf8 (body.to_vec ()).map_err (ServerError::Step3ErrorResponseNotUtf8)?; error! ("{}", body); if backoff_delay != err_backoff_delay { error! ("Non-timeout issue, increasing backoff_delay"); diff --git a/crates/ptth_server/src/load_toml.rs b/crates/ptth_server/src/load_toml.rs index 1922adb..f92b73d 100644 --- a/crates/ptth_server/src/load_toml.rs +++ b/crates/ptth_server/src/load_toml.rs @@ -7,19 +7,21 @@ use std::{ use serde::de::DeserializeOwned; +use crate::errors::LoadTomlError; + pub const CONFIG_PERMISSIONS_MODE: u32 = 33152; fn load_inner < T: DeserializeOwned > ( mut f: File -) -> T { +) -> Result { let mut buffer = vec! [0_u8; 4096]; - let bytes_read = f.read (&mut buffer).unwrap_or_else (|_| panic! ("Can't read config")); + let bytes_read = f.read (&mut buffer)?; buffer.truncate (bytes_read); - let config_s = String::from_utf8 (buffer).unwrap_or_else (|_| panic! ("Can't parse config as UTF-8")); - toml::from_str (&config_s).unwrap_or_else (|e| panic! ("Can't parse config as TOML: {}", e)) + let config_s = String::from_utf8 (buffer)?; + Ok (toml::from_str (&config_s)?) } /// For files that contain public-viewable information @@ -29,8 +31,8 @@ pub fn load_public < P: AsRef + Debug > ( config_file_path: P -) -> T { - let f = File::open (&config_file_path).unwrap_or_else (|_| panic! ("Can't open {:?}", config_file_path)); +) -> Result { + let f = File::open (&config_file_path)?; load_inner (f) } @@ -42,13 +44,15 @@ pub fn load < P: AsRef + Debug > ( config_file_path: P -) -> T { +) -> Result { use std::os::unix::fs::PermissionsExt; - let f = File::open (&config_file_path).unwrap_or_else (|_| panic! ("Can't open {:?}", config_file_path)); + let f = File::open (&config_file_path)?; - let mode = f.metadata ().unwrap ().permissions ().mode (); - assert_eq! (mode, CONFIG_PERMISSIONS_MODE, "Config file has bad permissions mode, it should be octal 0600"); + let mode = f.metadata ()?.permissions ().mode (); + if mode != CONFIG_PERMISSIONS_MODE { + return Err (LoadTomlError::ConfigBadPermissions); + } load_inner (f) } diff --git a/src/tests.rs b/src/tests.rs index a578242..6fef13c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -23,7 +23,7 @@ fn end_to_end () { // and we don't care if another test already installed a subscriber. tracing_subscriber::fmt ().try_init ().ok (); - let mut rt = Runtime::new ().unwrap (); + let mut rt = Runtime::new ().expect ("Can't create runtime for testing"); // Spawn the root task rt.block_on (async { @@ -41,14 +41,14 @@ fn end_to_end () { }, }; - let config = ptth_relay::config::Config::try_from (config_file).unwrap (); + let config = ptth_relay::config::Config::try_from (config_file).expect ("Can't load config"); - let relay_state = Arc::new (ptth_relay::RelayState::try_from (config).unwrap ()); + let relay_state = Arc::new (ptth_relay::RelayState::try_from (config).expect ("Can't create relay state")); let relay_state_2 = relay_state.clone (); let (stop_relay_tx, stop_relay_rx) = oneshot::channel (); let task_relay = spawn (async move { - ptth_relay::run_relay (relay_state_2, stop_relay_rx, None).await.unwrap (); + ptth_relay::run_relay (relay_state_2, stop_relay_rx, None).await }); assert! (relay_state.list_servers ().await.is_empty ()); @@ -65,7 +65,7 @@ fn end_to_end () { let (stop_server_tx, stop_server_rx) = oneshot::channel (); let task_server = { spawn (async move { - ptth_server::run_server (config_file, stop_server_rx, None, None).await.unwrap (); + ptth_server::run_server (config_file, stop_server_rx, None, None).await }) }; @@ -77,15 +77,15 @@ fn end_to_end () { let client = Client::builder () .timeout (Duration::from_secs (2)) - .build ().unwrap (); + .build ().expect ("Couldn't build HTTP client"); let resp = client.get (&format! ("{}/frontend/relay_up_check", relay_url)) - .send ().await.unwrap ().bytes ().await.unwrap (); + .send ().await.expect ("Couldn't check if relay is up").bytes ().await.expect ("Couldn't check if relay is up"); assert_eq! (resp, "Relay is up\n"); let resp = client.get (&format! ("{}/frontend/servers/{}/files/COPYING", relay_url, server_name)) - .send ().await.unwrap ().bytes ().await.unwrap (); + .send ().await.expect ("Couldn't find license").bytes ().await.expect ("Couldn't find license"); if blake3::hash (&resp) != blake3::Hash::from ([ 0xca, 0x02, 0x92, 0x78, @@ -98,28 +98,28 @@ fn end_to_end () { 0x2c, 0x4a, 0xac, 0x1f, 0x1a, 0xbb, 0xa8, 0xef, ]) { - panic! ("{}", String::from_utf8 (resp.to_vec ()).unwrap ()); + panic! ("{}", String::from_utf8 (resp.to_vec ()).expect ("???")); } // Requesting a file from a server that isn't registered // will error out let resp = client.get (&format! ("{}/frontend/servers/obviously_this_server_does_not_exist/files/COPYING", relay_url)) - .send ().await.unwrap (); + .send ().await.expect ("Couldn't send request to bogus server"); assert_eq! (resp.status (), reqwest::StatusCode::NOT_FOUND); info! ("Shutting down end-to-end test"); - stop_server_tx.send (()).unwrap (); - stop_relay_tx.send (()).unwrap (); + stop_server_tx.send (()).expect ("Couldn't shut down server"); + stop_relay_tx.send (()).expect ("Couldn't shut down relay"); info! ("Sent stop messages"); - task_relay.await.unwrap (); + task_relay.await.expect ("Couldn't join relay").expect ("Relay error"); info! ("Relay stopped"); - task_server.await.unwrap (); + task_server.await.expect ("Couldn't join server").expect ("Server error"); info! ("Server stopped"); }); }