Bug 1402944: Part 4 - Fold start/stop listener into ChannelWrapper. r=mixedpuppy,ehsan
authorKris Maglione <maglione.k@gmail.com>
Tue, 26 Sep 2017 13:39:30 -0700
changeset 383531 364f04c7fee00054c8af092229ff01ed3a2f7bdc
parent 383530 2c79c9374ca7899ce4e9fb81382976cbaaef0221
child 383532 cd219dd09639d421b6ebf2f85ada518dd8a4c0c2
push id32595
push userkwierso@gmail.com
push dateThu, 28 Sep 2017 23:57:40 +0000
treeherdermozilla-central@e6c32278f32c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmixedpuppy, ehsan
bugs1402944
milestone58.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 1402944: Part 4 - Fold start/stop listener into ChannelWrapper. r=mixedpuppy,ehsan MozReview-Commit-ID: 52zZNjgaCEj
dom/webidl/ChannelWrapper.webidl
toolkit/components/build/nsToolkitCompsModule.cpp
toolkit/components/extensions/test/xpcshell/test_ext_redirects.js
toolkit/components/extensions/webrequest/ChannelWrapper.cpp
toolkit/components/extensions/webrequest/ChannelWrapper.h
toolkit/components/extensions/webrequest/moz.build
toolkit/components/extensions/webrequest/nsIWebRequestListener.idl
toolkit/components/extensions/webrequest/nsWebRequestListener.cpp
toolkit/components/extensions/webrequest/nsWebRequestListener.h
toolkit/modules/addons/WebRequest.jsm
--- a/dom/webidl/ChannelWrapper.webidl
+++ b/dom/webidl/ChannelWrapper.webidl
@@ -164,16 +164,27 @@ interface ChannelWrapper : EventTarget {
   /**
    * Checks the request's current status and dispatches an error event if the
    * request has failed and one has not already been dispatched.
    */
   void errorCheck();
 
 
   /**
+   * Dispatched when the channel begins receiving data.
+   */
+  attribute EventHandler onstart;
+
+  /**
+   * Dispatched when the channel has finished receiving data.
+   */
+  attribute EventHandler onstop;
+
+
+  /**
    * Information about the proxy server which is handling this request, or
    * null if the request is not proxied.
    */
   [Cached, Frozen, GetterThrows, Pure]
   readonly attribute MozProxyInfo? proxyInfo;
 
   /**
    * For HTTP requests, the IP address of the remote server handling the
--- a/toolkit/components/build/nsToolkitCompsModule.cpp
+++ b/toolkit/components/build/nsToolkitCompsModule.cpp
@@ -41,18 +41,16 @@
 #include "mozilla/WebRequestService.h"
 
 #if defined(XP_WIN)
 #include "NativeFileWatcherWin.h"
 #else
 #include "NativeFileWatcherNotSupported.h"
 #endif // (XP_WIN)
 
-#include "nsWebRequestListener.h"
-
 #if !defined(MOZ_WIDGET_ANDROID)
 #define MOZ_HAS_TERMINATOR
 #endif
 
 #if defined(MOZ_HAS_TERMINATOR)
 #include "nsTerminator.h"
 #endif
 
@@ -126,18 +124,16 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(NativeOSF
 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)
 
 #if defined(MOZ_HAS_TERMINATOR)
 NS_DEFINE_NAMED_CID(NS_TOOLKIT_TERMINATOR_CID);
 #endif
@@ -163,17 +159,16 @@ NS_DEFINE_NAMED_CID(NS_UPDATEPROCESSOR_C
 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
 #if defined(MOZ_HAS_PERFSTATS)
   { &kNS_TOOLKIT_PERFORMANCESTATSSERVICE_CID, false, nullptr, nsPerformanceStatsServiceConstructor },
@@ -200,17 +195,16 @@ static const Module::CIDEntry kToolkitCI
   { &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)
   { NS_TOOLKIT_TERMINATOR_CONTRACTID, &kNS_TOOLKIT_TERMINATOR_CID },
 #endif
@@ -240,17 +234,16 @@ static const Module::ContractIDEntry kTo
   { 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/test/xpcshell/test_ext_redirects.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_redirects.js
@@ -1,51 +1,50 @@
 "use strict";
 
 // Tests whether we can redirect to a moz-extension: url.
 XPCOMUtils.defineLazyModuleGetter(this, "TestUtils",
                                   "resource://testing-common/TestUtils.jsm");
 const XMLHttpRequest = Components.Constructor("@mozilla.org/xmlextras/xmlhttprequest;1", "nsIXMLHttpRequest");
 
-// nsIWebRequestListener is a nsIThreadRetargetableStreamListener that handles
-// forwarding of nsIRequestObserver for JS consumers.  It does nothing more
-// than that.
-let WebRequestListener = Components.Constructor("@mozilla.org/webextensions/webRequestListener;1",
-                                                "nsIWebRequestListener", "init");
-
 const server = createHttpServer();
 const gServerUrl = `http://localhost:${server.identity.primaryPort}`;
 
 server.registerPathHandler("/redirect", (request, response) => {
   let params = new URLSearchParams(request.queryString);
   response.setStatusLine(request.httpVersion, 302, "Moved Temporarily");
   response.setHeader("Location", params.get("redirect_uri"));
 });
 
 server.registerPathHandler("/dummy", (request, response) => {
   response.setStatusLine(request.httpVersion, 200, "OK");
   response.write("ok");
 });
 
 function onStopListener(channel) {
   return new Promise(resolve => {
-    new WebRequestListener({
+    let orig = channel.QueryInterface(Ci.nsITraceableChannel).setNewListener({
       QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver,
                                              Ci.nsIStreamListener]),
       getFinalURI(request) {
         let {loadInfo} = request;
         return (loadInfo && loadInfo.resultPrincipalURI) || request.originalURI;
       },
+      onDataAvailable(...args) {
+        orig.onDataAvailable(...args);
+      },
       onStartRequest(request, context) {
+        orig.onStartRequest(request, context);
       },
       onStopRequest(request, context, statusCode) {
+        orig.onStopRequest(request, context, statusCode);
         let URI = this.getFinalURI(request.QueryInterface(Ci.nsIChannel));
         resolve(URI && URI.spec);
       },
-    }, channel);
+    });
   });
 }
 
 async function onModifyListener(originUrl, redirectToUrl) {
   return TestUtils.topicObserved("http-on-modify-request", (subject, data) => {
     let channel = subject.QueryInterface(Ci.nsIHttpChannel);
     return channel.URI && channel.URI.spec == originUrl;
   }).then(([subject, data]) => {
--- a/toolkit/components/extensions/webrequest/ChannelWrapper.cpp
+++ b/toolkit/components/extensions/webrequest/ChannelWrapper.cpp
@@ -24,18 +24,20 @@
 #include "nsIHttpChannelInternal.h"
 #include "nsIHttpHeaderVisitor.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
 #include "nsILoadContext.h"
 #include "nsILoadGroup.h"
 #include "nsIProxiedChannel.h"
 #include "nsIProxyInfo.h"
+#include "nsITraceableChannel.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsNetUtil.h"
+#include "nsProxyRelease.h"
 #include "nsPrintfCString.h"
 
 using namespace mozilla::dom;
 using namespace JS;
 
 namespace mozilla {
 namespace extensions {
 
@@ -768,16 +770,84 @@ ChannelWrapper::ErrorCheck()
       mFiredErrorEvent = true;
       ChannelWrapperBinding::ClearCachedErrorStringValue(this);
       FireEvent(NS_LITERAL_STRING("error"));
     }
   }
 }
 
 /*****************************************************************************
+ * nsIWebRequestListener
+ *****************************************************************************/
+
+NS_IMPL_ISUPPORTS(ChannelWrapper::RequestListener,
+                  nsIStreamListener,
+                  nsIRequestObserver,
+                  nsIThreadRetargetableStreamListener)
+
+ChannelWrapper::RequestListener::~RequestListener() {
+  NS_ReleaseOnMainThreadSystemGroup("RequestListener::mChannelWrapper",
+                                    mChannelWrapper.forget());
+}
+
+nsresult
+ChannelWrapper::RequestListener::Init()
+{
+  if (nsCOMPtr<nsITraceableChannel> chan = mChannelWrapper->QueryChannel()) {
+    return chan->SetNewListener(this, getter_AddRefs(mOrigStreamListener));
+  }
+  return NS_ERROR_UNEXPECTED;
+}
+
+NS_IMETHODIMP
+ChannelWrapper::RequestListener::OnStartRequest(nsIRequest *request, nsISupports * aCtxt)
+{
+  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
+
+  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->ErrorCheck();
+  mChannelWrapper->FireEvent(NS_LITERAL_STRING("stop"));
+
+  return mOrigStreamListener->OnStopRequest(request, aCtxt, aStatus);
+}
+
+NS_IMETHODIMP
+ChannelWrapper::RequestListener::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
+                                             nsIInputStream * inStr,
+                                             uint64_t sourceOffset, uint32_t count)
+{
+  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
+  return mOrigStreamListener->OnDataAvailable(request, aCtxt, inStr, sourceOffset, count);
+}
+
+NS_IMETHODIMP
+ChannelWrapper::RequestListener::CheckListenerChain()
+{
+    MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread!");
+    nsresult rv;
+    nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
+        do_QueryInterface(mOrigStreamListener, &rv);
+    if (retargetableListener) {
+        return retargetableListener->CheckListenerChain();
+    }
+    return rv;
+}
+
+/*****************************************************************************
  * Event dispatching
  *****************************************************************************/
 
 void
 ChannelWrapper::FireEvent(const nsAString& aType)
 {
   EventInit init;
   init.mBubbles = false;
@@ -785,16 +855,41 @@ ChannelWrapper::FireEvent(const nsAStrin
 
   RefPtr<Event> event = Event::Constructor(this, aType, init);
   event->SetTrusted(true);
 
   bool defaultPrevented;
   DispatchEvent(event, &defaultPrevented);
 }
 
+void
+ChannelWrapper::CheckEventListeners()
+{
+  if (!mAddedStreamListener && (HasListenersFor(nsGkAtoms::onerror) ||
+                                HasListenersFor(nsGkAtoms::onstart) ||
+                                HasListenersFor(nsGkAtoms::onstop))) {
+    auto listener = MakeRefPtr<RequestListener>(this);
+    if (!NS_WARN_IF(NS_FAILED(listener->Init()))) {
+      mAddedStreamListener = true;
+    }
+  }
+}
+
+void
+ChannelWrapper::EventListenerAdded(nsIAtom* aType)
+{
+  CheckEventListeners();
+}
+
+void
+ChannelWrapper::EventListenerRemoved(nsIAtom* aType)
+{
+  CheckEventListeners();
+}
+
 /*****************************************************************************
  * Glue
  *****************************************************************************/
 
 JSObject*
 ChannelWrapper::WrapObject(JSContext* aCx, HandleObject aGivenProto)
 {
   return ChannelWrapperBinding::Wrap(aCx, this, aGivenProto);
--- a/toolkit/components/extensions/webrequest/ChannelWrapper.h
+++ b/toolkit/components/extensions/webrequest/ChannelWrapper.h
@@ -13,16 +13,18 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/Maybe.h"
 
 #include "mozilla/DOMEventTargetHelper.h"
 #include "nsCOMPtr.h"
 #include "nsCycleCollectionParticipant.h"
 #include "nsIChannel.h"
 #include "nsIHttpChannel.h"
+#include "nsIStreamListener.h"
+#include "nsIThreadRetargetableStreamListener.h"
 #include "nsWeakPtr.h"
 #include "nsWrapperCache.h"
 
 #define NS_CHANNELWRAPPER_IID \
 { 0xc06162d2, 0xb803, 0x43b4, \
   { 0xaa, 0x31, 0xcf, 0x69, 0x7f, 0x93, 0x68, 0x1c } }
 
 class nsIDOMElement;
@@ -134,16 +136,18 @@ public:
 
   void GetStatusLine(nsCString& aRetVal) const;
 
   void GetErrorString(nsString& aRetVal) const;
 
   void ErrorCheck();
 
   IMPL_EVENT_HANDLER(error);
+  IMPL_EVENT_HANDLER(start);
+  IMPL_EVENT_HANDLER(stop);
 
 
   already_AddRefed<nsIURI> GetFinalURI(ErrorResult& aRv) const;
 
   void GetFinalURL(nsCString& aRetVal, ErrorResult& aRv) const;
 
 
   already_AddRefed<nsILoadInfo> GetLoadInfo() const
@@ -188,16 +192,22 @@ public:
 
   void GetResponseHeaders(JSContext* cx, JS::MutableHandle<JSObject*> aRetVal, ErrorResult& aRv) const;
 
   void SetRequestHeader(const nsCString& header, const nsCString& value, ErrorResult& aRv);
 
   void SetResponseHeader(const nsCString& header, const nsCString& value, ErrorResult& aRv);
 
 
+  using EventTarget::EventListenerAdded;
+  using EventTarget::EventListenerRemoved;
+  virtual void EventListenerAdded(nsIAtom* aType) override;
+  virtual void EventListenerRemoved(nsIAtom* aType) override;
+
+
   nsISupports* GetParentObject() const { return mParent; }
 
   JSObject* WrapObject(JSContext* aCx, JS::HandleObject aGivenProto) override;
 
 protected:
   ~ChannelWrapper() = default;
 
 private:
@@ -224,22 +234,55 @@ private:
   nsresult GetFrameAncestors(nsILoadInfo* aLoadInfo, nsTArray<dom::MozFrameAncestorInfo>& aFrameAncestors) const;
 
   static uint64_t GetNextId()
   {
     static uint64_t sNextId = 1;
     return ++sNextId;
   }
 
+  void CheckEventListeners();
+
+  mutable Maybe<URLInfo> mFinalURLInfo;
+  mutable Maybe<URLInfo> mDocumentURLInfo;
+
+  UniquePtr<WebRequestChannelEntry> mChannelEntry;
+
+  // The overridden Content-Type header value.
+  nsCString mContentTypeHdr = VoidCString();
 
   const uint64_t mId = GetNextId();
   nsCOMPtr<nsISupports> mParent;
 
+  bool mAddedStreamListener = false;
   bool mFiredErrorEvent = false;
   bool mSuspended = false;
+
+
+  class RequestListener final : public nsIStreamListener
+                              , public nsIThreadRetargetableStreamListener
+  {
+  public:
+    NS_DECL_THREADSAFE_ISUPPORTS
+    NS_DECL_NSIREQUESTOBSERVER
+    NS_DECL_NSISTREAMLISTENER
+    NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
+
+    explicit RequestListener(ChannelWrapper* aWrapper)
+      : mChannelWrapper(aWrapper) {}
+
+    nsresult Init();
+
+  protected:
+    virtual ~RequestListener();
+
+  private:
+    RefPtr<ChannelWrapper> mChannelWrapper;
+    nsCOMPtr<nsIStreamListener> mOrigStreamListener;
+  };
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(ChannelWrapper,
                               NS_CHANNELWRAPPER_IID)
 
 } // namespace extensions
 } // namespace mozilla
 
