Bug 1869043 assert that graph set access is main thread only r=padenot
[gecko.git] / netwerk / cookie / CookieServiceParent.cpp
bloba434fd57fb5b8339bb3a7047b9fea902cf01d8bb
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "CookieCommons.h"
7 #include "CookieLogging.h"
8 #include "mozilla/net/CookieService.h"
9 #include "mozilla/net/CookieServiceParent.h"
10 #include "mozilla/net/NeckoParent.h"
12 #include "mozilla/ipc/URIUtils.h"
13 #include "mozilla/StoragePrincipalHelper.h"
14 #include "mozIThirdPartyUtil.h"
15 #include "nsArrayUtils.h"
16 #include "nsIChannel.h"
17 #include "nsIEffectiveTLDService.h"
18 #include "nsNetCID.h"
19 #include "nsMixedContentBlocker.h"
21 using namespace mozilla::ipc;
23 namespace mozilla {
24 namespace net {
26 CookieServiceParent::CookieServiceParent() {
27 // Instantiate the cookieservice via the service manager, so it sticks around
28 // until shutdown.
29 nsCOMPtr<nsICookieService> cs = do_GetService(NS_COOKIESERVICE_CONTRACTID);
31 // Get the CookieService instance directly, so we can call internal methods.
32 mCookieService = CookieService::GetSingleton();
33 NS_ASSERTION(mCookieService, "couldn't get nsICookieService");
35 mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
36 MOZ_ALWAYS_TRUE(mTLDService);
38 mProcessingCookie = false;
41 void CookieServiceParent::RemoveBatchDeletedCookies(nsIArray* aCookieList) {
42 uint32_t len = 0;
43 aCookieList->GetLength(&len);
44 OriginAttributes attrs;
45 CookieStruct cookieStruct;
46 nsTArray<CookieStruct> cookieStructList;
47 nsTArray<OriginAttributes> attrsList;
48 for (uint32_t i = 0; i < len; i++) {
49 nsCOMPtr<nsICookie> xpcCookie = do_QueryElementAt(aCookieList, i);
50 const auto& cookie = xpcCookie->AsCookie();
51 attrs = cookie.OriginAttributesRef();
52 cookieStruct = cookie.ToIPC();
54 // Child only needs to know HttpOnly cookies exists, not its value
55 // Same for Secure cookies going to a process for an insecure site.
56 if (cookie.IsHttpOnly() || !InsecureCookieOrSecureOrigin(cookie)) {
57 cookieStruct.value() = "";
59 cookieStructList.AppendElement(cookieStruct);
60 attrsList.AppendElement(attrs);
62 Unused << SendRemoveBatchDeletedCookies(cookieStructList, attrsList);
65 void CookieServiceParent::RemoveAll() { Unused << SendRemoveAll(); }
67 void CookieServiceParent::RemoveCookie(const Cookie& cookie) {
68 const OriginAttributes& attrs = cookie.OriginAttributesRef();
69 CookieStruct cookieStruct = cookie.ToIPC();
71 // Child only needs to know HttpOnly cookies exists, not its value
72 // Same for Secure cookies going to a process for an insecure site.
73 if (cookie.IsHttpOnly() || !InsecureCookieOrSecureOrigin(cookie)) {
74 cookieStruct.value() = "";
76 Unused << SendRemoveCookie(cookieStruct, attrs);
79 void CookieServiceParent::AddCookie(const Cookie& cookie) {
80 const OriginAttributes& attrs = cookie.OriginAttributesRef();
81 CookieStruct cookieStruct = cookie.ToIPC();
83 // Child only needs to know HttpOnly cookies exists, not its value
84 // Same for Secure cookies going to a process for an insecure site.
85 if (cookie.IsHttpOnly() || !InsecureCookieOrSecureOrigin(cookie)) {
86 cookieStruct.value() = "";
88 Unused << SendAddCookie(cookieStruct, attrs);
91 bool CookieServiceParent::ContentProcessHasCookie(const Cookie& cookie) {
92 nsCString baseDomain;
93 if (NS_WARN_IF(NS_FAILED(CookieCommons::GetBaseDomainFromHost(
94 mTLDService, cookie.Host(), baseDomain)))) {
95 return false;
98 CookieKey cookieKey(baseDomain, cookie.OriginAttributesRef());
99 return mCookieKeysInContent.MaybeGet(cookieKey).isSome();
102 bool CookieServiceParent::InsecureCookieOrSecureOrigin(const Cookie& cookie) {
103 nsCString baseDomain;
104 // CookieStorage notifications triggering this won't fail to get base domain
105 MOZ_ALWAYS_SUCCEEDS(CookieCommons::GetBaseDomainFromHost(
106 mTLDService, cookie.Host(), baseDomain));
108 // cookie is insecure or cookie is associated with a secure-origin process
109 CookieKey cookieKey(baseDomain, cookie.OriginAttributesRef());
110 if (Maybe<bool> allowSecure = mCookieKeysInContent.MaybeGet(cookieKey)) {
111 return (!cookie.IsSecure() || *allowSecure);
113 return false;
116 void CookieServiceParent::TrackCookieLoad(nsIChannel* aChannel) {
117 nsCOMPtr<nsIURI> uri;
118 aChannel->GetURI(getter_AddRefs(uri));
120 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
121 OriginAttributes attrs = loadInfo->GetOriginAttributes();
122 bool isSafeTopLevelNav = CookieCommons::IsSafeTopLevelNav(aChannel);
123 bool hadCrossSiteRedirects = false;
124 bool isSameSiteForeign =
125 CookieCommons::IsSameSiteForeign(aChannel, uri, &hadCrossSiteRedirects);
127 StoragePrincipalHelper::PrepareEffectiveStoragePrincipalOriginAttributes(
128 aChannel, attrs);
130 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil;
131 thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
133 uint32_t rejectedReason = 0;
134 ThirdPartyAnalysisResult result = thirdPartyUtil->AnalyzeChannel(
135 aChannel, false, nullptr, nullptr, &rejectedReason);
137 UpdateCookieInContentList(uri, attrs);
139 // Send matching cookies to Child.
140 nsTArray<Cookie*> foundCookieList;
141 mCookieService->GetCookiesForURI(
142 uri, aChannel, result.contains(ThirdPartyAnalysis::IsForeign),
143 result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
144 result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
145 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
146 rejectedReason, isSafeTopLevelNav, isSameSiteForeign,
147 hadCrossSiteRedirects, false, true, attrs, foundCookieList);
148 nsTArray<CookieStruct> matchingCookiesList;
149 SerializeCookieList(foundCookieList, matchingCookiesList, uri);
150 Unused << SendTrackCookiesLoad(matchingCookiesList, attrs);
153 // we append outgoing cookie info into a list here so the ContentParent can
154 // filter cookies passing to unnecessary ContentProcesses
155 void CookieServiceParent::UpdateCookieInContentList(
156 nsIURI* uri, const OriginAttributes& originAttrs) {
157 nsCString baseDomain;
158 bool requireAHostMatch = false;
160 // prevent malformed urls from being added to the cookie list
161 if (NS_WARN_IF(NS_FAILED(CookieCommons::GetBaseDomain(
162 mTLDService, uri, baseDomain, requireAHostMatch)))) {
163 return;
166 CookieKey cookieKey(baseDomain, originAttrs);
167 bool& allowSecure = mCookieKeysInContent.LookupOrInsert(cookieKey, false);
168 allowSecure =
169 allowSecure || nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(uri);
172 // static
173 void CookieServiceParent::SerializeCookieList(
174 const nsTArray<Cookie*>& aFoundCookieList,
175 nsTArray<CookieStruct>& aCookiesList, nsIURI* aHostURI) {
176 for (uint32_t i = 0; i < aFoundCookieList.Length(); i++) {
177 Cookie* cookie = aFoundCookieList.ElementAt(i);
178 CookieStruct* cookieStruct = aCookiesList.AppendElement();
179 *cookieStruct = cookie->ToIPC();
181 // clear http-only cookie values
182 if (cookie->IsHttpOnly()) {
183 // Value only needs to exist if an HttpOnly cookie exists.
184 cookieStruct->value() = "";
187 // clear secure cookie values in insecure context
188 bool potentiallyTurstworthy =
189 nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
190 if (cookie->IsSecure() && !potentiallyTurstworthy) {
191 cookieStruct->value() = "";
196 IPCResult CookieServiceParent::RecvPrepareCookieList(
197 nsIURI* aHost, const bool& aIsForeign,
198 const bool& aIsThirdPartyTrackingResource,
199 const bool& aIsThirdPartySocialTrackingResource,
200 const bool& aStorageAccessPermissionGranted,
201 const uint32_t& aRejectedReason, const bool& aIsSafeTopLevelNav,
202 const bool& aIsSameSiteForeign, const bool& aHadCrossSiteRedirects,
203 const OriginAttributes& aAttrs) {
204 // Send matching cookies to Child.
205 if (!aHost) {
206 return IPC_FAIL(this, "aHost must not be null");
209 // we append outgoing cookie info into a list here so the ContentParent can
210 // filter cookies that do not need to go to certain ContentProcesses
211 UpdateCookieInContentList(aHost, aAttrs);
213 nsTArray<Cookie*> foundCookieList;
214 // Note: passing nullptr as aChannel to GetCookiesForURI() here is fine since
215 // this argument is only used for proper reporting of cookie loads, but the
216 // child process already does the necessary reporting in this case for us.
217 mCookieService->GetCookiesForURI(
218 aHost, nullptr, aIsForeign, aIsThirdPartyTrackingResource,
219 aIsThirdPartySocialTrackingResource, aStorageAccessPermissionGranted,
220 aRejectedReason, aIsSafeTopLevelNav, aIsSameSiteForeign,
221 aHadCrossSiteRedirects, false, true, aAttrs, foundCookieList);
222 nsTArray<CookieStruct> matchingCookiesList;
223 SerializeCookieList(foundCookieList, matchingCookiesList, aHost);
224 Unused << SendTrackCookiesLoad(matchingCookiesList, aAttrs);
225 return IPC_OK();
228 void CookieServiceParent::ActorDestroy(ActorDestroyReason aWhy) {
229 // Nothing needed here. Called right before destructor since this is a
230 // non-refcounted class.
233 IPCResult CookieServiceParent::RecvSetCookies(
234 const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
235 nsIURI* aHost, bool aFromHttp, const nsTArray<CookieStruct>& aCookies) {
236 return SetCookies(aBaseDomain, aOriginAttributes, aHost, aFromHttp, aCookies);
239 IPCResult CookieServiceParent::SetCookies(
240 const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
241 nsIURI* aHost, bool aFromHttp, const nsTArray<CookieStruct>& aCookies,
242 dom::BrowsingContext* aBrowsingContext) {
243 if (!mCookieService) {
244 return IPC_OK();
247 // Deserialize URI. Having a host URI is mandatory and should always be
248 // provided by the child; thus we consider failure fatal.
249 if (!aHost) {
250 return IPC_FAIL(this, "aHost must not be null");
253 // We set this to true while processing this cookie update, to make sure
254 // we don't send it back to the same content process.
255 mProcessingCookie = true;
257 bool ok =
258 mCookieService->SetCookiesFromIPC(aBaseDomain, aOriginAttributes, aHost,
259 aFromHttp, aCookies, aBrowsingContext);
260 mProcessingCookie = false;
261 return ok ? IPC_OK() : IPC_FAIL(this, "Invalid cookie received.");
264 } // namespace net
265 } // namespace mozilla