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 CookieMonsterChangeDispatcher(const CookieMonster* cookie_monster, 37 bool same_party_attribute_enabled); 38 39 CookieMonsterChangeDispatcher(const CookieMonsterChangeDispatcher&) = delete; 40 CookieMonsterChangeDispatcher& operator=( 41 const CookieMonsterChangeDispatcher&) = delete; 42 43 ~CookieMonsterChangeDispatcher() override; 44 45 // The key in CookieNameMap for a cookie name. 46 static std::string NameKey(std::string name); 47 48 // The key in CookieDomainName for a cookie domain. 49 static std::string DomainKey(const std::string& domain); 50 51 // The key in CookieDomainName for a listener URL. 52 static std::string DomainKey(const GURL& url); 53 54 // net::CookieChangeDispatcher 55 [[nodiscard]] std::unique_ptr<CookieChangeSubscription> AddCallbackForCookie( 56 const GURL& url, 57 const std::string& name, 58 const absl::optional<CookiePartitionKey>& cookie_partition_key, 59 CookieChangeCallback callback) override; 60 [[nodiscard]] std::unique_ptr<CookieChangeSubscription> AddCallbackForUrl( 61 const GURL& url, 62 const absl::optional<CookiePartitionKey>& cookie_partition_key, 63 CookieChangeCallback callback) override; 64 [[nodiscard]] std::unique_ptr<CookieChangeSubscription> 65 AddCallbackForAllChanges(CookieChangeCallback callback) override; 66 67 // |notify_global_hooks| is true if the function should run the 68 // global hooks in addition to the per-cookie hooks. 69 // 70 // TODO(pwnall): Remove |notify_global_hooks| and fix consumers. 71 void DispatchChange(const CookieChangeInfo& change, bool notify_global_hooks); 72 73 private: 74 class Subscription : public base::LinkNode<Subscription>, 75 public CookieChangeSubscription { 76 public: 77 Subscription(base::WeakPtr<CookieMonsterChangeDispatcher> change_dispatcher, 78 std::string domain_key, 79 std::string name_key, 80 GURL url, 81 CookiePartitionKeyCollection cookie_partition_key_collection, 82 bool same_party_attribute_enabled, 83 net::CookieChangeCallback callback); 84 85 Subscription(const Subscription&) = delete; 86 Subscription& operator=(const Subscription&) = delete; 87 88 ~Subscription() override; 89 90 // The lookup key used in the domain subscription map. 91 // 92 // The empty string means no domain filtering. domain_key()93 const std::string& domain_key() const { return domain_key_; } 94 // The lookup key used in the name subscription map. 95 // 96 // The empty string means no name filtering. name_key()97 const std::string& name_key() const { return name_key_; } 98 99 // Dispatches a cookie change notification if the listener is interested. 100 void DispatchChange(const CookieChangeInfo& change, 101 const CookieAccessDelegate* cookie_access_delegate); 102 103 private: 104 base::WeakPtr<CookieMonsterChangeDispatcher> change_dispatcher_; 105 const std::string domain_key_; // kGlobalDomainKey means no filtering. 106 const std::string name_key_; // kGlobalNameKey means no filtering. 107 const GURL url_; // empty() means no URL-based filtering. 108 const CookiePartitionKeyCollection cookie_partition_key_collection_; 109 const net::CookieChangeCallback callback_; 110 bool same_party_attribute_enabled_; 111 112 void DoDispatchChange(const CookieChangeInfo& change) const; 113 114 // Used to post DoDispatchChange() calls to this subscription's thread. 115 scoped_refptr<base::SingleThreadTaskRunner> task_runner_; 116 117 THREAD_CHECKER(thread_checker_); 118 119 // Used to cancel delayed calls to DoDispatchChange() when the subscription 120 // gets destroyed. 121 base::WeakPtrFactory<Subscription> weak_ptr_factory_{this}; 122 }; 123 124 // The last level of the subscription data structures. 125 using SubscriptionList = base::LinkedList<Subscription>; 126 127 // Buckets subscriptions according to cookie names. 128 // 129 // Map keys are cookie names, as we only support exact name matching. 130 using CookieNameMap = std::map<std::string, SubscriptionList>; 131 132 // Buckets subscriptions according to cookie domains. 133 // 134 // Map keys are the eTLD+1 of cookie domains. Cookies are either host-locked, 135 // or visible to all the subdomain of a given domain. A cookie's scope cannot 136 // exceed eTLD+1, so we stop there. 137 using CookieDomainMap = std::map<std::string, CookieNameMap>; 138 139 void DispatchChangeToDomainKey(const CookieChangeInfo& change, 140 const std::string& domain_key); 141 142 void DispatchChangeToNameKey(const CookieChangeInfo& change, 143 CookieNameMap& name_map, 144 const std::string& name_key); 145 146 // Inserts a subscription into the map. 147 // 148 // Called by the AddCallback* methods, after creating the Subscription. 149 void LinkSubscription(Subscription* subscription); 150 151 // Removes a subscription from the map. 152 // 153 // Called by the Subscription destructor. 154 void UnlinkSubscription(Subscription* subscription); 155 156 raw_ptr<const CookieMonster> cookie_monster_; 157 158 CookieDomainMap cookie_domain_map_; 159 160 const bool same_party_attribute_enabled_; 161 162 THREAD_CHECKER(thread_checker_); 163 164 // Vends weak pointers to subscriptions. 165 base::WeakPtrFactory<CookieMonsterChangeDispatcher> weak_ptr_factory_{this}; 166 }; 167 168 } // namespace net 169 170 #endif // NET_COOKIES_COOKIE_MONSTER_CHANGE_DISPATCHER_H_ 171