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