• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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