Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/cookie/CookieServiceChild.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
5
6
#include "mozilla/net/CookieServiceChild.h"
7
#include "mozilla/net/NeckoChannelParams.h"
8
#include "mozilla/AntiTrackingCommon.h"
9
#include "mozilla/LoadInfo.h"
10
#include "mozilla/BasePrincipal.h"
11
#include "mozilla/ClearOnShutdown.h"
12
#include "mozilla/dom/ContentChild.h"
13
#include "mozilla/ipc/URIUtils.h"
14
#include "mozilla/net/NeckoChild.h"
15
#include "mozilla/SystemGroup.h"
16
#include "nsCookie.h"
17
#include "nsCookieService.h"
18
#include "nsContentUtils.h"
19
#include "nsNetCID.h"
20
#include "nsNetUtil.h"
21
#include "nsIChannel.h"
22
#include "nsCookiePermission.h"
23
#include "nsIEffectiveTLDService.h"
24
#include "nsIURI.h"
25
#include "nsIPrefService.h"
26
#include "nsIPrefBranch.h"
27
#include "nsServiceManagerUtils.h"
28
#include "mozilla/Telemetry.h"
29
#include "mozilla/TimeStamp.h"
30
31
using namespace mozilla::ipc;
32
using mozilla::OriginAttributes;
33
34
namespace mozilla {
35
namespace net {
36
37
// Pref string constants
38
static const char kPrefCookieBehavior[] = "network.cookie.cookieBehavior";
39
static const char kPrefThirdPartySession[] =
40
  "network.cookie.thirdparty.sessionOnly";
41
static const char kPrefThirdPartyNonsecureSession[] =
42
  "network.cookie.thirdparty.nonsecureSessionOnly";
43
static const char kCookieLeaveSecurityAlone[] = "network.cookie.leave-secure-alone";
44
static const char kCookieMoveIntervalSecs[] = "network.cookie.move.interval_sec";
45
46
static StaticRefPtr<CookieServiceChild> gCookieService;
47
static uint32_t gMoveCookiesIntervalSeconds = 10;
48
49
already_AddRefed<CookieServiceChild>
50
CookieServiceChild::GetSingleton()
51
0
{
52
0
  if (!gCookieService) {
53
0
    gCookieService = new CookieServiceChild();
54
0
    ClearOnShutdown(&gCookieService);
55
0
  }
56
0
57
0
  return do_AddRef(gCookieService);
58
0
}
59
60
NS_IMPL_ISUPPORTS(CookieServiceChild,
61
                  nsICookieService,
62
                  nsIObserver,
63
                  nsITimerCallback,
64
                  nsISupportsWeakReference)
65
66
CookieServiceChild::CookieServiceChild()
67
  : mCookieBehavior(nsICookieService::BEHAVIOR_ACCEPT)
68
  , mThirdPartySession(false)
69
  , mThirdPartyNonsecureSession(false)
70
  , mLeaveSecureAlone(true)
71
  , mIPCOpen(false)
72
0
{
73
0
  NS_ASSERTION(IsNeckoChild(), "not a child process");
74
0
75
0
  mozilla::dom::ContentChild* cc =
76
0
    static_cast<mozilla::dom::ContentChild*>(gNeckoChild->Manager());
77
0
  if (cc->IsShuttingDown()) {
78
0
    return;
79
0
  }
80
0
81
0
  // This corresponds to Release() in DeallocPCookieService.
82
0
  NS_ADDREF_THIS();
83
0
84
0
  NeckoChild::InitNeckoChild();
85
0
86
0
  // Create a child PCookieService actor.
87
0
  gNeckoChild->SendPCookieServiceConstructor(this);
88
0
89
0
  mIPCOpen = true;
90
0
91
0
  mTLDService = do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
92
0
  NS_ASSERTION(mTLDService, "couldn't get TLDService");
93
0
94
0
  // Init our prefs and observer.
95
0
  nsCOMPtr<nsIPrefBranch> prefBranch =
96
0
    do_GetService(NS_PREFSERVICE_CONTRACTID);
97
0
  NS_WARNING_ASSERTION(prefBranch, "no prefservice");
98
0
  if (prefBranch) {
99
0
    prefBranch->AddObserver(kPrefCookieBehavior, this, true);
100
0
    prefBranch->AddObserver(kPrefThirdPartySession, this, true);
101
0
    prefBranch->AddObserver(kPrefThirdPartyNonsecureSession, this, true);
102
0
    prefBranch->AddObserver(kCookieLeaveSecurityAlone, this, true);
103
0
    prefBranch->AddObserver(kCookieMoveIntervalSecs, this, true);
104
0
    PrefChanged(prefBranch);
105
0
  }
106
0
107
0
  nsCOMPtr<nsIObserverService> observerService
108
0
    = mozilla::services::GetObserverService();
109
0
  if (observerService) {
110
0
    observerService->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
111
0
  }
112
0
}
113
114
void
115
CookieServiceChild::MoveCookies()
116
0
{
117
0
  TimeStamp start = TimeStamp::Now();
118
0
  for (auto iter = mCookiesMap.Iter(); !iter.Done(); iter.Next()) {
119
0
    CookiesList *cookiesList = iter.UserData();
120
0
    CookiesList newCookiesList;
121
0
    for (uint32_t i = 0; i < cookiesList->Length(); ++i) {
122
0
      nsCookie *cookie = cookiesList->ElementAt(i);
123
0
      RefPtr<nsCookie> newCookie = nsCookie::Create(cookie->Name(),
124
0
                                                    cookie->Value(),
125
0
                                                    cookie->Host(),
126
0
                                                    cookie->Path(),
127
0
                                                    cookie->Expiry(),
128
0
                                                    cookie->LastAccessed(),
129
0
                                                    cookie->CreationTime(),
130
0
                                                    cookie->IsSession(),
131
0
                                                    cookie->IsSecure(),
132
0
                                                    cookie->IsHttpOnly(),
133
0
                                                    cookie->OriginAttributesRef(),
134
0
                                                    cookie->SameSite());
135
0
      newCookiesList.AppendElement(newCookie);
136
0
    }
137
0
    cookiesList->SwapElements(newCookiesList);
138
0
  }
139
0
140
0
  Telemetry::AccumulateTimeDelta(Telemetry::COOKIE_TIME_MOVING_MS, start);
141
0
}
142
143
NS_IMETHODIMP
144
CookieServiceChild::Notify(nsITimer *aTimer)
145
0
{
146
0
  if (aTimer == mCookieTimer) {
147
0
    MoveCookies();
148
0
  } else {
149
0
    MOZ_CRASH("Unknown timer");
150
0
  }
151
0
  return NS_OK;
152
0
}
153
154
CookieServiceChild::~CookieServiceChild()
155
0
{
156
0
  gCookieService = nullptr;
157
0
}
158
159
void
160
CookieServiceChild::ActorDestroy(ActorDestroyReason why)
161
0
{
162
0
  mIPCOpen = false;
163
0
}
164
165
void
166
CookieServiceChild::TrackCookieLoad(nsIChannel *aChannel)
167
0
{
168
0
  if (!mIPCOpen) {
169
0
    return;
170
0
  }
171
0
172
0
  bool isForeign = false;
173
0
  bool isTrackingResource = false;
174
0
  bool firstPartyStorageAccessGranted = false;
175
0
  nsCOMPtr<nsIURI> uri;
176
0
  aChannel->GetURI(getter_AddRefs(uri));
177
0
  if (RequireThirdPartyCheck()) {
178
0
    mThirdPartyUtil->IsThirdPartyChannel(aChannel, uri, &isForeign);
179
0
  }
180
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
181
0
  if (httpChannel) {
182
0
    isTrackingResource = httpChannel->GetIsTrackingResource();
183
0
    // Check first-party storage access even for non-tracking resources, since
184
0
    // we will need the result when computing the access rights for the reject
185
0
    // foreign cookie behavior mode.
186
0
    if (isForeign &&
187
0
        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
188
0
                                                                uri,
189
0
                                                                nullptr)) {
190
0
      firstPartyStorageAccessGranted = true;
191
0
    }
192
0
  }
193
0
  nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
194
0
  mozilla::OriginAttributes attrs;
195
0
  if (loadInfo) {
196
0
    attrs = loadInfo->GetOriginAttributes();
197
0
  }
198
0
  URIParams uriParams;
199
0
  SerializeURI(uri, uriParams);
200
0
  bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
201
0
  bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, uri);
202
0
  SendPrepareCookieList(uriParams, isForeign, isTrackingResource,
203
0
                        firstPartyStorageAccessGranted, isSafeTopLevelNav,
204
0
                        isSameSiteForeign, attrs);
205
0
}
206
207
mozilla::ipc::IPCResult
208
0
CookieServiceChild::RecvRemoveAll(){
209
0
  mCookiesMap.Clear();
210
0
  return IPC_OK();
211
0
}
212
213
mozilla::ipc::IPCResult
214
CookieServiceChild::RecvRemoveCookie(const CookieStruct     &aCookie,
215
                                     const OriginAttributes &aAttrs)