--- a/toolkit/components/extensions/webrequest/moz.build
+++ b/toolkit/components/extensions/webrequest/moz.build
@@ -1,39 +1,33 @@
 # -*- 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 += [
     'ChannelWrapper.cpp',
-    'nsWebRequestListener.cpp',
     'StreamFilter.cpp',
     'StreamFilterChild.cpp',
     'StreamFilterEvents.cpp',
     'StreamFilterParent.cpp',
     'WebRequestService.cpp',
 ]
 
 IPDL_SOURCES += [
     'PStreamFilter.ipdl',
 ]
 
-EXPORTS += [
-    'nsWebRequestListener.h',
-]
-
 EXPORTS.mozilla += [
     'WebRequestService.h',
 ]
 
 EXPORTS.mozilla.extensions += [
     'ChannelWrapper.h',
     'StreamFilter.h',
     'StreamFilterBase.h',
deleted file mode 100644
--- a/toolkit/components/extensions/webrequest/nsIWebRequestListener.idl
+++ /dev/null
@@ -1,28 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/* 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"
-#include "nsIStreamListener.idl"
-#include "nsITraceableChannel.idl"
-
-/* nsIWebRequestListener is a nsIThreadRetargetableStreamListener that handles
- * forwarding of nsIRequestObserver for JS consumers. nsIWebRequestListener
- * is not cycle collected, JS consumers should not keep a reference to this.
- */
-
-[scriptable, uuid(699a50bb-1f18-2844-b9ea-9f216f62cb18)]
-interface nsIWebRequestListener : nsISupports
-{
-  void init(in nsIStreamListener aStreamListener,
-            in nsITraceableChannel aTraceableChannel);
-};
-
-%{C++
-/* ebea9901-e135-b546-82e2-052666992dbb */
-#define NS_WEBREQUESTLISTENER_CID                   \
- {0xebea9901, 0xe135, 0xb546,                       \
- {0x82, 0xe2, 0x05, 0x26, 0x66, 0x99, 0x2d, 0xbb} }
-#define NS_WEBREQUESTLISTENER_CONTRACTID "@mozilla.org/webextensions/webRequestListener;1"
-%}
\ No newline at end of file
deleted file mode 100644
--- a/toolkit/components/extensions/webrequest/nsWebRequestListener.cpp
+++ /dev/null
@@ -1,72 +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 "mozilla/ModuleUtils.h"
-#include "nsWebRequestListener.h"
-
-#ifdef DEBUG
-#include "MainThreadUtils.h"
-#endif
-
-using namespace mozilla;
-
-NS_IMPL_ISUPPORTS(nsWebRequestListener,
-                  nsIWebRequestListener,
-                  nsIStreamListener,
-                  nsIRequestObserver,
-                  nsIThreadRetargetableStreamListener)
-
-NS_IMETHODIMP
-nsWebRequestListener::Init(nsIStreamListener *aStreamListener, nsITraceableChannel *aTraceableChannel)
-{
-  MOZ_ASSERT(aStreamListener, "Should have aStreamListener");
-  MOZ_ASSERT(aTraceableChannel, "Should have aTraceableChannel");
-  mTargetStreamListener = aStreamListener;
-  return aTraceableChannel->SetNewListener(this, getter_AddRefs(mOrigStreamListener));
-}
-
-NS_IMETHODIMP
-nsWebRequestListener::OnStartRequest(nsIRequest *request, nsISupports * aCtxt)
-{
-  MOZ_ASSERT(mTargetStreamListener, "Should have mTargetStreamListener");
-  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
-
-  mTargetStreamListener->OnStartRequest(request, aCtxt);
-
-  return mOrigStreamListener->OnStartRequest(request, aCtxt);
-}
-
-NS_IMETHODIMP
-nsWebRequestListener::OnStopRequest(nsIRequest *request, nsISupports *aCtxt,
-                                           nsresult aStatus)
-{
-  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
-  MOZ_ASSERT(mTargetStreamListener, "Should have mTargetStreamListener");
-
-  mOrigStreamListener->OnStopRequest(request, aCtxt, aStatus);
-
-  return mTargetStreamListener->OnStopRequest(request, aCtxt, aStatus);
-}
-
-NS_IMETHODIMP
-nsWebRequestListener::OnDataAvailable(nsIRequest *request, nsISupports * aCtxt,
-                                             nsIInputStream * inStr,
-                                             uint64_t sourceOffset, uint32_t count)
-{
-  MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
-  return mOrigStreamListener->OnDataAvailable(request, aCtxt, inStr, sourceOffset, count);
-}
-
-NS_IMETHODIMP
-nsWebRequestListener::CheckListenerChain()
-{
-    MOZ_ASSERT(NS_IsMainThread(), "Should be on main thread!");
-    nsresult rv;
-    nsCOMPtr<nsIThreadRetargetableStreamListener> retargetableListener =
-        do_QueryInterface(mOrigStreamListener, &rv);
-    if (retargetableListener) {
-        return retargetableListener->CheckListenerChain();
-    }
-    return rv;
-}
deleted file mode 100644
--- a/toolkit/components/extensions/webrequest/nsWebRequestListener.h
+++ /dev/null
@@ -1,40 +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/. */
-
-#ifndef nsWebRequestListener_h__
-#define nsWebRequestListener_h__
-
-#include "nsCOMPtr.h"
-#include "nsIWebRequestListener.h"
-#include "nsIRequestObserver.h"
-#include "nsIStreamListener.h"
-#include "nsITraceableChannel.h"
-#include "nsIThreadRetargetableStreamListener.h"
-#include "nsProxyRelease.h"
-#include "mozilla/Attributes.h"
-
-class nsWebRequestListener final : public nsIWebRequestListener
-                                 , public nsIStreamListener
-                                 , public nsIThreadRetargetableStreamListener
-{
-public:
-  NS_DECL_THREADSAFE_ISUPPORTS
-  NS_DECL_NSIWEBREQUESTLISTENER
-  NS_DECL_NSIREQUESTOBSERVER
-  NS_DECL_NSISTREAMLISTENER
-  NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
-
-  nsWebRequestListener() {}
-
-private:
-  ~nsWebRequestListener() {
-    NS_ReleaseOnMainThreadSystemGroup("nsWebRequestListener::mTargetStreamListener",
-                                      mTargetStreamListener.forget());
-  }
-  nsCOMPtr<nsIStreamListener> mOrigStreamListener;
-  nsCOMPtr<nsIStreamListener> mTargetStreamListener;
-};
-
-#endif // nsWebRequestListener_h__
-
--- a/toolkit/modules/addons/WebRequest.jsm
+++ b/toolkit/modules/addons/WebRequest.jsm
@@ -28,19 +28,16 @@ XPCOMUtils.defineLazyModuleGetter(this, 
                                   "resource://gre/modules/WebRequestUpload.jsm");
 
 XPCOMUtils.defineLazyServiceGetter(this, "webReqService",
                                    "@mozilla.org/addons/webrequest-service;1",
                                    "mozIWebRequestService");
 
 XPCOMUtils.defineLazyGetter(this, "ExtensionError", () => ExtensionUtils.ExtensionError);
 
-let WebRequestListener = Components.Constructor("@mozilla.org/webextensions/webRequestListener;1",
-                                                "nsIWebRequestListener", "init");
-
 function runLater(job) {
   Services.tm.dispatchToMainThread(job);
 }
 
 function parseFilter(filter) {
   if (!filter) {
     filter = {};
   }
@@ -301,34 +298,16 @@ var ContentPolicyManager = {
 
     this.policyData.delete(id);
     this.idMap.delete(callback);
     this.policies.delete(id);
   },
 };
 ContentPolicyManager.init();
 
-function StartStopListener(manager, channel) {
-  this.manager = manager;
-  new WebRequestListener(this, channel.channel);
-}
-
-StartStopListener.prototype = {
-  QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver,
-                                         Ci.nsIStreamListener]),
-
-  onStartRequest: function(request, context) {
-    this.manager.onStartRequest(ChannelWrapper.get(request));
-  },
-
-  onStopRequest(request, context, statusCode) {
-    this.manager.onStopRequest(ChannelWrapper.get(request));
-  },
-};
-
 var ChannelEventSink = {
   _classDescription: "WebRequest channel event sink",
   _classID: Components.ID("115062f8-92f1-11e5-8b7f-080027b0f7ec"),
   _contractID: "@mozilla.org/webrequest/channel-event-sink;1",
 
   QueryInterface: XPCOMUtils.generateQI([Ci.nsIChannelEventSink,
                                          Ci.nsIFactory]),
 
@@ -527,16 +506,22 @@ HttpObserverManager = {
 
   getWrapper(nativeChannel) {
     let wrapper = ChannelWrapper.get(nativeChannel);
     if (!wrapper._addedListeners) {
       /* eslint-disable mozilla/balanced-listeners */
       if (this.listeners.onError.size) {
         wrapper.addEventListener("error", this);
       }
+      if (this.listeners.onStart.size) {
+        wrapper.addEventListener("start", this);
+      }
+      if (this.listeners.onStop.size) {
+        wrapper.addEventListener("stop", this);
+      }
       /* eslint-enable mozilla/balanced-listeners */
 
       wrapper._addedListeners = true;
     }
     return wrapper;
   },
 
   get activityDistributor() {
@@ -651,23 +636,16 @@ HttpObserverManager = {
   observeActivity(nativeChannel, activityType, activitySubtype /* , aTimestamp, aExtraSizeData, aExtraStringData */) {
     // Sometimes we get a NullHttpChannel, which implements
     // nsIHttpChannel but not nsIChannel.
     if (!(nativeChannel instanceof Ci.nsIChannel)) {
       return;
     }
     let channel = this.getWrapper(nativeChannel);
 
-    // StartStopListener has to be activated early in the request to catch
-    // SSL connection issues which do not get reported via nsIHttpActivityObserver.
-    if (activityType == nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION &&
-        activitySubtype == nsIHttpActivityObserver.ACTIVITY_SUBTYPE_REQUEST_HEADER) {
-      this.attachStartStopListener(channel);
-    }
-
     let lastActivity = channel.lastActivity || 0;
     if (activitySubtype === nsIHttpActivityObserver.ACTIVITY_SUBTYPE_RESPONSE_COMPLETE &&
         lastActivity && lastActivity !== this.GOOD_LAST_ACTIVITY) {
       // Make a trip through the event loop to make sure errors have a
       // chance to be processed before we fall back to a generic error
       // string.
       Services.tm.dispatchToMainThread(() => {
         channel.errorCheck();
@@ -767,16 +745,23 @@ HttpObserverManager = {
 
   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;
     }
   },
 
   runChannelListener(channel, kind, extraData = null) {
     let handlerResults = [];
     let requestHeaders;
     let responseHeaders;
 
@@ -925,35 +910,17 @@ HttpObserverManager = {
     for (let opts of listener.values()) {
       if (this.shouldRunListener(channel.type, channel.finalURI, opts.filter)) {
         return true;
       }
     }
     return false;
   },
 
-  attachStartStopListener(channel) {
-    // Check whether we've already added a listener to this channel,
-    // so we don't wind up chaining multiple listeners.
-    if (!this.needTracing || channel.hasListener ||
-        !(channel.channel instanceof Ci.nsITraceableChannel)) {
-      return;
-    }
-
-    // skip redirections, https://bugzilla.mozilla.org/show_bug.cgi?id=728901#c8
-    let {statusCode} = channel;
-    if (statusCode < 300 || statusCode >= 400) {
-      new StartStopListener(this, channel);
-      channel.hasListener = true;
-    }
-  },
-
   examine(channel, topic, data) {
-    this.attachStartStopListener(channel);
-
     if (this.listeners.headersReceived.size) {
       this.runChannelListener(channel, "headersReceived");
     }
 
     if (!channel.hasAuthRequestor && this.shouldHookListener(this.listeners.authRequired, channel)) {
       channel.channel.notificationCallbacks = new AuthRequestor(channel.channel, this);
       channel.hasAuthRequestor = true;
     }
@@ -963,25 +930,16 @@ HttpObserverManager = {
     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;
   },
-
-  onStartRequest(channel) {
-    this.destroyFilters(channel);
-    this.runChannelListener(channel, "onStart");
-  },
-
-  onStopRequest(channel) {
-    this.runChannelListener(channel, "onStop");
-  },
 };
 
 var onBeforeRequest = {
   allowedOptions: ["blocking", "requestBody"],
 
   addListener(callback, filter = null, options = null, optionsObject = null) {
     let opts = parseExtra(options, this.allowedOptions);
     opts.filter = parseFilter(filter);