Bug 1255894: Part 2 - Add mozIWebRequestService service for tracking filtered requests. r?mixedpuppy draft
authorKris Maglione <maglione.k@gmail.com>
Thu, 23 Mar 2017 12:18:29 -0700
changeset 653830 2f00320e74dcf8fecb279fe9dce9c8b492eeee55
parent 653623 eca521df662fffe4d3b6de833a01a5f152a3db6e
child 653831 61b6b114bcb472b1f413cae657cc960eb7667c87
push id76425
push usermaglione.k@gmail.com
push dateMon, 28 Aug 2017 04:09:59 +0000
reviewersmixedpuppy
bugs1255894
milestone57.0a1
Bug 1255894: Part 2 - Add mozIWebRequestService service for tracking filtered requests. r?mixedpuppy In order to allow extensions running in a content process to connect extension filters, we need to be able to track which requests they have permissions to modify, and which processes they have permissions to modify them from. This interface allows us to register channels that we've dispatched webRequest listeners for, and the TabParent (and, by proxy, content parent) we've dispatched them to. Extensions will only be able to filter those channels, and only from those processes. MozReview-Commit-ID: 46HTVeQ5ndi
toolkit/components/build/nsToolkitCompsCID.h
toolkit/components/build/nsToolkitCompsModule.cpp
toolkit/components/extensions/moz.build
toolkit/components/extensions/webrequest/WebRequestService.cpp
toolkit/components/extensions/webrequest/WebRequestService.h
toolkit/components/extensions/webrequest/moz.build
toolkit/components/extensions/webrequest/mozIWebRequestService.idl
--- a/toolkit/components/build/nsToolkitCompsCID.h
+++ b/toolkit/components/build/nsToolkitCompsCID.h
@@ -87,16 +87,19 @@
 #endif
 
 #define NS_ADDONCONTENTPOLICY_CONTRACTID \
   "@mozilla.org/addons/content-policy;1"
 
 #define NS_ADDONPATHSERVICE_CONTRACTID \
     "@mozilla.org/addon-path-service;1"
 
+#define NS_WEBREQUESTSERVICE_CONTRACTID \
+  "@mozilla.org/addons/webrequest-service;1"
+
 /////////////////////////////////////////////////////////////////////////////
 
 #define ALERT_NOTIFICATION_CID \
 { 0x9a7b7a41, 0x0b47, 0x47f7, { 0xb6, 0x1b, 0x15, 0xa2, 0x10, 0xd6, 0xf0, 0x20 } }
 
 // {A0CCAAF8-09DA-44D8-B250-9AC3E93C8117}
 #define NS_ALERTSSERVICE_CID \
 { 0xa0ccaaf8, 0x9da, 0x44d8, { 0xb2, 0x50, 0x9a, 0xc3, 0xe9, 0x3c, 0x81, 0x17 } }
@@ -187,8 +190,12 @@
 #define NS_ADDON_PATH_SERVICE_CID \
 { 0xa39f39d0, 0xdfb6, 0x11e3, { 0x8b, 0x68, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 } }
 
 #define NS_ADDON_POLICY_SERVICE_CID \
 { 0x562de129, 0x8338, 0x482c, { 0xbb, 0x96, 0xa1, 0xff, 0x09, 0xee, 0x53, 0xcc } }
 
 #define NS_ADDON_POLICY_SERVICE_CONTRACTID \
   "@mozilla.org/addons/policy-service;1"
+
+// {5dd0c968-d74d-42c3-b930-36145f885c3b}
+#define NS_WEBREQUEST_SERVICE_CID \
+{ 0x5dd0c968, 0xd74d, 0x42c3, { 0xb9, 0x30, 0x36, 0x14, 0x5f, 0x88, 0x5c, 0x3b } }
--- a/toolkit/components/build/nsToolkitCompsModule.cpp
+++ b/toolkit/components/build/nsToolkitCompsModule.cpp
@@ -33,16 +33,17 @@
 
 #include "nsBrowserStatusFilter.h"
 #include "mozilla/FinalizationWitnessService.h"
 #include "mozilla/NativeOSFileInternals.h"
 #include "mozilla/AddonContentPolicy.h"
 #include "mozilla/AddonManagerStartup.h"
 #include "mozilla/AddonPathService.h"
 #include "mozilla/ExtensionPolicyService.h"
+#include "mozilla/WebRequestService.h"
 
 #if defined(XP_WIN)
 #include "NativeFileWatcherWin.h"
 #else
 #include "NativeFileWatcherNotSupported.h"
 #endif // (XP_WIN)
 
 #include "nsWebRequestListener.h"
