http cookie减少互斥锁,优化性能

This commit is contained in:
ziyue 2022-02-11 14:33:11 +08:00
parent c510f3765a
commit 36f24527a4
3 changed files with 155 additions and 144 deletions

View File

@ -8,10 +8,10 @@
* may be found in the AUTHORS file in the root of the source tree. * may be found in the AUTHORS file in the root of the source tree.
*/ */
#include "Util/util.h"
#include "Util/MD5.h"
#include "Common/config.h"
#include "HttpCookieManager.h" #include "HttpCookieManager.h"
#include "Common/config.h"
#include "Util/MD5.h"
#include "Util/util.h"
using namespace std; using namespace std;
using namespace toolkit; using namespace toolkit;
@ -19,27 +19,25 @@ using namespace toolkit;
namespace mediakit { namespace mediakit {
//////////////////////////////HttpServerCookie//////////////////////////////////// //////////////////////////////HttpServerCookie////////////////////////////////////
HttpServerCookie::HttpServerCookie(const std::shared_ptr<HttpCookieManager> &manager, HttpServerCookie::HttpServerCookie(
const string &cookie_name, const std::shared_ptr<HttpCookieManager> &manager, const string &cookie_name, const string &uid,
const string &uid, const string &cookie, uint64_t max_elapsed) {
const string &cookie,
uint64_t max_elapsed){
_uid = uid; _uid = uid;
_max_elapsed = max_elapsed; _max_elapsed = max_elapsed;
_cookie_uuid = cookie; _cookie_uuid = cookie;
_cookie_name = cookie_name; _cookie_name = cookie_name;
_manager = manager; _manager = manager;
manager->onAddCookie(_cookie_name,_uid,_cookie_uuid); manager->onAddCookie(_cookie_name, _uid, _cookie_uuid);
} }
HttpServerCookie::~HttpServerCookie() { HttpServerCookie::~HttpServerCookie() {
auto strongManager = _manager.lock(); auto strongManager = _manager.lock();
if(strongManager){ if (strongManager) {
strongManager->onDelCookie(_cookie_name,_uid,_cookie_uuid); strongManager->onDelCookie(_cookie_name, _uid, _cookie_uuid);
} }
} }
const string & HttpServerCookie::getUid() const{ const string &HttpServerCookie::getUid() const {
return _uid; return _uid;
} }
@ -47,11 +45,11 @@ string HttpServerCookie::getCookie(const string &path) const {
return (StrPrinter << _cookie_name << "=" << _cookie_uuid << ";expires=" << cookieExpireTime() << ";path=" << path); return (StrPrinter << _cookie_name << "=" << _cookie_uuid << ";expires=" << cookieExpireTime() << ";path=" << path);
} }
const string& HttpServerCookie::getCookie() const { const string &HttpServerCookie::getCookie() const {
return _cookie_uuid; return _cookie_uuid;
} }
const string& HttpServerCookie::getCookieName() const{ const string &HttpServerCookie::getCookieName() const {
return _cookie_name; return _cookie_name;
} }
@ -63,11 +61,11 @@ bool HttpServerCookie::isExpired() {
return _ticker.elapsedTime() > _max_elapsed * 1000; return _ticker.elapsedTime() > _max_elapsed * 1000;
} }
std::shared_ptr<lock_guard<recursive_mutex> > HttpServerCookie::getLock(){ void HttpServerCookie::setAttach(std::shared_ptr<void> attach) {
return std::make_shared<lock_guard<recursive_mutex> >(_mtx); _attach = std::move(attach);
} }
string HttpServerCookie::cookieExpireTime() const{ string HttpServerCookie::cookieExpireTime() const {
char buf[64]; char buf[64];
time_t tt = time(NULL) + _max_elapsed; time_t tt = time(NULL) + _max_elapsed;
strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt)); strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
@ -78,10 +76,13 @@ INSTANCE_IMP(HttpCookieManager);
HttpCookieManager::HttpCookieManager() { HttpCookieManager::HttpCookieManager() {
//定时删除过期的cookie防止内存膨胀 //定时删除过期的cookie防止内存膨胀
_timer = std::make_shared<Timer>(10.0f,[this](){ _timer = std::make_shared<Timer>(
10.0f,
[this]() {
onManager(); onManager();
return true; return true;
}, nullptr); },
nullptr);
} }
HttpCookieManager::~HttpCookieManager() { HttpCookieManager::~HttpCookieManager() {
@ -91,11 +92,11 @@ HttpCookieManager::~HttpCookieManager() {
void HttpCookieManager::onManager() { void HttpCookieManager::onManager() {
lock_guard<recursive_mutex> lck(_mtx_cookie); lock_guard<recursive_mutex> lck(_mtx_cookie);
//先遍历所有类型 //先遍历所有类型
for(auto it_name = _map_cookie.begin() ; it_name != _map_cookie.end() ;){ for (auto it_name = _map_cookie.begin(); it_name != _map_cookie.end();) {
//再遍历该类型下的所有cookie //再遍历该类型下的所有cookie
for (auto it_cookie = it_name->second.begin() ; it_cookie != it_name->second.end() ; ){ for (auto it_cookie = it_name->second.begin(); it_cookie != it_name->second.end();) {
if(it_cookie->second->isExpired()){ if (it_cookie->second->isExpired()) {
//cookie过期,移除记录 // cookie过期,移除记录
DebugL << it_cookie->second->getUid() << " cookie过期:" << it_cookie->second->getCookie(); DebugL << it_cookie->second->getUid() << " cookie过期:" << it_cookie->second->getCookie();
it_cookie = it_name->second.erase(it_cookie); it_cookie = it_name->second.erase(it_cookie);
continue; continue;
@ -103,7 +104,7 @@ void HttpCookieManager::onManager() {
++it_cookie; ++it_cookie;
} }
if(it_name->second.empty()){ if (it_name->second.empty()) {
//该类型下没有任何cooki记录,移除之 //该类型下没有任何cooki记录,移除之
DebugL << "该path下没有任何cooki记录:" << it_name->first; DebugL << "该path下没有任何cooki记录:" << it_name->first;
it_name = _map_cookie.erase(it_name); it_name = _map_cookie.erase(it_name);
@ -113,36 +114,38 @@ void HttpCookieManager::onManager() {
} }
} }
HttpServerCookie::Ptr HttpCookieManager::addCookie(const string &cookie_name,const string &uidIn,uint64_t max_elapsed,int max_client) { HttpServerCookie::Ptr HttpCookieManager::addCookie(const string &cookie_name, const string &uid_in,
uint64_t max_elapsed, std::shared_ptr<void> attach, int max_client) {
lock_guard<recursive_mutex> lck(_mtx_cookie); lock_guard<recursive_mutex> lck(_mtx_cookie);
auto cookie = _geneator.obtain(); auto cookie = _geneator.obtain();
auto uid = uidIn.empty() ? cookie : uidIn; auto uid = uid_in.empty() ? cookie : uid_in;
auto oldCookie = getOldestCookie(cookie_name , uid, max_client); auto oldCookie = getOldestCookie(cookie_name, uid, max_client);
if(!oldCookie.empty()){ if (!oldCookie.empty()) {
//假如该账号已经登录了那么删除老的cookie。 //假如该账号已经登录了那么删除老的cookie。
//目的是实现单账号多地登录时挤占登录 //目的是实现单账号多地登录时挤占登录
delCookie(cookie_name,oldCookie); delCookie(cookie_name, oldCookie);
} }
HttpServerCookie::Ptr data(new HttpServerCookie(shared_from_this(),cookie_name,uid,cookie,max_elapsed)); HttpServerCookie::Ptr data(new HttpServerCookie(shared_from_this(), cookie_name, uid, cookie, max_elapsed));
data->setAttach(std::move(attach));
//保存该账号下的新cookie //保存该账号下的新cookie
_map_cookie[cookie_name][cookie] = data; _map_cookie[cookie_name][cookie] = data;
return data; return data;
} }
HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,const string &cookie) { HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name, const string &cookie) {
lock_guard<recursive_mutex> lck(_mtx_cookie); lock_guard<recursive_mutex> lck(_mtx_cookie);
auto it_name = _map_cookie.find(cookie_name); auto it_name = _map_cookie.find(cookie_name);
if(it_name == _map_cookie.end()){ if (it_name == _map_cookie.end()) {
//不存在该类型的cookie //不存在该类型的cookie
return nullptr; return nullptr;
} }
auto it_cookie = it_name->second.find(cookie); auto it_cookie = it_name->second.find(cookie);
if(it_cookie == it_name->second.end()){ if (it_cookie == it_name->second.end()) {
//该类型下没有对应的cookie //该类型下没有对应的cookie
return nullptr; return nullptr;
} }
if(it_cookie->second->isExpired()){ if (it_cookie->second->isExpired()) {
//cookie过期 // cookie过期
DebugL << "cookie过期:" << it_cookie->second->getCookie(); DebugL << "cookie过期:" << it_cookie->second->getCookie();
it_name->second.erase(it_cookie); it_name->second.erase(it_cookie);
return nullptr; return nullptr;
@ -150,7 +153,7 @@ HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,con
return it_cookie->second; return it_cookie->second;
} }
HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,const StrCaseMap &http_header) { HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name, const StrCaseMap &http_header) {
auto it = http_header.find("Cookie"); auto it = http_header.find("Cookie");
if (it == http_header.end()) { if (it == http_header.end()) {
return nullptr; return nullptr;
@ -159,100 +162,100 @@ HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name,con
if (!cookie.size()) { if (!cookie.size()) {
cookie = FindField(it->second.data(), (cookie_name + "=").data(), nullptr); cookie = FindField(it->second.data(), (cookie_name + "=").data(), nullptr);
} }
if(cookie.empty()){ if (cookie.empty()) {
return nullptr; return nullptr;
} }
return HttpCookieManager::Instance().getCookie(cookie_name , cookie); return HttpCookieManager::Instance().getCookie(cookie_name, cookie);
} }
HttpServerCookie::Ptr HttpCookieManager::getCookieByUid(const string &cookie_name,const string &uid){ HttpServerCookie::Ptr HttpCookieManager::getCookieByUid(const string &cookie_name, const string &uid) {
if(cookie_name.empty() || uid.empty()){ if (cookie_name.empty() || uid.empty()) {
return nullptr; return nullptr;
} }
auto cookie = getOldestCookie(cookie_name,uid); auto cookie = getOldestCookie(cookie_name, uid);
if(cookie.empty()){ if (cookie.empty()) {
return nullptr; return nullptr;
} }
return getCookie(cookie_name,cookie); return getCookie(cookie_name, cookie);
} }
bool HttpCookieManager::delCookie(const HttpServerCookie::Ptr &cookie) { bool HttpCookieManager::delCookie(const HttpServerCookie::Ptr &cookie) {
if(!cookie){ if (!cookie) {
return false; return false;
} }
return delCookie(cookie->getCookieName(),cookie->getCookie()); return delCookie(cookie->getCookieName(), cookie->getCookie());
} }
bool HttpCookieManager::delCookie(const string &cookie_name,const string &cookie) { bool HttpCookieManager::delCookie(const string &cookie_name, const string &cookie) {
lock_guard<recursive_mutex> lck(_mtx_cookie); lock_guard<recursive_mutex> lck(_mtx_cookie);
auto it_name = _map_cookie.find(cookie_name); auto it_name = _map_cookie.find(cookie_name);
if(it_name == _map_cookie.end()){ if (it_name == _map_cookie.end()) {
return false; return false;
} }
return it_name->second.erase(cookie); return it_name->second.erase(cookie);
} }
void HttpCookieManager::onAddCookie(const string &cookie_name,const string &uid,const string &cookie){ void HttpCookieManager::onAddCookie(const string &cookie_name, const string &uid, const string &cookie) {
//添加新的cookie我们记录下这个uid下有哪些cookie目的是实现单账号多地登录时挤占登录 //添加新的cookie我们记录下这个uid下有哪些cookie目的是实现单账号多地登录时挤占登录
lock_guard<recursive_mutex> lck(_mtx_cookie); lock_guard<recursive_mutex> lck(_mtx_cookie);
//相同用户下可以存在多个cookie(意味多地登录)这些cookie根据登录时间的早晚依次排序 //相同用户下可以存在多个cookie(意味多地登录)这些cookie根据登录时间的早晚依次排序
_map_uid_to_cookie[cookie_name][uid][getCurrentMillisecond()] = cookie; _map_uid_to_cookie[cookie_name][uid][getCurrentMillisecond()] = cookie;
} }
void HttpCookieManager::onDelCookie(const string &cookie_name,const string &uid,const string &cookie){
void HttpCookieManager::onDelCookie(const string &cookie_name, const string &uid, const string &cookie) {
lock_guard<recursive_mutex> lck(_mtx_cookie); lock_guard<recursive_mutex> lck(_mtx_cookie);
//回收随机字符串 //回收随机字符串
_geneator.release(cookie); _geneator.release(cookie);
auto it_name = _map_uid_to_cookie.find(cookie_name); auto it_name = _map_uid_to_cookie.find(cookie_name);
if(it_name == _map_uid_to_cookie.end()){ if (it_name == _map_uid_to_cookie.end()) {
//该类型下未有任意用户登录 //该类型下未有任意用户登录
return; return;
} }
auto it_uid = it_name->second.find(uid); auto it_uid = it_name->second.find(uid);
if(it_uid == it_name->second.end()){ if (it_uid == it_name->second.end()) {
//该用户尚未登录 //该用户尚未登录
return; return;
} }
//遍历同一名用户下的所有客户端,移除命中的客户端 //遍历同一名用户下的所有客户端,移除命中的客户端
for(auto it_cookie = it_uid->second.begin() ; it_cookie != it_uid->second.end() ; ++it_cookie ){ for (auto it_cookie = it_uid->second.begin(); it_cookie != it_uid->second.end(); ++it_cookie) {
if(it_cookie->second != cookie) { if (it_cookie->second != cookie) {
//不是该cookie //不是该cookie
continue; continue;
} }
//移除该用户名下的某个cookie这个设备cookie将失效 //移除该用户名下的某个cookie这个设备cookie将失效
it_uid->second.erase(it_cookie); it_uid->second.erase(it_cookie);
if(it_uid->second.size() != 0) { if (it_uid->second.size() != 0) {
break; break;
} }
//该用户名下没有任何设备在线,移除之 //该用户名下没有任何设备在线,移除之
it_name->second.erase(it_uid); it_name->second.erase(it_uid);
if(it_name->second.size() != 0) { if (it_name->second.size() != 0) {
break; break;
} }
//该类型下未有任何用户在线,移除之 //该类型下未有任何用户在线,移除之
_map_uid_to_cookie.erase(it_name); _map_uid_to_cookie.erase(it_name);
break; break;
} }
} }
string HttpCookieManager::getOldestCookie(const string &cookie_name,const string &uid, int max_client){ string HttpCookieManager::getOldestCookie(const string &cookie_name, const string &uid, int max_client) {
lock_guard<recursive_mutex> lck(_mtx_cookie); lock_guard<recursive_mutex> lck(_mtx_cookie);
auto it_name = _map_uid_to_cookie.find(cookie_name); auto it_name = _map_uid_to_cookie.find(cookie_name);
if(it_name == _map_uid_to_cookie.end()){ if (it_name == _map_uid_to_cookie.end()) {
//不存在该类型的cookie //不存在该类型的cookie
return ""; return "";
} }
auto it_uid = it_name->second.find(uid); auto it_uid = it_name->second.find(uid);
if(it_uid == it_name->second.end()){ if (it_uid == it_name->second.end()) {
//该用户从未登录过 //该用户从未登录过
return ""; return "";
} }
if(it_uid->second.size() < MAX(1,max_client)){ if (it_uid->second.size() < MAX(1, max_client)) {
//同一名用户下,客户端个数还没达到限制个数 //同一名用户下,客户端个数还没达到限制个数
return ""; return "";
} }
@ -261,28 +264,29 @@ string HttpCookieManager::getOldestCookie(const string &cookie_name,const string
} }
/////////////////////////////////RandStrGeneator//////////////////////////////////// /////////////////////////////////RandStrGeneator////////////////////////////////////
string RandStrGeneator::obtain(){ string RandStrGeneator::obtain() {
//获取唯一的防膨胀的随机字符串 //获取唯一的防膨胀的随机字符串
while (true){ while (true) {
auto str = obtain_l(); auto str = obtain_l();
if(_obtained.find(str) == _obtained.end()){ if (_obtained.find(str) == _obtained.end()) {
//没有重复 //没有重复
_obtained.emplace(str); _obtained.emplace(str);
return str; return str;
} }
} }
} }
void RandStrGeneator::release(const string &str){
void RandStrGeneator::release(const string &str) {
//从防膨胀库中移除 //从防膨胀库中移除
_obtained.erase(str); _obtained.erase(str);
} }
string RandStrGeneator::obtain_l(){ string RandStrGeneator::obtain_l() {
//12个伪随机字节 + 4个递增的整形字节然后md5即为随机字符串 // 12个伪随机字节 + 4个递增的整形字节然后md5即为随机字符串
auto str = makeRandStr(12,false); auto str = makeRandStr(12, false);
str.append((char *)&_index, sizeof(_index)); str.append((char *)&_index, sizeof(_index));
++_index; ++_index;
return MD5(str).hexdigest(); return MD5(str).hexdigest();
} }
}//namespace mediakit } // namespace mediakit

View File

@ -11,13 +11,13 @@
#ifndef SRC_HTTP_COOKIEMANAGER_H #ifndef SRC_HTTP_COOKIEMANAGER_H
#define SRC_HTTP_COOKIEMANAGER_H #define SRC_HTTP_COOKIEMANAGER_H
#include <memory> #include "Common/Parser.h"
#include <unordered_map> #include "Network/Socket.h"
#include "Util/TimeTicker.h"
#include "Util/mini.h" #include "Util/mini.h"
#include "Util/util.h" #include "Util/util.h"
#include "Util/TimeTicker.h" #include <memory>
#include "Network/Socket.h" #include <unordered_map>
#include "Common/Parser.h"
#define COOKIE_DEFAULT_LIFE (7 * 24 * 60 * 60) #define COOKIE_DEFAULT_LIFE (7 * 24 * 60 * 60)
@ -28,9 +28,9 @@ class HttpCookieManager;
/** /**
* cookie对象cookie的一些相关属性 * cookie对象cookie的一些相关属性
*/ */
class HttpServerCookie : public toolkit::AnyStorage , public toolkit::noncopyable{ class HttpServerCookie : public toolkit::noncopyable {
public: public:
typedef std::shared_ptr<HttpServerCookie> Ptr; using Ptr = std::shared_ptr<HttpServerCookie>;
/** /**
* cookie * cookie
* @param manager cookie管理者对象 * @param manager cookie管理者对象
@ -40,12 +40,10 @@ public:
* @param max_elapsed * @param max_elapsed
*/ */
HttpServerCookie(const std::shared_ptr<HttpCookieManager> &manager, HttpServerCookie(
const std::string &cookie_name, const std::shared_ptr<HttpCookieManager> &manager, const std::string &cookie_name, const std::string &uid,
const std::string &uid, const std::string &cookie, uint64_t max_elapsed);
const std::string &cookie, ~HttpServerCookie();
uint64_t max_elapsed);
~HttpServerCookie() ;
/** /**
* uid * uid
@ -65,13 +63,13 @@ public:
* cookie随机字符串 * cookie随机字符串
* @return cookie随机字符串 * @return cookie随机字符串
*/ */
const std::string& getCookie() const; const std::string &getCookie() const;
/** /**
* cookie名 * cookie名
* @return * @return
*/ */
const std::string& getCookieName() const; const std::string &getCookieName() const;
/** /**
* cookie的过期时间cookie不失效 * cookie的过期时间cookie不失效
@ -85,26 +83,35 @@ public:
bool isExpired(); bool isExpired();
/** /**
* *
* @return
*/ */
std::shared_ptr<std::lock_guard<std::recursive_mutex> > getLock(); void setAttach(std::shared_ptr<void> attach);
/*
*
*/
template <class T>
const T& getAttach() const {
return *static_cast<const T *>(_attach.get());
}
private: private:
std::string cookieExpireTime() const ; std::string cookieExpireTime() const;
private: private:
std::string _uid; std::string _uid;
std::string _cookie_name; std::string _cookie_name;
std::string _cookie_uuid; std::string _cookie_uuid;
uint64_t _max_elapsed; uint64_t _max_elapsed;
toolkit::Ticker _ticker; toolkit::Ticker _ticker;
std::recursive_mutex _mtx; std::shared_ptr<void> _attach;
std::weak_ptr<HttpCookieManager> _manager; std::weak_ptr<HttpCookieManager> _manager;
}; };
/** /**
* cookie随机字符串生成器 * cookie随机字符串生成器
*/ */
class RandStrGeneator{ class RandStrGeneator {
public: public:
RandStrGeneator() = default; RandStrGeneator() = default;
~RandStrGeneator() = default; ~RandStrGeneator() = default;
@ -120,8 +127,10 @@ public:
* @param str * @param str
*/ */
void release(const std::string &str); void release(const std::string &str);
private: private:
std::string obtain_l(); std::string obtain_l();
private: private:
//碰撞库 //碰撞库
std::unordered_set<std::string> _obtained; std::unordered_set<std::string> _obtained;
@ -135,8 +144,8 @@ private:
*/ */
class HttpCookieManager : public std::enable_shared_from_this<HttpCookieManager> { class HttpCookieManager : public std::enable_shared_from_this<HttpCookieManager> {
public: public:
typedef std::shared_ptr<HttpCookieManager> Ptr;
friend class HttpServerCookie; friend class HttpServerCookie;
using Ptr = std::shared_ptr<HttpCookieManager>;
~HttpCookieManager(); ~HttpCookieManager();
/** /**
@ -152,7 +161,10 @@ public:
* @param max_elapsed cookie过期时间 * @param max_elapsed cookie过期时间
* @return cookie对象 * @return cookie对象
*/ */
HttpServerCookie::Ptr addCookie(const std::string &cookie_name,const std::string &uid, uint64_t max_elapsed = COOKIE_DEFAULT_LIFE,int max_client = 1); HttpServerCookie::Ptr addCookie(
const std::string &cookie_name, const std::string &uid, uint64_t max_elapsed = COOKIE_DEFAULT_LIFE,
std::shared_ptr<void> attach = nullptr,
int max_client = 1);
/** /**
* cookie随机字符串查找cookie对象 * cookie随机字符串查找cookie对象
@ -160,7 +172,7 @@ public:
* @param cookie cookie随机字符串 * @param cookie cookie随机字符串
* @return cookie对象nullptr * @return cookie对象nullptr
*/ */
HttpServerCookie::Ptr getCookie(const std::string &cookie_name,const std::string &cookie); HttpServerCookie::Ptr getCookie(const std::string &cookie_name, const std::string &cookie);
/** /**
* http头中获取cookie对象 * http头中获取cookie对象
@ -168,7 +180,7 @@ public:
* @param http_header http头 * @param http_header http头
* @return cookie对象 * @return cookie对象
*/ */
HttpServerCookie::Ptr getCookie(const std::string &cookie_name,const StrCaseMap &http_header); HttpServerCookie::Ptr getCookie(const std::string &cookie_name, const StrCaseMap &http_header);
/** /**
* uid获取cookie * uid获取cookie
@ -176,7 +188,7 @@ public:
* @param uid id * @param uid id
* @return cookie对象 * @return cookie对象
*/ */
HttpServerCookie::Ptr getCookieByUid(const std::string &cookie_name,const std::string &uid); HttpServerCookie::Ptr getCookieByUid(const std::string &cookie_name, const std::string &uid);
/** /**
* cookie使 * cookie使
@ -184,8 +196,10 @@ public:
* @return * @return
*/ */
bool delCookie(const HttpServerCookie::Ptr &cookie); bool delCookie(const HttpServerCookie::Ptr &cookie);
private: private:
HttpCookieManager(); HttpCookieManager();
void onManager(); void onManager();
/** /**
* cookie对象时触发cookie * cookie对象时触发cookie
@ -193,7 +207,7 @@ private:
* @param uid id * @param uid id
* @param cookie cookie随机字符串 * @param cookie cookie随机字符串
*/ */
void onAddCookie(const std::string &cookie_name,const std::string &uid,const std::string &cookie); void onAddCookie(const std::string &cookie_name, const std::string &uid, const std::string &cookie);
/** /**
* cookie对象时触发 * cookie对象时触发
@ -201,7 +215,7 @@ private:
* @param uid id * @param uid id
* @param cookie cookie随机字符串 * @param cookie cookie随机字符串
*/ */
void onDelCookie(const std::string &cookie_name,const std::string &uid,const std::string &cookie); void onDelCookie(const std::string &cookie_name, const std::string &uid, const std::string &cookie);
/** /**
* cookie * cookie
@ -210,7 +224,7 @@ private:
* @param max_client * @param max_client
* @return cookie随机字符串 * @return cookie随机字符串
*/ */
std::string getOldestCookie(const std::string &cookie_name,const std::string &uid, int max_client = 1); std::string getOldestCookie(const std::string &cookie_name, const std::string &uid, int max_client = 1);
/** /**
* cookie * cookie
@ -218,16 +232,21 @@ private:
* @param cookie cookie随机字符串 * @param cookie cookie随机字符串
* @return true * @return true
*/ */
bool delCookie(const std::string &cookie_name,const std::string &cookie); bool delCookie(const std::string &cookie_name, const std::string &cookie);
private: private:
std::unordered_map<std::string/*cookie_name*/,std::unordered_map<std::string/*cookie*/,HttpServerCookie::Ptr/*cookie_data*/> >_map_cookie; std::unordered_map<
std::unordered_map<std::string/*cookie_name*/,std::unordered_map<std::string/*uid*/,std::map<uint64_t/*cookie time stamp*/,std::string/*cookie*/> > >_map_uid_to_cookie; std::string /*cookie_name*/, std::unordered_map<std::string /*cookie*/, HttpServerCookie::Ptr /*cookie_data*/>>
_map_cookie;
std::unordered_map<
std::string /*cookie_name*/,
std::unordered_map<std::string /*uid*/, std::map<uint64_t /*cookie time stamp*/, std::string /*cookie*/>>>
_map_uid_to_cookie;
std::recursive_mutex _mtx_cookie; std::recursive_mutex _mtx_cookie;
toolkit::Timer::Ptr _timer; toolkit::Timer::Ptr _timer;
RandStrGeneator _geneator; RandStrGeneator _geneator;
}; };
}//namespace mediakit } // namespace mediakit
#endif // SRC_HTTP_COOKIEMANAGER_H
#endif //SRC_HTTP_COOKIEMANAGER_H

View File

@ -33,9 +33,6 @@ static const string kCookieName = "ZL_COOKIE";
static const string kHlsSuffix = "/hls.m3u8"; static const string kHlsSuffix = "/hls.m3u8";
class HttpCookieAttachment { class HttpCookieAttachment {
public:
HttpCookieAttachment() {};
~HttpCookieAttachment() {};
public: public:
//cookie生效作用域本cookie只对该目录下的文件生效 //cookie生效作用域本cookie只对该目录下的文件生效
string _path; string _path;
@ -265,13 +262,12 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
if (cookie) { if (cookie) {
//找到了cookie对cookie上锁先 //找到了cookie对cookie上锁先
auto lck = cookie->getLock(); auto& attach = cookie->getAttach<HttpCookieAttachment>();
auto attachment = (*cookie)[kCookieName].get<HttpCookieAttachment>(); if (path.find(attach._path) == 0) {
if (path.find(attachment._path) == 0) {
//上次cookie是限定本目录 //上次cookie是限定本目录
if (attachment._err_msg.empty()) { if (attach._err_msg.empty()) {
//上次鉴权成功 //上次鉴权成功
if (attachment._is_hls) { if (attach._is_hls) {
//如果播放的是hls那么刷新hls的cookie(获取ts文件也会刷新) //如果播放的是hls那么刷新hls的cookie(获取ts文件也会刷新)
cookie->updateTime(); cookie->updateTime();
cookie_from_header = false; cookie_from_header = false;
@ -282,7 +278,7 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
//上次鉴权失败但是如果url参数发生变更那么也重新鉴权下 //上次鉴权失败但是如果url参数发生变更那么也重新鉴权下
if (parser.Params().empty() || parser.Params() == cookie->getUid()) { if (parser.Params().empty() || parser.Params() == cookie->getUid()) {
//url参数未变或者本来就没有url参数那么判断本次请求为重复请求无访问权限 //url参数未变或者本来就没有url参数那么判断本次请求为重复请求无访问权限
callback(attachment._err_msg, cookie_from_header ? nullptr : cookie); callback(attach._err_msg, cookie_from_header ? nullptr : cookie);
return; return;
} }
} }
@ -301,9 +297,9 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
//该用户从来未获取过cookie这个时候我们广播是否允许该用户访问该http目录 //该用户从来未获取过cookie这个时候我们广播是否允许该用户访问该http目录
HttpSession::HttpAccessPathInvoker accessPathInvoker = [callback, uid, path, is_dir, is_hls, mediaInfo, info] HttpSession::HttpAccessPathInvoker accessPathInvoker = [callback, uid, path, is_dir, is_hls, mediaInfo, info]
(const string &errMsg, const string &cookie_path_in, int cookieLifeSecond) { (const string &err_msg, const string &cookie_path_in, int life_second) {
HttpServerCookie::Ptr cookie; HttpServerCookie::Ptr cookie;
if (cookieLifeSecond) { if (life_second) {
//本次鉴权设置了有效期我们把鉴权结果缓存在cookie中 //本次鉴权设置了有效期我们把鉴权结果缓存在cookie中
string cookie_path = cookie_path_in; string cookie_path = cookie_path_in;
if (cookie_path.empty()) { if (cookie_path.empty()) {
@ -311,26 +307,22 @@ static void canAccessPath(TcpSession &sender, const Parser &parser, const MediaI
cookie_path = is_dir ? path : path.substr(0, path.rfind("/") + 1); cookie_path = is_dir ? path : path.substr(0, path.rfind("/") + 1);
} }
cookie = HttpCookieManager::Instance().addCookie(kCookieName, uid, cookieLifeSecond); auto attach = std::make_shared<HttpCookieAttachment>();
//对cookie上锁
auto lck = cookie->getLock();
HttpCookieAttachment attachment;
//记录用户能访问的路径 //记录用户能访问的路径
attachment._path = cookie_path; attach->_path = cookie_path;
//记录能否访问 //记录能否访问
attachment._err_msg = errMsg; attach->_err_msg = err_msg;
//记录访问的是否为hls //记录访问的是否为hls
attachment._is_hls = is_hls; attach->_is_hls = is_hls;
if (is_hls) { if (is_hls) {
//hls相关信息 // hls相关信息
attachment._hls_data = std::make_shared<HlsCookieData>(mediaInfo, info); attach->_hls_data = std::make_shared<HlsCookieData>(mediaInfo, info);
//hls未查找MediaSource // hls未查找MediaSource
attachment._have_find_media_source = false; attach->_have_find_media_source = false;
} }
(*cookie)[kCookieName].set<HttpCookieAttachment>(std::move(attachment)); callback(err_msg, HttpCookieManager::Instance().addCookie(kCookieName, uid, life_second, attach));
callback(errMsg, cookie);
} else { } else {
callback(errMsg, nullptr); callback(err_msg, nullptr);
} }
}; };
@ -401,8 +393,7 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
//文件鉴权失败 //文件鉴权失败
StrCaseMap headerOut; StrCaseMap headerOut;
if (cookie) { if (cookie) {
auto lck = cookie->getLock(); headerOut["Set-Cookie"] = cookie->getAttach<HttpCookieAttachment>()._path;
headerOut["Set-Cookie"] = cookie->getCookie((*cookie)[kCookieName].get<HttpCookieAttachment>()._path);
} }
cb(401, "text/html", headerOut, std::make_shared<HttpStringBody>(errMsg)); cb(401, "text/html", headerOut, std::make_shared<HttpStringBody>(errMsg));
return; return;
@ -411,15 +402,13 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
auto response_file = [file_exist, is_hls](const HttpServerCookie::Ptr &cookie, const HttpFileManager::invoker &cb, const string &strFile, const Parser &parser) { auto response_file = [file_exist, is_hls](const HttpServerCookie::Ptr &cookie, const HttpFileManager::invoker &cb, const string &strFile, const Parser &parser) {
StrCaseMap httpHeader; StrCaseMap httpHeader;
if (cookie) { if (cookie) {
auto lck = cookie->getLock(); httpHeader["Set-Cookie"] = cookie->getAttach<HttpCookieAttachment>()._path;
httpHeader["Set-Cookie"] = cookie->getCookie((*cookie)[kCookieName].get<HttpCookieAttachment>()._path);
} }
HttpSession::HttpResponseInvoker invoker = [&](int code, const StrCaseMap &headerOut, const HttpBody::Ptr &body) { HttpSession::HttpResponseInvoker invoker = [&](int code, const StrCaseMap &headerOut, const HttpBody::Ptr &body) {
if (cookie && file_exist) { if (cookie && file_exist) {
auto lck = cookie->getLock(); auto& attach = cookie->getAttach<HttpCookieAttachment>();
auto is_hls = (*cookie)[kCookieName].get<HttpCookieAttachment>()._is_hls; if (attach._is_hls) {
if (is_hls) { attach._hls_data->addByteUsage(body->remainSize());
(*cookie)[kCookieName].get<HttpCookieAttachment>()._hls_data->addByteUsage(body->remainSize());
} }
} }
cb(code, HttpFileManager::getContentType(strFile.data()), headerOut, body); cb(code, HttpFileManager::getContentType(strFile.data()), headerOut, body);
@ -436,10 +425,10 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
//是hls直播判断HLS直播流是否已经注册 //是hls直播判断HLS直播流是否已经注册
bool have_find_media_src = false; bool have_find_media_src = false;
if (cookie) { if (cookie) {
auto lck = cookie->getLock(); auto& attach = cookie->getAttach<HttpCookieAttachment>();
have_find_media_src = (*cookie)[kCookieName].get<HttpCookieAttachment>()._have_find_media_source; have_find_media_src = attach._have_find_media_source;
if (!have_find_media_src) { if (!have_find_media_src) {
(*cookie)[kCookieName].get<HttpCookieAttachment>()._have_find_media_source = true; const_cast<HttpCookieAttachment &>(attach)._have_find_media_source = true;
} }
} }
if (have_find_media_src) { if (have_find_media_src) {
@ -450,9 +439,8 @@ static void accessFile(TcpSession &sender, const Parser &parser, const MediaInfo
//hls文件不存在我们等待其生成并延后回复 //hls文件不存在我们等待其生成并延后回复
MediaSource::findAsync(mediaInfo, strongSession, [response_file, cookie, cb, strFile, parser](const MediaSource::Ptr &src) { MediaSource::findAsync(mediaInfo, strongSession, [response_file, cookie, cb, strFile, parser](const MediaSource::Ptr &src) {
if (cookie) { if (cookie) {
auto lck = cookie->getLock();
//尝试添加HlsMediaSource的观看人数(HLS是按需生成的这样可以触发HLS文件的生成) //尝试添加HlsMediaSource的观看人数(HLS是按需生成的这样可以触发HLS文件的生成)
(*cookie)[kCookieName].get<HttpCookieAttachment>()._hls_data->addByteUsage(0); cookie->getAttach<HttpCookieAttachment>()._hls_data->addByteUsage(0);
} }
if (src && File::is_file(strFile.data())) { if (src && File::is_file(strFile.data())) {
//流和m3u8文件都存在那么直接返回文件 //流和m3u8文件都存在那么直接返回文件
@ -531,7 +519,7 @@ void HttpFileManager::onAccessPath(TcpSession &sender, Parser &parser, const Htt
} }
StrCaseMap headerOut; StrCaseMap headerOut;
if (cookie) { if (cookie) {
headerOut["Set-Cookie"] = cookie->getCookie((*cookie)[kCookieName].get<HttpCookieAttachment>()._path); headerOut["Set-Cookie"] = cookie->getAttach<HttpCookieAttachment>()._path;
} }
cb(errMsg.empty() ? 200 : 401, "text/html", headerOut, std::make_shared<HttpStringBody>(strMenu)); cb(errMsg.empty() ? 200 : 401, "text/html", headerOut, std::make_shared<HttpStringBody>(strMenu));
}); });