From db0ad404a1748aed9be0926f9d739f62c65042f1 Mon Sep 17 00:00:00 2001 From: Mo8it Date: Thu, 23 Feb 2023 15:45:20 +0100 Subject: [PATCH] Use Mutex instead of RwLock and prevent unneeded allocation on answer check --- src/captcha_solutions.rs | 59 ++++++++++++++++++++++++---------------- src/routes.rs | 4 ++- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/captcha_solutions.rs b/src/captcha_solutions.rs index 0594a03..a960ac6 100644 --- a/src/captcha_solutions.rs +++ b/src/captcha_solutions.rs @@ -1,58 +1,71 @@ -use std::sync::RwLock; +use std::{ops::Deref, sync::Mutex}; -struct CaptchaSolutions { +pub struct CaptchaSolutions { last_id: u16, solutions: Vec>, } impl CaptchaSolutions { - fn get_sol(&self, id: u16) -> &Option { + fn get(&self, id: u16) -> &Option { &self.solutions[id as usize] } - fn set_sol(&mut self, id: u16, sol: Option) { + fn set(&mut self, id: u16, sol: Option) { self.solutions[id as usize] = sol; } + + #[must_use = "The new id has to be stored for future verification of an answer!"] + fn push(&mut self, sol: String) -> u16 { + self.last_id = self.last_id.wrapping_add(1); + self.set(self.last_id, Some(sol)); + + self.last_id + } } pub struct SharedCaptchaSolutions { - inner: RwLock, + inner: Mutex, } impl Default for SharedCaptchaSolutions { fn default() -> Self { - let max_size = (u16::MAX as usize) + 1; - let mut solutions = Vec::with_capacity(max_size); - solutions.resize(max_size, None); + let max_size = u16::MAX as usize + 1; Self { - inner: RwLock::new(CaptchaSolutions { + inner: Mutex::new(CaptchaSolutions { last_id: 0, - solutions, + solutions: vec![None; max_size], }), } } } +impl Deref for SharedCaptchaSolutions { + type Target = Mutex; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + impl SharedCaptchaSolutions { - pub fn store_sol(&self, sol: String) -> u16 { - let mut captcha_solutions = self.inner.write().unwrap(); + #[must_use = "The new id has to be stored for future verification of an answer!"] + pub fn store_solution(&self, sol: String) -> u16 { + let mut sols = self.lock().unwrap(); - let new_id = captcha_solutions.last_id.wrapping_add(1); - captcha_solutions.last_id = new_id; - - captcha_solutions.set_sol(new_id, Some(sol)); - - new_id + sols.push(sol) } pub fn check_answer(&self, id: u16, answer: &str) -> bool { - if *self.inner.read().unwrap().get_sol(id) != Some(answer.trim().to_string()) { - return false; + let mut sols = self.lock().unwrap(); + + if let Some(sol) = sols.get(id) { + if sol == answer.trim() { + sols.set(id, None); + return true; + } } - self.inner.write().unwrap().set_sol(id, None); - - true + false } } diff --git a/src/routes.rs b/src/routes.rs index be7b82c..adbdf86 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -43,7 +43,7 @@ pub async fn render_contact_form(params: IndexParams<'_>) -> Result Result { if !captcha_solutions.check_answer(form.id, &form.captcha_answer) { info!("Wrong CAPTCHA"); + return failed_submission( Arc::clone(&config), captcha_solutions, @@ -105,6 +106,7 @@ pub async fn submit( Ok(_) => (), Err(e) => { error!("{e:?}"); + return failed_submission( Arc::clone(&config), captcha_solutions,