1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_COOKIES_COOKIE_MONSTER_CHANGE_DISPATCHER_H_ 6 #define NET_COOKIES_COOKIE_MONSTER_CHANGE_DISPATCHER_H_ 7 8 #include <map> 9 #include <memory> 10 #include <string> 11 12 #include "base/callback_list.h" 13 #include "base/containers/linked_list.h" 14 #include "base/functional/callback.h" 15 #include "base/memory/raw_ptr.h" 16 #include "base/memory/scoped_refptr.h" 17 #include "base/memory/weak_ptr.h" 18 #include "base/task/single_thread_task_runner.h" 19 #include "base/threading/thread_checker.h" 20 #include "net/cookies/cookie_change_dispatcher.h" 21 #include "net/cookies/cookie_partition_key_collection.h" 22 #include "url/gurl.h" 23 24 namespace net { 25 26 class CookieAccessDelegate; 27 class CookieMonster; 28 29 // CookieChangeDispatcher implementation used by CookieMonster. 30 class CookieMonsterChangeDispatcher : public CookieChangeDispatcher { 31 public: 32 using CookieChangeCallbackList = 33 base::RepeatingCallbackList<void(const CookieChangeInfo&)>; 34 35 // Expects |cookie_monster| to outlive this. 36 explicit CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster); 37 38 CookieMonsterChangeDispatcher(const CookieMonsterChangeDispatcher&) = delete; 39 CookieMonsterChangeDispatcher& operator=( 40 const CookieMonsterChangeDispatcher&) = delete; 41 42 ~CookieMonsterChangeDispatcher() override; 43 44 // The key in CookieNameMap for a cookie name. 45 static std::string NameKey(std::string name); 46 47 // The key in CookieDomainName for a cookie domain. 48 static std::string DomainKey(const std::string& domain); 49 50 // The key in CookieDomainName for a listener URL. 51 static std::string DomainKey(const GURL& url); 52 53 // net::CookieChangeDispatcher 54 [[nodiscard]] std::unique_ptr<CookieChangeSubscription> AddCallbackForCookie( 55 const GURL& url, 56 const std::string& name, 57 const std::optional<CookiePartitionKey>& cookie_partition_key, 58 CookieChangeCallback callback) override; 59 [[nodiscard]] std::unique_ptr<CookieChangeSubscription> AddCallbackForUrl( 60 const GURL& url, 61 const std::optional<CookiePartitionKey>& cookie_partition_key, 62 CookieChangeCallback callback) override; 63 [[nodiscard]] std::unique_ptr<CookieChangeSubscription> 64 AddCallbackForAllChanges(CookieChangeCallback callback) override; 65 66 // |notify_global_hooks| is true if the function should run the 67 // global hooks in addition to the per-cookie hooks. 68 // 69 // TODO(pwnall): Remove |notify_global_hooks| and fix consumers. 70 void DispatchChange(const CookieChangeInfo& change, bool notify_global_hooks); 71 72 private: 73 class Subscription : public base::LinkNode<Subscription>, 74 public CookieChangeSubscription { 75 public: 76 Subscription(base::WeakPtr<CookieMonsterChangeDispatcher> change_dispatcher, 77 std::string domain_key, 78 std::string name_key, 79 GURL url, 80 CookiePartitionKeyCollection cookie_partition_key_collection, 81 net::CookieChangeCallback callback); 82 83 Subscription(const Subscription&) = delete; 84 Subscription& operator=(const Subscription&) = delete; 85 86 ~Subscription() override; 87 88 // The lookup key used in the domain subscription map. 89 // 90 // The empty string means no domain filtering. domain_key()91 const std::string& domain_key() const { return domain_key_; } 92 // The lookup key used in the name subscription map. 93 // 94 // The empty string means no name filtering. name_key()95 const std::string& name_key() const { return name_key_; } 96 97 // Dispatches a cookie change notification if the listener is interested. 98 void DispatchChange(const CookieChangeInfo& change, 99 const CookieAccessDelegate* cookie_access_delegate); 100 101 private: 102 base::WeakPtr<CookieMonsterChangeDispatcher> change_dispatcher_; 103 const std::string domain_key_; // kGlobalDomainKey means no filtering. 104 const std::string name_key_; // kGlobalNameKey means no filtering. 105 const GURL url_; // empty() means no URL-based filtering. 106 const CookiePartitionKeyCollection cookie_partition_key_collection_; 107 const net::CookieChangeCallback callback_; 108 109 void DoDispatchChange(const CookieChangeInfo& change) const; 110 111 // Used to post DoDispatchChange() calls to this subscription's thread. 112 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 113 114 THREAD_CHECKER(thread_checker_); 115 116 // Used to cancel delayed calls to DoDispatchChange() when the subscription 117 // gets destroyed. 118 base::WeakPtrFactory<Subscription> weak_ptr_factory_{this}; 119 }; 120 121 // The last level of the subscription data structures. 122 using SubscriptionList = base::LinkedList<Subscription>; 123 124 // Buckets subscriptions according to cookie names. 125 // 126 // Map keys are cookie names, as we only support exact name matching. 127 using CookieNameMap = std::map<std::string, SubscriptionList>; 128 129 // Buckets subscriptions according to cookie domains. 130 // 131 // Map keys are the eTLD+1 of cookie domains. Cookies are either host-locked, 132 // or visible to all the subdomain of a given domain. A cookie's scope cannot 133 // exceed eTLD+1, so we stop there. 134 using CookieDomainMap = std::map<std::string, CookieNameMap>; 135 136 void DispatchChangeToDomainKey(const CookieChangeInfo& change, 137 const std::string& domain_key); 138 139 void DispatchChangeToNameKey(const CookieChangeInfo& change, 140 CookieNameMap& name_map, 141 const std::string& name_key); 142 143 // Inserts a subscription into the map. 144 // 145 // Called by the AddCallback* methods, after creating the Subscription. 146 void LinkSubscription(Subscription* subscription); 147 148 // Removes a subscription from the map. 149 // 150 // Called by the Subscription destructor. 151 void UnlinkSubscription(Subscription* subscription); 152 153 raw_ptr<const CookieMonster> cookie_monster_; 154 155 CookieDomainMap cookie_domain_map_; 156 157 THREAD_CHECKER(thread_checker_); 158 159 // Vends weak pointers to subscriptions. 160 base::WeakPtrFactory<CookieMonsterChangeDispatcher> weak_ptr_factory_{this}; 161 }; 162 163 } // namespace net 164 165 #endif // NET_COOKIES_COOKIE_MONSTER_CHANGE_DISPATCHER_H_ 166