Bug 1402944: Part 7 - Move traceable channel registration to ChannelWrapper. r?mixedpuppy,ehsan draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 23 Sep 2017 02:39:32 -0700
changeset 670806 9019b2d2e99c9e287968649ef29e611ff005a446
parent 670805 46a93dbaeee0f24c946abc85388cfc64f93a482b
child 670807 b0b60850e4b3e4fd890826815fe3fb5d63fde2d9
push id81714
push usermaglione.k@gmail.com
push dateTue, 26 Sep 2017 21:30:45 +0000
reviewersmixedpuppy, ehsan
bugs1402944
milestone58.0a1
Bug 1402944: Part 7 - Move traceable channel registration to ChannelWrapper. r?mixedpuppy,ehsan MozReview-Commit-ID: 6hGmh4VpJMQ
dom/webidl/ChannelWrapper.webidl
toolkit/components/build/nsToolkitCompsCID.h
toolkit/components/build/nsToolkitCompsModule.cpp
toolkit/components/extensions/webrequest/ChannelWrapper.cpp
toolkit/components/extensions/webrequest/ChannelWrapper.h
toolkit/components/extensions/webrequest/WebRequestService.cpp
toolkit/components/extensions/webrequest/WebRequestService.h
toolkit/components/extensions/webrequest/moz.build
toolkit/components/extensions/webrequest/mozIWebRequestService.idl
toolkit/modules/addons/WebRequest.jsm
--- a/dom/webidl/ChannelWrapper.webidl
+++ b/dom/webidl/ChannelWrapper.webidl
@@ -1,14 +1,15 @@
 /* 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/. */
 
 interface LoadInfo;
 interface MozChannel;
