xref: /aosp_15_r20/external/cronet/net/cookies/cookie_change_dispatcher.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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_CHANGE_DISPATCHER_H_
6 #define NET_COOKIES_COOKIE_CHANGE_DISPATCHER_H_
7 
8 #include <memory>
9 #include <string>
10 
11 #include "base/functional/callback.h"
12 #include "net/base/net_export.h"
13 #include "net/cookies/canonical_cookie.h"
14 #include "net/cookies/cookie_access_result.h"
15 
16 class GURL;
17 
18 namespace net {
19 
20 class CanonicalCookie;
21 
22 // The publicly relevant reasons a cookie might be changed.
23 enum class CookieChangeCause {
24   // The cookie was inserted.
25   INSERTED,
26   // The cookie was changed directly by a consumer's action.
27   EXPLICIT,
28   // The cookie was deleted, but no more details are known.
29   UNKNOWN_DELETION,
30   // The cookie was automatically removed due to an insert operation that
31   // overwrote it.
32   OVERWRITE,
33   // The cookie was automatically removed as it expired.
34   EXPIRED,
35   // The cookie was automatically evicted during garbage collection.
36   EVICTED,
37   // The cookie was overwritten with an already-expired expiration date.
38   EXPIRED_OVERWRITE
39 };
40 
41 struct NET_EXPORT CookieChangeInfo {
42   CookieChangeInfo();
43   CookieChangeInfo(const CanonicalCookie& cookie,
44                    CookieAccessResult access_result,
45                    CookieChangeCause cause);
46   ~CookieChangeInfo();
47 
48   // The cookie that changed.
49   CanonicalCookie cookie;
50 
51   // The access result of the cookie at the time of the change.
52   CookieAccessResult access_result;
53 
54   // The reason for the change.
55   CookieChangeCause cause = CookieChangeCause::EXPLICIT;
56 };
57 
58 // Return a string corresponding to the change cause.  For debugging/logging.
59 NET_EXPORT const char* CookieChangeCauseToString(CookieChangeCause cause);
60 
61 // Returns whether |cause| is one that could be a reason for deleting a cookie.
62 // This function assumes that ChangeCause::EXPLICIT is a reason for deletion.
63 NET_EXPORT bool CookieChangeCauseIsDeletion(CookieChangeCause cause);
64 
65 // Called when a cookie is changed in a CookieStore.
66 //
67 // Receives the CanonicalCookie which was added to or removed from the store,
68 // the CookieAccessSemantics of the cookie at the time of the change event,
69 // and a CookieStore::ChangeCause indicating if the cookie was added, updated,
70 // or removed.
71 //
72 // Note that the callback is called twice when a cookie is updated: the first
73 // call communicates the removal of the existing cookie, and the second call
74 // expresses the addition of the new cookie.
75 //
76 // The callback must not synchronously modify any cookie in the CookieStore
77 // whose change it is observing.
78 using CookieChangeCallback =
79     base::RepeatingCallback<void(const CookieChangeInfo&)>;
80 
81 // Records a listener's interest in CookieStore changes.
82 //
83 // Each call to CookieChangeDispatcher::Add*() is a listener expressing an
84 // interest in observing CookieStore changes. Each call creates a
85 // CookieChangeSubscription instance whose ownership is passed to the listener.
86 //
87 // When the listener's interest disappears (usually at destruction time), the
88 // listener must communicate this by destroying the CookieChangeSubscription
89 // instance. The callback passed to the Add*() method will not to be called
90 // after the returned handle is destroyed.
91 //
92 // CookieChangeSubscription instances do not keep the observed CookieStores
93 // alive.
94 //
95 // Instances of this class are not thread-safe, and must be destroyed on the
96 // same thread that they were obtained on.
97 class CookieChangeSubscription {
98  public:
99   CookieChangeSubscription() = default;
100 
101   CookieChangeSubscription(const CookieChangeSubscription&) = delete;
102   CookieChangeSubscription& operator=(const CookieChangeSubscription&) = delete;
103 
104   virtual ~CookieChangeSubscription() = default;
105 };
106 
107 // Exposes changes to a CookieStore's contents.
108 //
109 // A component that wishes to react to changes in a CookieStore (the listener)
110 // must register its interest (subscribe) by calling one of the Add*() methods
111 // exposed by this interface.
112 //
113 // CookieChangeDispatch instances are intended to be embedded in CookieStore
114 // implementations, so they are not intended to be created as standalone objects
115 // on the heap.
116 //
117 // At the time of this writing (Q1 2018), using this interface has non-trivial
118 // performance implications on all implementations. This issue should be fixed
119 // by the end of 2018, at which point this warning should go away. Until then,
120 // please understand and reason about the performance impact of your change if
121 // you're adding uses of this to the codebase.
122 class CookieChangeDispatcher {
123  public:
124   CookieChangeDispatcher() = default;
125 
126   CookieChangeDispatcher(const CookieChangeDispatcher&) = delete;
127   CookieChangeDispatcher& operator=(const CookieChangeDispatcher&) = delete;
128 
129   virtual ~CookieChangeDispatcher() = default;
130 
131   // Observe changes to all cookies named `name` that would be sent in a
132   // request to `url`.
133   //
134   // If `cookie_partition_key` is nullopt, then we ignore all change events for
135   // partitioned cookies. Otherwise it only subscribes to change events for
136   // partitioned cookies with the same provided key.
137   // Unpartitioned cookies are not affected by the `cookie_partition_key`
138   // parameter.
139   [[nodiscard]] virtual std::unique_ptr<CookieChangeSubscription>
140   AddCallbackForCookie(
141       const GURL& url,
142       const std::string& name,
143       const std::optional<CookiePartitionKey>& cookie_partition_key,
144       CookieChangeCallback callback) = 0;
145 
146   // Observe changes to the cookies that would be sent for a request to `url`.
147   //
148   // If `cookie_partition_key` is nullopt, then we ignore all change events for
149   // partitioned cookies. Otherwise it only subscribes to change events for
150   // partitioned cookies with the same provided key.
151   // Unpartitioned cookies are not affected by the `cookie_partition_key`
152   // parameter.
153   [[nodiscard]] virtual std::unique_ptr<CookieChangeSubscription>
154   AddCallbackForUrl(
155       const GURL& url,
156       const std::optional<CookiePartitionKey>& cookie_partition_key,
157       CookieChangeCallback callback) = 0;
158 
159   // Observe all the CookieStore's changes.
160   //
161   // The callback will not observe a few bookkeeping changes.
162   // See kChangeCauseMapping in cookie_monster.cc for details.
163   // TODO(crbug.com/1225444): Add support for Partitioned cookies.
164   [[nodiscard]] virtual std::unique_ptr<CookieChangeSubscription>
165   AddCallbackForAllChanges(CookieChangeCallback callback) = 0;
166 };
167 
168 }  // namespace net
169 
170 #endif  // NET_COOKIES_COOKIE_CHANGE_DISPATCHER_H_
171