Bug 1880216 - Migrate Fenix docs into Sphinx. r=owlish,geckoview-reviewers,android...
[gecko.git] / netwerk / cookie / CookieServiceParent.cpp
blob75c024cec6a134426f7e481a64b233bf11667dd8
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 "CookieServiceParent.h"
9 #include "mozilla/net/CookieService.h"
10 #include "mozilla/net/CookieServiceParent.h"
11 #include "mozilla/net/NeckoParent.h"
13 #include "mozilla/ipc/URIUtils.h"
14 #include "mozilla/StoragePrincipalHelper.h"
15 #include "mozIThirdPartyUtil.h"
16 #include "nsArrayUtils.h"
17 #include "nsIChannel.h"
18 #include "nsIEffectiveTLDService.h"
19 #include "nsNetCID.h"
20 #include "nsMixedContentBlocker.h"
22 using namespace mozilla::ipc;
24 namespace mozilla {
25 namespace net {
27 CookieServiceParent::CookieServiceParent() {
28 // Instantiate the cookieservice via the service manager, so it sticks around
29 // until shutdown.
30 nsCOMPtr<nsICookieService> cs = do_GetService(NS_COOKIESERVICE_CONTRACTID);
32 // Get the CookieService instance directly, so we can call internal methods.
33 mCookieService = CookieService::GetSingleton();
34 NS_ASSERTION(mCookieService, "couldn't get nsICookieService");
36 mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
37 MOZ_ALWAYS_TRUE(mTLDService);
39 mProcessingCookie = false;
42 void CookieServiceParent::RemoveBatchDeletedCookies(nsIArray* aCookieList) {
43 uint32_t len = 0;
44 aCookieList->GetLength(&len);
45 OriginAttributes attrs;
46 CookieStruct cookieStruct;
47 nsTArray<CookieStruct> cookieStructList;
48 nsTArray<OriginAttributes> attrsList;
49 for (uint32_t i = 0; i < len; i++) {
50 nsCOMPtr<nsICookie> xpcCookie = do_QueryElementAt(aCookieList, i);
51 const auto& cookie = xpcCookie->AsCookie();
52 attrs = cookie.OriginAttributesRef();
53 cookieStruct = cookie.ToIPC();
55 // Child only needs to know HttpOnly cookies exists, not its value
56 // Same for Secure cookies going to a process for an insecure site.
57 if (cookie.IsHttpOnly() || !InsecureCookieOrSecureOrigin(cookie)) {
58 cookieStruct.value() = "";
60 cookieStructList.AppendElement(cookieStruct);
61 attrsList.AppendElement(attrs);
63 Unused << SendRemoveBatchDeletedCookies(cookieStructList, attrsList);
66 void CookieServiceParent::RemoveAll() { Unused << SendRemoveAll(); }
68 void CookieServiceParent::RemoveCookie(const Cookie& cookie) {
69 const OriginAttributes& attrs = cookie.OriginAttributesRef();
70 CookieStruct cookieStruct = cookie.ToIPC();
72 // Child only needs to know HttpOnly cookies exists, not its value
73 // Same for Secure cookies going to a process for an insecure site.
74 if (cookie.IsHttpOnly() || !InsecureCookieOrSecureOrigin(cookie)) {
75 cookieStruct.value() = "";
77 Unused << SendRemoveCookie(cookieStruct, attrs);
80 void CookieServiceParent::AddCookie(const Cookie& cookie) {
81 const OriginAttributes& attrs = cookie.OriginAttributesRef();
82 CookieStruct cookieStruct = cookie.ToIPC();
84 // Child only needs to know HttpOnly cookies exists, not its value
85 // Same for Secure cookies going to a process for an insecure site.
86 if (cookie.IsHttpOnly() || !InsecureCookieOrSecureOrigin(cookie)) {
87 cookieStruct.value() = "";
89 Unused << SendAddCookie(cookieStruct, attrs);
92 bool CookieServiceParent::ContentProcessHasCookie(const Cookie& cookie) {
93 nsCString baseDomain;
94 if (NS_WARN_IF(NS_FAILED(CookieCommons::GetBaseDomainFromHost(
95 mTLDService, cookie.Host(), baseDomain)))) {
96 return false;
99 CookieKey cookieKey(baseDomain, cookie.OriginAttributesRef());
100 return mCookieKeysInContent.MaybeGet(cookieKey).isSome();
103 bool CookieServiceParent::InsecureCookieOrSecureOrigin(const Cookie& cookie) {
104 nsCString baseDomain;
105 // CookieStorage notifications triggering this won't fail to get base domain
106 MOZ_ALWAYS_SUCCEEDS(CookieCommons::GetBaseDomainFromHost(
107 mTLDService, cookie.Host(), baseDomain));
109 // cookie is insecure or cookie is associated with a secure-origin process
110 CookieKey cookieKey(baseDomain, cookie.OriginAttributesRef());
111 if (Maybe<bool> allowSecure = mCookieKeysInContent.MaybeGet(cookieKey)) {
112 return (!cookie.IsSecure() || *allowSecure);
114 return false;
117 void CookieServiceParent::TrackCookieLoad(nsIChannel* aChannel) {
118 nsCOMPtr<nsIURI> uri;
119 aChannel->GetURI(getter_AddRefs(uri));
121 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
122 OriginAttributes attrs = loadInfo->GetOriginAttributes();
123 bool isSafeTopLevelNav = CookieCommons::IsSafeTopLevelNav(aChannel);
124 bool hadCrossSiteRedirects = false;
125 bool isSameSiteForeign =
126 CookieCommons::IsSameSiteForeign(aChannel, uri, &hadCrossSiteRedirects);
128 // TODO (Bug 1874174): A channel could load both unpartitioned and partitioned
129 // cookie jars together. We will need to track both originAttributes for them.
130 StoragePrincipalHelper::PrepareEffectiveStoragePrincipalOriginAttributes(
131 aChannel, attrs);
133 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil;
134 thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
136 uint32_t rejectedReason = 0;
137 ThirdPartyAnalysisResult result = thirdPartyUtil->AnalyzeChannel(
138 aChannel, false, nullptr, nullptr, &rejectedReason);
140 nsTArray<OriginAttributes> originAttributesList;
141 originAttributesList.AppendElement(attrs);
143 for (auto& originAttributes : originAttributesList) {
144 UpdateCookieInContentList(uri, originAttributes);
147 // Send matching cookies to Child.
148 nsTArray<Cookie*> foundCookieList;
149 mCookieService->GetCookiesForURI(
150 uri, aChannel, result.contains(ThirdPartyAnalysis::IsForeign),
151 result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
152 result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
153 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
154 rejectedReason, isSafeTopLevelNav, isSameSiteForeign,
155 hadCrossSiteRedirects, false, true, originAttributesList,
156 foundCookieList);
157 nsTArray<CookieStructTable> matchingCookiesListTable;
158 SerializeCookieListTable(foundCookieList, matchingCookiesListTable, uri);
159 Unused << SendTrackCookiesLoad(matchingCookiesListTable);
162 // we append outgoing cookie info into a list here so the ContentParent can
163 // filter cookies passing to unnecessary ContentProcesses
164 void CookieServiceParent::UpdateCookieInContentList(
165 nsIURI* uri, const OriginAttributes& originAttrs) {
166 nsCString baseDomain;
167 bool requireAHostMatch = false;
169 // prevent malformed urls from being added to the cookie list
170 if (NS_WARN_IF(NS_FAILED(CookieCommons::GetBaseDomain(
171 mTLDService, uri, baseDomain, requireAHostMatch)))) {
172 return;
175 CookieKey cookieKey(baseDomain, originAttrs);
176 bool& allowSecure = mCookieKeysInContent.LookupOrInsert(cookieKey, false);
177 allowSecure =
178 allowSecure || nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(uri);
181 // static
182 void CookieServiceParent::SerializeCookieListTable(
183 const nsTArray<Cookie*>& aFoundCookieList,
184 nsTArray<CookieStructTable>& aCookiesListTable, nsIURI* aHostURI) {
185 nsTHashMap<nsCStringHashKey, CookieStructTable*> cookieListTable;
187 for (Cookie* cookie : aFoundCookieList) {
188 nsAutoCString attrsSuffix;
189 cookie->OriginAttributesRef().CreateSuffix(attrsSuffix);
190 CookieStructTable* table =
191 cookieListTable.LookupOrInsertWith(attrsSuffix, [&] {
192 CookieStructTable* newTable = aCookiesListTable.AppendElement();
193 newTable->attrs() = cookie->OriginAttributesRef();
194 return newTable;
197 CookieStruct* cookieStruct = table->cookies().AppendElement();
198 *cookieStruct = cookie->ToIPC();
200 // clear http-only cookie values
201 if (cookie->IsHttpOnly()) {
202 // Value only needs to exist if an HttpOnly cookie exists.
203 cookieStruct->value() = "";
206 // clear secure cookie values in insecure context
207 bool potentiallyTurstworthy =
208 nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
209 if (cookie->IsSecure() && !potentiallyTurstworthy) {
210 cookieStruct->value() = "";
215 IPCResult CookieServiceParent::RecvGetCookieList(
216 nsIURI* aHost, const bool& aIsForeign,
217 const bool& aIsThirdPartyTrackingResource,
218 const bool& aIsThirdPartySocialTrackingResource,
219 const bool& aStorageAccessPermissionGranted,
220 const uint32_t& aRejectedReason, const bool& aIsSafeTopLevelNav,
221 const bool& aIsSameSiteForeign, const bool& aHadCrossSiteRedirects,
222 nsTArray<OriginAttributes>&& aAttrsList, GetCookieListResolver&& aResolve) {
223 // Send matching cookies to Child.
224 if (!aHost) {
225 return IPC_FAIL(this, "aHost must not be null");
228 // we append outgoing cookie info into a list here so the ContentParent can
229 // filter cookies that do not need to go to certain ContentProcesses
230 for (const auto& attrs : aAttrsList) {
231 UpdateCookieInContentList(aHost, attrs);
234 nsTArray<Cookie*> foundCookieList;
235 // Note: passing nullptr as aChannel to GetCookiesForURI() here is fine since
236 // this argument is only used for proper reporting of cookie loads, but the
237 // child process already does the necessary reporting in this case for us.
238 mCookieService->GetCookiesForURI(
239 aHost, nullptr, aIsForeign, aIsThirdPartyTrackingResource,
240 aIsThirdPartySocialTrackingResource, aStorageAccessPermissionGranted,
241 aRejectedReason, aIsSafeTopLevelNav, aIsSameSiteForeign,
242 aHadCrossSiteRedirects, false, true, aAttrsList, foundCookieList);
244 nsTArray<CookieStructTable> matchingCookiesListTable;
245 SerializeCookieListTable(foundCookieList, matchingCookiesListTable, aHost);
247 aResolve(matchingCookiesListTable);
249 return IPC_OK();
252 void CookieServiceParent::ActorDestroy(ActorDestroyReason aWhy) {
253 // Nothing needed here. Called right before destructor since this is a
254 // non-refcounted class.
257 IPCResult CookieServiceParent::RecvSetCookies(
258 const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
259 nsIURI* aHost, bool aFromHttp, const nsTArray<CookieStruct>& aCookies) {
260 return SetCookies(aBaseDomain, aOriginAttributes, aHost, aFromHttp, aCookies);
263 IPCResult CookieServiceParent::SetCookies(
264 const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
265 nsIURI* aHost, bool aFromHttp, const nsTArray<CookieStruct>& aCookies,
266 dom::BrowsingContext* aBrowsingContext) {
267 if (!mCookieService) {
268 return IPC_OK();
271 // Deserialize URI. Having a host URI is mandatory and should always be
272 // provided by the child; thus we consider failure fatal.
273 if (!aHost) {
274 return IPC_FAIL(this, "aHost must not be null");
277 // We set this to true while processing this cookie update, to make sure
278 // we don't send it back to the same content process.
279 mProcessingCookie = true;
281 bool ok =
282 mCookieService->SetCookiesFromIPC(aBaseDomain, aOriginAttributes, aHost,
283 aFromHttp, aCookies, aBrowsingContext);
284 mProcessingCookie = false;
285 return ok ? IPC_OK() : IPC_FAIL(this, "Invalid cookie received.");
288 } // namespace net
289 } // namespace mozilla