Bug 1402944: Part 7 - Move traceable channel registration to ChannelWrapper. r=mixedpuppy,ehsan

MozReview-Commit-ID: 6hGmh4VpJMQ

--HG--
extra : rebase_source : 082f3cb19ec957b81536b67a56969ba714e81e79
This commit is contained in:
Kris Maglione 2017-09-27 18:15:39 -07:00
Родитель 32f579d0e3
Коммит 30a2ef9ec1
11 изменённых файлов: 132 добавлений и 269 удалений

Просмотреть файл

@ -4,6 +4,7 @@
interface LoadInfo;
interface MozChannel;
interface TabParent;
interface URI;
interface nsISupports;
@ -133,6 +134,12 @@ interface ChannelWrapper : EventTarget {
optional MozRequestMatchOptions options);
/**
* 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.

Просмотреть файл

@ -92,9 +92,6 @@
#define NS_ADDONPATHSERVICE_CONTRACTID \
"@mozilla.org/addon-path-service;1"
#define NS_WEBREQUESTSERVICE_CONTRACTID \
"@mozilla.org/addons/webrequest-service;1"
/////////////////////////////////////////////////////////////////////////////
#define ALERT_NOTIFICATION_CID \
@ -195,7 +192,3 @@
#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 } }

Просмотреть файл

@ -38,7 +38,6 @@
#include "mozilla/AddonManagerStartup.h"
#include "mozilla/AddonPathService.h"
#include "mozilla/ExtensionPolicyService.h"
#include "mozilla/WebRequestService.h"
#if defined(XP_WIN)
#include "NativeFileWatcherWin.h"
@ -127,7 +126,6 @@ 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)
@ -162,7 +160,6 @@ 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[] = {
@ -198,7 +195,6 @@ 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 },
{ nullptr }
};
@ -237,7 +233,6 @@ 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 },
{ nullptr }
};

Просмотреть файл

@ -20,6 +20,7 @@
#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"
@ -629,6 +630,39 @@ ChannelWrapper::GetFrameAncestors(nsILoadInfo* aLoadInfo, nsTArray<dom::MozFrame
return NS_OK;
}
/*****************************************************************************
* 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<nsITraceableChannel>
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) {
nsCOMPtr<nsITraceableChannel> chan = QueryChannel();
return chan.forget();
}
}
return nullptr;
}
/*****************************************************************************
* ...
*****************************************************************************/
@ -850,6 +884,7 @@ ChannelWrapper::ErrorCheck()
nsAutoString error;
GetErrorString(error);
if (error.Length()) {
mChannelEntry = nullptr;
mFiredErrorEvent = true;
ChannelWrapperBinding::ClearCachedErrorStringValue(this);
FireEvent(NS_LITERAL_STRING("error"));
@ -885,6 +920,7 @@ ChannelWrapper::RequestListener::OnStartRequest(nsIRequest *request, nsISupports
{
MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
mChannelWrapper->mChannelEntry = nullptr;
mChannelWrapper->ErrorCheck();
mChannelWrapper->FireEvent(NS_LITERAL_STRING("start"));
@ -897,6 +933,7 @@ ChannelWrapper::RequestListener::OnStopRequest(nsIRequest *request, nsISupports
{
MOZ_ASSERT(mOrigStreamListener, "Should have mOrigStreamListener");
mChannelWrapper->mChannelEntry = nullptr;
mChannelWrapper->ErrorCheck();
mChannelWrapper->FireEvent(NS_LITERAL_STRING("stop"));
@ -948,7 +985,8 @@ 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;

Просмотреть файл

@ -10,11 +10,14 @@
#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"
@ -22,7 +25,10 @@
#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"
@ -32,8 +38,12 @@
class nsIDOMElement;
class nsILoadContext;
class nsITraceableChannel;
namespace mozilla {
namespace dom {
class nsIContentParent;
}
namespace extensions {
namespace detail {
@ -97,10 +107,14 @@ namespace detail {
};
}
class WebRequestChannelEntry;
class ChannelWrapper final : public DOMEventTargetHelper
, public SupportsWeakPtr<ChannelWrapper>
, private detail::ChannelHolder
{
public:
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(ChannelWrapper)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(ChannelWrapper, DOMEventTargetHelper)
@ -130,6 +144,11 @@ public:
void SetContentType(const nsACString& aContentType);
void RegisterTraceableChannel(const WebExtensionPolicy& aAddon, nsITabParent* aTabParent);
already_AddRefed<nsITraceableChannel> GetTraceableChannel(nsIAtom* aAddonId, dom::nsIContentParent* aContentParent) const;
void GetMethod(nsCString& aRetVal) const;
dom::MozContentPolicyType Type() const;
@ -270,6 +289,9 @@ private:
bool mSuspended = false;
nsInterfaceHashtable<nsPtrHashKey<const nsIAtom>, nsITabParent> mAddonEntries;
class RequestListener final : public nsIStreamListener
, public nsIThreadRetargetableStreamListener
{

Просмотреть файл

@ -55,7 +55,7 @@ StreamFilterParent::Create(dom::ContentParent* aContentParent, uint64_t aChannel
auto& webreq = WebRequestService::GetSingleton();
RefPtr<nsIAtom> addonId = NS_Atomize(aAddonId);
nsCOMPtr<nsIChannel> channel = webreq.GetTraceableChannel(aChannelId, addonId, aContentParent);
nsCOMPtr<nsITraceableChannel> channel = webreq.GetTraceableChannel(aChannelId, addonId, aContentParent);
RefPtr<nsHttpChannel> chan = do_QueryObject(channel);
NS_ENSURE_TRUE(chan, false);

Просмотреть файл

@ -8,44 +8,19 @@
#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()
{
@ -63,126 +38,41 @@ WebRequestService::GetSingleton()
}
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));
RefPtr<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>
already_AddRefed<nsITraceableChannel>
WebRequestService::GetTraceableChannel(uint64_t aChannelId,
nsIAtom* aAddonId,
nsIContentParent* aContentParent)
{
MutexAutoLock al(mDataLock);
if (auto entry = mChannelEntries.Get(aChannelId)) {
if (entry->mChannel) {
return entry->mChannel->GetTraceableChannel(aAddonId, aContentParent);
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;
}
WebRequestChannelEntry::WebRequestChannelEntry(ChannelWrapper* aChannel)
: mChannelId(aChannel->Id())
, mChannel(aChannel)
{}
WebRequestService::ChannelParent::ChannelParent(uint64_t aChannelId, nsIChannel* aChannel,
nsIAtom* aAddonId, nsITabParent* aTabParent)
: mTabParent(static_cast<TabParent*>(aTabParent))
, mAddonId(aAddonId)
, mChannelId(aChannelId)
WebRequestChannelEntry::~WebRequestChannelEntry()
{
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;
}
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)

Просмотреть файл

@ -7,33 +7,47 @@
#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"
#include "mozilla/UniquePtr.h"
using namespace mozilla;
#include "mozilla/extensions/ChannelWrapper.h"
#include "mozilla/extensions/WebExtensionPolicy.h"
#include "nsHashKeys.h"
#include "nsDataHashtable.h"
class nsIAtom;
class nsITabParent;
class nsITraceableChannel;
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();
explicit WebRequestService();
private:
friend class WebRequestService;
explicit WebRequestChannelEntry(ChannelWrapper* aChannel);
uint64_t mChannelId;
WeakPtr<ChannelWrapper> mChannel;
};
class WebRequestService final
{
public:
NS_INLINE_DECL_REFCOUNTING(WebRequestService)
WebRequestService() = default;
static already_AddRefed<WebRequestService> GetInstance()
{
@ -42,63 +56,25 @@ public:
static WebRequestService& GetSingleton();
already_AddRefed<nsIChannel>
using ChannelEntry = WebRequestChannelEntry;
UniquePtr<ChannelEntry> RegisterChannel(ChannelWrapper* aChannel);
void UnregisterTraceableChannel(uint64_t aChannelId);
already_AddRefed<nsITraceableChannel>
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();
~WebRequestService();
void Detach();
friend ChannelEntry;
const RefPtr<dom::TabParent> mTabParent;
const RefPtr<nsIAtom> 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:
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

Просмотреть файл

@ -4,12 +4,6 @@
# 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',

Просмотреть файл

@ -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);
};

Просмотреть файл

@ -27,10 +27,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebRequestCommon",
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) {
@ -703,34 +699,6 @@ HttpObserverManager = {
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) {
@ -739,7 +707,6 @@ HttpObserverManager = {
channel, "onError", {error: channel.errorString});
break;
case "start":
this.destroyFilters(channel);
this.runChannelListener(channel, "onStart");
break;
case "stop":
@ -777,8 +744,8 @@ HttpObserverManager = {
}
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) {
@ -919,7 +886,6 @@ HttpObserverManager = {
// 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;
},