From 43a21ddc9cc96a1e2e7b20beca5e2439fb5ffa45 Mon Sep 17 00:00:00 2001 From: An Tao Date: Mon, 3 Aug 2020 19:18:47 +0800 Subject: [PATCH] Provide users with a method to change the session ID of a session (#523) --- lib/inc/drogon/CacheMap.h | 24 ++++++++++-- lib/inc/drogon/Cookie.h | 4 ++ lib/inc/drogon/Session.h | 65 +++++++++++++++++++++++---------- lib/src/HttpAppFrameworkImpl.cc | 4 ++ lib/src/SessionManager.cc | 21 ++++++++++- lib/src/SessionManager.h | 1 + 6 files changed, 96 insertions(+), 23 deletions(-) diff --git a/lib/inc/drogon/CacheMap.h b/lib/inc/drogon/CacheMap.h index 34c92aef..cfed5d0a 100644 --- a/lib/inc/drogon/CacheMap.h +++ b/lib/inc/drogon/CacheMap.h @@ -303,6 +303,26 @@ class CacheMap return loop_; } + /** + * @brief run the task function after a period of time. + * + * @param delay in seconds + * @param task + * @note This timer is a low-precision timer whose accuracy depends on the + * tickInterval parameter of the cache. The advantage of the timer is its + * low cost. + */ + void runAfter(size_t delay, std::function &&task) + { + std::lock_guard lock(bucketMutex_); + insertEntry(delay, std::make_shared(std::move(task))); + } + void runAfter(size_t delay, const std::function &task) + { + std::lock_guard lock(bucketMutex_); + insertEntry(delay, std::make_shared(task)); + } + private: std::unordered_map map_; @@ -394,10 +414,8 @@ class CacheMap } } }; - - entryPtr = std::make_shared(cb); + entryPtr = std::make_shared(std::move(cb)); map_[key].weakEntryPtr_ = entryPtr; - { std::lock_guard lock(bucketMutex_); insertEntry(delay, entryPtr); diff --git a/lib/inc/drogon/Cookie.h b/lib/inc/drogon/Cookie.h index 6f725564..c054b192 100644 --- a/lib/inc/drogon/Cookie.h +++ b/lib/inc/drogon/Cookie.h @@ -34,6 +34,10 @@ class Cookie : key_(key), value_(value) { } + Cookie(std::string &&key, std::string &&value) + : key_(std::move(key)), value_(std::move(value)) + { + } Cookie() = default; /** diff --git a/lib/inc/drogon/Session.h b/lib/inc/drogon/Session.h index f5643bae..bf4f8fc9 100644 --- a/lib/inc/drogon/Session.h +++ b/lib/inc/drogon/Session.h @@ -127,32 +127,21 @@ class Session /** * @brief Get the session ID of the current session. */ - const std::string &sessionId() const + std::string sessionId() const { + std::lock_guard lck(mutex_); return sessionId_; } /** - * @brief If the session ID needs to be set to the client through cookie, - * return true + * @brief Let the framework create a new session ID for this session and set + * it to the client. + * @note This method does not change the session ID now. */ - bool needSetToClient() const - { - return needToSet_; - } - /** - * @brief Change the state of the session, usually called by the framework - */ - void hasSet() - { - needToSet_ = false; - } - /** - * @brief Constructor, usually called by the framework - */ - Session(const std::string &id, bool needToSet) - : sessionId_(id), needToSet_(needToSet) + void changeSessionIdToClient() { + needToChange_ = true; + needToSet_ = true; } Session() = delete; @@ -162,6 +151,44 @@ class Session mutable std::mutex mutex_; std::string sessionId_; bool needToSet_{false}; + bool needToChange_{false}; + friend class SessionManager; + friend class HttpAppFrameworkImpl; + /** + * @brief Constructor, usually called by the framework + */ + Session(const std::string &id, bool needToSet) + : sessionId_(id), needToSet_(needToSet) + { + } + /** + * @brief Change the state of the session, usually called by the framework + */ + void hasSet() + { + needToSet_ = false; + } + /** + * @brief If the session ID needs to be changed. + * + */ + bool needToChangeSessionId() const + { + return needToChange_; + } + /** + * @brief If the session ID needs to be set to the client through cookie, + * return true + */ + bool needSetToClient() const + { + return needToSet_; + } + void setSessionId(const std::string &id) + { + std::lock_guard lck(mutex_); + sessionId_ = id; + } }; using SessionPtr = std::shared_ptr; diff --git a/lib/src/HttpAppFrameworkImpl.cc b/lib/src/HttpAppFrameworkImpl.cc index a10cfec7..34eae771 100644 --- a/lib/src/HttpAppFrameworkImpl.cc +++ b/lib/src/HttpAppFrameworkImpl.cc @@ -686,6 +686,10 @@ void HttpAppFrameworkImpl::callCallback( { auto sessionPtr = req->getSession(); assert(sessionPtr); + if (sessionPtr->needToChangeSessionId()) + { + sessionManagerPtr_->changeSessionId(sessionPtr); + } if (sessionPtr->needSetToClient()) { if (resp->expiredTime() >= 0) diff --git a/lib/src/SessionManager.cc b/lib/src/SessionManager.cc index e2a7d6b8..52d5c098 100644 --- a/lib/src/SessionManager.cc +++ b/lib/src/SessionManager.cc @@ -13,6 +13,7 @@ */ #include "SessionManager.h" +#include using namespace drogon; @@ -57,9 +58,27 @@ SessionPtr SessionManager::getSession(const std::string &sessionID, std::lock_guard lock(mapMutex_); if (sessionMapPtr_->findAndFetch(sessionID, sessionPtr) == false) { - sessionPtr = std::make_shared(sessionID, needToSet); + sessionPtr = + std::shared_ptr(new Session(sessionID, needToSet)); sessionMapPtr_->insert(sessionID, sessionPtr, timeout_); return sessionPtr; } return sessionPtr; +} + +void SessionManager::changeSessionId(const SessionPtr &sessionPtr) +{ + auto oldId = sessionPtr->sessionId(); + auto newId = utils::getUuid(); + sessionPtr->setSessionId(newId); + { + std::lock_guard lock(mapMutex_); + // For requests sent before setting the new session ID to the client, we + // reserve the old session slot for a period of time. + sessionMapPtr_->runAfter(10, [this, oldId = std::move(oldId)]() { + LOG_TRACE << "remove the old slot of the session"; + sessionMapPtr_->erase(oldId); + }); + sessionMapPtr_->insert(newId, sessionPtr, timeout_); + } } \ No newline at end of file diff --git a/lib/src/SessionManager.h b/lib/src/SessionManager.h index bbe7b047..23555948 100644 --- a/lib/src/SessionManager.h +++ b/lib/src/SessionManager.h @@ -33,6 +33,7 @@ class SessionManager : public trantor::NonCopyable sessionMapPtr_.reset(); } SessionPtr getSession(const std::string &sessionID, bool needToSet); + void changeSessionId(const SessionPtr &sessionPtr); private: std::unique_ptr> sessionMapPtr_;