From f6660740ac7c3604c6de46d8b992506aa88abbae Mon Sep 17 00:00:00 2001 From: Shane Caraveo Date: Tue, 18 Apr 2017 15:50:53 -0700 Subject: [PATCH] Bug 1326298 implement off-main-thread delivery with start/stop/error listeners, r=kmag MozReview-Commit-ID: Ke4NsthrbP2 --HG-- extra : rebase_source : 0324030e5f7f534256ff0c469bb486dc52e282c2 --- browser/installer/package-manifest.in | 1 + mobile/android/installer/package-manifest.in | 1 + .../components/build/nsToolkitCompsModule.cpp | 7 ++ toolkit/components/extensions/moz.build | 5 +- .../test/mochitest/file_WebRequest_page3.html | 4 +- .../mochitest/test_ext_webrequest_basic.html | 2 +- .../extensions/webrequest/moz.build | 21 ++++++ .../webrequest/nsIWebRequestListener.idl | 28 +++++++ .../webrequest/nsWebRequestListener.cpp | 74 +++++++++++++++++++ .../webrequest/nsWebRequestListener.h | 36 +++++++++ toolkit/modules/addons/WebRequest.jsm | 21 ++---- 11 files changed, 182 insertions(+), 18 deletions(-) create mode 100644 toolkit/components/extensions/webrequest/moz.build create mode 100644 toolkit/components/extensions/webrequest/nsIWebRequestListener.idl create mode 100644 toolkit/components/extensions/webrequest/nsWebRequestListener.cpp create mode 100644 toolkit/components/extensions/webrequest/nsWebRequestListener.h diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index 5bc0c2e0e191..66f973bfb25f 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -330,6 +330,7 @@ @RESPATH@/components/urlformatter.xpt @RESPATH@/components/webBrowser_core.xpt @RESPATH@/components/webbrowserpersist.xpt +@RESPATH@/components/webextensions.xpt @RESPATH@/components/widget.xpt #ifdef XP_MACOSX @RESPATH@/components/widget_cocoa.xpt diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index 620ba681aded..e81951a817c3 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -241,6 +241,7 @@ @BINPATH@/components/urlformatter.xpt @BINPATH@/components/webBrowser_core.xpt @BINPATH@/components/webbrowserpersist.xpt +@BINPATH@/components/webextensions.xpt @BINPATH@/components/widget.xpt @BINPATH@/components/widget_android.xpt @BINPATH@/components/windowcreator.xpt diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index 675c8c92b087..88007fecf4b3 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -44,6 +44,8 @@ #include "NativeFileWatcherNotSupported.h" #endif // (XP_WIN) +#include "nsWebRequestListener.h" + #if !defined(MOZ_WIDGET_GONK) && !defined(MOZ_WIDGET_ANDROID) #define MOZ_HAS_TERMINATOR #endif @@ -125,6 +127,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(NativeFileWatcherService, Init) NS_GENERIC_FACTORY_CONSTRUCTOR(AddonContentPolicy) NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AddonPathService, AddonPathService::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); @@ -158,6 +162,7 @@ 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(NATIVE_FILEWATCHER_SERVICE_CID); +NS_DEFINE_NAMED_CID(NS_WEBREQUESTLISTENER_CID); static const Module::CIDEntry kToolkitCIDs[] = { { &kNS_TOOLKIT_APPSTARTUP_CID, false, nullptr, nsAppStartupConstructor }, @@ -192,6 +197,7 @@ static const Module::CIDEntry kToolkitCIDs[] = { { &kNS_ADDONCONTENTPOLICY_CID, false, nullptr, AddonContentPolicyConstructor }, { &kNS_ADDON_PATH_SERVICE_CID, false, nullptr, AddonPathServiceConstructor }, { &kNATIVE_FILEWATCHER_SERVICE_CID, false, nullptr, NativeFileWatcherServiceConstructor }, + { &kNS_WEBREQUESTLISTENER_CID, false, nullptr, nsWebRequestListenerConstructor }, { nullptr } }; @@ -228,6 +234,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = { { NS_ADDONCONTENTPOLICY_CONTRACTID, &kNS_ADDONCONTENTPOLICY_CID }, { NS_ADDONPATHSERVICE_CONTRACTID, &kNS_ADDON_PATH_SERVICE_CID }, { NATIVE_FILEWATCHER_SERVICE_CONTRACTID, &kNATIVE_FILEWATCHER_SERVICE_CID }, + { NS_WEBREQUESTLISTENER_CONTRACTID, &kNS_WEBREQUESTLISTENER_CID }, { nullptr } }; diff --git a/toolkit/components/extensions/moz.build b/toolkit/components/extensions/moz.build index a653a61f7a88..3106cfa5a875 100644 --- a/toolkit/components/extensions/moz.build +++ b/toolkit/components/extensions/moz.build @@ -39,7 +39,10 @@ TESTING_JS_MODULES += [ 'ExtensionXPCShellUtils.jsm', ] -DIRS += ['schemas'] +DIRS += [ + 'schemas', + 'webrequest', +] JAR_MANIFESTS += ['jar.mn'] diff --git a/toolkit/components/extensions/test/mochitest/file_WebRequest_page3.html b/toolkit/components/extensions/test/mochitest/file_WebRequest_page3.html index 5807dd439f24..d33cc8ec801c 100644 --- a/toolkit/components/extensions/test/mochitest/file_WebRequest_page3.html +++ b/toolkit/components/extensions/test/mochitest/file_WebRequest_page3.html @@ -5,7 +5,9 @@ diff --git a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html index 3a0c83a9e161..c6f246f084ff 100644 --- a/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html +++ b/toolkit/components/extensions/test/mochitest/test_ext_webrequest_basic.html @@ -239,7 +239,7 @@ add_task(function* test_webRequest_tabId() { }; extension.sendMessage("set-expected", {expect, origin: location.href}); yield extension.awaitMessage("continue"); - let a = addLink("file_WebRequest_page3.html?trigger=a"); + let a = addLink(`file_WebRequest_page3.html?trigger=a&nocache=${Math.random()}`); a.click(); yield extension.awaitMessage("done"); }); diff --git a/toolkit/components/extensions/webrequest/moz.build b/toolkit/components/extensions/webrequest/moz.build new file mode 100644 index 000000000000..49bc4fe568ce --- /dev/null +++ b/toolkit/components/extensions/webrequest/moz.build @@ -0,0 +1,21 @@ +# -*- 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 += [ + 'nsIWebRequestListener.idl', +] + +XPIDL_MODULE = 'webextensions' + +EXPORTS += [ + 'nsWebRequestListener.h', +] + +UNIFIED_SOURCES += [ + 'nsWebRequestListener.cpp', +] + +FINAL_LIBRARY = 'xul' \ No newline at end of file diff --git a/toolkit/components/extensions/webrequest/nsIWebRequestListener.idl b/toolkit/components/extensions/webrequest/nsIWebRequestListener.idl new file mode 100644 index 000000000000..94d4819f3e9d --- /dev/null +++ b/toolkit/components/extensions/webrequest/nsIWebRequestListener.idl @@ -0,0 +1,28 @@ +/* -*- 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 diff --git a/toolkit/components/extensions/webrequest/nsWebRequestListener.cpp b/toolkit/components/extensions/webrequest/nsWebRequestListener.cpp new file mode 100644 index 000000000000..35965552df92 --- /dev/null +++ b/toolkit/components/extensions/webrequest/nsWebRequestListener.cpp @@ -0,0 +1,74 @@ +/* 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"); + + nsresult rv = mTargetStreamListener->OnStartRequest(request, aCtxt); + NS_ENSURE_SUCCESS(rv, rv); + + 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"); + + nsresult rv = mOrigStreamListener->OnStopRequest(request, aCtxt, aStatus); + NS_ENSURE_SUCCESS(rv, rv); + + 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 retargetableListener = + do_QueryInterface(mOrigStreamListener, &rv); + if (retargetableListener) { + return retargetableListener->CheckListenerChain(); + } + return rv; +} diff --git a/toolkit/components/extensions/webrequest/nsWebRequestListener.h b/toolkit/components/extensions/webrequest/nsWebRequestListener.h new file mode 100644 index 000000000000..771c97a8fb72 --- /dev/null +++ b/toolkit/components/extensions/webrequest/nsWebRequestListener.h @@ -0,0 +1,36 @@ +/* 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 "mozilla/Attributes.h" + +class nsWebRequestListener final : public nsIWebRequestListener + , public nsIStreamListener + , public nsIThreadRetargetableStreamListener +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIWEBREQUESTLISTENER + NS_DECL_NSIREQUESTOBSERVER + NS_DECL_NSISTREAMLISTENER + NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER + + nsWebRequestListener() {} + +private: + ~nsWebRequestListener() {} + nsCOMPtr mOrigStreamListener; + nsCOMPtr mTargetStreamListener; +}; + +#endif // nsWebRequestListener_h__ + diff --git a/toolkit/modules/addons/WebRequest.jsm b/toolkit/modules/addons/WebRequest.jsm index c744a777879f..b85d023f9cdc 100644 --- a/toolkit/modules/addons/WebRequest.jsm +++ b/toolkit/modules/addons/WebRequest.jsm @@ -30,6 +30,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebRequestUpload", XPCOMUtils.defineLazyGetter(this, "ExtensionError", () => ExtensionUtils.ExtensionError); +let WebRequestListener = Components.Constructor("@mozilla.org/webextensions/webRequestListener;1", + "nsIWebRequestListener", "init"); + function attachToChannel(channel, key, data) { if (channel instanceof Ci.nsIWritablePropertyBag2) { let wrapper = {wrappedJSObject: data}; @@ -326,10 +329,10 @@ var ContentPolicyManager = { }; ContentPolicyManager.init(); -function StartStopListener(manager, loadContext) { +function StartStopListener(manager, channel, loadContext) { this.manager = manager; this.loadContext = loadContext; - this.orig = null; + new WebRequestListener(this, channel); } StartStopListener.prototype = { @@ -338,21 +341,11 @@ StartStopListener.prototype = { onStartRequest: function(request, context) { this.manager.onStartRequest(request, this.loadContext); - this.orig.onStartRequest(request, context); }, onStopRequest(request, context, statusCode) { - try { - this.orig.onStopRequest(request, context, statusCode); - } catch (e) { - Cu.reportError(e); - } this.manager.onStopRequest(request, this.loadContext); }, - - onDataAvailable(...args) { - return this.orig.onDataAvailable(...args); - }, }; var ChannelEventSink = { @@ -1000,9 +993,7 @@ HttpObserverManager = { let responseStatus = channel.responseStatus; // skip redirections, https://bugzilla.mozilla.org/show_bug.cgi?id=728901#c8 if (responseStatus < 300 || responseStatus >= 400) { - let listener = new StartStopListener(this, loadContext); - let orig = channel.setNewListener(listener); - listener.orig = orig; + new StartStopListener(this, channel, loadContext); channelData.hasListener = true; } }