216
0
{
217
0
  nsCString baseDomain;
218
0
  nsCookieService::
219
0
    GetBaseDomainFromHost(mTLDService, aCookie.host(), baseDomain);
220
0
  nsCookieKey key(baseDomain, aAttrs);
221
0
  CookiesList *cookiesList = nullptr;
222
0
  mCookiesMap.Get(key, &cookiesList);
223
0
224
0
  if (!cookiesList) {
225
0
    return IPC_OK();
226
0
  }
227
0
228
0
  for (uint32_t i = 0; i < cookiesList->Length(); i++) {
229
0
    nsCookie *cookie = cookiesList->ElementAt(i);
230
0
    if (cookie->Name().Equals(aCookie.name()) &&
231
0
        cookie->Host().Equals(aCookie.host()) &&
232
0
        cookie->Path().Equals(aCookie.path())) {
233
0
      cookiesList->RemoveElementAt(i);
234
0
      break;
235
0
    }
236
0
  }
237
0
238
0
  return IPC_OK();
239
0
}
240
241
mozilla::ipc::IPCResult
242
CookieServiceChild::RecvAddCookie(const CookieStruct     &aCookie,
243
                                  const OriginAttributes &aAttrs)
244
0
{
245
0
  RefPtr<nsCookie> cookie = nsCookie::Create(aCookie.name(),
246
0
                                             aCookie.value(),
247
0
                                             aCookie.host(),
248
0
                                             aCookie.path(),
249
0
                                             aCookie.expiry(),
250
0
                                             aCookie.lastAccessed(),
251
0
                                             aCookie.creationTime(),
252
0
                                             aCookie.isSession(),
253
0
                                             aCookie.isSecure(),
254
0
                                             aCookie.isHttpOnly(),
255
0
                                             aAttrs,
256
0
                                             aCookie.sameSite());
257
0
  RecordDocumentCookie(cookie, aAttrs);
258
0
  return IPC_OK();
259
0
}
260
261
mozilla::ipc::IPCResult
262
CookieServiceChild::RecvRemoveBatchDeletedCookies(nsTArray<CookieStruct>&& aCookiesList,
263
                                                  nsTArray<OriginAttributes>&& aAttrsList)
