1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::borrow::Cow;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::Ordering;
use rand;
use rand::Rng;
use rand::distributions::Alphanumeric;
use Request;
use Response;
use input;
pub fn session<'r, F>(request: &'r Request, cookie_name: &str, timeout_s: u64, inner: F) -> Response
where F: FnOnce(&Session<'r>) -> Response
{
let mut cookie = input::cookies(request).into_iter();
let cookie = cookie.find(|&(ref k, _)| k == &cookie_name);
let cookie = cookie.map(|(_, v)| v);
let session = if let Some(cookie) = cookie {
Session {
key_was_retreived: AtomicBool::new(false),
key_was_given: true,
key: cookie.into(),
}
} else {
Session {
key_was_retreived: AtomicBool::new(false),
key_was_given: false,
key: generate_session_id().into(),
}
};
let mut response = inner(&session);
if session.key_was_retreived.load(Ordering::Relaxed) {
let header_value = format!("{}={}; Max-Age={}; Path=/; HttpOnly",
cookie_name, session.key, timeout_s);
response.headers.push(("Set-Cookie".into(), header_value.into()));
}
response
}
pub struct Session<'r> {
key_was_retreived: AtomicBool,
key_was_given: bool,
key: Cow<'r, str>,
}
impl<'r> Session<'r> {
#[inline]
pub fn client_has_sid(&self) -> bool {
self.key_was_given
}
#[inline]
pub fn id(&self) -> &str {
self.key_was_retreived.store(true, Ordering::Relaxed);
&self.key
}
}
pub fn generate_session_id() -> String {
rand::OsRng::new().expect("Failed to initialize OsRng")
.sample_iter(&Alphanumeric)
.filter(|&c| (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
(c >= '0' && c <= '9'))
.take(64).collect::<String>()
}