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 // 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
);
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(
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
)))) {
165 CookieKey
cookieKey(baseDomain
, originAttrs
);
166 bool& allowSecure
= mCookieKeysInContent
.LookupOrInsert(cookieKey
, false);
168 allowSecure
|| nsMixedContentBlocker::IsPotentiallyTrustworthyOrigin(uri
);
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.
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
);
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
) {
246 // Deserialize URI. Having a host URI is mandatory and should always be
247 // provided by the child; thus we consider failure fatal.
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;
257 mCookieService
->SetCookiesFromIPC(aBaseDomain
, aOriginAttributes
, aHost
,
258 aFromHttp
, aCookies
, aBrowsingContext
);
259 mProcessingCookie
= false;
260 return ok
? IPC_OK() : IPC_FAIL(this, "Invalid cookie received.");
264 } // namespace mozilla