diff --git a/bserv/include/bserv/router.hpp b/bserv/include/bserv/router.hpp index 4fabbdf..8367001 100644 --- a/bserv/include/bserv/router.hpp +++ b/bserv/include/bserv/router.hpp @@ -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_ptr; if (cookie_dict.count(SESSION_NAME) != 0) { session_id = cookie_dict[SESSION_NAME]; } - std::shared_ptr session_ptr; - if (resources.resources.session_mgr->get_or_create(session_id, session_ptr)) { + else if (cookie_list.count(SESSION_NAME) != 0) { + std::vector& 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; diff --git a/bserv/include/bserv/session.hpp b/bserv/include/bserv/session.hpp index 9d5c502..58d0c5f 100644 --- a/bserv/include/bserv/session.hpp +++ b/bserv/include/bserv/session.hpp @@ -37,6 +37,12 @@ namespace bserv { virtual bool get_or_create( std::string& key, std::shared_ptr& 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_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_ptr); + bool try_get( + const std::string& key, + std::shared_ptr& session_ptr); }; } // bserv diff --git a/bserv/session.cpp b/bserv/session.cpp index 2ab42f1..238298d 100644 --- a/bserv/session.cpp +++ b/bserv/session.cpp @@ -47,4 +47,39 @@ namespace bserv { return created; } + bool memory_session_manager::try_get( + const std::string& key, + std::shared_ptr& session_ptr) { + std::lock_guard 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 \ No newline at end of file