Backed out changeset b71c8c052463 (bug 1943846) for causing mass failures. CLOSED...
[gecko.git] / netwerk / cookie / CookieJarSettings.h
blobadb9b538217b84b1012cd35d2e041b8b4fd3874b
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_net_CookieJarSettings_h
8 #define mozilla_net_CookieJarSettings_h
10 #include "mozilla/Maybe.h"
12 #include "nsICookieJarSettings.h"
13 #include "nsIPermission.h"
14 #include "nsTArray.h"
16 #define COOKIEJARSETTINGS_CONTRACTID "@mozilla.org/cookieJarSettings;1"
17 // 4ce234f1-52e8-47a9-8c8d-b02f815733c7
18 #define COOKIEJARSETTINGS_CID \
19 {0x4ce234f1, 0x52e8, 0x47a9, {0x8c, 0x8d, 0xb0, 0x2f, 0x81, 0x57, 0x33, 0xc7}}
21 namespace mozilla {
22 namespace net {
24 class CookieJarSettingsArgs;
26 /**
27 * CookieJarSettings
28 * ~~~~~~~~~~~~~~
30 * CookieJarSettings is a snapshot of the cookie jar's configurations in a
31 * precise moment of time, such as the cookie policy and cookie permissions.
32 * This object is used by top-level documents to have a consistent cookie jar
33 * configuration also in case the user changes it. New configurations will apply
34 * only to new top-level documents.
36 * CookieJarSettings creation
37 * ~~~~~~~~~~~~~~~~~~~~~~~
39 * CookieJarSettings is created when the top-level document's nsIChannel's
40 * nsILoadInfo is constructed. Any sub-resource and any sub-document inherits it
41 * from that nsILoadInfo. Also dedicated workers and their resources inherit it
42 * from the parent document.
44 * SharedWorkers and ServiceWorkers have their own CookieJarSettings because
45 * they don't have a single parent document (SharedWorkers could have more than
46 * one, ServiceWorkers have none).
48 * In Chrome code, we have a new CookieJarSettings when we download resources
49 * via 'Save-as...' and we also have a new CookieJarSettings for favicon
50 * downloading.
52 * Content-scripts WebExtensions also have their own CookieJarSettings because
53 * they don't have a direct access to the document they are running into.
55 * Anything else will have a special CookieJarSettings which blocks everything
56 * (CookieJarSettings::GetBlockingAll()) by forcing BEHAVIOR_REJECT as policy.
57 * When this happens, that context will not have access to the cookie jar and no
58 * cookies are sent or received.
60 * Propagation of CookieJarSettings
61 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
63 * CookieJarSettings are shared inside the same top-level document via its
64 * nsIChannel's nsILoadInfo. This is done automatically if you pass a nsINode
65 * to NS_NewChannel(), and it must be done manually if you use a different
66 * channel constructor. For instance, this happens for any worker networking
67 * operation.
69 * We use the same CookieJarSettings for any resource belonging to the top-level
70 * document even if cross-origin. This makes the browser behave consistently a
71 * scenario where A loads B which loads A again, and cookie policy/permission
72 * changes in the meantime.
74 * Cookie Permissions propagation
75 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77 * CookieJarSettings populates the known cookie permissions only when required.
78 * Initially the list is empty, but when CookieJarSettings::CookiePermission()
79 * is called, the requested permission is stored in the internal list if it
80 * doesn't exist yet.
82 * This is actually nice because it relies on the permission propagation from
83 * parent to content process. No extra IPC is required.
85 * Note that we store permissions with UNKNOWN_ACTION values too because they
86 * can be set after the loading of the top-level document and we don't want to
87 * return a different value when this happens.
89 * Use of CookieJarSettings
90 * ~~~~~~~~~~~~~~~~~~~~~
92 * In theory, there should not be direct access to cookie permissions or
93 * cookieBehavior pref. Everything should pass through CookieJarSettings.
95 * A reference to CookieJarSettings can be obtained from
96 * nsILoadInfo::GetCookieJarSettings(), from Document::CookieJarSettings() and
97 * from the WorkerPrivate::CookieJarSettings().
99 * CookieJarSettings is thread-safe, but the permission list must be touched
100 * only on the main-thread.
102 * Testing
103 * ~~~~~~~
105 * If you need to test the changing of cookie policy or a cookie permission, you
106 * need to workaround CookieJarSettings. This can be done opening a new window
107 * and running the test into that new global.
111 * Class that provides an nsICookieJarSettings implementation.
113 class CookieJarSettings final : public nsICookieJarSettings {
114 public:
115 typedef nsTArray<RefPtr<nsIPermission>> CookiePermissionList;
117 NS_DECL_THREADSAFE_ISUPPORTS
118 NS_DECL_NSICOOKIEJARSETTINGS
119 NS_DECL_NSISERIALIZABLE
121 static already_AddRefed<nsICookieJarSettings> GetBlockingAll(
122 bool aShouldResistFingerprinting);
124 enum CreateMode { eRegular, ePrivate };
126 static already_AddRefed<nsICookieJarSettings> Create(
127 CreateMode aMode, bool aShouldResistFingerprinting);
129 static already_AddRefed<nsICookieJarSettings> Create(
130 nsIPrincipal* aPrincipal);
132 // This function should be only called for XPCOM. You should never use this
133 // for other purposes.
134 static already_AddRefed<nsICookieJarSettings> CreateForXPCOM();
136 static already_AddRefed<nsICookieJarSettings> Create(
137 uint32_t aCookieBehavior, const nsAString& aPartitionKey,
138 bool aIsFirstPartyIsolated, bool aIsOnContentBlockingAllowList,
139 bool aShouldResistFingerprinting);
141 static CookieJarSettings* Cast(nsICookieJarSettings* aCS) {
142 return static_cast<CookieJarSettings*>(aCS);
145 already_AddRefed<CookieJarSettings> Clone() {
146 RefPtr<CookieJarSettings> clone = new CookieJarSettings(*this);
147 return clone.forget();
150 void Serialize(CookieJarSettingsArgs& aData);
152 static void Deserialize(const CookieJarSettingsArgs& aData,
153 nsICookieJarSettings** aCookieJarSettings);
155 // Merge the current CookieJarSettings with the new CookieJarSettingsArgs. It
156 // returns a new merged CookieJarSettings.
157 already_AddRefed<nsICookieJarSettings> Merge(
158 const CookieJarSettingsArgs& aData);
160 // We don't want to send this object from parent to child process if there are
161 // no reasons. HasBeenChanged() returns true if the object has changed its
162 // internal state and it must be sent beck to the content process.
163 bool HasBeenChanged() const { return mToBeMerged; }
165 void UpdateIsOnContentBlockingAllowList(nsIChannel* aChannel);
166 void SetIsOnContentBlockingAllowList(bool aIsOnContentBlockingAllowList) {
167 mIsOnContentBlockingAllowList = aIsOnContentBlockingAllowList;
170 void SetPartitionKey(nsIURI* aURI, bool aForeignByAncestorContext);
171 void SetPartitionKey(const nsAString& aPartitionKey) {
172 mPartitionKey = aPartitionKey;
174 const nsAString& GetPartitionKey() { return mPartitionKey; };
176 void UpdatePartitionKeyForDocumentLoadedByChannel(nsIChannel* aChannel);
178 void SetFingerprintingRandomizationKey(const nsTArray<uint8_t>& aKey) {
179 mFingerprintingRandomKey.reset();
181 mFingerprintingRandomKey.emplace(aKey.Clone());
184 // Utility function to test if the passed cookiebahvior is
185 // BEHAVIOR_REJECT_TRACKER, BEHAVIOR_REJECT_TRACKER_AND_PARTITION_FOREIGN or
186 // BEHAVIOR_REJECT_FOREIGN when
187 // network.cookie.rejectForeignWithExceptions.enabled pref is set to true.
188 static bool IsRejectThirdPartyContexts(uint32_t aCookieBehavior);
190 void SetTopLevelWindowContextId(uint64_t aId) {
191 mTopLevelWindowContextId = aId;
193 uint64_t GetTopLevelWindowContextId() { return mTopLevelWindowContextId; }
195 private:
196 enum State {
197 // No cookie permissions are allowed to be stored in this object.
198 eFixed,
200 // Cookie permissions can be stored in case they are unknown when they are
201 // asked or when they are sent from the parent process.
202 eProgressive,
205 CookieJarSettings(uint32_t aCookieBehavior, bool aIsFirstPartyIsolated,
206 bool aShouldResistFingerprinting, State aState);
208 CookieJarSettings(const CookieJarSettings& aOther) {
209 mCookieBehavior = aOther.mCookieBehavior;
210 mIsFirstPartyIsolated = aOther.mIsFirstPartyIsolated;
211 mCookiePermissions = aOther.mCookiePermissions.Clone();
213 mIsOnContentBlockingAllowList = aOther.mIsOnContentBlockingAllowList;
214 mIsOnContentBlockingAllowListUpdated =
215 aOther.mIsOnContentBlockingAllowListUpdated;
217 mPartitionKey = aOther.mPartitionKey;
218 mState = aOther.mState;
219 mToBeMerged = aOther.mToBeMerged;
221 mShouldResistFingerprinting = aOther.mShouldResistFingerprinting;
222 if (aOther.mFingerprintingRandomKey.isSome()) {
223 mFingerprintingRandomKey =
224 Some(aOther.mFingerprintingRandomKey.ref().Clone());
227 mTopLevelWindowContextId = aOther.mTopLevelWindowContextId;
230 ~CookieJarSettings();
232 uint32_t mCookieBehavior;
233 bool mIsFirstPartyIsolated;
234 CookiePermissionList mCookiePermissions;
235 bool mIsOnContentBlockingAllowList;
236 bool mIsOnContentBlockingAllowListUpdated;
237 nsString mPartitionKey;
239 State mState;
241 bool mToBeMerged;
243 // DO NOT USE THIS MEMBER TO CHECK IF YOU SHOULD RESIST FINGERPRINTING.
244 // USE THE nsContentUtils::ShouldResistFingerprinting() METHODS ONLY.
246 // As we move to fine-grained RFP control, we want to support per-domain
247 // exemptions from ResistFingerprinting. Specifically the behavior should be
248 // as such:
250 // Top-Level Document is on an Exempted Domain
251 // - RFP is disabled.
253 // Top-Level Document on an Exempted Domain embedding a non-exempted
254 // cross-origin iframe
255 // - RFP in the iframe is enabled (NOT exempted). (**)
257 // Top-Level Document on an Exempted Domain embedding an exempted cross-origin
258 // iframe
259 // - RFP in the iframe is disabled (exempted).
261 // Top-Level Document on a Non-Exempted Domain
262 // - RFP is enabled (NOT exempted).
264 // Top-Level Document on a Non-Exempted Domain embeds an exempted cross-origin
265 // iframe
266 // - RFP in the iframe is enabled (NOT exempted). (*)
268 // Exempted Document (top-level or iframe) contacts any cross-origin domain
269 // (exempted or non-exempted)
270 // - RFP is disabled (exempted) for the request
272 // Non-Exempted Document (top-level or iframe) contacts any cross-origin
273 // domain
274 // (exempted or non-exempted)
275 // - RFP is enabled (NOT exempted) for the request
277 // This boolean on CookieJarSettings will enable us to apply the most
278 // difficult rule, marked in (*). (It is difficult because the
279 // subdocument's loadinfo will look like it should be exempted.)
280 // However if we trusted this member blindly, it would not correctly apply
281 // the one marked with (**). (Because it would inherit an exemption into
282 // a subdocument that should not be exempted.)
283 // To handle this case, we only trust a CookieJar's ShouldRFP value if it
284 // says we should resist fingerprinting. If it says that we _should not_,
285 // we continue and check the channel's URI or LoadInfo and if
286 // the domain specified there is not an exempted domain, enforce RFP anyway.
287 // This all occurrs in the nscontentUtils::ShouldResistFingerprinting
288 // functions which you should be using.
289 bool mShouldResistFingerprinting;
291 // The key used to generate the random noise for randomizing the browser
292 // fingerprint. The key is decided by the session key and the top-level site.
293 // So, the browse fingerprint will look different to the same tracker
294 // under different top-level sites. Also, the fingerprint will change as
295 // browsing session changes. This can prevent trackers to identify individuals
296 // by using browser fingerprints.
297 Maybe<nsTArray<uint8_t>> mFingerprintingRandomKey;
299 // This field caches the top level window context id when loading the top
300 // level document.
301 uint64_t mTopLevelWindowContextId;
304 } // namespace net
305 } // namespace mozilla
307 #endif // mozilla_net_CookieJarSettings_h