|
|
@ -1,4 +1,4 @@ |
|
|
|
use parking_lot::{RwLock, RwLockUpgradableReadGuard, Mutex}; |
|
|
|
use parking_lot::{Mutex, RwLock, RwLockUpgradableReadGuard}; |
|
|
|
use rand::Rng; |
|
|
|
use rand::Rng; |
|
|
|
|
|
|
|
|
|
|
|
use rocket::{ |
|
|
|
use rocket::{ |
|
|
@ -8,12 +8,12 @@ use rocket::{ |
|
|
|
Outcome, Request, Response, Rocket, State, |
|
|
|
Outcome, Request, Response, Rocket, State, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
use std::borrow::Cow; |
|
|
|
use std::collections::HashMap; |
|
|
|
use std::collections::HashMap; |
|
|
|
|
|
|
|
use std::fmt::{self, Display, Formatter}; |
|
|
|
use std::marker::PhantomData; |
|
|
|
use std::marker::PhantomData; |
|
|
|
use std::ops::Add; |
|
|
|
use std::ops::Add; |
|
|
|
use std::time::{Duration, Instant}; |
|
|
|
use std::time::{Duration, Instant}; |
|
|
|
use std::borrow::Cow; |
|
|
|
|
|
|
|
use std::fmt::{Display, Formatter, self}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Session store (shared state)
|
|
|
|
/// Session store (shared state)
|
|
|
|
#[derive(Debug)] |
|
|
|
#[derive(Debug)] |
|
|
@ -55,14 +55,16 @@ impl Default for SessionConfig { |
|
|
|
#[derive(Debug)] |
|
|
|
#[derive(Debug)] |
|
|
|
struct StoreInner<D> |
|
|
|
struct StoreInner<D> |
|
|
|
where |
|
|
|
where |
|
|
|
D: 'static + Sync + Send + Default { |
|
|
|
D: 'static + Sync + Send + Default, |
|
|
|
|
|
|
|
{ |
|
|
|
sessions: HashMap<String, Mutex<SessionInstance<D>>>, |
|
|
|
sessions: HashMap<String, Mutex<SessionInstance<D>>>, |
|
|
|
last_expiry_sweep: Instant, |
|
|
|
last_expiry_sweep: Instant, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl<D> Default for StoreInner<D> |
|
|
|
impl<D> Default for StoreInner<D> |
|
|
|
where |
|
|
|
where |
|
|
|
D: 'static + Sync + Send + Default { |
|
|
|
D: 'static + Sync + Send + Default, |
|
|
|
|
|
|
|
{ |
|
|
|
fn default() -> Self { |
|
|
|
fn default() -> Self { |
|
|
|
Self { |
|
|
|
Self { |
|
|
|
sessions: Default::default(), |
|
|
|
sessions: Default::default(), |
|
|
@ -138,7 +140,8 @@ impl<'a, 'r, D> FromRequest<'a, 'r> for Session<'a, D> |
|
|
|
|
|
|
|
|
|
|
|
let expires = Instant::now().add(store.config.lifespan); |
|
|
|
let expires = Instant::now().add(store.config.lifespan); |
|
|
|
|
|
|
|
|
|
|
|
if let Some(m) = id.as_ref() |
|
|
|
if let Some(m) = id |
|
|
|
|
|
|
|
.as_ref() |
|
|
|
.and_then(|token| store_ug.sessions.get(token.as_str())) |
|
|
|
.and_then(|token| store_ug.sessions.get(token.as_str())) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// --- ID obtained from a cookie && session found in the store ---
|
|
|
|
// --- ID obtained from a cookie && session found in the store ---
|
|
|
@ -166,8 +169,7 @@ impl<'a, 'r, D> FromRequest<'a, 'r> for Session<'a, D> |
|
|
|
// Throttle by lifespan - e.g. sweep every hour
|
|
|
|
// Throttle by lifespan - e.g. sweep every hour
|
|
|
|
if store_wg.last_expiry_sweep.elapsed() > store.config.lifespan { |
|
|
|
if store_wg.last_expiry_sweep.elapsed() > store.config.lifespan { |
|
|
|
let now = Instant::now(); |
|
|
|
let now = Instant::now(); |
|
|
|
store_wg.sessions |
|
|
|
store_wg.sessions.retain(|_k, v| v.lock().expires > now); |
|
|
|
.retain(|_k, v| v.lock().expires > now); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
store_wg.last_expiry_sweep = now; |
|
|
|
store_wg.last_expiry_sweep = now; |
|
|
|
} |
|
|
|
} |
|
|
@ -231,7 +233,9 @@ impl<'a, D> Session<'a, D> |
|
|
|
|
|
|
|
|
|
|
|
// Unlock the session's mutex.
|
|
|
|
// Unlock the session's mutex.
|
|
|
|
// Expiry was checked and prolonged at the beginning of the request
|
|
|
|
// Expiry was checked and prolonged at the beginning of the request
|
|
|
|
let mut instance = store_rg.sessions.get(self.id.as_str()) |
|
|
|
let mut instance = store_rg |
|
|
|
|
|
|
|
.sessions |
|
|
|
|
|
|
|
.get(self.id.as_str()) |
|
|
|
.expect("Session data unexpectedly missing") |
|
|
|
.expect("Session data unexpectedly missing") |
|
|
|
.lock(); |
|
|
|
.lock(); |
|
|
|
|
|
|
|
|
|
|
@ -251,7 +255,7 @@ pub struct SessionFairing<D> |
|
|
|
|
|
|
|
|
|
|
|
impl<D> SessionFairing<D> |
|
|
|
impl<D> SessionFairing<D> |
|
|
|
where |
|
|
|
where |
|
|
|
D: 'static + Sync + Send + Default |
|
|
|
D: 'static + Sync + Send + Default, |
|
|
|
{ |
|
|
|
{ |
|
|
|
fn new() -> Self { |
|
|
|
fn new() -> Self { |
|
|
|
Self::default() |
|
|
|
Self::default() |
|
|
@ -314,8 +318,11 @@ impl<D> Fairing for SessionFairing<D> |
|
|
|
let session = request.local_cache(|| SessionID("".to_string())); |
|
|
|
let session = request.local_cache(|| SessionID("".to_string())); |
|
|
|
|
|
|
|
|
|
|
|
if !session.0.is_empty() { |
|
|
|
if !session.0.is_empty() { |
|
|
|
response.adjoin_header(Cookie::build(self.config.cookie_name.clone(), session.to_string()) |
|
|
|
response.adjoin_header( |
|
|
|
.path("/").finish()); |
|
|
|
Cookie::build(self.config.cookie_name.clone(), session.to_string()) |
|
|
|
|
|
|
|
.path("/") |
|
|
|
|
|
|
|
.finish(), |
|
|
|
|
|
|
|
); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|