264
0
{
265
0
  MOZ_ASSERT(aCookiesList.Length() == aAttrsList.Length());
266
0
  for (uint32_t i = 0; i < aCookiesList.Length(); i++) {
267
0
    CookieStruct cookieStruct = aCookiesList.ElementAt(i);
268
0
    RecvRemoveCookie(cookieStruct, aAttrsList.ElementAt(i));
269
0
  }
270
0
  return IPC_OK();
271
0
}
272
273
mozilla::ipc::IPCResult
274
CookieServiceChild::RecvTrackCookiesLoad(nsTArray<CookieStruct>&& aCookiesList,
275
                                         const OriginAttributes &aAttrs)
276
0
{
277
0
  for (uint32_t i = 0; i < aCookiesList.Length(); i++) {
278
0
    RefPtr<nsCookie> cookie = nsCookie::Create(aCookiesList[i].name(),
279
0
                                               aCookiesList[i].value(),
280
0
                                               aCookiesList[i].host(),
281
0
                                               aCookiesList[i].path(),
282
0
                                               aCookiesList[i].expiry(),
283
0
                                               aCookiesList[i].lastAccessed(),
284
0
                                               aCookiesList[i].creationTime(),
285
0
                                               aCookiesList[i].isSession(),
286
0
                                               aCookiesList[i].isSecure(),
287
0
                                               false,
288
0
                                               aAttrs,
289
0
                                               aCookiesList[i].sameSite());
290
0
    RecordDocumentCookie(cookie, aAttrs);
291
0
  }
292
0
293
0
  return IPC_OK();
294
0
}
295
296
void
297
CookieServiceChild::PrefChanged(nsIPrefBranch *aPrefBranch)
298
0
{
299
0
  int32_t val;
300
0
  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kPrefCookieBehavior, &val)))
301
0
    mCookieBehavior =
302
0
      val >= nsICookieService::BEHAVIOR_ACCEPT &&