@@ -123,16 +124,17 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsUpdateP
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(FinalizationWitnessService, Init)
 NS_GENERIC_FACTORY_CONSTRUCTOR(NativeOSFileInternalsService)
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::GetInstance)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonManagerStartup, AddonManagerStartup::GetInstance)
 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(ExtensionPolicyService, ExtensionPolicyService::GetInstance)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WebRequestService, WebRequestService::GetInstance)
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsWebRequestListener)
 
 NS_DEFINE_NAMED_CID(NS_TOOLKIT_APPSTARTUP_CID);
 #if defined(MOZ_HAS_PERFSTATS)
 NS_DEFINE_NAMED_CID(NS_TOOLKIT_PERFORMANCESTATSSERVICE_CID);
 #endif // defined (MOZ_HAS_PERFSTATS)
 
@@ -159,16 +161,17 @@ NS_DEFINE_NAMED_CID(NS_BROWSERSTATUSFILT
 NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_CID);
 #endif
 NS_DEFINE_NAMED_CID(FINALIZATIONWITNESSSERVICE_CID);
 NS_DEFINE_NAMED_CID(NATIVE_OSFILE_INTERNALS_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_ADDONCONTENTPOLICY_CID);
 NS_DEFINE_NAMED_CID(NS_ADDON_PATH_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_ADDON_MANAGER_STARTUP_CID);
 NS_DEFINE_NAMED_CID(NS_ADDON_POLICY_SERVICE_CID);
