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"
19 #include "nsMixedContentBlocker.h"
21 using namespace mozilla::ipc
;
26 CookieServiceParent::CookieServiceParent() {
27 // Instantiate the cookieservice via the service manager, so it sticks around
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
) {
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
) {
93 if (NS_WARN_IF(NS_FAILED(CookieCommons::GetBaseDomainFromHost(
94 mTLDService
, cookie
.Host(), baseDomain
)))) {
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
);
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(
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
)))) {
166 CookieKey
cookieKey(baseDomain
, originAttrs
);
167 bool& allowSecure
= mCookieKeysInContent
.LookupOrInsert(cookieKey
, false);
169 allowSecure
|| nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(uri
);
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.
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
);
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
) {
247 // Deserialize URI. Having a host URI is mandatory and should always be
248 // provided by the child; thus we consider failure fatal.
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;
258 mCookieService
->SetCookiesFromIPC(aBaseDomain
, aOriginAttributes
, aHost
,
259 aFromHttp
, aCookies
, aBrowsingContext
);
260 mProcessingCookie
= false;
261 return ok
? IPC_OK() : IPC_FAIL(this, "Invalid cookie received.");
265 } // namespace mozilla