Bug 1268889 - Implement Clear-Site-Data header - part 1, r=mayhemer
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 20 Jun 2018 11:57:49 -0400
changeset 423161 dd3b7047ea6f00c7488329b50842623f1bbdd3fb
parent 423160 40461ea89e0c5fef3016f06d31e5048d36ab4641
child 423162 b2320061fbcb5a844162e50fe22f409ce9a03ff9
push id34164
push usercsabou@mozilla.com
push dateThu, 21 Jun 2018 01:17:13 +0000
treeherdermozilla-central@d231a3231680 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmayhemer
bugs1268889
milestone62.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1268889 - Implement Clear-Site-Data header - part 1, r=mayhemer
dom/locales/en-US/chrome/security/security.properties
layout/build/nsLayoutStatics.cpp
testing/web-platform/meta/clear-site-data/navigation.https.html.ini
testing/web-platform/meta/clear-site-data/storage.https.html.ini
toolkit/components/cleardata/ClearDataService.js
toolkit/components/clearsitedata/ClearSiteData.cpp
toolkit/components/clearsitedata/ClearSiteData.h
toolkit/components/clearsitedata/moz.build
toolkit/components/moz.build
--- a/dom/locales/en-US/chrome/security/security.properties
+++ b/dom/locales/en-US/chrome/security/security.properties
@@ -89,8 +89,10 @@ BlockScriptWithWrongMimeType=Script from “%1$S” was blocked because of a disallowed MIME type.
 BlockTopLevelDataURINavigation=Navigation to toplevel data: URI not allowed (Blocked loading of: “%1$S”)
 BlockSubresourceRedirectToData=Redirecting to insecure data: URI not allowed (Blocked loading of: “%1$S”)
 
 BlockSubresourceFTP=Loading FTP subresource within http(s) page not allowed (Blocked loading of: “%1$S”)
 
 # LOCALIZATION NOTE (BrowserUpgradeInsecureDisplayRequest):
 # %1$S is the browser name "brandShortName"; %2$S is the URL of the upgraded request; %1$S is the upgraded scheme.
 BrowserUpgradeInsecureDisplayRequest = %1$S is upgrading an insecure display request ‘%2$S’ to use ‘%3$S’
+RunningClearSiteDataValue=Clear-Site-Data header forces the clean up of “%S” data.
+UnknownClearSiteDataValue=Clear-Site-Data header found. Unknown value “%S”.
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -98,16 +98,17 @@
 #include "nsApplicationCacheService.h"
 #include "mozilla/dom/CustomElementRegistry.h"
 #include "mozilla/EventDispatcher.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/dom/HTMLVideoElement.h"
 #include "TouchManager.h"
 #include "DecoderDoctorLogger.h"
 #include "MediaDecoder.h"
+#include "mozilla/ClearSiteData.h"
 #include "mozilla/ServoBindings.h"
 #include "mozilla/StaticPresData.h"
 #include "mozilla/dom/WebIDLGlobalNameHash.h"
 #include "mozilla/dom/ipc/IPCBlobInputStreamStorage.h"
 #include "mozilla/dom/U2FTokenManager.h"
 #include "mozilla/dom/PointerEventHandler.h"
 #include "mozilla/dom/BlobURLProtocolHandler.h"
 #include "nsThreadManager.h"
@@ -280,16 +281,18 @@ nsLayoutStatics::Initialize()
   if (XRE_IsParentProcess()) {
     // On content process we initialize DOMPrefs when PContentChild is fully
     // initialized.
     mozilla::dom::DOMPrefs::Initialize();
   }
 
   nsThreadManager::InitializeShutdownObserver();
 
+  ClearSiteData::Initialize();
+
   return NS_OK;
 }
 
 void
 nsLayoutStatics::Shutdown()
 {
   // Don't need to shutdown nsWindowMemoryReporter, that will be done by the
   // memory reporter manager.
@@ -388,9 +391,11 @@ nsLayoutStatics::Shutdown()
 
   DisplayItemClip::Shutdown();
 
   CacheObserver::Shutdown();
 
   PromiseDebugging::Shutdown();
 
   BlobURLProtocolHandler::RemoveDataEntries();
+
+  ClearSiteData::Shutdown();
 }
