tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

CookieStoreNotifier.cpp (5628B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "CookieStoreNotifier.h"
      8 
      9 #include "CookieChangeEvent.h"
     10 #include "CookieStore.h"
     11 #include "mozilla/dom/Document.h"
     12 #include "mozilla/dom/WorkerPrivate.h"
     13 #include "mozilla/net/Cookie.h"
     14 #include "mozilla/net/CookieCommons.h"
     15 #include "nsGlobalWindowInner.h"
     16 #include "nsICookie.h"
     17 #include "nsICookieNotification.h"
     18 #include "nsISerialEventTarget.h"
     19 
     20 namespace mozilla::dom {
     21 
     22 NS_IMPL_ISUPPORTS(CookieStoreNotifier, nsIObserver);
     23 
     24 // static
     25 already_AddRefed<CookieStoreNotifier> CookieStoreNotifier::Create(
     26    CookieStore* aCookieStore) {
     27  MOZ_ASSERT(NS_IsMainThread());
     28 
     29  nsCOMPtr<nsPIDOMWindowInner> window = aCookieStore->GetOwnerWindow();
     30  MOZ_ASSERT(window);
     31 
     32  nsCOMPtr<Document> document = window->GetExtantDoc();
     33  if (NS_WARN_IF(!document)) {
     34    return nullptr;
     35  }
     36 
     37  nsIPrincipal* principal = document->NodePrincipal();
     38  if (NS_WARN_IF(!principal)) {
     39    return nullptr;
     40  }
     41 
     42  nsCString baseDomain;
     43  if (NS_WARN_IF(NS_FAILED(
     44          net::CookieCommons::GetBaseDomain(principal, baseDomain)))) {
     45    return nullptr;
     46  }
     47 
     48  if (baseDomain.IsEmpty()) {
     49    return nullptr;
     50  }
     51 
     52  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     53  if (NS_WARN_IF(!os)) {
     54    return nullptr;
     55  }
     56 
     57  RefPtr<CookieStoreNotifier> notifier = new CookieStoreNotifier(
     58      aCookieStore, baseDomain, principal->OriginAttributesRef());
     59 
     60  nsresult rv =
     61      os->AddObserver(notifier,
     62                      principal->OriginAttributesRef().IsPrivateBrowsing()
     63                          ? "private-cookie-changed"
     64                          : "cookie-changed",
     65                      false);
     66  (void)NS_WARN_IF(NS_FAILED(rv));
     67 
     68  return notifier.forget();
     69 }
     70 
     71 CookieStoreNotifier::CookieStoreNotifier(
     72    CookieStore* aCookieStore, const nsACString& aBaseDomain,
     73    const OriginAttributes& aOriginAttributes)
     74    : mCookieStore(aCookieStore),
     75      mBaseDomain(aBaseDomain),
     76      mOriginAttributes(aOriginAttributes) {
     77  MOZ_ASSERT(NS_IsMainThread());
     78  MOZ_ASSERT(aCookieStore);
     79 }
     80 
     81 CookieStoreNotifier::~CookieStoreNotifier() = default;
     82 
     83 void CookieStoreNotifier::Disentangle() {
     84  MOZ_ASSERT(NS_IsMainThread());
     85 
     86  mCookieStore = nullptr;
     87 
     88  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
     89  if (NS_WARN_IF(!os)) {
     90    return;
     91  }
     92 
     93  nsresult rv = os->RemoveObserver(this, mOriginAttributes.IsPrivateBrowsing()
     94                                             ? "private-cookie-changed"
     95                                             : "cookie-changed");
     96  (void)NS_WARN_IF(NS_FAILED(rv));
     97 }
     98 
     99 NS_IMETHODIMP
    100 CookieStoreNotifier::Observe(nsISupports* aSubject, const char* aTopic,
    101                             const char16_t* aData) {
    102  MOZ_ASSERT(NS_IsMainThread());
    103 
    104  nsCOMPtr<nsICookieNotification> notification = do_QueryInterface(aSubject);
    105  NS_ENSURE_TRUE(notification, NS_ERROR_FAILURE);
    106 
    107  auto action = notification->GetAction();
    108  if (action != nsICookieNotification::COOKIE_DELETED &&
    109      action != nsICookieNotification::COOKIE_ADDED &&
    110      action != nsICookieNotification::COOKIE_CHANGED) {
    111    return NS_OK;
    112  }
    113 
    114  nsAutoCString baseDomain;
    115  nsresult rv = notification->GetBaseDomain(baseDomain);
    116  if (NS_WARN_IF(NS_FAILED(rv)) || baseDomain.IsEmpty()) {
    117    return rv;
    118  }
    119 
    120  if (baseDomain != mBaseDomain) {
    121    return NS_OK;
    122  }
    123 
    124  nsCOMPtr<nsICookie> cookie;
    125  rv = notification->GetCookie(getter_AddRefs(cookie));
    126  if (NS_WARN_IF(NS_FAILED(rv))) {
    127    return rv;
    128  }
    129 
    130  if (cookie->OriginAttributesNative() != mOriginAttributes) {
    131    return NS_OK;
    132  }
    133 
    134  bool isHttpOnly;
    135  rv = cookie->GetIsHttpOnly(&isHttpOnly);
    136  if (NS_WARN_IF(NS_FAILED(rv))) {
    137    return rv;
    138  }
    139 
    140  if (isHttpOnly) {
    141    return NS_OK;
    142  }
    143 
    144  CookieListItem item;
    145  CookieStore::CookieStructToItem(net::Cookie::Cast(cookie)->ToIPC(), &item);
    146 
    147  if (action == nsICookieNotification::COOKIE_DELETED) {
    148    item.mValue.Reset();
    149  }
    150 
    151  bool deletedEvent = action == nsICookieNotification::COOKIE_DELETED;
    152 
    153  GetCurrentSerialEventTarget()->Dispatch(NS_NewRunnableFunction(
    154      __func__, [self = RefPtr(this), item, deletedEvent] {
    155        self->DispatchEvent(item, deletedEvent);
    156      }));
    157 
    158  return NS_OK;
    159 }
    160 
    161 void CookieStoreNotifier::DispatchEvent(const CookieListItem& aItem,
    162                                        bool aDeletedEvent) {
    163  MOZ_ASSERT(NS_IsMainThread());
    164 
    165  if (!mCookieStore) {
    166    return;
    167  }
    168 
    169  RefPtr<Event> event =
    170      aDeletedEvent
    171          ? CookieChangeEvent::CreateForDeletedCookie(mCookieStore, aItem)
    172          : CookieChangeEvent::CreateForChangedCookie(mCookieStore, aItem);
    173 
    174  if (!event) {
    175    return;
    176  }
    177 
    178  nsCOMPtr<nsPIDOMWindowInner> window = mCookieStore->GetOwnerWindow();
    179  if (!window) {
    180    return;
    181  }
    182 
    183  RefPtr<BrowsingContext> bc = window->GetBrowsingContext();
    184  if (!bc) {
    185    return;
    186  }
    187 
    188  if (bc->IsInBFCache() ||
    189      (window->GetExtantDoc() && window->GetExtantDoc()->GetBFCacheEntry())) {
    190    mDelayedDOMEvents.AppendElement(event);
    191    return;
    192  }
    193 
    194  mCookieStore->DispatchEvent(*event);
    195 }
    196 
    197 void CookieStoreNotifier::FireDelayedDOMEvents() {
    198  MOZ_ASSERT(NS_IsMainThread());
    199 
    200  nsTArray<RefPtr<Event>> delayedDOMEvents;
    201  delayedDOMEvents.SwapElements(mDelayedDOMEvents);
    202 
    203  for (Event* event : delayedDOMEvents) {
    204    mCookieStore->DispatchEvent(*event);
    205  }
    206 }
    207 
    208 }  // namespace mozilla::dom