1
0
mirror of https://github.com/actix/actix-extras.git synced 2025-01-22 14:55:56 +01:00

Do not create a session if the session state is empty (#207)

This commit is contained in:
Luca Palmieri 2021-12-11 16:23:22 +00:00 committed by GitHub
parent 74ec115161
commit e77ed16f49
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 39 additions and 59 deletions

View File

@ -1,8 +1,10 @@
# Changes
## Unreleased - 2021-xx-xx
* A session will be created in Redis if and only if there is some data inside the session state. This reduces the performance impact of `RedisSession` on routes that do not leverage sessions. [#207]
* Update `actix-web` dependency to `4.0.0.beta-14`. [#209]
[#207]: https://github.com/actix/actix-extras/pull/207
[#209]: https://github.com/actix/actix-extras/pull/209

View File

@ -170,14 +170,11 @@ where
let mut res = srv.call(req).await?;
match Session::get_changes(&mut res) {
(SessionStatus::Unchanged, state) => {
if value.is_none() {
// implies the session is new
inner.update(res, state, value).await
} else {
(SessionStatus::Unchanged, _) => {
// If the session already exists, we don't need to update the state stored in Redis
// If the session is new, creating an empty session in Redis is unnecessary overhead
Ok(res)
}
}
(SessionStatus::Changed, state) => inner.update(res, state, value).await,
@ -453,14 +450,14 @@ mod test {
#[actix_rt::test]
async fn test_session_workflow() {
// Step 1: GET index
// - set-cookie actix-session will be in response (session cookie #1)
// - set-cookie actix-session should NOT be in response (session data is empty)
// - response should be: {"counter": 0, "user_id": None}
// - cookie should have default max-age of 7 days
// Step 2: GET index, including session cookie #1 in request
// - set-cookie will *not* be in response
// - response should be: {"counter": 0, "user_id": None}
// Step 3: POST to do_something, including session cookie #1 in request
// Step 2: POST to do_something
// - adds new session state in redis: {"counter": 1}
// - set-cookie actix-session should be in response (session cookie #1)
// - response should be: {"counter": 1, "user_id": None}
// Step 3: GET index, including session cookie #1 in request
// - set-cookie will *not* be in response
// - response should be: {"counter": 1, "user_id": None}
// Step 4: POST again to do_something, including session cookie #1 in request
// - updates session state in redis: {"counter": 2}
@ -472,15 +469,15 @@ mod test {
// - response should be: {"counter": 2, "user_id": "ferris"}
// Step 7: POST again to do_something, including session cookie #2 in request
// - updates session state in redis: {"counter": 3, "user_id": "ferris"}
// - response should be: {"counter": 2, "user_id": None}
// - response should be: {"counter": 3, "user_id": "ferris"}
// Step 8: GET index, including session cookie #1 in request
// - set-cookie actix-session will be in response (session cookie #3)
// - set-cookie actix-session should NOT be in response (session data is empty)
// - response should be: {"counter": 0, "user_id": None}
// Step 9: POST to logout, including session cookie #2
// - set-cookie actix-session will be in response with session cookie #2
// invalidation logic
// Step 10: GET index, including session cookie #2 in request
// - set-cookie actix-session will be in response (session cookie #3)
// - set-cookie actix-session should NOT be in response (session data is empty)
// - response should be: {"counter": 0, "user_id": None}
let srv = actix_test::start(|| {
@ -494,17 +491,11 @@ mod test {
});
// Step 1: GET index
// - set-cookie actix-session will be in response (session cookie #1)
// - set-cookie actix-session should NOT be in response (session data is empty)
// - response should be: {"counter": 0, "user_id": None}
let req_1a = srv.get("/").send();
let mut resp_1 = req_1a.await.unwrap();
let cookie_1 = resp_1
.cookies()
.unwrap()
.clone()
.into_iter()
.find(|c| c.name() == "test-session")
.unwrap();
assert!(resp_1.cookies().unwrap().is_empty());
let result_1 = resp_1.json::<IndexResponse>().await.unwrap();
assert_eq!(
result_1,
@ -513,26 +504,28 @@ mod test {
counter: 0
}
);
assert_eq!(cookie_1.max_age(), Some(Duration::days(7)));
// Step 2: GET index, including session cookie #1 in request
// - set-cookie will *not* be in response
// - response should be: {"counter": 0, "user_id": None}
let req_2 = srv.get("/").cookie(cookie_1.clone()).send();
// Step 2: POST to do_something
// - adds new session state in redis: {"counter": 1}
// - set-cookie actix-session should be in response (session cookie #1)
// - response should be: {"counter": 1, "user_id": None}
let req_2 = srv.post("/do_something").send();
let resp_2 = req_2.await.unwrap();
let cookie_2 = resp_2
let cookie_1 = resp_2
.cookies()
.unwrap()
.clone()
.into_iter()
.find(|c| c.name() == "test-session");
assert_eq!(cookie_2, None);
.find(|c| c.name() == "test-session")
.unwrap();
assert_eq!(cookie_1.max_age(), Some(Duration::days(7)));
// Step 3: POST to do_something, including session cookie #1 in request
// - adds new session state in redis: {"counter": 1}
// Step 3: GET index, including session cookie #1 in request
// - set-cookie will *not* be in response
// - response should be: {"counter": 1, "user_id": None}
let req_3 = srv.post("/do_something").cookie(cookie_1.clone()).send();
let req_3 = srv.get("/").cookie(cookie_1.clone()).send();
let mut resp_3 = req_3.await.unwrap();
assert!(resp_3.cookies().unwrap().is_empty());
let result_3 = resp_3.json::<IndexResponse>().await.unwrap();
assert_eq!(
result_3,
@ -597,7 +590,7 @@ mod test {
// Step 7: POST again to do_something, including session cookie #2 in request
// - updates session state in redis: {"counter": 3, "user_id": "ferris"}
// - response should be: {"counter": 2, "user_id": None}
// - response should be: {"counter": 3, "user_id": "ferris"}
let req_7 = srv.post("/do_something").cookie(cookie_2.clone()).send();
let mut resp_7 = req_7.await.unwrap();
let result_7 = resp_7.json::<IndexResponse>().await.unwrap();
@ -610,17 +603,11 @@ mod test {
);
// Step 8: GET index, including session cookie #1 in request
// - set-cookie actix-session will be in response (session cookie #3)
// - set-cookie actix-session should NOT be in response (session data is empty)
// - response should be: {"counter": 0, "user_id": None}
let req_8 = srv.get("/").cookie(cookie_1.clone()).send();
let mut resp_8 = req_8.await.unwrap();
let cookie_3 = resp_8
.cookies()
.unwrap()
.clone()
.into_iter()
.find(|c| c.name() == "test-session")
.unwrap();
assert!(resp_8.cookies().unwrap().is_empty());
let result_8 = resp_8.json::<IndexResponse>().await.unwrap();
assert_eq!(
result_8,
@ -629,14 +616,13 @@ mod test {
counter: 0
}
);
assert_ne!(cookie_3.value(), cookie_2.value());
// Step 9: POST to logout, including session cookie #2
// - set-cookie actix-session will be in response with session cookie #2
// invalidation logic
let req_9 = srv.post("/logout").cookie(cookie_2.clone()).send();
let resp_9 = req_9.await.unwrap();
let cookie_4 = resp_9
let cookie_3 = resp_9
.cookies()
.unwrap()
.clone()
@ -645,17 +631,18 @@ mod test {
.unwrap();
assert_ne!(
OffsetDateTime::now_utc().year(),
cookie_4
cookie_3
.expires()
.map(|t| t.datetime().expect("Expiration is a datetime").year())
.unwrap()
);
// Step 10: GET index, including session cookie #2 in request
// - set-cookie actix-session will be in response (session cookie #3)
// - set-cookie actix-session should NOT be in response (session data is empty)
// - response should be: {"counter": 0, "user_id": None}
let req_10 = srv.get("/").cookie(cookie_2.clone()).send();
let mut resp_10 = req_10.await.unwrap();
assert!(resp_10.cookies().unwrap().is_empty());
let result_10 = resp_10.json::<IndexResponse>().await.unwrap();
assert_eq!(
result_10,
@ -664,15 +651,6 @@ mod test {
counter: 0
}
);
let cookie_5 = resp_10
.cookies()
.unwrap()
.clone()
.into_iter()
.find(|c| c.name() == "test-session")
.unwrap();
assert_ne!(cookie_5.value(), cookie_2.value());
}
#[actix_rt::test]
@ -688,10 +666,10 @@ mod test {
.cookie_max_age(None),
)
.wrap(middleware::Logger::default())
.service(resource("/").route(get().to(index)))
.service(resource("/do_something").route(post().to(do_something)))
});
let req = srv.get("/").send();
let req = srv.post("/do_something").send();
let resp = req.await.unwrap();
let cookie = resp
.cookies()