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 "mozilla/net/CookieServiceParent.h"
7 #include "mozilla/dom/PContentParent.h"
8 #include "mozilla/net/NeckoParent.h"
10 #include "mozilla/BasePrincipal.h"
11 #include "mozilla/ipc/URIUtils.h"
12 #include "nsArrayUtils.h"
13 #include "nsCookieService.h"
14 #include "nsIChannel.h"
15 #include "nsIEffectiveTLDService.h"
16 #include "nsIScriptSecurityManager.h"
17 #include "nsIPrivateBrowsingChannel.h"
19 #include "nsPrintfCString.h"
21 using namespace mozilla::ipc
;
22 using mozilla::BasePrincipal
;
23 using mozilla::OriginAttributes
;
24 using mozilla::dom::PContentParent
;
25 using mozilla::net::NeckoParent
;
29 // Ignore failures from this function, as they only affect whether we do or
30 // don't show a dialog box in private browsing mode if the user sets a pref.
32 CreateDummyChannel(nsIURI
* aHostURI
, nsIURI
* aChannelURI
,
33 OriginAttributes
& aAttrs
, nsIChannel
** aChannel
)
35 nsCOMPtr
<nsIPrincipal
> principal
=
36 BasePrincipal::CreateCodebasePrincipal(aHostURI
, aAttrs
);
41 // The following channel is never openend, so it does not matter what
42 // securityFlags we pass; let's follow the principle of least privilege.
43 nsCOMPtr
<nsIChannel
> dummyChannel
;
44 NS_NewChannel(getter_AddRefs(dummyChannel
), aChannelURI
, principal
,
45 nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_DATA_IS_BLOCKED
,
46 nsIContentPolicy::TYPE_INVALID
);
47 nsCOMPtr
<nsIPrivateBrowsingChannel
> pbChannel
= do_QueryInterface(dummyChannel
);
52 pbChannel
->SetPrivate(aAttrs
.mPrivateBrowsingId
> 0);
53 dummyChannel
.forget(aChannel
);
61 CookieServiceParent::CookieServiceParent()
63 // Instantiate the cookieservice via the service manager, so it sticks around
65 nsCOMPtr
<nsICookieService
> cs
= do_GetService(NS_COOKIESERVICE_CONTRACTID
);
67 // Get the nsCookieService instance directly, so we can call internal methods.
68 mCookieService
= nsCookieService::GetSingleton();
69 NS_ASSERTION(mCookieService
, "couldn't get nsICookieService");
70 mProcessingCookie
= false;
74 GetInfoFromCookie(nsCookie
*aCookie
,
75 CookieStruct
&aCookieStruct
)
77 aCookieStruct
.name() = aCookie
->Name();
78 aCookieStruct
.value() = aCookie
->Value();
79 aCookieStruct
.host() = aCookie
->Host();
80 aCookieStruct
.path() = aCookie
->Path();
81 aCookieStruct
.expiry() = aCookie
->Expiry();
82 aCookieStruct
.lastAccessed() = aCookie
->LastAccessed();
83 aCookieStruct
.creationTime() = aCookie
->CreationTime();
84 aCookieStruct
.isSession() = aCookie
->IsSession();
85 aCookieStruct
.isSecure() = aCookie
->IsSecure();
86 aCookieStruct
.isHttpOnly() = aCookie
->IsHttpOnly();
87 aCookieStruct
.sameSite() = aCookie
->SameSite();
91 CookieServiceParent::RemoveBatchDeletedCookies(nsIArray
*aCookieList
) {
93 aCookieList
->GetLength(&len
);
94 OriginAttributes attrs
;
95 CookieStruct cookieStruct
;
96 nsTArray
<CookieStruct
> cookieStructList
;
97 nsTArray
<OriginAttributes
> attrsList
;
98 for (uint32_t i
= 0; i
< len
; i
++) {
99 nsCOMPtr
<nsICookie
> xpcCookie
= do_QueryElementAt(aCookieList
, i
);
100 auto cookie
= static_cast<nsCookie
*>(xpcCookie
.get());
101 attrs
= cookie
->OriginAttributesRef();
102 GetInfoFromCookie(cookie
, cookieStruct
);
103 if (cookie
->IsHttpOnly()) {
104 // Child only needs to exist if an HttpOnly cookie exists, not its value
105 cookieStruct
.value() = "";
107 cookieStructList
.AppendElement(cookieStruct
);
108 attrsList
.AppendElement(attrs
);
110 Unused
<< SendRemoveBatchDeletedCookies(cookieStructList
, attrsList
);
114 CookieServiceParent::RemoveAll()
116 Unused
<< SendRemoveAll();
120 CookieServiceParent::RemoveCookie(nsICookie
*aCookie
)
122 auto cookie
= static_cast<nsCookie
*>(aCookie
);
123 OriginAttributes attrs
= cookie
->OriginAttributesRef();
124 CookieStruct cookieStruct
;
125 GetInfoFromCookie(cookie
, cookieStruct
);
126 if (cookie
->IsHttpOnly()) {
127 cookieStruct
.value() = "";
129 Unused
<< SendRemoveCookie(cookieStruct
, attrs
);
133 CookieServiceParent::AddCookie(nsICookie
*aCookie
)
135 auto cookie
= static_cast<nsCookie
*>(aCookie
);
136 OriginAttributes attrs
= cookie
->OriginAttributesRef();
137 CookieStruct cookieStruct
;
138 GetInfoFromCookie(cookie
, cookieStruct
);
139 if (cookie
->IsHttpOnly()) {
140 cookieStruct
.value() = "";
142 Unused
<< SendAddCookie(cookieStruct
, attrs
);
146 CookieServiceParent::TrackCookieLoad(nsIChannel
*aChannel
)
148 nsCOMPtr
<nsIURI
> uri
;
149 aChannel
->GetURI(getter_AddRefs(uri
));
151 nsCOMPtr
<nsILoadInfo
> loadInfo
= aChannel
->GetLoadInfo();
152 mozilla::OriginAttributes attrs
;
154 attrs
= loadInfo
->GetOriginAttributes();
156 bool isSafeTopLevelNav
= NS_IsSafeTopLevelNav(aChannel
);
157 bool aIsSameSiteForeign
= NS_IsSameSiteForeign(aChannel
, uri
);
159 // Send matching cookies to Child.
160 nsCOMPtr
<mozIThirdPartyUtil
> thirdPartyUtil
;
161 thirdPartyUtil
= do_GetService(THIRDPARTYUTIL_CONTRACTID
);
162 bool isForeign
= true;
163 thirdPartyUtil
->IsThirdPartyChannel(aChannel
, uri
, &isForeign
);
165 bool isTrackingResource
= false;
166 bool storageAccessGranted
= false;
167 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(aChannel
);
169 isTrackingResource
= httpChannel
->GetIsTrackingResource();
170 // Check first-party storage access even for non-tracking resources, since
171 // we will need the result when computing the access rights for the reject
172 // foreign cookie behavior mode.
174 AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel
,
177 storageAccessGranted
= true;
181 nsTArray
<nsCookie
*> foundCookieList
;
182 mCookieService
->GetCookiesForURI(uri
, isForeign
, isTrackingResource
,
183 storageAccessGranted
, isSafeTopLevelNav
,
184 aIsSameSiteForeign
, false, attrs
,
186 nsTArray
<CookieStruct
> matchingCookiesList
;
187 SerialializeCookieList(foundCookieList
, matchingCookiesList
, uri
);
188 Unused
<< SendTrackCookiesLoad(matchingCookiesList
, attrs
);
192 CookieServiceParent::SerialializeCookieList(const nsTArray
<nsCookie
*> &aFoundCookieList
,
193 nsTArray
<CookieStruct
> &aCookiesList
,
196 for (uint32_t i
= 0; i
< aFoundCookieList
.Length(); i
++) {
197 nsCookie
*cookie
= aFoundCookieList
.ElementAt(i
);
198 CookieStruct
* cookieStruct
= aCookiesList
.AppendElement();
199 cookieStruct
->name() = cookie
->Name();
200 if (!cookie
->IsHttpOnly()) {
201 cookieStruct
->value() = cookie
->Value();
203 cookieStruct
->host() = cookie
->Host();
204 cookieStruct
->path() = cookie
->Path();
205 cookieStruct
->expiry() = cookie
->Expiry();
206 cookieStruct
->lastAccessed() = cookie
->LastAccessed();
207 cookieStruct
->creationTime() = cookie
->CreationTime();
208 cookieStruct
->isSession() = cookie
->IsSession();
209 cookieStruct
->isSecure() = cookie
->IsSecure();
210 cookieStruct
->sameSite() = cookie
->SameSite();
214 mozilla::ipc::IPCResult
215 CookieServiceParent::RecvPrepareCookieList(const URIParams
&aHost
,
216 const bool &aIsForeign
,
217 const bool &aIsTrackingResource
,
218 const bool &aFirstPartyStorageAccessGranted
,
219 const bool &aIsSafeTopLevelNav
,
220 const bool &aIsSameSiteForeign
,
221 const OriginAttributes
&aAttrs
)
223 nsCOMPtr
<nsIURI
> hostURI
= DeserializeURI(aHost
);
225 // Send matching cookies to Child.
226 nsTArray
<nsCookie
*> foundCookieList
;
227 mCookieService
->GetCookiesForURI(hostURI
, aIsForeign
, aIsTrackingResource
,
228 aFirstPartyStorageAccessGranted
, aIsSafeTopLevelNav
,
229 aIsSameSiteForeign
, false, aAttrs
,
231 nsTArray
<CookieStruct
> matchingCookiesList
;
232 SerialializeCookieList(foundCookieList
, matchingCookiesList
, hostURI
);
233 Unused
<< SendTrackCookiesLoad(matchingCookiesList
, aAttrs
);
238 CookieServiceParent::ActorDestroy(ActorDestroyReason aWhy
)
240 // Nothing needed here. Called right before destructor since this is a
241 // non-refcounted class.
244 mozilla::ipc::IPCResult
245 CookieServiceParent::RecvSetCookieString(const URIParams
& aHost
,
246 const OptionalURIParams
& aChannelURI
,
247 const bool& aIsForeign
,
248 const bool& aIsTrackingResource
,
249 const bool& aFirstPartyStorageAccessGranted
,
250 const nsCString
& aCookieString
,
251 const nsCString
& aServerTime
,
252 const OriginAttributes
& aAttrs
,
253 const bool& aFromHttp
)
258 // Deserialize URI. Having a host URI is mandatory and should always be
259 // provided by the child; thus we consider failure fatal.
260 nsCOMPtr
<nsIURI
> hostURI
= DeserializeURI(aHost
);
262 return IPC_FAIL_NO_REASON(this);
264 nsCOMPtr
<nsIURI
> channelURI
= DeserializeURI(aChannelURI
);
266 // This is a gross hack. We've already computed everything we need to know
267 // for whether to set this cookie or not, but we need to communicate all of
268 // this information through to nsICookiePermission, which indirectly
269 // computes the information from the channel. We only care about the
270 // aIsPrivate argument as nsCookieService::SetCookieStringInternal deals
271 // with aIsForeign before we have to worry about nsCookiePermission trying
272 // to use the channel to inspect it.
273 nsCOMPtr
<nsIChannel
> dummyChannel
;
274 CreateDummyChannel(hostURI
, channelURI
,
275 const_cast<OriginAttributes
&>(aAttrs
),
276 getter_AddRefs(dummyChannel
));
278 // NB: dummyChannel could be null if something failed in CreateDummyChannel.
279 nsDependentCString
cookieString(aCookieString
, 0);
281 // We set this to true while processing this cookie update, to make sure
282 // we don't send it back to the same content process.
283 mProcessingCookie
= true;
284 mCookieService
->SetCookieStringInternal(hostURI
, aIsForeign
,
286 aFirstPartyStorageAccessGranted
,
287 cookieString
, aServerTime
, aFromHttp
,
288 aAttrs
, dummyChannel
);
289 mProcessingCookie
= false;
294 } // namespace mozilla