303
0
      val <= nsICookieService::BEHAVIOR_LAST
304
0
        ? val : nsICookieService::BEHAVIOR_ACCEPT;
305
0
306
0
  bool boolval;
307
0
  if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartySession, &boolval)))
308
0
    mThirdPartySession = !!boolval;
309
0
310
0
  if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kPrefThirdPartyNonsecureSession,
311
0
                                            &boolval)))
312
0
    mThirdPartyNonsecureSession = boolval;
313
0
314
0
  if (NS_SUCCEEDED(aPrefBranch->GetBoolPref(kCookieLeaveSecurityAlone, &boolval)))
315
0
    mLeaveSecureAlone = !!boolval;
316
0
317
0
  if (!mThirdPartyUtil && RequireThirdPartyCheck()) {
318
0
    mThirdPartyUtil = do_GetService(THIRDPARTYUTIL_CONTRACTID);
319
0
    NS_ASSERTION(mThirdPartyUtil, "require ThirdPartyUtil service");
320
0
  }
321
0
322
0
  if (NS_SUCCEEDED(aPrefBranch->GetIntPref(kCookieMoveIntervalSecs, &val))) {
323
0
    gMoveCookiesIntervalSeconds = clamped<uint32_t>(val, 0, 3600);
324
0
    if (gMoveCookiesIntervalSeconds && !mCookieTimer) {
325
0
      NS_NewTimerWithCallback(getter_AddRefs(mCookieTimer),
326
0
                              this, gMoveCookiesIntervalSeconds * 1000,
327
0
                              nsITimer::TYPE_REPEATING_SLACK_LOW_PRIORITY);
328
0
    }
329
0
    if (!gMoveCookiesIntervalSeconds && mCookieTimer) {
330
0
      mCookieTimer->Cancel();
331
0
      mCookieTimer = nullptr;
332
0
    }
333
0
    if (mCookieTimer) {
334
0
      mCookieTimer->SetDelay(gMoveCookiesIntervalSeconds * 1000);
335
0
    }
336
0
  }
337
0
}
338
339
void
340
CookieServiceChild::GetCookieStringFromCookieHashTable(nsIURI                 *aHostURI,
341
                                                       bool                   aIsForeign,
342
                                                       bool                   aIsTrackingResource,
343
                                                       bool                   aFirstPartyStorageAccessGranted,
344
                                                       bool                   aIsSafeTopLevelNav,
345
                                                       bool                   aIsSameSiteForeign,
346
                                                       const OriginAttributes &aOriginAttrs,
347
                                                       nsCString              &aCookieString)
348
0
{
349
0
  nsCOMPtr<nsIEffectiveTLDService> TLDService =
350
0
    do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID);
351
0
  NS_ASSERTION(TLDService, "Can't get TLDService");
352
0
  bool requireHostMatch;
353
0
  nsAutoCString baseDomain;
354
0
  nsCookieService::
355
0
    GetBaseDomain(TLDService, aHostURI, baseDomain, requireHostMatch);
356
0
  nsCookieKey key(baseDomain, aOriginAttrs);
357
0
  CookiesList *cookiesList = nullptr;
358
0
  mCookiesMap.Get(key, &cookiesList);
359
0
360
0
  if (!cookiesList) {
361
0
    return;
362
0
  }
363
0
364
0
  nsAutoCString hostFromURI, pathFromURI;
365
0
  bool isSecure;
366
0
  aHostURI->GetAsciiHost(hostFromURI);
367
0
  aHostURI->GetPathQueryRef(pathFromURI);
368
0
  aHostURI->SchemeIs("https", &isSecure);
369
0
  int64_t currentTimeInUsec = PR_Now();
370
0
  int64_t currentTime = currentTimeInUsec / PR_USEC_PER_SEC;
371
0
372
0
  nsCOMPtr<nsICookiePermission> permissionService =
373
0
    nsCookiePermission::GetOrCreate();
374
0
  CookieStatus cookieStatus =
375
0
    nsCookieService::CheckPrefs(permissionService, mCookieBehavior,
376
0
                                mThirdPartySession,
377
0
                                mThirdPartyNonsecureSession, aHostURI,
378
0
                                aIsForeign, aIsTrackingResource,
379
0
                                aFirstPartyStorageAccessGranted, nullptr,
380
0
                                CountCookiesFromHashTable(baseDomain, aOriginAttrs),
381
0
                                aOriginAttrs, nullptr);