deleted file mode 100644
--- a/testing/web-platform/meta/clear-site-data/navigation.https.html.ini
+++ /dev/null
@@ -1,12 +0,0 @@
-[navigation.https.html]
-  expected: TIMEOUT
-  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1387007
-  [Clear datatypes on navigation: cookies]
-    expected: TIMEOUT
-
-  [Clear datatypes on navigation: storage]
-    expected: NOTRUN
-
-  [Clear datatypes on navigation: cookies, storage]
-    expected: NOTRUN
-
--- a/testing/web-platform/meta/clear-site-data/storage.https.html.ini
+++ b/testing/web-platform/meta/clear-site-data/storage.https.html.ini
@@ -1,7 +1,2 @@
 [storage.https.html]
-  [Clear backend when 'storage' is deleted: Indexed DB]
-    expected: FAIL
-
-  [Clear backend when 'storage' is deleted: service workers]
-    expected: FAIL
-
+  disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1456995
--- a/toolkit/components/cleardata/ClearDataService.js
+++ b/toolkit/components/cleardata/ClearDataService.js
@@ -698,17 +698,17 @@ ClearDataService.prototype = Object.free
   },
 
   deleteDataFromPrincipal(aPrincipal, aIsUserRequest, aFlags, aCallback) {
     if (!aPrincipal || !aCallback) {
       return Cr.NS_ERROR_INVALID_ARG;
     }
 
     return this._deleteInternal(aFlags, aCallback, aCleaner => {
-      if ("deleteByPrincipal" in aCleaner && aCleaner.deleteByPrincipal) {
+      if (aCleaner.deleteByPrincipal) {
         return aCleaner.deleteByPrincipal(aPrincipal);
       }
       // Some of the 'Cleaners' do not support to delete by principal. Fallback
       // is to delete by host.
       if (aCleaner.deleteByHost) {
         return aCleaner.deleteByHost(aPrincipal.URI.host,
                                      aPrincipal.originAttributes);
       }
new file mode 100644
--- /dev/null
+++ b/toolkit/components/clearsitedata/ClearSiteData.cpp
@@ -0,0 +1,429 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "ClearSiteData.h"
+
+#include "mozilla/OriginAttributes.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+#include "mozilla/Unused.h"
+#include "nsASCIIMask.h"
+#include "nsCharSeparatedTokenizer.h"
+#include "nsContentUtils.h"
+#include "nsIClearDataService.h"
+#include "nsIHttpChannel.h"
+#include "nsIHttpProtocolHandler.h"
+#include "nsIObserverService.h"
+#include "nsIPrincipal.h"
+#include "nsIScriptError.h"
+#include "nsNetUtil.h"
+
+using namespace mozilla;
+
+namespace {
+
+StaticRefPtr<ClearSiteData> gClearSiteData;
+
+} // anonymous
+
+// This object is used to suspend/resume the channel.
+class ClearSiteData::PendingCleanupHolder final
+  : public nsIClearDataCallback
+{
+public:
+  NS_DECL_ISUPPORTS
+
+  explicit PendingCleanupHolder(nsIHttpChannel* aChannel)
+    : mChannel(aChannel)
+    , mPendingOp(false)
+  {}
+
+  nsresult
+  Start()
+  {
+    MOZ_ASSERT(!mPendingOp);
+    nsresult rv = mChannel->Suspend();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+
+    mPendingOp = true;
+    return NS_OK;
+  }
+
+  // This method must be called after any Start() call.
+  void
+  BrowsingContextsReloadNeeded(const nsACString& aOrigin)
+  {
+    mContextsReloadOrigin = aOrigin;
+    MaybeBrowsingContextsReload();
+  }
+
+  // nsIClearDataCallback interface
+
+  NS_IMETHOD
+  OnDataDeleted(uint32_t aFailedFlags) override
+  {
+    MOZ_ASSERT(mPendingOp);
+    mPendingOp = false;
+
+    mChannel->Resume();
+    mChannel = nullptr;
+
+    MaybeBrowsingContextsReload();
+    return NS_OK;
+  }
+
+private:
+  ~PendingCleanupHolder()
+  {
+    if (mPendingOp) {
+      mChannel->Resume();
+    }
+  }
+
+  void
+  MaybeBrowsingContextsReload()
+  {
+    if (mPendingOp || mContextsReloadOrigin.IsEmpty()) {
+      return;
+    }
+
+    nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+    if (NS_WARN_IF(!obs)) {
+      return;
+    }
+
+    NS_ConvertUTF8toUTF16 origin(mContextsReloadOrigin);
+    nsresult rv = obs->NotifyObservers(nullptr, "clear-site-data-reload-needed",
+                                       origin.get());
+    Unused << NS_WARN_IF(NS_FAILED(rv));
+  }
+
+  nsCOMPtr<nsIHttpChannel> mChannel;
+  bool mPendingOp;
+  nsCString mContextsReloadOrigin;
+};
+
+NS_INTERFACE_MAP_BEGIN(ClearSiteData::PendingCleanupHolder)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIClearDataCallback)
+  NS_INTERFACE_MAP_ENTRY(nsIClearDataCallback)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(ClearSiteData::PendingCleanupHolder)
+NS_IMPL_RELEASE(ClearSiteData::PendingCleanupHolder)
+
+/* static */ void
+ClearSiteData::Initialize()
+{
+  MOZ_ASSERT(!gClearSiteData);
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!XRE_IsParentProcess()) {
+    return;
+  }
+
+  RefPtr<ClearSiteData> service = new ClearSiteData();
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return;
+  }
+
+  obs->AddObserver(service, NS_HTTP_ON_EXAMINE_RESPONSE_TOPIC, false);
+  gClearSiteData = service;
+}
+
+/* static */ void
+ClearSiteData::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  if (!gClearSiteData) {
+    return;
+  }
+
+  RefPtr<ClearSiteData> service = gClearSiteData;
+  gClearSiteData = nullptr;
+
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  if (NS_WARN_IF(!obs)) {
+    return;
+  }
+
+  obs->RemoveObserver(service, NS_HTTP_ON_EXAMINE_RESPONSE_TOPIC);
+}
+
+ClearSiteData::ClearSiteData() = default;
+ClearSiteData::~ClearSiteData() = default;
+
+NS_IMETHODIMP
+ClearSiteData::Observe(nsISupports* aSubject, const char* aTopic,
+                       const char16_t* aData)
+{
+  MOZ_ASSERT(!strcmp(aTopic, NS_HTTP_ON_EXAMINE_RESPONSE_TOPIC));
+
+  nsCOMPtr<nsIHttpChannel> channel = do_QueryInterface(aSubject);
+  if (NS_WARN_IF(!channel)) {
+    return NS_OK;
+  }
+
+  ClearDataFromChannel(channel);
+  return NS_OK;
+}
+
+void
+ClearSiteData::ClearDataFromChannel(nsIHttpChannel* aChannel)
+{
+  nsresult rv;
+  nsCOMPtr<nsIURI> uri;
+
+  // We want to use the final URI to check if Clear-Site-Data should be allowed
+  // or not.
+  rv = aChannel->GetURI(getter_AddRefs(uri));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  if (!IsSecureURI(uri)) {
+    return;
+  }
+
+  uint32_t flags = ParseHeader(aChannel, uri);
+  if (flags == 0) {
+    // Nothing to do.
+    return;
+  }
+
+  nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
+  if (NS_WARN_IF(!ssm)) {
+    return;
+  }
+
+  nsCOMPtr<nsIPrincipal> principal;
+  rv = ssm->GetChannelURIPrincipal(aChannel, getter_AddRefs(principal));
+  if (NS_WARN_IF(NS_FAILED(rv)) || !principal) {
+    return;
+  }
+
+  int32_t cleanFlags = 0;
+  RefPtr<PendingCleanupHolder> holder = new PendingCleanupHolder(aChannel);
+
+  if (flags & eCache) {
+    LogOpToConsole(aChannel, uri, eCache);
+    cleanFlags |= nsIClearDataService::CLEAR_ALL_CACHES;
+  }
+
+  if (flags & eCookies) {
+    LogOpToConsole(aChannel, uri, eCookies);
+    cleanFlags |= nsIClearDataService::CLEAR_COOKIES;
+  }
+
+  if (flags & eStorage) {
+    LogOpToConsole(aChannel, uri, eStorage);
+    cleanFlags |= nsIClearDataService::CLEAR_DOM_STORAGES;
+  }
+
+  if (cleanFlags) {
+    nsCOMPtr<nsIClearDataService> csd =
+      do_GetService("@mozilla.org/clear-data-service;1");
+    MOZ_ASSERT(csd);
+
+    rv = holder->Start();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    rv = csd->DeleteDataFromPrincipal(principal,
+                                      false /* user request */,
+                                      cleanFlags, holder);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+  }
+
+  if (flags & eExecutionContexts) {
+    LogOpToConsole(aChannel, uri, eExecutionContexts);
+    BrowsingContextsReload(holder, principal);
+  }
+}
+
+bool
+ClearSiteData::IsSecureURI(nsIURI* aURI) const
+{
+  MOZ_ASSERT(aURI);
+
+  bool prioriAuthenticated = false;
+  if (NS_WARN_IF(NS_FAILED(NS_URIChainHasFlags(aURI,
+                                               nsIProtocolHandler::URI_IS_POTENTIALLY_TRUSTWORTHY,
+                                               &prioriAuthenticated)))) {
+    return false;
+  }
+
+  return prioriAuthenticated;
+}
+
+uint32_t
+ClearSiteData::ParseHeader(nsIHttpChannel* aChannel, nsIURI* aURI) const
+{
+  MOZ_ASSERT(aChannel);
+
+  nsAutoCString headerValue;
+  nsresult rv = aChannel->GetResponseHeader(NS_LITERAL_CSTRING("Clear-Site-Data"),
+                                            headerValue);
+  if (NS_FAILED(rv)) {
+    return 0;
+  }
+
+  uint32_t flags = 0;
+
+  nsCCharSeparatedTokenizer token(headerValue, ',');
+  while (token.hasMoreTokens()) {
+    auto value = token.nextToken();
+    value.StripTaggedASCII(mozilla::ASCIIMask::MaskWhitespace());
+
+    if (value.EqualsLiteral("\"cache\"")) {
+      flags |= eCache;
+      continue;
+    }
+
+    if (value.EqualsLiteral("\"cookies\"")) {
+      flags |= eCookies;
+      continue;
+    }
+
+    if (value.EqualsLiteral("\"storage\"")) {
+      flags |= eStorage;
+      continue;
+    }
+
+    if (value.EqualsLiteral("\"executionContexts\"")) {
+      flags |= eExecutionContexts;
+      continue;
+    }
+
+    if (value.EqualsLiteral("\"*\"")) {
+      flags = eCache | eCookies | eStorage | eExecutionContexts;
+      break;
+    }
+
+    LogErrorToConsole(aChannel, aURI, value);
+  }
+
+  return flags;
+}
+
+void
+ClearSiteData::LogOpToConsole(nsIHttpChannel* aChannel, nsIURI* aURI,
+                              Type aType) const
+{
+  nsAutoString type;
+  TypeToString(aType, type);
+
+  nsTArray<nsString> params;
+  params.AppendElement(type);
+
+  LogToConsoleInternal(aChannel, aURI, "RunningClearSiteDataValue", params);
+}
+
+void
+ClearSiteData::LogErrorToConsole(nsIHttpChannel* aChannel,
+                                 nsIURI* aURI,
+                                 const nsACString& aUnknownType) const
+{
+  nsTArray<nsString> params;
+  params.AppendElement(NS_ConvertUTF8toUTF16(aUnknownType));
+
+  LogToConsoleInternal(aChannel, aURI, "UnknownClearSiteDataValue", params);
+}
+
+void
+ClearSiteData::LogToConsoleInternal(nsIHttpChannel* aChannel, nsIURI* aURI,
+                                    const char* aMsg,
+                                    const nsTArray<nsString>& aParams) const
+{
+  MOZ_ASSERT(aChannel);
+  MOZ_ASSERT(aURI);
+
+  uint64_t windowID = 0;
+
+  nsresult rv = aChannel->GetTopLevelContentWindowId(&windowID);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  if (!windowID) {
+    nsCOMPtr<nsILoadGroup> loadGroup;
+    nsresult rv = aChannel->GetLoadGroup(getter_AddRefs(loadGroup));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return;
+    }
+
+    if (loadGroup) {
+      windowID = nsContentUtils::GetInnerWindowID(loadGroup);
+    }
+  }
+
+  nsAutoString localizedMsg;
+  rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eSECURITY_PROPERTIES,
+                                             aMsg, aParams, localizedMsg);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  rv = nsContentUtils::ReportToConsoleByWindowID(localizedMsg,
+                                                 nsIScriptError::infoFlag,
+                                                 NS_LITERAL_CSTRING("Clear-Site-Data"),
+                                                 windowID,
+                                                 aURI);
+  Unused << NS_WARN_IF(NS_FAILED(rv));
+}
+
+void
+ClearSiteData::TypeToString(Type aType, nsAString& aStr) const
+{
+  switch (aType) {
+  case eCache:
+    aStr.AssignLiteral("cache");
+    break;
+
+  case eCookies:
+    aStr.AssignLiteral("cookies");
+    break;
+
+  case eStorage:
+    aStr.AssignLiteral("storage");
+    break;
+
+  case eExecutionContexts:
+    aStr.AssignLiteral("executionContexts");
+    break;
+
+  default:
+    MOZ_CRASH("Unknown type.");
+  }
+}
+
+void
+ClearSiteData::BrowsingContextsReload(PendingCleanupHolder* aHolder,
+                                      nsIPrincipal* aPrincipal) const
+{
+  nsAutoCString origin;
+  nsresult rv = aPrincipal->GetOrigin(origin);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return;
+  }
+
+  aHolder->BrowsingContextsReloadNeeded(origin);
+}
+
+NS_INTERFACE_MAP_BEGIN(ClearSiteData)
+  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
+  NS_INTERFACE_MAP_ENTRY(nsIObserver)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_ADDREF(ClearSiteData)
+NS_IMPL_RELEASE(ClearSiteData)
new file mode 100644
--- /dev/null
+++ b/toolkit/components/clearsitedata/ClearSiteData.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_clearsitedata_h
+#define mozilla_clearsitedata_h
+
+#include "nsIObserver.h"
+#include "nsTArray.h"
+
+class nsIHttpChannel;
+class nsIPrincipal;
+class nsIURI;
+
+namespace mozilla {
+
+class ClearSiteData final : public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  static void
+  Initialize();
+
+  static void
+  Shutdown();
+
+private:
+  ClearSiteData();
+  ~ClearSiteData();
+
+  class PendingCleanupHolder;
+
+  // Starts the cleanup if the channel contains the Clear-Site-Data header and
+  // if the URI is secure.
+  void
+  ClearDataFromChannel(nsIHttpChannel* aChannel);
+
+  // This method checks if the protocol handler of the URI has the
+  // URI_IS_POTENTIALLY_TRUSTWORTHY flag.
+  bool
+  IsSecureURI(nsIURI* aURI) const;
+
+  // From the Clear-Site-Data header, it returns a bitmap with Type values.
+  uint32_t
+  ParseHeader(nsIHttpChannel* aChannel, nsIURI* aURI) const;
+
+  enum Type
+  {
+    eCache = 0x01,
+    eCookies = 0x02,
+    eStorage = 0x04,
+    eExecutionContexts = 0x08,
+  };
+
+  // This method writes a console message when a cleanup operation is going to
+  // be executed.
+  void
+  LogOpToConsole(nsIHttpChannel* aChannel, nsIURI* aURI, Type aType) const;
+
+  // Logging of an unknown type value.
+  void
+  LogErrorToConsole(nsIHttpChannel* aChannel, nsIURI* aURI,
+                    const nsACString& aUnknownType) const;
+
+  void
+  LogToConsoleInternal(nsIHttpChannel* aChannel, nsIURI* aURI,
+                       const char* aMsg,
+                       const nsTArray<nsString>& aParams) const;
+
+  // This method converts a Type to the corrisponding string format.
+  void
+  TypeToString(Type aType, nsAString& aStr) const;
+
+  // When called, after the cleanup, PendingCleanupHolder will reload all the
+  // browsing contexts.
+  void
+  BrowsingContextsReload(PendingCleanupHolder* aHolder,
+                         nsIPrincipal* aPrincipal) const;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_clearsitedata_h
new file mode 100644
--- /dev/null
+++ b/toolkit/components/clearsitedata/moz.build
@@ -0,0 +1,20 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+EXPORTS.mozilla = [
+    'ClearSiteData.h',
+]
+
+UNIFIED_SOURCES += [
+    'ClearSiteData.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+with Files('**'):
+    BUG_COMPONENT = ('Toolkit', 'Data Sanitization')
+
+FINAL_LIBRARY = 'xul'
--- a/toolkit/components/moz.build
+++ b/toolkit/components/moz.build
@@ -17,16 +17,17 @@ DIRS += [
     'aboutmemory',
     'aboutperformance',
     'alerts',
     'apppicker',
     'asyncshutdown',
     'backgroundhangmonitor',
     'browser',
     'cleardata',
+    'clearsitedata',
     'cloudstorage',
     'commandlines',
     'contentprefs',
     'contextualidentity',
     'crashes',
     'crashmonitor',
     'diskspacewatcher',
     'downloads',