+interface TabParent;
 interface URI;
 interface nsISupports;
 
 /**
  * Load types that correspond to the external types in nsIContentPolicy.idl.
  * Please also update that IDL when updating this list.
  */
 enum MozContentPolicyType {
@@ -128,16 +129,22 @@ interface ChannelWrapper : EventTarget {
    * Returns true if the request matches the given request filter, and the
    * given extension has permission to access it.
    */
   boolean matches(optional MozRequestFilter filter,
                   optional WebExtensionPolicy? extension = null);
 
 
   /**
+   * Register's this channel as traceable by the given add-on when accessed
+   * via the process of the given TabParent.
+   */
+  void registerTraceableChannel(WebExtensionPolicy extension, TabParent? tabParent);
+
+  /**
    * The current HTTP status code of the request. This will be 0 if a response
    * has not yet been received, or if the request is not an HTTP request.
    */
   [Cached, Pure]
   readonly attribute unsigned long statusCode;
 
   /**
    * The HTTP status line for the request (e.g., "HTTP/1.0 200 Success"). This
--- a/toolkit/components/build/nsToolkitCompsCID.h
+++ b/toolkit/components/build/nsToolkitCompsCID.h
@@ -87,19 +87,16 @@
 #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 } }
@@ -190,12 +187,8 @@
 #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,17 +33,16 @@
 
 #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)
 
 #if !defined(MOZ_WIDGET_ANDROID)
@@ -122,17 +121,16 @@ 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_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)
 
 #if defined(MOZ_HAS_TERMINATOR)
 NS_DEFINE_NAMED_CID(NS_TOOLKIT_TERMINATOR_CID);
@@ -157,17 +155,16 @@ 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);
 
 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
 #if defined(MOZ_HAS_PERFSTATS)
@@ -193,17 +190,16 @@ 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 },
   { nullptr }
 };
 
 static const Module::ContractIDEntry kToolkitContracts[] = {
   { NS_APPSTARTUP_CONTRACTID, &kNS_TOOLKIT_APPSTARTUP_CID },
 #if defined(MOZ_HAS_TERMINATOR)
   { NS_TOOLKIT_TERMINATOR_CONTRACTID, &kNS_TOOLKIT_TERMINATOR_CID },
@@ -232,17 +228,16 @@ 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 },
   { nullptr }
 };
 
 static const mozilla::Module::CategoryEntry kToolkitCategories[] = {
   { "content-policy", NS_ADDONCONTENTPOLICY_CONTRACTID, NS_ADDONCONTENTPOLICY_CONTRACTID },
   { nullptr }
 };
--- a/toolkit/components/extensions/webrequest/ChannelWrapper.cpp
+++ b/toolkit/components/extensions/webrequest/ChannelWrapper.cpp
@@ -15,16 +15,17 @@
 #include "NSSErrorsService.h"
 #include "nsITransportSecurityInfo.h"
 
 #include "mozilla/AddonManagerWebAPI.h"
 #include "mozilla/ErrorNames.h"
 #include "mozilla/ResultExtensions.h"
 #include "mozilla/Unused.h"
 #include "mozilla/dom/Event.h"
+#include "mozilla/dom/TabParent.h"
 #include "nsIContentPolicy.h"
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadContext.h"
 #include "nsILoadGroup.h"
 #include "nsIProxiedChannel.h"
@@ -559,16 +560,48 @@ ChannelWrapper::ParentWindowId() const
       parentID = loadInfo->GetParentOuterWindowID();
     }
     return NormalizeWindowID(loadInfo, parentID);
   }
   return -1;
 }
 
 /*****************************************************************************
+ * Response filtering
+ *****************************************************************************/
+
+void
+ChannelWrapper::RegisterTraceableChannel(const WebExtensionPolicy& aAddon, nsITabParent* aTabParent)
+{
+  mAddonEntries.Put(aAddon.Id(), aTabParent);
+  if (!mChannelEntry) {
+    mChannelEntry = WebRequestService::GetSingleton().RegisterChannel(this);
+    CheckEventListeners();
+  }
+}
+
+already_AddRefed<nsIChannel>
+ChannelWrapper::GetTraceableChannel(nsIAtom* aAddonId, dom::nsIContentParent* aContentParent) const
+{
+  nsCOMPtr<nsITabParent> tabParent;
+  if (mAddonEntries.Get(aAddonId, getter_AddRefs(tabParent))) {
+    nsIContentParent* contentParent = nullptr;
+    if (tabParent) {
+      contentParent = static_cast<nsIContentParent*>(
+          static_cast<TabParent*>(tabParent.get())->Manager());
+    }
+
+    if (contentParent == aContentParent) {
+      return MaybeChannel();
+    }
+  }
+  return nullptr;
+}
+
+/*****************************************************************************
  * ...
  *****************************************************************************/
 
 MozContentPolicyType
 GetContentPolicyType(uint32_t aType)
 {
   // Note: Please keep this function in sync with the external types in
   // nsIContentPolicy.idl
@@ -777,16 +810,17 @@ ChannelWrapper::GetErrorString(nsString&
 
 void
 ChannelWrapper::ErrorCheck()
 {
   if (!mFiredErrorEvent) {
     nsAutoString error;
     GetErrorString(error);
     if (error.Length()) {
+      mChannelEntry = nullptr;
       mFiredErrorEvent = true;
       ChannelWrapperBinding::ClearCachedErrorStringValue(this);
       FireEvent(NS_LITERAL_STRING("error"));
     }
   }
 }
 
 /*****************************************************************************
@@ -812,28 +846,30 @@ ChannelWrapper::RequestListener::Init()
   return NS_ERROR_UNEXPECTED;
 }
 
 NS_IMETHODIMP
 ChannelWrapper::RequestListener::OnStartRequest(nsIRequest *request, nsISupports * aCtxt)
 {
   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
 
+  mChannelWrapper->mChannelEntry = nullptr;
   mChannelWrapper->ErrorCheck();
   mChannelWrapper->FireEvent(NS_LITERAL_STRING("start"));
 
   return mOrigStreamListener->OnStartRequest(request, aCtxt);
 }
 
 NS_IMETHODIMP
 ChannelWrapper::RequestListener::OnStopRequest(nsIRequest *request, nsISupports *aCtxt,
                                            nsresult aStatus)
 {
   MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
 
+  mChannelWrapper->mChannelEntry = nullptr;
   mChannelWrapper->ErrorCheck();
   mChannelWrapper->FireEvent(NS_LITERAL_STRING("stop"));
 
   return mOrigStreamListener->OnStopRequest(request, aCtxt, aStatus);
 }
 
 NS_IMETHODIMP
 ChannelWrapper::RequestListener::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
@@ -875,17 +911,18 @@ ChannelWrapper::FireEvent(const nsAStrin
   DispatchEvent(event, &defaultPrevented);
 }
 
 void
 ChannelWrapper::CheckEventListeners()
 {
   if (!mAddedStreamListener && (HasListenersFor(nsGkAtoms::onerror) ||
                                 HasListenersFor(nsGkAtoms::onstart) ||
-                                HasListenersFor(nsGkAtoms::onstop))) {
+                                HasListenersFor(nsGkAtoms::onstop) ||
+                                mChannelEntry)) {
     auto listener = MakeRefPtr<RequestListener>(this);
     if (!NS_WARN_IF(NS_FAILED(listener->Init()))) {
       mAddedStreamListener = true;
     }
   }
 }
 
 void
--- a/toolkit/components/extensions/webrequest/ChannelWrapper.h
+++ b/toolkit/components/extensions/webrequest/ChannelWrapper.h
@@ -5,40 +5,49 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_extensions_ChannelWrapper_h
 #define mozilla_extensions_ChannelWrapper_h
 
 #include "mozilla/dom/BindingDeclarations.h"
 #include "mozilla/dom/ChannelWrapperBinding.h"
 
+#include "mozilla/WebRequestService.h"
 #include "mozilla/extensions/MatchPattern.h"
 #include "mozilla/extensions/WebExtensionPolicy.h"
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
+#include "mozilla/WeakPtr.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIChannel.h"
 #include "nsIHttpChannel.h"
 #include "nsIStreamListener.h"
+#include "nsITabParent.h"
 #include "nsIThreadRetargetableStreamListener.h"
+#include "nsPointerHashKeys.h"
+#include "nsInterfaceHashtable.h"
 #include "nsWeakPtr.h"
 #include "nsWrapperCache.h"
 
 #define NS_CHANNELWRAPPER_IID \
 { 0xc06162d2, 0xb803, 0x43b4, \
   { 0xaa, 0x31, 0xcf, 0x69, 0x7f, 0x93, 0x68, 0x1c } }
 
 class nsIDOMElement;
 class nsILoadContext;
 
 namespace mozilla {
+namespace dom {
+  class nsIContentParent;
+}
 namespace extensions {
 
 namespace detail {
 
   // We need to store our wrapped channel as a weak reference, since channels
   // are not cycle collected, and we're going to be hanging this wrapper
   // instance off the channel in order to ensure the same channel always has
   // the same wrapper.
@@ -92,17 +101,20 @@ namespace detail {
   private:
     nsWeakPtr mChannel;
 
     mutable nsIChannel* MOZ_NON_OWNING_REF mWeakChannel;
     mutable Maybe<nsIHttpChannel*> MOZ_NON_OWNING_REF mWeakHttpChannel;
   };
 }
 
+class WebRequestChannelEntry;
+
 class ChannelWrapper final : public DOMEventTargetHelper
+                           , public SupportsWeakPtr<ChannelWrapper>
                            , private detail::ChannelHolder
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ChannelWrapper, DOMEventTargetHelper)
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_CHANNELWRAPPER_IID)
 
@@ -125,16 +137,21 @@ public:
 
   void SetSuspended(bool aSuspended, ErrorResult& aRv);
 
 
   void GetContentType(nsCString& aContentType) const;
   void SetContentType(const nsACString& aContentType);
 
 
+  void RegisterTraceableChannel(const WebExtensionPolicy& aAddon, nsITabParent* aTabParent);
+
+  already_AddRefed<nsIChannel> GetTraceableChannel(nsIAtom* aAddonId, dom::nsIContentParent* aContentParent) const;
+
+
   void GetMethod(nsCString& aRetVal) const;
 
   dom::MozContentPolicyType Type() const;
 
 
   uint32_t StatusCode() const;
 
   void GetStatusLine(nsCString& aRetVal) const;
@@ -256,24 +273,29 @@ private:
   UniquePtr<WebRequestChannelEntry> mChannelEntry;
 
   // The overridden Content-Type header value.
   nsCString mContentTypeHdr = VoidCString();
 
   mutable Maybe<URLInfo> mFinalURLInfo;
   mutable Maybe<URLInfo> mDocumentURLInfo;
 
+  UniquePtr<WebRequestChannelEntry> mChannelEntry;
+
   const uint64_t mId = GetNextId();
   nsCOMPtr<nsISupports> mParent;
 
   bool mAddedStreamListener = false;
   bool mFiredErrorEvent = false;
   bool mSuspended = false;
 
 
+  nsInterfaceHashtable<nsPtrHashKey<const nsIAtom>, nsITabParent> mAddonEntries;
+
+
   class RequestListener final : public nsIStreamListener
                               , public nsIThreadRetargetableStreamListener
   {
   public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIREQUESTOBSERVER
     NS_DECL_NSISTREAMLISTENER
     NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
--- a/toolkit/components/extensions/webrequest/WebRequestService.cpp
+++ b/toolkit/components/extensions/webrequest/WebRequestService.cpp
@@ -3,54 +3,29 @@
 /* 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 "nsTArray.h"
-
-#include "mozilla/dom/TabParent.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
+using namespace mozilla::extensions;
 
 static WebRequestService* sWeakWebRequestService;
 
-WebRequestService::WebRequestService()
-  : mDataLock("WebRequest service data lock")
-{
-}
-
 WebRequestService::~WebRequestService()
 {
-  // Store existing entries in an array, since Detach can't safely remove them
-  // while we're iterating the hashtable.
-  AutoTArray<ChannelEntry*, 32> entries;
-  for (auto iter = mChannelEntries.Iter(); !iter.Done(); iter.Next()) {
-    entries.AppendElement(iter.Data());
-  }
-
-  for (auto channel : entries) {
-    channel->DetachAll();
-  }
-
   sWeakWebRequestService = nullptr;
 }
 
-NS_IMPL_ISUPPORTS(WebRequestService, mozIWebRequestService)
-
 /* static */ WebRequestService&
 WebRequestService::GetSingleton()
 {
   static RefPtr<WebRequestService> instance;
   if (!sWeakWebRequestService) {
     instance = new WebRequestService();
     ClearOnShutdown(&instance);
 
@@ -58,131 +33,46 @@ WebRequestService::GetSingleton()
     // original service is alive, even after our strong reference is cleared to
     // allow the service to be destroyed.
     sWeakWebRequestService = instance;
   }
   return *sWeakWebRequestService;
 }
 
 
-NS_IMETHODIMP
-WebRequestService::RegisterTraceableChannel(uint64_t aChannelId,
-                                            nsIChannel* aChannel,
-                                            const nsAString& aAddonId,
-                                            nsITabParent* aTabParent,
-                                            nsIJSRAIIHelper** aHelper)
+UniquePtr<WebRequestChannelEntry>
+WebRequestService::RegisterChannel(ChannelWrapper* aChannel)
 {
-  nsCOMPtr<nsITraceableChannel> traceableChannel = do_QueryInterface(aChannel);
-  NS_ENSURE_TRUE(traceableChannel, NS_ERROR_INVALID_ARG);
+  UniquePtr<ChannelEntry> entry(new ChannelEntry(aChannel));
 
-  nsCOMPtr<nsIAtom> addonId = NS_Atomize(aAddonId);
-  ChannelParent* entry = new ChannelParent(aChannelId, aChannel,
-                                           addonId, aTabParent);
+  auto key = mChannelEntries.LookupForAdd(entry->mChannelId);
+  MOZ_DIAGNOSTIC_ASSERT(!key);
+  key.OrInsert([&entry]() { return entry.get(); });
 
-  RefPtr<Destructor> destructor = new Destructor(entry);
-  destructor.forget(aHelper);
+  return Move(entry);
 
-  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;
-  }
+  if (auto entry = mChannelEntries.Get(aChannelId)) {
+    if (entry->mChannel) {
+      return entry->mChannel->GetTraceableChannel(aAddonId, aContentParent);
 
-  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 = &GetSingleton();
-  MutexAutoLock al(service->mDataLock);
-
-  auto entry = service->mChannelEntries.LookupOrAdd(mChannelId);
+WebRequestChannelEntry::WebRequestChannelEntry(ChannelWrapper* aChannel)
+  : mChannelId(aChannel->Id())
+  , mChannel(aChannel)
+{}
 
-  entry->mChannel = do_GetWeakReference(aChannel);
-  entry->mTabParents.insertBack(this);
-}
-
-WebRequestService::ChannelParent::~ChannelParent()
-{
-  MOZ_ASSERT(mDetached);
-}
-
-void
-WebRequestService::ChannelParent::Detach()
+WebRequestChannelEntry::~WebRequestChannelEntry()
 {
-  if (mDetached) {
-    return;
-  }
-  auto service = &GetSingleton();
-  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);
-  }
-  mDetached = true;
-}
-
-void
-WebRequestService::ChannelEntry::DetachAll()
-{
-  // Store the next link gecore calling Detach(), since the last Detach() call
-  // will destroy this instance and poison our mTabParents member.
-  for (ChannelParent *parent, *next = mTabParents.getFirst();
-       (parent = next);) {
-    next = parent->getNext();
-    parent->Detach();
+  if (sWeakWebRequestService) {
+    sWeakWebRequestService->mChannelEntries.Remove(mChannelId);
   }
 }
-
-WebRequestService::Destructor::~Destructor()
-{
-  if (NS_WARN_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)
--- a/toolkit/components/extensions/webrequest/WebRequestService.h
+++ b/toolkit/components/extensions/webrequest/WebRequestService.h
@@ -2,103 +2,78 @@
 /* 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/UniquePtr.h"
 
-#include "mozilla/LinkedList.h"
-#include "mozilla/Mutex.h"
-#include "nsCOMPtr.h"
+#include "mozilla/extensions/ChannelWrapper.h"
+#include "mozilla/extensions/WebExtensionPolicy.h"
+
 #include "nsHashKeys.h"
-#include "nsClassHashtable.h"
-#include "nsIAtom.h"
-#include "nsIDOMWindowUtils.h"
-#include "nsWeakPtr.h"
+#include "nsDataHashtable.h"
 
-using namespace mozilla;
+class nsIAtom;
+class nsITabParent;
 
 namespace mozilla {
 namespace dom {
   class TabParent;
   class nsIContentParent;
 }
-}
 
-class WebRequestService : public mozIWebRequestService
+namespace extensions {
+
+class WebRequestChannelEntry final
 {
 public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_MOZIWEBREQUESTSERVICE
+  ~WebRequestChannelEntry();
+
+private:
+  friend class WebRequestService;
+
+  WebRequestChannelEntry(ChannelWrapper* aChannel);
 
-  explicit WebRequestService();
+  uint64_t mChannelId;
+  WeakPtr<ChannelWrapper> mChannel;
+};
+
+class WebRequestService final
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(WebRequestService)
+
+  WebRequestService() = default;
 
   static already_AddRefed<WebRequestService> GetInstance()
   {
     return do_AddRef(&GetSingleton());
   }
 
   static WebRequestService& GetSingleton();
 
+  using ChannelEntry = WebRequestChannelEntry;
+
+  UniquePtr<ChannelEntry> RegisterChannel(ChannelWrapper* aChannel);
+
+  void UnregisterTraceableChannel(uint64_t aChannelId);
+
   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;
-    bool mDetached = false;
-  };
-
-  class Destructor : public nsIJSRAIIHelper
-  {
-  public:
-    NS_DECL_ISUPPORTS
-    NS_DECL_NSIJSRAIIHELPER
+  ~WebRequestService();
 
-    explicit Destructor(ChannelParent* aChannelParent)
-      : mChannelParent(aChannelParent)
-      , mDestructCalled(false)
-    {}
-
-  protected:
-    virtual ~Destructor();
-
-  private:
-    ChannelParent* mChannelParent;
-    bool mDestructCalled;
-  };
+  friend ChannelEntry;
 
-  class ChannelEntry
-  {
-  public:
-    void DetachAll();
-
-    // 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;
+  nsDataHashtable<nsUint64HashKey, ChannelEntry*> mChannelEntries;
 };
 
+}
+}
+
 #endif // mozilla_WebRequestService_h
--- a/toolkit/components/extensions/webrequest/moz.build
+++ b/toolkit/components/extensions/webrequest/moz.build
@@ -1,20 +1,14 @@
 # -*- 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',
-]
-
-XPIDL_MODULE = 'webextensions'
-
 UNIFIED_SOURCES += [
     'ChannelWrapper.cpp',
     'StreamFilter.cpp',
     'StreamFilterChild.cpp',
     'StreamFilterEvents.cpp',
     'StreamFilterParent.cpp',
     'WebRequestService.cpp',
 ]
deleted file mode 100644
--- a/toolkit/components/extensions/webrequest/mozIWebRequestService.idl
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 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);
-};
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -22,20 +22,16 @@ Cu.import("resource://gre/modules/XPCOMU
 
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionUtils",
                                   "resource://gre/modules/ExtensionUtils.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WebRequestCommon",
                                   "resource://gre/modules/WebRequestCommon.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "WebRequestUpload",
                                   "resource://gre/modules/WebRequestUpload.jsm");
 
-XPCOMUtils.defineLazyServiceGetter(this, "webReqService",
-                                   "@mozilla.org/addons/webrequest-service;1",
-                                   "mozIWebRequestService");
-
 XPCOMUtils.defineLazyGetter(this, "ExtensionError", () => ExtensionUtils.ExtensionError);
 
 function runLater(job) {
   Services.tm.dispatchToMainThread(job);
 }
 
 function parseFilter(filter) {
   if (!filter) {
@@ -696,53 +692,24 @@ HttpObserverManager = {
       proxyInfo: channel.proxyInfo,
 
       serialize: serializeRequestData,
     };
 
     return Object.assign(data, extraData);
   },
 
-  registerChannel(channel, opts) {
-    if (!opts.blockingAllowed || !opts.addonId) {
-      return;
-    }
-
-    if (!channel.registeredFilters) {
-      channel.registeredFilters = new Map();
-    } else if (channel.registeredFilters.has(opts.addonId)) {
-      return;
-    }
-
-    let filter = webReqService.registerTraceableChannel(
-      channel.id,
-      channel.channel,
-      opts.addonId,
-      opts.tabParent);
-
-    channel.registeredFilters.set(opts.addonId, filter);
-  },
-
-  destroyFilters(channel) {
-    let filters = channel.registeredFilters || new Map();
-    for (let [key, filter] of filters.entries()) {
-      filter.destruct();
-      filters.delete(key);
-    }
-  },
-
   handleEvent(event) {
     let channel = event.currentTarget;
     switch (event.type) {
       case "error":
         this.runChannelListener(
           channel, "onError", {error: channel.errorString});
         break;
       case "start":
-        this.destroyFilters(channel);
         this.runChannelListener(channel, "onStart");
         break;
       case "stop":
         this.runChannelListener(channel, "onStop");
         break;
     }
   },
 
@@ -770,18 +737,18 @@ HttpObserverManager = {
           commonData = this.getRequestData(channel, extraData);
           if (includeStatus) {
             commonData.statusCode = channel.statusCode;
             commonData.statusLine = channel.statusLine;
           }
         }
         let data = Object.assign({}, commonData);
 
-        if (registerFilter && opts.blocking) {
-          this.registerChannel(channel, opts);
+        if (registerFilter && opts.blocking && opts.extension) {
+          channel.registerTraceableChannel(opts.extension, opts.tabParent);
         }
 
         if (opts.requestHeaders) {
           requestHeaders = requestHeaders || new RequestHeaderChanger(channel);
           data.requestHeaders = requestHeaders.toArray();
         }
 
         if (opts.responseHeaders) {
@@ -902,17 +869,16 @@ HttpObserverManager = {
     }
   },
 
   onChannelReplaced(oldChannel, newChannel) {
     let channel = this.getWrapper(oldChannel);
 
     // We want originalURI, this will provide a moz-ext rather than jar or file
     // uri on redirects.
-    this.destroyFilters(channel);
     this.runChannelListener(channel, "onRedirect", {redirectUrl: newChannel.originalURI.spec});
     channel.channel = newChannel;
   },
 };
 
 var onBeforeRequest = {
   allowedOptions: ["blocking", "requestBody"],