382
0
383
0
  if (cookieStatus != STATUS_ACCEPTED && cookieStatus != STATUS_ACCEPT_SESSION) {
384
0
    return;
385
0
  }
386
0
387
0
  cookiesList->Sort(CompareCookiesForSending());
388
0
  for (uint32_t i = 0; i < cookiesList->Length(); i++) {
389
0
    nsCookie *cookie = cookiesList->ElementAt(i);
390
0
    // check the host, since the base domain lookup is conservative.
391
0
    if (!nsCookieService::DomainMatches(cookie, hostFromURI))
392
0
      continue;
393
0
394
0
    // if the cookie is secure and the host scheme isn't, we can't send it
395
0
    if (cookie->IsSecure() && !isSecure)
396
0
      continue;
397
0
398
0
    int32_t sameSiteAttr = 0;
399
0
    cookie->GetSameSite(&sameSiteAttr);
400
0
    if (aIsSameSiteForeign && nsCookieService::IsSameSiteEnabled()) {
401
0
      // it if's a cross origin request and the cookie is same site only (strict)
402
0
      // don't send it
403
0
      if (sameSiteAttr == nsICookie2::SAMESITE_STRICT) {
404
0
        continue;
405
0
      }
406
0
      // if it's a cross origin request, the cookie is same site lax, but it's not
407
0
      // a top-level navigation, don't send it
408
0
      if (sameSiteAttr == nsICookie2::SAMESITE_LAX && !aIsSafeTopLevelNav) {
409
0
        continue;
410
0
      }
411
0
    }
412
0
413
0
    // if the nsIURI path doesn't match the cookie path, don't send it back
414
0
    if (!nsCookieService::PathMatches(cookie, pathFromURI))
415
0
      continue;
416
0
417
0
    // check if the cookie has expired
418
0
    if (cookie->Expiry() <= currentTime) {
419
0
      continue;
420
0
    }
421
0
422
0
    if (!cookie->Name().IsEmpty() || !cookie->Value().IsEmpty()) {
423
0
      if (!aCookieString.IsEmpty()) {
424
0
        aCookieString.AppendLiteral("; ");
425
0
      }
426
0
      if (!cookie->Name().IsEmpty()) {
427
0
        aCookieString.Append(cookie->Name().get());
428
0
        aCookieString.AppendLiteral("=");
429
0
        aCookieString.Append(cookie->Value().get());
430
0
      } else {
431
0
        aCookieString.Append(cookie->Value().get());
432
0
      }
433
0
    }
434
0
  }
435
0
}
436
437
uint32_t
438
CookieServiceChild::CountCookiesFromHashTable(const nsCString &aBaseDomain,
439
                                              const OriginAttributes &aOriginAttrs)
440
0
{
441
0
  CookiesList *cookiesList = nullptr;
442
0
443
0
  nsCString baseDomain;
444
0
  nsCookieKey key(aBaseDomain, aOriginAttrs);
445
0
  mCookiesMap.Get(key, &cookiesList);
446
0
447
0
  return cookiesList ? cookiesList->Length() : 0;
448
0
}
449
450
void
451
CookieServiceChild::SetCookieInternal(nsCookieAttributes              &aCookieAttributes,
452
                                      const mozilla::OriginAttributes &aAttrs,
453
                                      nsIChannel                      *aChannel,
454
                                      bool                             aFromHttp,
455
                                      nsICookiePermission             *aPermissionService)
456
0
{
457
0
  int64_t currentTimeInUsec = PR_Now();
458
0
  RefPtr<nsCookie> cookie =
459
0
    nsCookie::Create(aCookieAttributes.name,
460
0
                     aCookieAttributes.value,
461
0
                     aCookieAttributes.host,
462
0
                     aCookieAttributes.path,
463
0
                     aCookieAttributes.expiryTime,
464
0
                     currentTimeInUsec,
465
0
                     nsCookie::GenerateUniqueCreationTime(currentTimeInUsec),
466
0
                     aCookieAttributes.isSession,
467
0
                     aCookieAttributes.isSecure,
468
0
                     aCookieAttributes.isHttpOnly,
469
0
                     aAttrs,
470
0
                     aCookieAttributes.sameSite);
471
0
472
0
  RecordDocumentCookie(cookie, aAttrs);
473
0
}
474
475
bool
476
CookieServiceChild::RequireThirdPartyCheck()
477
0
{
478
0
  return mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_FOREIGN ||
479
0
    mCookieBehavior == nsICookieService::BEHAVIOR_LIMIT_FOREIGN ||
480
0
    mCookieBehavior == nsICookieService::BEHAVIOR_REJECT_TRACKER ||
481
0
    mThirdPartySession ||
482
0
    mThirdPartyNonsecureSession;
483
0
}
484
485
void
486
CookieServiceChild::RecordDocumentCookie(nsCookie               *aCookie,
487
                                         const OriginAttributes &aAttrs)