+NS_DEFINE_NAMED_CID(NS_WEBREQUEST_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NATIVE_FILEWATCHER_SERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_WEBREQUESTLISTENER_CID);
 
 static const Module::CIDEntry kToolkitCIDs[] = {
   { &kNS_TOOLKIT_APPSTARTUP_CID, false, nullptr, nsAppStartupConstructor },
 #if defined(MOZ_HAS_TERMINATOR)
   { &kNS_TOOLKIT_TERMINATOR_CID, false, nullptr, nsTerminatorConstructor },
 #endif
@@ -195,16 +198,17 @@ static const Module::CIDEntry kToolkitCI
   { &kNS_UPDATEPROCESSOR_CID, false, nullptr, nsUpdateProcessorConstructor },
 #endif
   { &kFINALIZATIONWITNESSSERVICE_CID, false, nullptr, FinalizationWitnessServiceConstructor },
   { &kNATIVE_OSFILE_INTERNALS_SERVICE_CID, false, nullptr, NativeOSFileInternalsServiceConstructor },
   { &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor },
   { &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor },
   { &kNS_ADDON_MANAGER_STARTUP_CID, false, nullptr, AddonManagerStartupConstructor },
   { &kNS_ADDON_POLICY_SERVICE_CID, false, nullptr, ExtensionPolicyServiceConstructor },
+  { &kNS_WEBREQUEST_SERVICE_CID, false, nullptr, WebRequestServiceConstructor },
   { &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor },
   { &kNS_WEBREQUESTLISTENER_CID, false, nullptr, nsWebRequestListenerConstructor },
   { nullptr }
 };
 
 static const Module::ContractIDEntry kToolkitContracts[] = {
   { NS_APPSTARTUP_CONTRACTID, &kNS_TOOLKIT_APPSTARTUP_CID },
 #if defined(MOZ_HAS_TERMINATOR)
@@ -234,16 +238,17 @@ static const Module::ContractIDEntry kTo
   { NS_UPDATEPROCESSOR_CONTRACTID, &kNS_UPDATEPROCESSOR_CID },
 #endif
   { FINALIZATIONWITNESSSERVICE_CONTRACTID, &kFINALIZATIONWITNESSSERVICE_CID },
   { NATIVE_OSFILE_INTERNALS_SERVICE_CONTRACTID, &kNATIVE_OSFILE_INTERNALS_SERVICE_CID },
   { NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID },
   { NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID },
   { NS_ADDONMANAGERSTARTUP_CONTRACTID, &kNS_ADDON_MANAGER_STARTUP_CID },
   { NS_ADDON_POLICY_SERVICE_CONTRACTID, &kNS_ADDON_POLICY_SERVICE_CID },
+  { NS_WEBREQUESTSERVICE_CONTRACTID, &kNS_WEBREQUEST_SERVICE_CID },
   { NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID },
   { NS_WEBREQUESTLISTENER_CONTRACTID, &kNS_WEBREQUESTLISTENER_CID },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kToolkitCategories[] = {
   { "content-policy", NS_ADDONCONTENTPOLICY_CONTRACTID, NS_ADDONCONTENTPOLICY_CONTRACTID },
   { nullptr }
--- a/toolkit/components/extensions/moz.build
+++ b/toolkit/components/extensions/moz.build
@@ -1,14 +1,15 @@
 # -*- 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/.
 
+
 with Files('**'):
     BUG_COMPONENT = ('Toolkit', 'WebExtensions: General')
 
 EXTRA_JS_MODULES += [
     'Extension.jsm',
     'ExtensionChild.jsm',
     'ExtensionChildDevToolsUtils.jsm',
     'ExtensionCommon.jsm',
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/webrequest/WebRequestService.cpp
@@ -0,0 +1,151 @@
+/* -*- 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 "WebRequestService.h"
+
+#include "mozilla/Assertions.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "nsCOMPtr.h"
+#include "nsIChannel.h"
+#include "nsIDOMWindowUtils.h"
+#include "nsISupports.h"
+#include "nsITabParent.h"
+#include "nsITraceableChannel.h"
+
+#include "mozilla/dom/TabParent.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+WebRequestService::WebRequestService()
+  : mDataLock("WebRequest service data lock")
+{
+}
+
+WebRequestService::~WebRequestService()
+{
+}
+
+NS_IMPL_ISUPPORTS(WebRequestService, mozIWebRequestService)
+
+/* static */ WebRequestService*
+WebRequestService::GetInstance()
+{
+  static RefPtr<WebRequestService> instance;
+  if (!instance) {
+    instance = new WebRequestService();
+    ClearOnShutdown(&instance);
+  }
+  return instance;
+}
+
+
+NS_IMETHODIMP
+WebRequestService::RegisterTraceableChannel(uint64_t aChannelId,
+                                            nsIChannel* aChannel,
+                                            const nsAString& aAddonId,
+                                            nsITabParent* aTabParent,
+                                            nsIJSRAIIHelper** aHelper)
+{
+  nsCOMPtr<nsITraceableChannel> traceableChannel = do_QueryInterface(aChannel);
+  NS_ENSURE_TRUE(traceableChannel, NS_ERROR_INVALID_ARG);
+
+  nsCOMPtr<nsIAtom> addonId = NS_Atomize(aAddonId);
+  ChannelParent* entry = new ChannelParent(aChannelId, aChannel,
+                                           addonId, aTabParent);
+
+  RefPtr<Destructor> destructor = new Destructor(entry);
+  destructor.forget(aHelper);
+
+  return NS_OK;
+}
+
+already_AddRefed<nsIChannel>
+WebRequestService::GetTraceableChannel(uint64_t aChannelId,
+                                       nsIAtom* aAddonId,
+                                       nsIContentParent* aContentParent)
+{
+  MutexAutoLock al(mDataLock);
+
+  auto entry = mChannelEntries.Get(aChannelId);
+  if (!entry) {
+    return nullptr;
+  }
+
+  for (auto channelEntry : entry->mTabParents) {
+    nsIContentParent* contentParent = nullptr;
+    if (channelEntry->mTabParent) {
+      contentParent = static_cast<nsIContentParent*>(
+        channelEntry->mTabParent->Manager());
+    }
+
+    if (channelEntry->mAddonId == aAddonId && contentParent == aContentParent) {
+      nsCOMPtr<nsIChannel> channel = do_QueryReferent(entry->mChannel);
+      return channel.forget();
+    }
+  }
+
+  return nullptr;
+}
+
+
+WebRequestService::ChannelParent::ChannelParent(uint64_t aChannelId, nsIChannel* aChannel,
+                                                nsIAtom* aAddonId, nsITabParent* aTabParent)
+  : mTabParent(static_cast<TabParent*>(aTabParent))
+  , mAddonId(aAddonId)
+  , mChannelId(aChannelId)
+{
+  auto service = GetInstance();
+  MutexAutoLock al(service->mDataLock);
+
+  auto entry = service->mChannelEntries.LookupOrAdd(mChannelId);
+
+  entry->mChannel = do_GetWeakReference(aChannel);
+  entry->mTabParents.insertBack(this);
+}
+
+WebRequestService::ChannelParent::~ChannelParent()
+{}
+
+void
+WebRequestService::ChannelParent::Detach()
+{
+  auto service = GetInstance();
+  MutexAutoLock al(service->mDataLock);
+
+  auto& map = service->mChannelEntries;
+  auto entry = map.Get(mChannelId);
+  MOZ_ASSERT(entry);
+
+  removeFrom(entry->mTabParents);
+  if (entry->mTabParents.isEmpty()) {
+    map.Remove(mChannelId);
+  }
+}
+
+WebRequestService::Destructor::~Destructor()
+{
+  MOZ_ASSERT(mDestructCalled);
+  if (!mDestructCalled) {
+    Destruct();
+  }
+}
+
+NS_IMETHODIMP
+WebRequestService::Destructor::Destruct()
+{
+  if (NS_WARN_IF(mDestructCalled)) {
+    return NS_ERROR_FAILURE;
+  }
+  mDestructCalled = true;
+
+  mChannelParent->Detach();
+  delete mChannelParent;
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(WebRequestService::Destructor, nsIJSRAIIHelper)
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/webrequest/WebRequestService.h
@@ -0,0 +1,97 @@
+/* -*- 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_WebRequestService_h
+#define mozilla_WebRequestService_h
+
+#include "mozIWebRequestService.h"
+
+#include "mozilla/LinkedList.h"
+#include "mozilla/Mutex.h"
+#include "nsCOMPtr.h"
+#include "nsHashKeys.h"
+#include "nsClassHashtable.h"
+#include "nsIAtom.h"
+#include "nsIDOMWindowUtils.h"
+#include "nsWeakPtr.h"
+
+using namespace mozilla;
+
+namespace mozilla {
+namespace dom {
+  class TabParent;
+  class nsIContentParent;
+}
+}
+
+class WebRequestService : public mozIWebRequestService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_MOZIWEBREQUESTSERVICE
+
+  explicit WebRequestService();
+
+  static WebRequestService*
+  GetInstance();
+
+  already_AddRefed<nsIChannel>
+  GetTraceableChannel(uint64_t aChannelId, nsIAtom* aAddonId,
+                      dom::nsIContentParent* aContentParent);
+
+protected:
+  virtual ~WebRequestService();
+
+private:
+  class ChannelParent : public LinkedListElement<ChannelParent>
+  {
+  public:
+    explicit ChannelParent(uint64_t aChannelId, nsIChannel* aChannel, nsIAtom* aAddonId, nsITabParent* aTabParent);
+    ~ChannelParent();
+
+    void Detach();
+
+    const RefPtr<dom::TabParent> mTabParent;
+    const nsCOMPtr<nsIAtom> mAddonId;
+
+  private:
+    const uint64_t mChannelId;
+  };
+
+  class Destructor : public nsIJSRAIIHelper
+  {
+  public:
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIJSRAIIHELPER
+
+    explicit Destructor(ChannelParent* aChannelParent)
+      : mChannelParent(aChannelParent)
+      , mDestructCalled(false)
+    {}
+
+  protected:
+    virtual ~Destructor();
+
+  private:
+    ChannelParent* mChannelParent;
+    bool mDestructCalled;
+  };
+
+  class ChannelEntry
+  {
+  public:
+    // Note: We can't keep a strong pointer to the channel here, since channels
+    // are not cycle collected, and a reference to this object will be stored on
+    // the channel in order to keep the entry alive.
+    nsWeakPtr mChannel;
+    LinkedList<ChannelParent> mTabParents;
+  };
+
+  nsClassHashtable<nsUint64HashKey, ChannelEntry> mChannelEntries;
+  Mutex mDataLock;
+};
+
+#endif // mozilla_WebRequestService_h
--- a/toolkit/components/extensions/webrequest/moz.build
+++ b/toolkit/components/extensions/webrequest/moz.build
@@ -1,21 +1,30 @@
 # -*- 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/.
 
 XPIDL_SOURCES += [
+    'mozIWebRequestService.idl',
     'nsIWebRequestListener.idl',
 ]
 
 XPIDL_MODULE = 'webextensions'
 
+UNIFIED_SOURCES += [
+    'nsWebRequestListener.cpp',
+    'WebRequestService.cpp',
+]
+
 EXPORTS += [
     'nsWebRequestListener.h',
 ]
 
-UNIFIED_SOURCES += [
-    'nsWebRequestListener.cpp',
+EXPORTS.mozilla += [
+    'WebRequestService.h',
 ]
 
-FINAL_LIBRARY = 'xul'
\ No newline at end of file
+FINAL_LIBRARY = 'xul'
+
+with Files("**"):
+    BUG_COMPONENT = ("Toolkit", "WebExtensions: Request Handling")
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/webrequest/mozIWebRequestService.idl
@@ -0,0 +1,18 @@
+/* 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 "nsISupports.idl"
+
+interface nsIChannel;
+interface nsIJSRAIIHelper;
+interface nsITabParent;
+
+[scriptable, builtinclass, uuid(1b1118ed-f208-4cfc-b841-5b31a78c2b7a)]
+interface mozIWebRequestService : nsISupports
+{
+  nsIJSRAIIHelper registerTraceableChannel(in uint64_t channelId,
+                                           in nsIChannel channel,
+                                           in AString addonId,
+                                           [optional] in nsITabParent tabParent);
+};