From 6e695960ca0b89d57e04eeaa99e7213462f47f70 Mon Sep 17 00:00:00 2001 From: Dietmar Maurer Date: Sat, 18 Apr 2020 08:49:20 +0200 Subject: [PATCH] src/config/cached_user_info.rs: cache it up to 5 seconds --- src/config/cached_user_info.rs | 43 ++++++++++++++++++++++++++++------ src/server/rest.rs | 2 +- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/src/config/cached_user_info.rs b/src/config/cached_user_info.rs index beb229c5..4422f7bc 100644 --- a/src/config/cached_user_info.rs +++ b/src/config/cached_user_info.rs @@ -1,10 +1,11 @@ //! Cached user info for fast ACL permission checks -use std::sync::Arc; +use std::sync::{RwLock, Arc}; use anyhow::{Error, bail}; use proxmox::api::section_config::SectionConfigData; +use lazy_static::lazy_static; use proxmox::api::UserInformation; use super::acl::{AclTree, ROLE_NAMES}; @@ -16,14 +17,43 @@ pub struct CachedUserInfo { acl_tree: Arc, } +fn now() -> i64 { unsafe { libc::time(std::ptr::null_mut()) } } + +struct ConfigCache { + data: Option>, + last_update: i64, +} + +lazy_static! { + static ref CACHED_CONFIG: RwLock = RwLock::new( + ConfigCache { data: None, last_update: 0 } + ); +} + impl CachedUserInfo { - /// Creates a new instance. - pub fn new() -> Result { - Ok(CachedUserInfo { + /// Returns a cached instance (up to 5 seconds old). + pub fn new() -> Result, Error> { + let now = now(); + { // limit scope + let cache = CACHED_CONFIG.read().unwrap(); + if (now - cache.last_update) < 5 { + if let Some(ref config) = cache.data { + return Ok(config.clone()); + } + } + } + + let config = Arc::new(CachedUserInfo { user_cfg: super::user::cached_config()?, acl_tree: super::acl::cached_config()?, - }) + }); + + let mut cache = CACHED_CONFIG.write().unwrap(); + cache.last_update = now; + cache.data = Some(config.clone()); + + Ok(config) } /// Test if a user account is enabled and not expired @@ -34,8 +64,7 @@ impl CachedUserInfo { } if let Some(expire) = info.expire { if expire > 0 { - let now = unsafe { libc::time(std::ptr::null_mut()) }; - if expire <= now { + if expire <= now() { return false; } } diff --git a/src/server/rest.rs b/src/server/rest.rs index 27ac93f2..f648af3a 100644 --- a/src/server/rest.rs +++ b/src/server/rest.rs @@ -562,7 +562,7 @@ pub async fn handle_request(api: Arc, req: Request) -> Result { let user = rpcenv.get_user(); - if !check_api_permission(api_method.access.permission, user.as_deref(), &uri_param, &user_info) { + if !check_api_permission(api_method.access.permission, user.as_deref(), &uri_param, user_info.as_ref()) { let err = http_err!(FORBIDDEN, format!("permission check failed")); tokio::time::delay_until(Instant::from_std(access_forbidden_time)).await; return Ok((formatter.format_error)(err));