Backed out changeset f1426851ae30 (bug 1844755) for causing failures on test_printpre...
[gecko.git] / netwerk / cookie / CookieServiceParent.cpp
blobba62d310b1b3a3a3c2bcf1e8f3a874502e96005d
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 // CookieStorage notifications triggering this won't fail to get base domain
94 MOZ_ALWAYS_SUCCEEDS(CookieCommons::GetBaseDomainFromHost(
95 mTLDService, cookie.Host(), baseDomain));
97 CookieKey cookieKey(baseDomain, cookie.OriginAttributesRef());
98 return mCookieKeysInContent.MaybeGet(cookieKey).isSome();
101 bool CookieServiceParent::InsecureCookieOrSecureOrigin(const Cookie& cookie) {
102 nsCString baseDomain;
103 // CookieStorage notifications triggering this won't fail to get base domain
104 MOZ_ALWAYS_SUCCEEDS(CookieCommons::GetBaseDomainFromHost(
105 mTLDService, cookie.Host(), baseDomain));
107 // cookie is insecure or cookie is associated with a secure-origin process
108 CookieKey cookieKey(baseDomain, cookie.OriginAttributesRef());
109 if (Maybe<bool> allowSecure = mCookieKeysInContent.MaybeGet(cookieKey)) {
110 return (!cookie.IsSecure() || *allowSecure);
112 return false;
115 void CookieServiceParent::TrackCookieLoad(nsIChannel* aChannel) {
116 nsCOMPtr<nsIURI> uri;
117 aChannel->GetURI(getter_AddRefs(uri));
119 nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
120 OriginAttributes attrs = loadInfo->GetOriginAttributes();
121 bool isSafeTopLevelNav = CookieCommons::IsSafeTopLevelNav(aChannel);
122 bool hadCrossSiteRedirects = false;
123 bool isSameSiteForeign =
124 CookieCommons::IsSameSiteForeign(aChannel, uri, &hadCrossSiteRedirects);
126 StoragePrincipalHelper::PrepareEffectiveStoragePrincipalOriginAttributes(
127 aChannel, attrs);
129 nsCOMPtr<mozIThirdPartyUtil> thirdPartyUtil;
130 thirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
132 uint32_t rejectedReason = 0;
133 ThirdPartyAnalysisResult result = thirdPartyUtil->AnalyzeChannel(
134 aChannel, false, nullptr, nullptr, &rejectedReason);
136 UpdateCookieInContentList(uri, attrs);
138 // Send matching cookies to Child.
139 nsTArray<Cookie*> foundCookieList;
140 mCookieService->GetCookiesForURI(
141 uri, aChannel, result.contains(ThirdPartyAnalysis::IsForeign),
142 result.contains(ThirdPartyAnalysis::IsThirdPartyTrackingResource),
143 result.contains(ThirdPartyAnalysis::IsThirdPartySocialTrackingResource),
144 result.contains(ThirdPartyAnalysis::IsStorageAccessPermissionGranted),
145 rejectedReason, isSafeTopLevelNav, isSameSiteForeign,
146 hadCrossSiteRedirects, false, true, attrs, foundCookieList);
147 nsTArray<CookieStruct> matchingCookiesList;
148 SerializeCookieList(foundCookieList, matchingCookiesList, uri);
149 Unused << SendTrackCookiesLoad(matchingCookiesList, attrs);
152 // we append outgoing cookie info into a list here so the ContentParent can
153 // filter cookies passing to unnecessary ContentProcesses
154 void CookieServiceParent::UpdateCookieInContentList(
155 nsIURI* uri, const OriginAttributes& originAttrs) {
156 nsCString baseDomain;
157 bool requireAHostMatch = false;
159 // prevent malformed urls from being added to the cookie list
160 if (NS_WARN_IF(NS_FAILED(CookieCommons::GetBaseDomain(
161 mTLDService, uri, baseDomain, requireAHostMatch)))) {
162 return;
165 CookieKey cookieKey(baseDomain, originAttrs);
166 bool& allowSecure = mCookieKeysInContent.LookupOrInsert(cookieKey, false);
167 allowSecure =
168 allowSecure || nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(uri);
171 // static
172 void CookieServiceParent::SerializeCookieList(
173 const nsTArray<Cookie*>& aFoundCookieList,
174 nsTArray<CookieStruct>& aCookiesList, nsIURI* aHostURI) {
175 for (uint32_t i = 0; i < aFoundCookieList.Length(); i++) {
176 Cookie* cookie = aFoundCookieList.ElementAt(i);
177 CookieStruct* cookieStruct = aCookiesList.AppendElement();
178 *cookieStruct = cookie->ToIPC();
180 // clear http-only cookie values
181 if (cookie->IsHttpOnly()) {
182 // Value only needs to exist if an HttpOnly cookie exists.
183 cookieStruct->value() = "";
186 // clear secure cookie values in insecure context
187 bool potentiallyTurstworthy =
188 nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(aHostURI);
189 if (cookie->IsSecure() && !potentiallyTurstworthy) {
190 cookieStruct->value() = "";
195 IPCResult CookieServiceParent::RecvPrepareCookieList(
196 nsIURI* aHost, const bool& aIsForeign,
197 const bool& aIsThirdPartyTrackingResource,
198 const bool& aIsThirdPartySocialTrackingResource,
199 const bool& aStorageAccessPermissionGranted,
200 const uint32_t& aRejectedReason, const bool& aIsSafeTopLevelNav,
201 const bool& aIsSameSiteForeign, const bool& aHadCrossSiteRedirects,
202 const OriginAttributes& aAttrs) {
203 // Send matching cookies to Child.
204 if (!aHost) {
205 return IPC_FAIL(this, "aHost must not be null");
208 // we append outgoing cookie info into a list here so the ContentParent can
209 // filter cookies that do not need to go to certain ContentProcesses
210 UpdateCookieInContentList(aHost, aAttrs);
212 nsTArray<Cookie*> foundCookieList;
213 // Note: passing nullptr as aChannel to GetCookiesForURI() here is fine since
214 // this argument is only used for proper reporting of cookie loads, but the
215 // child process already does the necessary reporting in this case for us.
216 mCookieService->GetCookiesForURI(
217 aHost, nullptr, aIsForeign, aIsThirdPartyTrackingResource,
218 aIsThirdPartySocialTrackingResource, aStorageAccessPermissionGranted,
219 aRejectedReason, aIsSafeTopLevelNav, aIsSameSiteForeign,
220 aHadCrossSiteRedirects, false, true, aAttrs, foundCookieList);
221 nsTArray<CookieStruct> matchingCookiesList;
222 SerializeCookieList(foundCookieList, matchingCookiesList, aHost);
223 Unused << SendTrackCookiesLoad(matchingCookiesList, aAttrs);
224 return IPC_OK();
227 void CookieServiceParent::ActorDestroy(ActorDestroyReason aWhy) {
228 // Nothing needed here. Called right before destructor since this is a
229 // non-refcounted class.
232 IPCResult CookieServiceParent::RecvSetCookies(
233 const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
234 nsIURI* aHost, bool aFromHttp, const nsTArray<CookieStruct>& aCookies) {
235 return SetCookies(aBaseDomain, aOriginAttributes, aHost, aFromHttp, aCookies);
238 IPCResult CookieServiceParent::SetCookies(
239 const nsCString& aBaseDomain, const OriginAttributes& aOriginAttributes,
240 nsIURI* aHost, bool aFromHttp, const nsTArray<CookieStruct>& aCookies,
241 dom::BrowsingContext* aBrowsingContext) {
242 if (!mCookieService) {
243 return IPC_OK();
246 // Deserialize URI. Having a host URI is mandatory and should always be
247 // provided by the child; thus we consider failure fatal.
248 if (!aHost) {
249 return IPC_FAIL(this, "aHost must not be null");
252 // We set this to true while processing this cookie update, to make sure
253 // we don't send it back to the same content process.
254 mProcessingCookie = true;
256 bool ok =
257 mCookieService->SetCookiesFromIPC(aBaseDomain, aOriginAttributes, aHost,
258 aFromHttp, aCookies, aBrowsingContext);
259 mProcessingCookie = false;
260 return ok ? IPC_OK() : IPC_FAIL(this, "Invalid cookie received.");
263 } // namespace net
264 } // namespace mozilla