From 5613873ecb2d1081f623313eed409bed87031ea6 Mon Sep 17 00:00:00 2001 From: Kris Maglione Date: Thu, 23 Mar 2017 12:18:29 -0700 Subject: [PATCH] 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 --HG-- extra : rebase_source : aadfadef3b72044302b3f4e6c88a5a06ff138c84 --- toolkit/components/build/nsToolkitCompsCID.h | 7 + .../components/build/nsToolkitCompsModule.cpp | 5 + toolkit/components/extensions/moz.build | 1 + .../webrequest/WebRequestService.cpp | 163 ++++++++++++++++++ .../extensions/webrequest/WebRequestService.h | 103 +++++++++++ .../extensions/webrequest/moz.build | 15 +- .../webrequest/mozIWebRequestService.idl | 18 ++ 7 files changed, 309 insertions(+), 3 deletions(-) create mode 100644 toolkit/components/extensions/webrequest/WebRequestService.cpp create mode 100644 toolkit/components/extensions/webrequest/WebRequestService.h create mode 100644 toolkit/components/extensions/webrequest/mozIWebRequestService.idl diff --git a/toolkit/components/build/nsToolkitCompsCID.h b/toolkit/components/build/nsToolkitCompsCID.h index bac82f0e866a..cc4e8cf88f44 100644 --- a/toolkit/components/build/nsToolkitCompsCID.h +++ b/toolkit/components/build/nsToolkitCompsCID.h @@ -92,6 +92,9 @@ #define NS_ADDONPATHSERVICE_CONTRACTID \ "@mozilla.org/addon-path-service;1" +#define NS_WEBREQUESTSERVICE_CONTRACTID \ + "@mozilla.org/addons/webrequest-service;1" + ///////////////////////////////////////////////////////////////////////////// #define ALERT_NOTIFICATION_CID \ @@ -192,3 +195,7 @@ #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 } } diff --git a/toolkit/components/build/nsToolkitCompsModule.cpp b/toolkit/components/build/nsToolkitCompsModule.cpp index 4e95adea7f6f..48eb2f528d20 100644 --- a/toolkit/components/build/nsToolkitCompsModule.cpp +++ b/toolkit/components/build/nsToolkitCompsModule.cpp @@ -38,6 +38,7 @@ #include "mozilla/AddonManagerStartup.h" #include "mozilla/AddonPathService.h" #include "mozilla/ExtensionPolicyService.h" +#include "mozilla/WebRequestService.h" #if defined(XP_WIN) #include "NativeFileWatcherWin.h" @@ -128,6 +129,7 @@ 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) @@ -164,6 +166,7 @@ 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); @@ -200,6 +203,7 @@ static const Module::CIDEntry kToolkitCIDs[] = { { &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 } @@ -239,6 +243,7 @@ static const Module::ContractIDEntry kToolkitContracts[] = { { 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 } diff --git a/toolkit/components/extensions/moz.build b/toolkit/components/extensions/moz.build index b41a89f94982..dc68196aa4bd 100644 --- a/toolkit/components/extensions/moz.build +++ b/toolkit/components/extensions/moz.build @@ -4,6 +4,7 @@ # 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') diff --git a/toolkit/components/extensions/webrequest/WebRequestService.cpp b/toolkit/components/extensions/webrequest/WebRequestService.cpp new file mode 100644 index 000000000000..90f9858d3528 --- /dev/null +++ b/toolkit/components/extensions/webrequest/WebRequestService.cpp @@ -0,0 +1,163 @@ +/* -*- 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::GetSingleton() +{ + static RefPtr 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 traceableChannel = do_QueryInterface(aChannel); + NS_ENSURE_TRUE(traceableChannel, NS_ERROR_INVALID_ARG); + + nsCOMPtr addonId = NS_Atomize(aAddonId); + ChannelParent* entry = new ChannelParent(aChannelId, aChannel, + addonId, aTabParent); + + RefPtr destructor = new Destructor(entry); + destructor.forget(aHelper); + + return NS_OK; +} + +already_AddRefed +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( + channelEntry->mTabParent->Manager()); + } + + if (channelEntry->mAddonId == aAddonId && contentParent == aContentParent) { + nsCOMPtr 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(aTabParent)) + , mAddonId(aAddonId) + , mChannelId(aChannelId) +{ + auto service = &GetSingleton(); + MutexAutoLock al(service->mDataLock); + + auto entry = service->mChannelEntries.LookupOrAdd(mChannelId); + + entry->mChannel = do_GetWeakReference(aChannel); + entry->mTabParents.insertBack(this); +} + +WebRequestService::ChannelParent::~ChannelParent() +{ + MOZ_ASSERT(mDetached); +} + +void +WebRequestService::ChannelParent::Detach() +{ + 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; +} + +WebRequestService::ChannelEntry::~ChannelEntry() +{ + while (ChannelParent* parent = mTabParents.getFirst()) { + parent->Detach(); + } +} + +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) diff --git a/toolkit/components/extensions/webrequest/WebRequestService.h b/toolkit/components/extensions/webrequest/WebRequestService.h new file mode 100644 index 000000000000..fb01fdcc044b --- /dev/null +++ b/toolkit/components/extensions/webrequest/WebRequestService.h @@ -0,0 +1,103 @@ +/* -*- 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 already_AddRefed GetInstance() + { + return do_AddRef(&GetSingleton()); + } + + static WebRequestService& GetSingleton(); + + already_AddRefed + GetTraceableChannel(uint64_t aChannelId, nsIAtom* aAddonId, + dom::nsIContentParent* aContentParent); + +protected: + virtual ~WebRequestService(); + +private: + class ChannelParent : public LinkedListElement + { + public: + explicit ChannelParent(uint64_t aChannelId, nsIChannel* aChannel, nsIAtom* aAddonId, nsITabParent* aTabParent); + ~ChannelParent(); + + void Detach(); + + const RefPtr mTabParent; + const nsCOMPtr mAddonId; + + private: + const uint64_t mChannelId; + bool mDetached = false; + }; + + 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: + ~ChannelEntry(); + // 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 mTabParents; + }; + + nsClassHashtable mChannelEntries; + Mutex mDataLock; +}; + +#endif // mozilla_WebRequestService_h diff --git a/toolkit/components/extensions/webrequest/moz.build b/toolkit/components/extensions/webrequest/moz.build index 49bc4fe568ce..668989fff498 100644 --- a/toolkit/components/extensions/webrequest/moz.build +++ b/toolkit/components/extensions/webrequest/moz.build @@ -5,17 +5,26 @@ # 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") diff --git a/toolkit/components/extensions/webrequest/mozIWebRequestService.idl b/toolkit/components/extensions/webrequest/mozIWebRequestService.idl new file mode 100644 index 000000000000..9fd805304432 --- /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); +};