session: try fixing bug: multiple bsessionids lead to login failure

This commit is contained in:
jie 2021-11-26 21:48:13 +08:00
parent 811888ba7d
commit 56ca972d19
3 changed files with 56 additions and 2 deletions

View File

@ -164,11 +164,21 @@ namespace bserv {
= utils::parse_params(cookie_str, 0, ';');
boost::ignore_unused(cookie_list);
std::string session_id;
std::shared_ptr<session_type> session_ptr;
if (cookie_dict.count(SESSION_NAME) != 0) {
session_id = cookie_dict[SESSION_NAME];
}
std::shared_ptr<session_type> session_ptr;
if (resources.resources.session_mgr->get_or_create(session_id, session_ptr)) {
else if (cookie_list.count(SESSION_NAME) != 0) {
std::vector<std::string>& session_ids = cookie_list[SESSION_NAME];
for (auto& sess_id : session_ids) {
if (resources.resources.session_mgr->try_get(sess_id, session_ptr)) {
session_id = sess_id;
break;
}
}
}
if (session_ptr == nullptr
&& resources.resources.session_mgr->get_or_create(session_id, session_ptr)) {
resources.response.set(http::field::set_cookie, SESSION_NAME + "=" + session_id);
}
resources.session_ptr = session_ptr;

View File

@ -37,6 +37,12 @@ namespace bserv {
virtual bool get_or_create(
std::string& key,
std::shared_ptr<session_type>& session_ptr) = 0;
// if `key` refers to an existing session, that session will be placed in
// `session_ptr` and this function will return `true`. otherwise, `false`.
// NOTE: a `shared_ptr` is returned instead of a reference.
virtual bool try_get(
const std::string& key,
std::shared_ptr<session_type>& session_ptr) = 0;
};
class memory_session_manager : public session_manager_base {
@ -62,6 +68,9 @@ namespace bserv {
bool get_or_create(
std::string& key,
std::shared_ptr<session_type>& session_ptr);
bool try_get(
const std::string& key,
std::shared_ptr<session_type>& session_ptr);
};
} // bserv

View File

@ -47,4 +47,39 @@ namespace bserv {
return created;
}
bool memory_session_manager::try_get(
const std::string& key,
std::shared_ptr<session_type>& session_ptr) {
std::lock_guard<std::mutex> lg{ lock_ };
time_point now = std::chrono::steady_clock::now();
// removes the expired sessions
while (!queue_.empty() && queue_.begin()->first < now) {
std::size_t another_key = queue_.begin()->second;
sessions_.erase(another_key);
expiry_.erase(another_key);
str_to_int_.erase(int_to_str_[another_key]);
int_to_str_.erase(another_key);
queue_.erase(queue_.begin());
}
bool found = true;
std::size_t int_key;
if (key.empty() || str_to_int_.count(key) == 0) {
found = false;
}
else {
int_key = str_to_int_[key];
queue_.erase(
queue_.lower_bound(
std::make_pair(expiry_[int_key], int_key)));
}
// the expiry is set to be 20 minutes from now.
// if the session is re-visited within 20 minutes,
// the expiry will be extended.
expiry_[int_key] = now + std::chrono::minutes(20);
// pushes expiry-key tuple (pair) to the queue
queue_.emplace(expiry_[int_key], int_key);
session_ptr = sessions_[int_key];
return found;
}
} // bserv