488
0
{
489
0
  nsAutoCString baseDomain;
490
0
  nsCookieService::
491
0
    GetBaseDomainFromHost(mTLDService, aCookie->Host(), baseDomain);
492
0
493
0
  nsCookieKey key(baseDomain, aAttrs);
494
0
  CookiesList *cookiesList = nullptr;
495
0
  mCookiesMap.Get(key, &cookiesList);
496
0
497
0
  if (!cookiesList) {
498
0
    cookiesList = mCookiesMap.LookupOrAdd(key);
499
0
  }
500
0
  for (uint32_t i = 0; i < cookiesList->Length(); i++) {
501
0
    nsCookie *cookie = cookiesList->ElementAt(i);
502
0
    if (cookie->Name().Equals(aCookie->Name()) &&
503
0
        cookie->Host().Equals(aCookie->Host()) &&
504
0
        cookie->Path().Equals(aCookie->Path())) {
505
0
      if (cookie->Value().Equals(aCookie->Value()) &&
506
0
          cookie->Expiry() == aCookie->Expiry() &&
507
0
          cookie->IsSecure() == aCookie->IsSecure() &&
508
0
          cookie->SameSite() == aCookie->SameSite() &&
509
0
          cookie->IsSession() == aCookie->IsSession() &&
510
0
          cookie->IsHttpOnly() == aCookie->IsHttpOnly()) {
511
0
        cookie->SetLastAccessed(aCookie->LastAccessed());
512
0
        return;
513
0
      }
514
0
      cookiesList->RemoveElementAt(i);
515
0
      break;
516
0
    }
517
0
  }
518
0
519
0
  int64_t currentTime = PR_Now() / PR_USEC_PER_SEC;
520
0
  if (aCookie->Expiry() <= currentTime) {
521
0
    return;
522
0
  }
523
0
524
0
  if (!aCookie->IsHttpOnly()) {
525
0
    cookiesList->AppendElement(aCookie);
526
0
  }
527
0
}
528
529
nsresult
530
CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI,
531
                                            nsIChannel *aChannel,
532
                                            char **aCookieString)
533
0
{
534
0
  NS_ENSURE_ARG(aHostURI);
535
0
  NS_ENSURE_ARG_POINTER(aCookieString);
536
0
537
0
  *aCookieString = nullptr;
538
0
539
0
  // Fast past: don't bother sending IPC messages about nullprincipal'd
540
0
  // documents.
541
0
  nsAutoCString scheme;
542
0
  aHostURI->GetScheme(scheme);
543
0
  if (scheme.EqualsLiteral("moz-nullprincipal"))
544
0
    return NS_OK;
545
0
546
0
  nsCOMPtr<nsILoadInfo> loadInfo;
547
0
  mozilla::OriginAttributes attrs;
548
0
  if (aChannel) {
549
0
    loadInfo = aChannel->GetLoadInfo();
550
0
    if (loadInfo) {
551
0
      attrs = loadInfo->GetOriginAttributes();
552
0
    }
553
0
  }
554
0
555
0
  // Asynchronously call the parent.
556
0
  bool isForeign = true;
557
0
  if (RequireThirdPartyCheck())
558
0
    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
559
0
560
0
  bool isTrackingResource = false;
561
0
  bool firstPartyStorageAccessGranted = false;
562
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
563
0
  if (httpChannel) {
564
0
    isTrackingResource = httpChannel->GetIsTrackingResource();
565
0
    // Check first-party storage access even for non-tracking resources, since
566
0
    // we will need the result when computing the access rights for the reject
567
0
    // foreign cookie behavior mode.
568
0
    if (isForeign &&
569
0
        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
570
0
                                                                aHostURI,
571
0
                                                                nullptr)) {
572
0
      firstPartyStorageAccessGranted = true;
573
0
    }
574
0
  }
575
0
576
0
  bool isSafeTopLevelNav = NS_IsSafeTopLevelNav(aChannel);
