/* * Copyright: JessMA Open Source (ldcsaa@gmail.com) * * Author : Bruce Liang * Website : https://github.com/ldcsaa * Project : https://github.com/ldcsaa/HP-Socket * Blog : http://www.cnblogs.com/ldcsaa * Wiki : http://www.oschina.net/p/hp-socket * QQ Group : 44636872, 75375912 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include "hpsocket/HPTypeDef.h" #include "common/GeneralHelper.h" #ifdef _HTTP_SUPPORT #define COOKIE_DOMAIN "domain" #define COOKIE_PATH "path" #define COOKIE_EXPIRES "expires" #define COOKIE_MAX_AGE "Max-Age" #define COOKIE_HTTPONLY "HttpOnly" #define COOKIE_SECURE "secure" #define COOKIE_SAMESITE "SameSite" #define COOKIE_SAMESITE_STRICT "Strict" #define COOKIE_SAMESITE_LAX "Lax" #define COOKIE_SAMESITE_NONE "None" #define COOKIE_DEFAULT_PATH "/" #define COOKIE_FIELD_SEP ";" #define COOKIE_DOMAIN_SEP_CHAR '.' #define COOKIE_PATH_SEP_CHAR '/' #define COOKIE_KV_SEP_CHAR '=' class CCookie { public: enum EnSameSite { SS_UNKNOWN = 0, SS_STRICT = 1, SS_LAX = 2, SS_NONE = 3 }; CStringA name; CStringA value; CStringA domain; CStringA path; __time64_t expires; BOOL httpOnly; BOOL secure; EnSameSite sameSite; CCookie(LPCSTR lpszName = nullptr, LPCSTR lpszValue = nullptr, LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, EnSameSite enSameSite = SS_UNKNOWN) : name (lpszName) , value (lpszValue) , domain (lpszDomain) , path (lpszPath) , expires (MaxAgeToExpires(iMaxAge)) , httpOnly (bHttpOnly) , secure (bSecure) , sameSite (enSameSite) { AdjustDomain(domain); AdjustPath(path); } static __time64_t CurrentUTCTime() {return _time64(nullptr);} static __time64_t MaxAgeToExpires(int iMaxAge) {return iMaxAge > 0 ? _time64(nullptr) + iMaxAge : (iMaxAge < 0 ? -1 : 0);} static int ExpiresToMaxAge(__time64_t tmExpires) {if(tmExpires < 0) return -1; __time64_t tmDiff = tmExpires - _time64(nullptr); return (tmDiff > 0 ? (int)tmDiff : 0);} static __time64_t GetUTCTime(tm& t, int iSecondOffsetTZ); static void ParseFieldKV(const CStringA& strField, CStringA& strKey, CStringA& strVal, char chSep); static BOOL ParseExpires(LPCSTR lpszExpires, __time64_t& tmExpires); static BOOL AdjustDomain(CStringA& strDomain, LPCSTR lpszDefaultDomain = nullptr); static BOOL AdjustPath(CStringA& strPath, LPCSTR lpszDefaultPath = nullptr); static CStringA MakeExpiresStr(__time64_t tmExpires); static BOOL MakeExpiresStr(char lpszBuff[], int& iBuffLen, __time64_t tmExpires); static CCookie* FromString(const CStringA& strCookie, LPCSTR lpszDefaultDomain = nullptr, LPCSTR lpszDefaultPath = nullptr); static CStringA ToString(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, EnSameSite enSameSite = SS_UNKNOWN); static BOOL ToString(char lpszBuff[], int& iBuffLen, LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, EnSameSite enSameSite = SS_UNKNOWN); CStringA ToString(); BOOL Match(LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp, BOOL bSecure); BOOL IsSameDomain(LPCSTR lpszDomain); BOOL IsTransient() const {return expires < 0;} BOOL IsExpired() const {return !IsTransient() && expires <= _time64(nullptr);} BOOL IsValid() const {return !name.IsEmpty() && !domain.IsEmpty() && !path.IsEmpty();} }; struct ccookie_hash_func { struct hash { size_t operator() (const CCookie& c) const { return hash_value((LPCSTR)(c.name)); } }; struct equal_to { bool operator () (const CCookie& cA, const CCookie& cB) const { return (cA.name == cB.name); } }; }; // ------------------------------------------------------------------------------------------------------------- // typedef unordered_set CCookiePtrSet; typedef CCookiePtrSet::const_iterator CCookiePtrSetCI; typedef CCookiePtrSet::iterator CCookiePtrSetI; typedef unordered_set CCookieSet; typedef CCookieSet::const_iterator CCookieSetCI; typedef CCookieSet::iterator CCookieSetI; typedef unordered_map CCookiePathMap; typedef CCookiePathMap::const_iterator CCookiePathMapCI; typedef CCookiePathMap::iterator CCookiePathMapI; typedef unordered_map CCookieDomainMap; typedef CCookieDomainMap::const_iterator CCookieDomainMapCI; typedef CCookieDomainMap::iterator CCookieDomainMapI; class CCookieMgr { public: BOOL LoadFromFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE); BOOL SaveToFile(LPCSTR lpszFile, BOOL bKeepExists = TRUE); BOOL ClearCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr); BOOL RemoveExpiredCookies(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr); BOOL GetCookies(CCookieSet& cookies, LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp, BOOL bSecure); BOOL SetCookie(LPCSTR lpszName, LPCSTR lpszValue, LPCSTR lpszDomain, LPCSTR lpszPath, int iMaxAge = -1, BOOL bHttpOnly = FALSE, BOOL bSecure = FALSE, CCookie::EnSameSite enSameSite = CCookie::SS_UNKNOWN, BOOL bOnlyUpdateValueIfExists = TRUE); BOOL SetCookie(const CStringA& strCookie, BOOL bOnlyUpdateValueIfExists = TRUE); BOOL SetCookie(const CCookie& cookie, BOOL bOnlyUpdateValueIfExists = TRUE); BOOL DeleteCookie(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName); BOOL DeleteCookie(const CCookie& cookie); private: void ClearDomainCookiesNoLock(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr); void ClearPathCookiesNoLock(CCookiePathMap& paths, LPCSTR lpszPath = nullptr); void RemoveExpiredCookiesNoLock(LPCSTR lpszDomain = nullptr, LPCSTR lpszPath = nullptr); void RemoveDomainExpiredCookiesNoLock(CCookiePathMap& paths, LPCSTR lpszPath = nullptr); void RemovePathExpiredCookiesNoLock(CCookieSet& cookies); const CCookie* GetCookieNoLock(LPCSTR lpszDomain, LPCSTR lpszPath, LPCSTR lpszName); const CCookie* GetCookieNoLock(const CCookie& cookie); void MatchCookiesNoLock(CCookieSet& cookies, LPCSTR lpszDomain, LPCSTR lpszPath, BOOL bHttp = TRUE, BOOL bSecure = FALSE); BOOL SetCookieNoLock(const CCookie& cookie, BOOL bOnlyUpdateValueIfExists = TRUE); BOOL DeleteCookieNoLock(const CCookie& cookie); CCookieSet* GetCookieSetNoLock(LPCSTR lpszDomain, LPCSTR lpszPath); private: static BOOL LoadDomainAndPath(LPSTR lpszBuff, CStringA& strDomain, CStringA& strPath); static BOOL LoadCookie(LPSTR lpszBuff, LPCSTR lpszDomain, LPCSTR lpszPath, CCookie& cookie); static BOOL AdjustDomainAndPath(LPCSTR& lpszDomain, LPCSTR& lpszPath, CStringA& strDomain, CStringA& strPath, BOOL bKeepNull = TRUE); public: CCookieMgr(BOOL bEnableThirdPartyCookie = TRUE); void SetEnableThirdPartyCookie (BOOL bEnableThirdPartyCookie = TRUE) {m_bEnableThirdPartyCookie = bEnableThirdPartyCookie;} BOOL IsEnableThirdPartyCookie () {return m_bEnableThirdPartyCookie;} private: CSimpleRWLock m_cs; CCookieDomainMap m_cookies; BOOL m_bEnableThirdPartyCookie; }; extern CCookieMgr g_CookieMgr; #endif