2019-08-08 19:01:45 +08:00
|
|
|
|
/*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
|
2019-06-12 17:53:48 +08:00
|
|
|
|
*
|
2021-01-17 18:31:50 +08:00
|
|
|
|
* This file is part of ZLMediaKit(https://github.com/xia-chu/ZLMediaKit).
|
2019-06-12 17:53:48 +08:00
|
|
|
|
*
|
2020-04-04 20:30:09 +08:00
|
|
|
|
* Use of this source code is governed by MIT license that can be found in the
|
|
|
|
|
* LICENSE file in the root of the source tree. All contributing project authors
|
|
|
|
|
* may be found in the AUTHORS file in the root of the source tree.
|
2019-06-12 17:53:48 +08:00
|
|
|
|
*/
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
#include "HttpCookieManager.h"
|
2022-02-11 14:33:11 +08:00
|
|
|
|
#include "Common/config.h"
|
|
|
|
|
#include "Util/MD5.h"
|
|
|
|
|
#include "Util/util.h"
|
2019-06-12 17:53:48 +08:00
|
|
|
|
|
2022-02-02 20:34:50 +08:00
|
|
|
|
using namespace std;
|
|
|
|
|
using namespace toolkit;
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
namespace mediakit {
|
|
|
|
|
|
|
|
|
|
//////////////////////////////HttpServerCookie////////////////////////////////////
|
2022-02-11 14:33:11 +08:00
|
|
|
|
HttpServerCookie::HttpServerCookie(
|
|
|
|
|
const std::shared_ptr<HttpCookieManager> &manager, const string &cookie_name, const string &uid,
|
|
|
|
|
const string &cookie, uint64_t max_elapsed) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
_uid = uid;
|
|
|
|
|
_max_elapsed = max_elapsed;
|
|
|
|
|
_cookie_uuid = cookie;
|
2019-06-13 12:00:41 +08:00
|
|
|
|
_cookie_name = cookie_name;
|
2019-06-12 17:53:48 +08:00
|
|
|
|
_manager = manager;
|
2022-02-11 14:33:11 +08:00
|
|
|
|
manager->onAddCookie(_cookie_name, _uid, _cookie_uuid);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
HttpServerCookie::~HttpServerCookie() {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
auto strongManager = _manager.lock();
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (strongManager) {
|
|
|
|
|
strongManager->onDelCookie(_cookie_name, _uid, _cookie_uuid);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
const string &HttpServerCookie::getUid() const {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
return _uid;
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
string HttpServerCookie::getCookie(const string &path) const {
|
|
|
|
|
return (StrPrinter << _cookie_name << "=" << _cookie_uuid << ";expires=" << cookieExpireTime() << ";path=" << path);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
const string &HttpServerCookie::getCookie() const {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
return _cookie_uuid;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
const string &HttpServerCookie::getCookieName() const {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
return _cookie_name;
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
void HttpServerCookie::updateTime() {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
_ticker.resetTime();
|
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
|
|
|
|
|
bool HttpServerCookie::isExpired() {
|
|
|
|
|
return _ticker.elapsedTime() > _max_elapsed * 1000;
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
void HttpServerCookie::setAttach(std::shared_ptr<void> attach) {
|
|
|
|
|
_attach = std::move(attach);
|
2019-06-14 18:42:09 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
string HttpServerCookie::cookieExpireTime() const {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
char buf[64];
|
|
|
|
|
time_t tt = time(NULL) + _max_elapsed;
|
|
|
|
|
strftime(buf, sizeof buf, "%a, %b %d %Y %H:%M:%S GMT", gmtime(&tt));
|
|
|
|
|
return buf;
|
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//////////////////////////////CookieManager////////////////////////////////////
|
|
|
|
|
INSTANCE_IMP(HttpCookieManager);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
HttpCookieManager::HttpCookieManager() {
|
|
|
|
|
//定时删除过期的cookie,防止内存膨胀
|
2022-02-11 14:33:11 +08:00
|
|
|
|
_timer = std::make_shared<Timer>(
|
|
|
|
|
10.0f,
|
|
|
|
|
[this]() {
|
|
|
|
|
onManager();
|
|
|
|
|
return true;
|
|
|
|
|
},
|
|
|
|
|
nullptr);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
HttpCookieManager::~HttpCookieManager() {
|
|
|
|
|
_timer.reset();
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
void HttpCookieManager::onManager() {
|
|
|
|
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
|
|
|
|
//先遍历所有类型
|
2022-02-11 14:33:11 +08:00
|
|
|
|
for (auto it_name = _map_cookie.begin(); it_name != _map_cookie.end();) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//再遍历该类型下的所有cookie
|
2022-02-11 14:33:11 +08:00
|
|
|
|
for (auto it_cookie = it_name->second.begin(); it_cookie != it_name->second.end();) {
|
|
|
|
|
if (it_cookie->second->isExpired()) {
|
|
|
|
|
// cookie过期,移除记录
|
2019-06-14 18:42:09 +08:00
|
|
|
|
DebugL << it_cookie->second->getUid() << " cookie过期:" << it_cookie->second->getCookie();
|
2019-06-13 12:00:41 +08:00
|
|
|
|
it_cookie = it_name->second.erase(it_cookie);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
++it_cookie;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_name->second.empty()) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//该类型下没有任何cooki记录,移除之
|
2019-06-14 18:42:09 +08:00
|
|
|
|
DebugL << "该path下没有任何cooki记录:" << it_name->first;
|
2019-06-13 12:00:41 +08:00
|
|
|
|
it_name = _map_cookie.erase(it_name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
++it_name;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-06-12 17:53:48 +08:00
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
HttpServerCookie::Ptr HttpCookieManager::addCookie(const string &cookie_name, const string &uid_in,
|
|
|
|
|
uint64_t max_elapsed, std::shared_ptr<void> attach, int max_client) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
|
|
|
|
auto cookie = _geneator.obtain();
|
2022-02-11 14:33:11 +08:00
|
|
|
|
auto uid = uid_in.empty() ? cookie : uid_in;
|
|
|
|
|
auto oldCookie = getOldestCookie(cookie_name, uid, max_client);
|
|
|
|
|
if (!oldCookie.empty()) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//假如该账号已经登录了,那么删除老的cookie。
|
|
|
|
|
//目的是实现单账号多地登录时挤占登录
|
2022-02-11 14:33:11 +08:00
|
|
|
|
delCookie(cookie_name, oldCookie);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
HttpServerCookie::Ptr data(new HttpServerCookie(shared_from_this(), cookie_name, uid, cookie, max_elapsed));
|
|
|
|
|
data->setAttach(std::move(attach));
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//保存该账号下的新cookie
|
2019-06-13 12:00:41 +08:00
|
|
|
|
_map_cookie[cookie_name][cookie] = data;
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return data;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name, const string &cookie) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
2019-06-13 12:00:41 +08:00
|
|
|
|
auto it_name = _map_cookie.find(cookie_name);
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_name == _map_cookie.end()) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//不存在该类型的cookie
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
auto it_cookie = it_name->second.find(cookie);
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_cookie == it_name->second.end()) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//该类型下没有对应的cookie
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_cookie->second->isExpired()) {
|
|
|
|
|
// cookie过期
|
2019-06-14 18:42:09 +08:00
|
|
|
|
DebugL << "cookie过期:" << it_cookie->second->getCookie();
|
2019-06-13 12:00:41 +08:00
|
|
|
|
it_name->second.erase(it_cookie);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return it_cookie->second;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
HttpServerCookie::Ptr HttpCookieManager::getCookie(const string &cookie_name, const StrCaseMap &http_header) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
auto it = http_header.find("Cookie");
|
|
|
|
|
if (it == http_header.end()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
auto cookie = FindField(it->second.data(), (cookie_name + "=").data(), ";");
|
|
|
|
|
if (!cookie.size()) {
|
|
|
|
|
cookie = FindField(it->second.data(), (cookie_name + "=").data(), nullptr);
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (cookie.empty()) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
return HttpCookieManager::Instance().getCookie(cookie_name, cookie);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
HttpServerCookie::Ptr HttpCookieManager::getCookieByUid(const string &cookie_name, const string &uid) {
|
|
|
|
|
if (cookie_name.empty() || uid.empty()) {
|
2019-06-14 15:19:02 +08:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
auto cookie = getOldestCookie(cookie_name, uid);
|
|
|
|
|
if (cookie.empty()) {
|
2019-06-14 15:19:02 +08:00
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
return getCookie(cookie_name, cookie);
|
2019-06-14 15:19:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
bool HttpCookieManager::delCookie(const HttpServerCookie::Ptr &cookie) {
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (!cookie) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
return delCookie(cookie->getCookieName(), cookie->getCookie());
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
bool HttpCookieManager::delCookie(const string &cookie_name, const string &cookie) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
2019-06-13 12:00:41 +08:00
|
|
|
|
auto it_name = _map_cookie.find(cookie_name);
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_name == _map_cookie.end()) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
return false;
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
return it_name->second.erase(cookie);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
void HttpCookieManager::onAddCookie(const string &cookie_name, const string &uid, const string &cookie) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//添加新的cookie,我们记录下这个uid下有哪些cookie,目的是实现单账号多地登录时挤占登录
|
|
|
|
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
|
|
|
|
//相同用户下可以存在多个cookie(意味多地登录),这些cookie根据登录时间的早晚依次排序
|
2019-06-13 12:00:41 +08:00
|
|
|
|
_map_uid_to_cookie[cookie_name][uid][getCurrentMillisecond()] = cookie;
|
2019-06-12 17:53:48 +08:00
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
|
|
|
|
|
void HttpCookieManager::onDelCookie(const string &cookie_name, const string &uid, const string &cookie) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
|
|
|
|
//回收随机字符串
|
|
|
|
|
_geneator.release(cookie);
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
auto it_name = _map_uid_to_cookie.find(cookie_name);
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_name == _map_uid_to_cookie.end()) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//该类型下未有任意用户登录
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
auto it_uid = it_name->second.find(uid);
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_uid == it_name->second.end()) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//该用户尚未登录
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//遍历同一名用户下的所有客户端,移除命中的客户端
|
2022-02-11 14:33:11 +08:00
|
|
|
|
for (auto it_cookie = it_uid->second.begin(); it_cookie != it_uid->second.end(); ++it_cookie) {
|
|
|
|
|
if (it_cookie->second != cookie) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//不是该cookie
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
//移除该用户名下的某个cookie,这个设备cookie将失效
|
|
|
|
|
it_uid->second.erase(it_cookie);
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_uid->second.size() != 0) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//该用户名下没有任何设备在线,移除之
|
2019-06-13 12:00:41 +08:00
|
|
|
|
it_name->second.erase(it_uid);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_name->second.size() != 0) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//该类型下未有任何用户在线,移除之
|
|
|
|
|
_map_uid_to_cookie.erase(it_name);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
string HttpCookieManager::getOldestCookie(const string &cookie_name, const string &uid, int max_client) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
lock_guard<recursive_mutex> lck(_mtx_cookie);
|
2019-06-13 12:00:41 +08:00
|
|
|
|
auto it_name = _map_uid_to_cookie.find(cookie_name);
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_name == _map_uid_to_cookie.end()) {
|
2019-06-13 12:00:41 +08:00
|
|
|
|
//不存在该类型的cookie
|
2019-06-12 17:53:48 +08:00
|
|
|
|
return "";
|
|
|
|
|
}
|
2019-06-13 12:00:41 +08:00
|
|
|
|
auto it_uid = it_name->second.find(uid);
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_uid == it_name->second.end()) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//该用户从未登录过
|
|
|
|
|
return "";
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (it_uid->second.size() < MAX(1, max_client)) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//同一名用户下,客户端个数还没达到限制个数
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
//客户端个数超过限制,移除最先登录的客户端
|
|
|
|
|
return it_uid->second.begin()->second;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-13 12:00:41 +08:00
|
|
|
|
/////////////////////////////////RandStrGeneator////////////////////////////////////
|
2022-02-11 14:33:11 +08:00
|
|
|
|
string RandStrGeneator::obtain() {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//获取唯一的防膨胀的随机字符串
|
2022-02-11 14:33:11 +08:00
|
|
|
|
while (true) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
auto str = obtain_l();
|
2022-02-11 14:33:11 +08:00
|
|
|
|
if (_obtained.find(str) == _obtained.end()) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//没有重复
|
|
|
|
|
_obtained.emplace(str);
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-11 14:33:11 +08:00
|
|
|
|
|
|
|
|
|
void RandStrGeneator::release(const string &str) {
|
2019-06-12 17:53:48 +08:00
|
|
|
|
//从防膨胀库中移除
|
|
|
|
|
_obtained.erase(str);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
string RandStrGeneator::obtain_l() {
|
|
|
|
|
// 12个伪随机字节 + 4个递增的整形字节,然后md5即为随机字符串
|
|
|
|
|
auto str = makeRandStr(12, false);
|
2019-06-12 17:53:48 +08:00
|
|
|
|
str.append((char *)&_index, sizeof(_index));
|
|
|
|
|
++_index;
|
|
|
|
|
return MD5(str).hexdigest();
|
2019-06-13 12:00:41 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-02-11 14:33:11 +08:00
|
|
|
|
} // namespace mediakit
|