577
0
  bool isSameSiteForeign = NS_IsSameSiteForeign(aChannel, aHostURI);
578
0
579
0
  nsAutoCString result;
580
0
  GetCookieStringFromCookieHashTable(aHostURI, isForeign, isTrackingResource,
581
0
                                     firstPartyStorageAccessGranted, isSafeTopLevelNav,
582
0
                                     isSameSiteForeign, attrs, result);
583
0
584
0
  if (!result.IsEmpty())
585
0
    *aCookieString = ToNewCString(result);
586
0
587
0
  return NS_OK;
588
0
}
589
590
nsresult
591
CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
592
                                            nsIChannel *aChannel,
593
                                            const char *aCookieString,
594
                                            const char *aServerTime,
595
                                            bool aFromHttp)
596
0
{
597
0
  NS_ENSURE_ARG(aHostURI);
598
0
  NS_ENSURE_ARG_POINTER(aCookieString);
599
0
600
0
  // Fast past: don't bother sending IPC messages about nullprincipal'd
601
0
  // documents.
602
0
  nsAutoCString scheme;
603
0
  aHostURI->GetScheme(scheme);
604
0
  if (scheme.EqualsLiteral("moz-nullprincipal"))
605
0
    return NS_OK;
606
0
607
0
  // Determine whether the request is foreign. Failure is acceptable.
608
0
  bool isForeign = true;
609
0
  if (RequireThirdPartyCheck())
610
0
    mThirdPartyUtil->IsThirdPartyChannel(aChannel, aHostURI, &isForeign);
611
0
612
0
  bool isTrackingResource = false;
613
0
  bool firstPartyStorageAccessGranted = false;
614
0
  nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel);
615
0
  if (httpChannel) {
616
0
    isTrackingResource = httpChannel->GetIsTrackingResource();
617
0
    // Check first-party storage access even for non-tracking resources, since
618
0
    // we will need the result when computing the access rights for the reject
619
0
    // foreign cookie behavior mode.
620
0
    if (isForeign &&
621
0
        AntiTrackingCommon::IsFirstPartyStorageAccessGrantedFor(httpChannel,
622
0
                                                                aHostURI,
623
0
                                                                nullptr)) {
624
0
      firstPartyStorageAccessGranted = true;
625
0
    }
626
0
  }
627
0
628
0
  nsDependentCString cookieString(aCookieString);
629
0
  nsDependentCString stringServerTime;
630
0
  if (aServerTime)
631
0
    stringServerTime.Rebind(aServerTime);
632
0
633
0
  URIParams hostURIParams;
634
0
  SerializeURI(aHostURI, hostURIParams);
635
0
636
0
  OptionalURIParams channelURIParams;
637
0
  mozilla::OriginAttributes attrs;
638
0
  if (aChannel) {
639
0
    nsCOMPtr<nsIURI> channelURI;
640
0
    aChannel->GetURI(getter_AddRefs(channelURI));
641
0
    SerializeURI(channelURI, channelURIParams);
642
0
643
0
    nsCOMPtr<nsILoadInfo> loadInfo = aChannel->GetLoadInfo();
644
0
    if (loadInfo) {
645
0
      attrs = loadInfo->GetOriginAttributes();
646
0
    }
647
0
  } else {
648
0
    SerializeURI(nullptr, channelURIParams);
649
0
  }
650
0
651
0
  // Asynchronously call the parent.
652
0
  if (mIPCOpen) {
653
0
    SendSetCookieString(hostURIParams, channelURIParams,
654
0
                        isForeign, isTrackingResource,
655
0
                        firstPartyStorageAccessGranted, cookieString,
656
0
                        stringServerTime, attrs, aFromHttp);
657
0
  }
658
0
659
0
  bool requireHostMatch;
660
0
  nsCString baseDomain;
661
0
  nsCookieService::
662
0
    GetBaseDomain(mTLDService, aHostURI, baseDomain, requireHostMatch);
663
0
664
0
  nsCOMPtr<nsICookiePermission> permissionService =
665
0
    nsCookiePermission::GetOrCreate();
666
0
667
0
  CookieStatus cookieStatus =
668
0
    nsCookieService::CheckPrefs(permissionService, mCookieBehavior,
669
0
                                mThirdPartySession,
670
0
                                mThirdPartyNonsecureSession, aHostURI,
671
0
                                isForeign, isTrackingResource,
672
0
                                firstPartyStorageAccessGranted, aCookieString,
673
0
                                CountCookiesFromHashTable(baseDomain, attrs),
674
0
                                attrs, nullptr);
675
0
676
0
  if (cookieStatus != STATUS_ACCEPTED && cookieStatus != STATUS_ACCEPT_SESSION) {
677
0
    return NS_OK;
678
0
  }
679
0
680
0
  nsCString serverTimeString(aServerTime);
681
0
  int64_t serverTime = nsCookieService::ParseServerTime(serverTimeString);
682
0
  bool moreCookies;
683
0
  do {
684
0
    nsCookieAttributes cookieAttributes;
685
0
    bool canSetCookie = false;
686
0
    nsCookieKey key(baseDomain, attrs);
687
0
    moreCookies = nsCookieService::CanSetCookie(aHostURI, key, cookieAttributes,
688
0
                                                requireHostMatch, cookieStatus,
689
0
                                                cookieString, serverTime, aFromHttp,
690
0
                                                aChannel, mLeaveSecureAlone,
691
0
                                                canSetCookie, mThirdPartyUtil);
692
0
693
0
    if (canSetCookie) {
694
0
      SetCookieInternal(cookieAttributes, attrs, aChannel,
695
0
                        aFromHttp, permissionService);
696
0
    }
697
0
698
0
    // document.cookie can only set one cookie at a time.
699
0
    if (!aFromHttp) {
700
0
      break;
701
0
    }
702
0
703
0
  } while (moreCookies);
704
0
  return NS_OK;
705
0
}
706
707
NS_IMETHODIMP
708
CookieServiceChild::Observe(nsISupports     *aSubject,
709
                            const char      *aTopic,
710
                            const char16_t *aData)
711
0
{
712
0
  if (!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
713
0
    if (mCookieTimer) {
714
0
      mCookieTimer->Cancel();
715
0
      mCookieTimer = nullptr;
716
0
    }
717
0
    nsCOMPtr<nsIObserverService> observerService
718
0
      = mozilla::services::GetObserverService();
719
0
    if (observerService) {
720
0
      observerService->RemoveObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID);
721
0
    }
722
0
  } else if (!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) {
723
0
    nsCOMPtr<nsIPrefBranch> prefBranch = do_QueryInterface(aSubject);
724
0
    if (prefBranch) {
725
0
      PrefChanged(prefBranch);
726
0
    }
727
0
  } else {
728
0
    MOZ_ASSERT(false, "unexpected topic!");
729
0
  }
730
0
731
0
  return NS_OK;
732
0
}
733
734
NS_IMETHODIMP
735
CookieServiceChild::GetCookieString(nsIURI *aHostURI,
736
                                    nsIChannel *aChannel,
737
                                    char **aCookieString)
738
0
{
739
0
  return GetCookieStringInternal(aHostURI, aChannel, aCookieString);
740
0
}
741
742
NS_IMETHODIMP
743
CookieServiceChild::GetCookieStringFromHttp(nsIURI *aHostURI,
744
                                            nsIURI *aFirstURI,
745
                                            nsIChannel *aChannel,
746
                                            char **aCookieString)
747
0
{
748
0
  return NS_ERROR_NOT_IMPLEMENTED;
749
0
}
750
751
NS_IMETHODIMP
752
CookieServiceChild::SetCookieString(nsIURI *aHostURI,
753
                                    nsIPrompt *aPrompt,
754
                                    const char *aCookieString,
755
                                    nsIChannel *aChannel)
756
0
{
757
0
  return SetCookieStringInternal(aHostURI, aChannel, aCookieString,
758
0
                                 nullptr, false);
759
0
}
760
761
NS_IMETHODIMP
762
CookieServiceChild::SetCookieStringFromHttp(nsIURI     *aHostURI,
763
                                            nsIURI     *aFirstURI,
764
                                            nsIPrompt  *aPrompt,
765
                                            const char *aCookieString,
766
                                            const char *aServerTime,
767
                                            nsIChannel *aChannel)
768
0
{
769
0
  return SetCookieStringInternal(aHostURI, aChannel, aCookieString,
770
0
                                 aServerTime, true);
771
0
}
772
773
NS_IMETHODIMP
774
CookieServiceChild::RunInTransaction(nsICookieTransactionCallback* aCallback)
775
0
{
776
0
  return NS_ERROR_NOT_IMPLEMENTED;
777
0
}
778
779
} // namespace net
780
} // namespace mozilla