Backed out 10 changesets (bug 1581859) for causing hazard failures on ExtensionsParent.cpp.

Backed out changeset 6020ec7d7f32 (bug 1581859)
Backed out changeset 07901e457839 (bug 1581859)
Backed out changeset e23389fc98b5 (bug 1581859)
Backed out changeset 4287eebc2c77 (bug 1581859)
Backed out changeset eeff6f501cfc (bug 1581859)
Backed out changeset 22db36f7d16d (bug 1581859)
Backed out changeset 16831d45d0ed (bug 1581859)
Backed out changeset 816643de7694 (bug 1581859)
Backed out changeset 6fd5aa7895e3 (bug 1581859)
Backed out changeset 2b68d2eee18e (bug 1581859)
This commit is contained in:
Cosmin Sabou 2021-03-23 05:48:27 +02:00
Родитель ca179d4005
Коммит 7eba371387
36 изменённых файлов: 649 добавлений и 1031 удалений

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

@ -274,9 +274,6 @@ static void LogShellLoadType(nsIDocShell* aDocShell) {
case LOAD_REFRESH:
printf("refresh; ");
break;
case LOAD_REFRESH_REPLACE:
printf("refresh replace; ");
break;
case LOAD_RELOAD_CHARSET_CHANGE:
printf("reload charset change; ");
break;

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

@ -94,6 +94,8 @@ add_task(async function test_window_open_in_named_win() {
},
});
assertNoPendingCreatedNavigationTargetData();
BrowserTestUtils.removeTab(tab1);
await extension.unload();

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

@ -94,6 +94,8 @@ add_task(async function test_window_open_from_subframe() {
},
});
assertNoPendingCreatedNavigationTargetData();
BrowserTestUtils.removeTab(tab1);
await extension.unload();
@ -161,6 +163,8 @@ add_task(async function test_window_open_close_from_browserAction_popup() {
},
});
assertNoPendingCreatedNavigationTargetData();
BrowserTestUtils.removeTab(tab1);
await extension.unload();

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

@ -94,6 +94,8 @@ add_task(async function test_window_open() {
},
});
assertNoPendingCreatedNavigationTargetData();
BrowserTestUtils.removeTab(tab1);
await extension.unload();
@ -161,6 +163,8 @@ add_task(async function test_window_open_close_from_browserAction_popup() {
},
});
assertNoPendingCreatedNavigationTargetData();
BrowserTestUtils.removeTab(tab1);
await extension.unload();

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

@ -3,7 +3,7 @@
"use strict";
/* exported BASE_URL, SOURCE_PAGE, OPENED_PAGE,
runCreatedNavigationTargetTest */
runCreatedNavigationTargetTest, assertNoPendingCreatedNavigationTargetData */
const BASE_URL =
"http://mochi.test:8888/browser/browser/components/extensions/test/browser";
@ -47,3 +47,19 @@ async function runCreatedNavigationTargetTest({
"Got the expected webNavigation.onCompleted url property"
);
}
// Test that there are no pending createdNavigationTarget messages still tracked
// in WebNavigation.jsm (to be called before the extension is unloaded, because
// once the last extension which have subscribed a webNavigation event is unloaded
// all the pending created navigation target data is completely cleared).
function assertNoPendingCreatedNavigationTargetData() {
const { Manager } = ChromeUtils.import(
"resource://gre/modules/WebNavigation.jsm",
null
);
Assert.equal(
Manager.createdNavigationTargetByOuterWindowId.size,
0,
"There should be no pending createdNavigationTarget messages in WebNavigation"
);
}

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

@ -5368,7 +5368,7 @@ nsDocShell::ForceRefreshURI(nsIURI* aURI, nsIPrincipal* aPrincipal,
* we have in mind (15000 ms as defined by REFRESH_REDIRECT_TIMER).
* Pass a REPLACE flag to LoadURI().
*/
loadState->SetLoadType(LOAD_REFRESH_REPLACE);
loadState->SetLoadType(LOAD_NORMAL_REPLACE);
/* For redirects we mimic HTTP, which passes the
* original referrer.
@ -5846,7 +5846,6 @@ nsresult nsDocShell::Embed(nsIContentViewer* aContentViewer,
// Determine if this type of load should update history
switch (mLoadType) {
case LOAD_NORMAL_REPLACE:
case LOAD_REFRESH_REPLACE:
case LOAD_STOP_CONTENT_AND_REPLACE:
case LOAD_RELOAD_BYPASS_CACHE:
case LOAD_RELOAD_BYPASS_PROXY:
@ -8733,6 +8732,7 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
targetContext = newBC;
}
}
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(targetContext, rv);
@ -8754,27 +8754,6 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
return targetContext->InternalLoad(aLoadState);
}
static nsAutoCString RefMaybeNull(nsIURI* aURI) {
nsAutoCString result;
if (NS_FAILED(aURI->GetRef(result))) {
result.SetIsVoid(true);
}
return result;
}
uint32_t nsDocShell::GetSameDocumentNavigationFlags(nsIURI* aNewURI) {
uint32_t flags = LOCATION_CHANGE_SAME_DOCUMENT;
bool equal = false;
if (mCurrentURI &&
NS_SUCCEEDED(mCurrentURI->EqualsExceptRef(aNewURI, &equal)) && equal &&
RefMaybeNull(mCurrentURI) != RefMaybeNull(aNewURI)) {
flags |= LOCATION_CHANGE_HASHCHANGE;
}
return flags;
}
bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState,
SameDocumentNavigationState& aState) {
MOZ_ASSERT(aLoadState);
@ -8976,10 +8955,6 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
newURIPartitionedPrincipalToInherit = doc->PartitionedPrincipal();
newCsp = doc->GetCsp();
}
uint32_t locationChangeFlags =
GetSameDocumentNavigationFlags(aLoadState->URI());
// Pass true for aCloneSHChildren, since we're not
// changing documents here, so all of our subframes are
// still relevant to the new session history entry.
@ -9167,7 +9142,8 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
}
if (locationChangeNeeded) {
FireOnLocationChange(this, nullptr, aLoadState->URI(), locationChangeFlags);
FireOnLocationChange(this, nullptr, aLoadState->URI(),
LOCATION_CHANGE_SAME_DOCUMENT);
}
/* Restore the original LSHE if we were loading something
@ -11136,7 +11112,7 @@ bool nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
// in session history.
if (!mozilla::SessionHistoryInParent() && rootSH &&
((mLoadType & (LOAD_CMD_HISTORY | LOAD_CMD_RELOAD)) ||
mLoadType == LOAD_NORMAL_REPLACE || mLoadType == LOAD_REFRESH_REPLACE)) {
mLoadType == LOAD_NORMAL_REPLACE)) {
mPreviousEntryIndex = rootSH->Index();
if (!mozilla::SessionHistoryInParent()) {
rootSH->LegacySHistory()->UpdateIndex();
@ -11561,7 +11537,7 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
aDocument->SetDocumentURI(aNewURI);
SetCurrentURI(aNewURI, nullptr, /* aFireLocationChange */ true,
/* aIsInitialAboutBlank */ false,
GetSameDocumentNavigationFlags(aNewURI));
LOCATION_CHANGE_SAME_DOCUMENT);
AddURIVisit(aNewURI, aCurrentURI, 0);
@ -12240,23 +12216,22 @@ nsDocShell::MakeEditable(bool aInWaitForUriLoad) {
return;
}
nsresult rv;
nsCOMPtr<nsIURI> uri(do_GetProperty(props, u"docshell.previousURI"_ns, &rv));
if (NS_SUCCEEDED(rv)) {
uri.forget(aURI);
nsresult rv = props->GetPropertyAsInterface(u"docshell.previousURI"_ns,
NS_GET_IID(nsIURI),
reinterpret_cast<void**>(aURI));
if (NS_FAILED(rv)) {
// There is no last visit for this channel, so this must be the first
// link. Link the visit to the referrer of this request, if any.
// Treat referrer as null if there is an error getting it.
(void)NS_GetReferrerFromChannel(aChannel, aURI);
} else {
rv = props->GetPropertyAsUint32(u"docshell.previousFlags"_ns,
aChannelRedirectFlags);
NS_WARNING_ASSERTION(
NS_SUCCEEDED(rv),
"Could not fetch previous flags, URI will be treated like referrer");
} else {
// There is no last visit for this channel, so this must be the first
// link. Link the visit to the referrer of this request, if any.
// Treat referrer as null if there is an error getting it.
NS_GetReferrerFromChannel(aChannel, aURI);
}
}

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

@ -1040,8 +1040,6 @@ class nsDocShell final : public nsDocLoader,
nsresult HandleSameDocumentNavigation(nsDocShellLoadState* aLoadState,
SameDocumentNavigationState& aState);
uint32_t GetSameDocumentNavigationFlags(nsIURI* aNewURI);
// Called when the Private Browsing state of a nsDocShell changes.
void NotifyPrivateBrowsingChanged();

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

@ -77,10 +77,6 @@ enum LoadType : uint32_t {
nsIWebNavigation::LOAD_FLAGS_IS_LINK),
LOAD_REFRESH = MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL,
nsIWebNavigation::LOAD_FLAGS_IS_REFRESH),
LOAD_REFRESH_REPLACE =
MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_NORMAL,
nsIWebNavigation::LOAD_FLAGS_IS_REFRESH |
nsIWebNavigation::LOAD_FLAGS_REPLACE_HISTORY),
LOAD_RELOAD_CHARSET_CHANGE =
MAKE_LOAD_TYPE(nsIDocShell::LOAD_CMD_RELOAD,
nsIWebNavigation::LOAD_FLAGS_CHARSET_CHANGE),
@ -146,7 +142,6 @@ static inline bool IsValidLoadType(uint32_t aLoadType) {
case LOAD_RELOAD_ALLOW_MIXED_CONTENT:
case LOAD_LINK:
case LOAD_REFRESH:
case LOAD_REFRESH_REPLACE:
case LOAD_RELOAD_CHARSET_CHANGE:
case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_PROXY_AND_CACHE:
case LOAD_RELOAD_CHARSET_CHANGE_BYPASS_CACHE:
@ -178,11 +173,6 @@ static inline nsDOMNavigationTiming::Type ConvertLoadTypeToNavigationType(
case LOAD_NORMAL_ALLOW_MIXED_CONTENT:
case LOAD_LINK:
case LOAD_STOP_CONTENT:
// FIXME: It isn't clear that LOAD_REFRESH_REPLACE should have a different
// navigation type than LOAD_REFRESH. Those loads historically used the
// LOAD_NORMAL_REPLACE type, and therefore wound up with TYPE_NAVIGATE by
// default.
case LOAD_REFRESH_REPLACE:
case LOAD_REPLACE_BYPASS_CACHE:
result = nsDOMNavigationTiming::TYPE_NAVIGATE;
break;

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

@ -2698,9 +2698,13 @@ void Document::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
// timeline will have the same global clock time as the old one.
mDocumentTimeline = nullptr;
if (nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel)) {
if (nsCOMPtr<nsIURI> baseURI = do_GetProperty(bag, u"baseURI"_ns)) {
mDocumentBaseURI = baseURI.forget();
nsCOMPtr<nsIPropertyBag2> bag = do_QueryInterface(aChannel);
if (bag) {
nsCOMPtr<nsIURI> baseURI;
bag->GetPropertyAsInterface(u"baseURI"_ns, NS_GET_IID(nsIURI),
getter_AddRefs(baseURI));
if (baseURI) {
mDocumentBaseURI = baseURI;
mChromeXHRDocBaseURI = nullptr;
}
}

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

@ -1257,15 +1257,21 @@ already_AddRefed<nsIPrincipal> nsOuterWindowProxy::GetNoPDFJSPrincipal(
return nullptr;
}
if (Document* doc = inner->GetExtantDoc()) {
if (nsCOMPtr<nsIPropertyBag2> propBag =
do_QueryInterface(doc->GetChannel())) {
nsCOMPtr<nsIPrincipal> principal(
do_GetProperty(propBag, u"noPDFJSPrincipal"_ns));
return principal.forget();
}
Document* doc = inner->GetExtantDoc();
if (!doc) {
return nullptr;
}
return nullptr;
nsCOMPtr<nsIPropertyBag2> propBag(do_QueryInterface(doc->GetChannel()));
if (!propBag) {
return nullptr;
}
nsCOMPtr<nsIPrincipal> principal;
propBag->GetPropertyAsInterface(u"noPDFJSPrincipal"_ns,
NS_GET_IID(nsIPrincipal),
getter_AddRefs(principal));
return principal.forget();
}
const nsOuterWindowProxy nsOuterWindowProxy::singleton;

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

@ -81,7 +81,6 @@
#include "mozilla/dom/WorkerDebugger.h"
#include "mozilla/dom/WorkerDebuggerManager.h"
#include "mozilla/dom/ipc/SharedMap.h"
#include "mozilla/extensions/ExtensionsChild.h"
#include "mozilla/extensions/StreamFilterParent.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/gfx/gfxVars.h"

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

@ -126,7 +126,6 @@
#include "mozilla/dom/power/PowerManagerService.h"
#include "mozilla/dom/quota/QuotaManagerService.h"
#include "mozilla/embedding/printingui/PrintingParent.h"
#include "mozilla/extensions/ExtensionsParent.h"
#include "mozilla/extensions/StreamFilterParent.h"
#include "mozilla/gfx/GPUProcessManager.h"
#include "mozilla/gfx/gfxVars.h"
@ -4993,11 +4992,6 @@ mozilla::ipc::IPCResult ContentParent::RecvCreateAudioIPCConnection(
return IPC_OK();
}
already_AddRefed<extensions::PExtensionsParent>
ContentParent::AllocPExtensionsParent() {
return MakeAndAddRef<extensions::ExtensionsParent>();
}
PFileDescriptorSetParent* ContentParent::AllocPFileDescriptorSetParent(
const FileDescriptor& aFD) {
return new FileDescriptorSetParent(aFD);

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

@ -1177,8 +1177,6 @@ class ContentParent final
mozilla::ipc::IPCResult RecvCreateAudioIPCConnection(
CreateAudioIPCConnectionResolver&& aResolver);
already_AddRefed<extensions::PExtensionsParent> AllocPExtensionsParent();
PFileDescriptorSetParent* AllocPFileDescriptorSetParent(
const mozilla::ipc::FileDescriptor&);

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

@ -10,7 +10,6 @@ include protocol PCompositorManager;
include protocol PContentPermissionRequest;
include protocol PCycleCollectWithLogs;
include protocol PDocumentChannel;
include protocol PExtensions;
include protocol PExternalHelperApp;
include protocol PHandlerService;
include protocol PFileDescriptorSet;
@ -407,7 +406,6 @@ nested(upto inside_cpow) sync protocol PContent
manages PBrowser;
manages PContentPermissionRequest;
manages PCycleCollectWithLogs;
manages PExtensions;
manages PExternalHelperApp;
manages PFileDescriptorSet;
manages PHal;
@ -472,8 +470,6 @@ parent:
async CloneDocumentTreeInto(MaybeDiscardedBrowsingContext aSourceBc,
MaybeDiscardedBrowsingContext aTargetBc);
async PExtensions();
child:
async ConstructBrowser(ManagedEndpoint<PBrowserChild> browserEp,
ManagedEndpoint<PWindowGlobalChild> windowEp,

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

@ -4,7 +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/. */
include protocol PExtensions;
include protocol PWindowGlobal;
include DOMTypes;
@ -22,7 +21,6 @@ namespace dom {
*/
async refcounted protocol PInProcess
{
manages PExtensions;
manages PWindowGlobal;
};

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

@ -9,7 +9,6 @@
#include <functional>
#include "js/TypeDecls.h"
#include "js/Value.h"
#include "mozilla/Maybe.h"
#include "nsISupports.h"

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

@ -1167,15 +1167,15 @@ nsresult NS_GetURLSpecFromDir(nsIFile* file, nsACString& url,
void NS_GetReferrerFromChannel(nsIChannel* channel, nsIURI** referrer) {
*referrer = nullptr;
if (nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(channel)) {
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(channel));
if (props) {
// We have to check for a property on a property bag because the
// referrer may be empty for security reasons (for example, when loading
// an http page with an https referrer).
nsresult rv;
nsCOMPtr<nsIURI> uri(
do_GetProperty(props, u"docshell.internalReferrer"_ns, &rv));
nsresult rv = props->GetPropertyAsInterface(
u"docshell.internalReferrer"_ns, NS_GET_IID(nsIURI),
reinterpret_cast<void**>(referrer));
if (NS_SUCCEEDED(rv)) {
uri.forget(referrer);
return;
}
}

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

@ -1,61 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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/extensions/ExtensionsChild.h"
#include "mozilla/extensions/ExtensionsParent.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/InProcessChild.h"
#include "mozilla/dom/InProcessParent.h"
#include "mozilla/ipc/Endpoint.h"
#include "nsXULAppAPI.h"
using namespace mozilla::dom;
namespace mozilla {
namespace extensions {
NS_IMPL_ISUPPORTS0(ExtensionsChild)
/* static */
ExtensionsChild& ExtensionsChild::Get() {
static RefPtr<ExtensionsChild> sInstance;
if (MOZ_UNLIKELY(!sInstance)) {
sInstance = new ExtensionsChild();
sInstance->Init();
ClearOnShutdown(&sInstance);
}
return *sInstance;
}
/* static */
already_AddRefed<ExtensionsChild> ExtensionsChild::GetSingleton() {
return do_AddRef(&Get());
}
void ExtensionsChild::Init() {
if (XRE_IsContentProcess()) {
ContentChild::GetSingleton()->SendPExtensionsConstructor(this);
} else {
InProcessChild* ipChild = InProcessChild::Singleton();
InProcessParent* ipParent = InProcessParent::Singleton();
if (!ipChild || !ipParent) {
return;
}
RefPtr parent = new ExtensionsParent();
ManagedEndpoint<PExtensionsParent> endpoint =
ipChild->OpenPExtensionsEndpoint(this);
ipParent->BindPExtensionsEndpoint(std::move(endpoint), parent);
}
}
void ExtensionsChild::ActorDestroy(ActorDestroyReason aWhy) {}
} // namespace extensions
} // namespace mozilla

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

@ -1,36 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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_extensions_ExtensionsChild_h
#define mozilla_extensions_ExtensionsChild_h
#include "mozilla/extensions/PExtensionsChild.h"
#include "nsISupportsImpl.h"
namespace mozilla {
namespace extensions {
class ExtensionsChild final : public nsISupports, public PExtensionsChild {
public:
NS_DECL_ISUPPORTS
static already_AddRefed<ExtensionsChild> GetSingleton();
static ExtensionsChild& Get();
private:
ExtensionsChild() = default;
~ExtensionsChild() = default;
void Init();
protected:
void ActorDestroy(ActorDestroyReason aWhy) override;
};
} // namespace extensions
} // namespace mozilla
#endif // mozilla_extensions_ExtensionsChild_h

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

@ -1,124 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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 "extIWebNavigation.h"
#include "mozilla/extensions/ExtensionsParent.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/RefPtr.h"
#include "jsapi.h"
#include "nsImportModule.h"
#include "xpcpublic.h"
namespace mozilla {
namespace extensions {
ExtensionsParent::ExtensionsParent() {}
ExtensionsParent::~ExtensionsParent() {}
extIWebNavigation* ExtensionsParent::WebNavigation() {
if (!mWebNavigation) {
mWebNavigation = do_ImportModule("resource://gre/modules/WebNavigation.jsm",
"WebNavigationManager");
MOZ_RELEASE_ASSERT(mWebNavigation);
}
return mWebNavigation;
}
void ExtensionsParent::ActorDestroy(ActorDestroyReason aWhy) {}
static inline JS::Handle<JS::Value> ToJSBoolean(bool aValue) {
return aValue ? JS::TrueHandleValue : JS::FalseHandleValue;
}
JS::Value FrameTransitionDataToJSValue(const FrameTransitionData& aData) {
dom::AutoJSAPI jsapi;
MOZ_ALWAYS_TRUE(jsapi.Init(xpc::PrivilegedJunkScope()));
JSContext* cx = jsapi.cx();
JS::Rooted<JSObject*> obj(cx, JS_NewPlainObject(cx));
if (!obj ||
!JS_SetProperty(cx, obj, "forward_back",
ToJSBoolean(aData.forwardBack())) ||
!JS_SetProperty(cx, obj, "form_submit",
ToJSBoolean(aData.formSubmit())) ||
!JS_SetProperty(cx, obj, "reload", ToJSBoolean(aData.reload())) ||
!JS_SetProperty(cx, obj, "server_redirect",
ToJSBoolean(aData.serverRedirect())) ||
!JS_SetProperty(cx, obj, "client_redirect",
ToJSBoolean(aData.clientRedirect()))) {
return JS::UndefinedValue();
}
return JS::ObjectValue(*obj);
}
ipc::IPCResult ExtensionsParent::RecvDocumentChange(
MaybeDiscardedBrowsingContext&& aBC, FrameTransitionData&& aTransitionData,
nsIURI* aLocation) {
if (aBC.IsNullOrDiscarded()) {
return IPC_OK();
}
JS::Rooted<JS::Value> transitionData(
dom::RootingCx(), FrameTransitionDataToJSValue(aTransitionData));
WebNavigation()->OnDocumentChange(aBC.get(), transitionData, aLocation);
return IPC_OK();
}
ipc::IPCResult ExtensionsParent::RecvHistoryChange(
MaybeDiscardedBrowsingContext&& aBC, FrameTransitionData&& aTransitionData,
nsIURI* aLocation, bool aIsHistoryStateUpdated,
bool aIsReferenceFragmentUpdated) {
if (aBC.IsNullOrDiscarded()) {
return IPC_OK();
}
JS::Rooted<JS::Value> transitionData(
dom::RootingCx(), FrameTransitionDataToJSValue(aTransitionData));
WebNavigation()->OnHistoryChange(aBC.get(), transitionData, aLocation,
aIsHistoryStateUpdated,
aIsReferenceFragmentUpdated);
return IPC_OK();
}
ipc::IPCResult ExtensionsParent::RecvStateChange(
MaybeDiscardedBrowsingContext&& aBC, nsIURI* aRequestURI, nsresult aStatus,
uint32_t aStateFlags) {
if (aBC.IsNullOrDiscarded()) {
return IPC_OK();
}
WebNavigation()->OnStateChange(aBC.get(), aRequestURI, aStatus, aStateFlags);
return IPC_OK();
}
ipc::IPCResult ExtensionsParent::RecvCreatedNavigationTarget(
MaybeDiscardedBrowsingContext&& aBC,
MaybeDiscardedBrowsingContext&& aSourceBC, const nsCString& aURL) {
if (aBC.IsNullOrDiscarded() || aSourceBC.IsNull()) {
return IPC_OK();
}
WebNavigation()->OnCreatedNavigationTarget(
aBC.get(), aSourceBC.GetMaybeDiscarded(), aURL);
return IPC_OK();
}
ipc::IPCResult ExtensionsParent::RecvDOMContentLoaded(
MaybeDiscardedBrowsingContext&& aBC, nsIURI* aDocumentURI) {
if (aBC.IsNullOrDiscarded()) {
return IPC_OK();
}
WebNavigation()->OnDOMContentLoaded(aBC.get(), aDocumentURI);
return IPC_OK();
}
} // namespace extensions
} // namespace mozilla

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

@ -1,58 +0,0 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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_extensions_ExtensionsParent_h
#define mozilla_extensions_ExtensionsParent_h
#include "mozilla/extensions/PExtensionsParent.h"
#include "nsISupportsImpl.h"
class extIWebNavigation;
namespace mozilla {
namespace extensions {
class ExtensionsParent final : public PExtensionsParent {
public:
NS_INLINE_DECL_REFCOUNTING(ExtensionsParent, final)
ExtensionsParent();
ipc::IPCResult RecvDocumentChange(MaybeDiscardedBrowsingContext&& aBC,
FrameTransitionData&& aTransitionData,
nsIURI* aLocation);
ipc::IPCResult RecvHistoryChange(MaybeDiscardedBrowsingContext&& aBC,
FrameTransitionData&& aTransitionData,
nsIURI* aLocation,
bool aIsHistoryStateUpdated,
bool aIsReferenceFragmentUpdated);
ipc::IPCResult RecvStateChange(MaybeDiscardedBrowsingContext&& aBC,
nsIURI* aRequestURI, nsresult aStatus,
uint32_t aStateFlags);
ipc::IPCResult RecvCreatedNavigationTarget(
MaybeDiscardedBrowsingContext&& aBC,
MaybeDiscardedBrowsingContext&& aSourceBC, const nsCString& aURI);
ipc::IPCResult RecvDOMContentLoaded(MaybeDiscardedBrowsingContext&& aBC,
nsIURI* aDocumentURI);
private:
~ExtensionsParent();
extIWebNavigation* WebNavigation();
nsCOMPtr<extIWebNavigation> mWebNavigation;
protected:
void ActorDestroy(ActorDestroyReason aWhy) override;
};
} // namespace extensions
} // namespace mozilla
#endif // mozilla_extensions_ExtensionsParent_h

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

@ -1,61 +0,0 @@
/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
/* 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 protocol PContent;
include protocol PInProcess;
include DOMTypes;
include "mozilla/ipc/URIUtils.h";
namespace mozilla {
namespace extensions {
struct FrameTransitionData
{
bool clientRedirect;
bool formSubmit;
bool forwardBack;
bool reload;
bool serverRedirect;
};
/**
* A generic protocol used by the extension framework for process-level IPC. A
* child instance is created at startup in the parent process and each content
* child process, which can be accessed via
* `mozilla::extensions::ExtensionsChild::Get()`.
*/
refcounted protocol PExtensions
{
manager PContent or PInProcess;
parent:
async __delete__();
async DocumentChange(MaybeDiscardedBrowsingContext bc,
FrameTransitionData transitionData,
nsIURI location);
async HistoryChange(MaybeDiscardedBrowsingContext bc,
FrameTransitionData transitionData,
nsIURI location,
bool isHistoryStateUpdated,
bool isReferenceFragmentUpdated);
async StateChange(MaybeDiscardedBrowsingContext bc,
nsIURI requestURI,
nsresult status,
uint32_t stateFlags);
async CreatedNavigationTarget(MaybeDiscardedBrowsingContext bc,
MaybeDiscardedBrowsingContext sourceBC,
nsCString url);
async DOMContentLoaded(MaybeDiscardedBrowsingContext bc,
nsIURI documentURI);
};
} // namespace extensions
} // namespace mozilla

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

@ -4,7 +4,7 @@
"use strict";
const EXPORTED_SYMBOLS = ["WebNavigation", "WebNavigationManager"];
const EXPORTED_SYMBOLS = ["WebNavigation"];
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { AppConstants } = ChromeUtils.import(
@ -26,11 +26,6 @@ ChromeUtils.defineModuleGetter(
"UrlbarUtils",
"resource:///modules/UrlbarUtils.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"ClickHandlerParent",
@ -42,11 +37,7 @@ ChromeUtils.defineModuleGetter(
// e.g. nsNavHistory::CheckIsRecentEvent, but with a lower threshold value).
const RECENT_DATA_THRESHOLD = 5 * 1000000;
function getBrowser(bc) {
return bc.top.embedderElement;
}
var WebNavigationManager = {
var Manager = {
// Map[string -> Map[listener -> URLFilter]]
listeners: new Map(),
@ -55,6 +46,11 @@ var WebNavigationManager = {
// browser -> tabTransitionData
this.recentTabTransitionData = new WeakMap();
// Collect the pending created navigation target events that still have to
// pair the message received from the source tab to the one received from
// the new tab.
this.createdNavigationTargetByOuterWindowId = new Map();
Services.obs.addObserver(this, "urlbar-user-start-navigation", true);
Services.obs.addObserver(this, "webNavigation-createdNavigationTarget");
@ -62,6 +58,17 @@ var WebNavigationManager = {
if (AppConstants.MOZ_BUILD_APP == "browser") {
ClickHandlerParent.addContentClickListener(this);
}
Services.mm.addMessageListener("Extension:DOMContentLoaded", this);
Services.mm.addMessageListener("Extension:StateChange", this);
Services.mm.addMessageListener("Extension:DocumentChange", this);
Services.mm.addMessageListener("Extension:HistoryChange", this);
Services.mm.addMessageListener("Extension:CreatedNavigationTarget", this);
Services.mm.loadFrameScript(
"resource://gre/modules/WebNavigationContent.js",
true
);
},
uninit() {
@ -73,7 +80,22 @@ var WebNavigationManager = {
ClickHandlerParent.removeContentClickListener(this);
}
Services.mm.removeMessageListener("Extension:StateChange", this);
Services.mm.removeMessageListener("Extension:DocumentChange", this);
Services.mm.removeMessageListener("Extension:HistoryChange", this);
Services.mm.removeMessageListener("Extension:DOMContentLoaded", this);
Services.mm.removeMessageListener(
"Extension:CreatedNavigationTarget",
this
);
Services.mm.removeDelayedFrameScript(
"resource://gre/modules/WebNavigationContent.js"
);
Services.mm.broadcastAsyncMessage("Extension:DisableWebNavigation");
this.recentTabTransitionData = new WeakMap();
this.createdNavigationTargetByOuterWindowId.clear();
},
addListener(type, listener, filters, context) {
@ -108,7 +130,6 @@ var WebNavigationManager = {
* to keep track of the urlbar user interaction.
*/
QueryInterface: ChromeUtils.generateQI([
"extIWebNavigation",
"nsIObserver",
"nsISupportsWeakReference",
]),
@ -135,11 +156,16 @@ var WebNavigationManager = {
sourceTabBrowser,
} = subject.wrappedJSObject;
this.fire("onCreatedNavigationTarget", createdTabBrowser, null, {
sourceTabBrowser,
sourceFrameId: sourceFrameID,
url,
});
this.fire(
"onCreatedNavigationTarget",
createdTabBrowser,
{},
{
sourceTabBrowser,
sourceFrameId: sourceFrameID,
url,
}
);
}
},
@ -269,6 +295,34 @@ var WebNavigationManager = {
return data;
},
/**
* Receive messages from the WebNavigationContent.js framescript
* over message manager events.
*/
receiveMessage({ name, data, target }) {
switch (name) {
case "Extension:StateChange":
this.onStateChange(target, data);
break;
case "Extension:DocumentChange":
this.onDocumentChange(target, data);
break;
case "Extension:HistoryChange":
this.onHistoryChange(target, data);
break;
case "Extension:DOMContentLoaded":
this.onLoad(target, data);
break;
case "Extension:CreatedNavigationTarget":
this.onCreatedNavigationTarget(target, data);
break;
}
},
onContentClick(target, data) {
// We are interested only on clicks to links which are not "add to bookmark" commands
if (data.href && !data.bookmark) {
@ -280,101 +334,128 @@ var WebNavigationManager = {
}
},
onCreatedNavigationTarget(bc, sourceBC, url) {
if (!this.listeners.size) {
onCreatedNavigationTarget(browser, data) {
const { createdOuterWindowId, isSourceTab, sourceFrameId, url } = data;
// We are going to receive two message manager messages for a single
// onCreatedNavigationTarget event related to a window.open that is happening
// in the child process (one from the source tab and one from the created tab),
// the unique createdWindowId (the outerWindowID of the created docShell)
// to pair them together.
const pairedMessage = this.createdNavigationTargetByOuterWindowId.get(
createdOuterWindowId
);
if (!isSourceTab) {
if (pairedMessage) {
// This should not happen, print a warning before overwriting the unexpected pending data.
Services.console.logStringMessage(
`Discarding onCreatedNavigationTarget for ${createdOuterWindowId}: ` +
"unexpected pending data while receiving the created tab data"
);
}
// Store a weak reference to the browser XUL element, so that we don't prevent
// it to be garbage collected if it has been destroyed.
const browserWeakRef = Cu.getWeakReference(browser);
this.createdNavigationTargetByOuterWindowId.set(createdOuterWindowId, {
browserWeakRef,
data,
});
return;
}
let browser = getBrowser(bc);
if (!pairedMessage) {
// The sourceTab should always be received after the message coming from the created
// top level frame because the "webNavigation-createdNavigationTarget-from-js" observers
// subscribed by WebNavigationContent.js are going to be executed in reverse order
// (See http://searchfox.org/mozilla-central/rev/f54c1723be/xpcom/ds/nsObserverList.cpp#76)
// and the observer subscribed to the created target will be the last one subscribed
// to the ObserverService (and the first one to be triggered).
Services.console.logStringMessage(
`Discarding onCreatedNavigationTarget for ${createdOuterWindowId}: ` +
"received source tab data without any created tab data available"
);
this.fire("onCreatedNavigationTarget", browser, null, {
sourceTabBrowser: getBrowser(sourceBC),
sourceFrameId: WebNavigationFrames.getFrameId(sourceBC),
url,
});
return;
}
this.createdNavigationTargetByOuterWindowId.delete(createdOuterWindowId);
let sourceTabBrowser = browser;
let createdTabBrowser = pairedMessage.browserWeakRef.get();
if (!createdTabBrowser) {
Services.console.logStringMessage(
`Discarding onCreatedNavigationTarget for ${createdOuterWindowId}: ` +
"the created tab has been already destroyed"
);
return;
}
this.fire(
"onCreatedNavigationTarget",
createdTabBrowser,
{},
{
sourceTabBrowser,
sourceFrameId,
url,
}
);
},
onStateChange(bc, requestURI, status, stateFlags) {
if (!this.listeners.size) {
return;
}
let browser = getBrowser(bc);
onStateChange(browser, data) {
let stateFlags = data.stateFlags;
if (stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) {
let url = requestURI.spec;
let url = data.requestURL;
if (stateFlags & Ci.nsIWebProgressListener.STATE_START) {
this.fire("onBeforeNavigate", browser, bc, { url });
this.fire("onBeforeNavigate", browser, data, { url });
} else if (stateFlags & Ci.nsIWebProgressListener.STATE_STOP) {
if (Components.isSuccessCode(status)) {
this.fire("onCompleted", browser, bc, { url });
if (Components.isSuccessCode(data.status)) {
this.fire("onCompleted", browser, data, { url });
} else {
let error = `Error code ${status}`;
this.fire("onErrorOccurred", browser, bc, { error, url });
let error = `Error code ${data.status}`;
this.fire("onErrorOccurred", browser, data, { error, url });
}
}
}
},
onDocumentChange(bc, frameTransitionData, location) {
if (!this.listeners.size) {
return;
}
let browser = getBrowser(bc);
onDocumentChange(browser, data) {
let extra = {
url: location ? location.spec : "",
url: data.location,
// Transition data which is coming from the content process.
frameTransitionData,
frameTransitionData: data.frameTransitionData,
tabTransitionData: this.getAndForgetRecentTabTransitionData(browser),
};
this.fire("onCommitted", browser, bc, extra);
this.fire("onCommitted", browser, data, extra);
},
onHistoryChange(
bc,
frameTransitionData,
location,
isHistoryStateUpdated,
isReferenceFragmentUpdated
) {
if (!this.listeners.size) {
return;
}
let browser = getBrowser(bc);
onHistoryChange(browser, data) {
let extra = {
url: location ? location.spec : "",
url: data.location,
// Transition data which is coming from the content process.
frameTransitionData,
frameTransitionData: data.frameTransitionData,
tabTransitionData: this.getAndForgetRecentTabTransitionData(browser),
};
if (isReferenceFragmentUpdated) {
this.fire("onReferenceFragmentUpdated", browser, bc, extra);
} else if (isHistoryStateUpdated) {
this.fire("onHistoryStateUpdated", browser, bc, extra);
if (data.isReferenceFragmentUpdated) {
this.fire("onReferenceFragmentUpdated", browser, data, extra);
} else if (data.isHistoryStateUpdated) {
this.fire("onHistoryStateUpdated", browser, data, extra);
}
},
onDOMContentLoaded(bc, documentURI) {
if (!this.listeners.size) {
return;
}
let browser = getBrowser(bc);
this.fire("onDOMContentLoaded", browser, bc, { url: documentURI.spec });
onLoad(browser, data) {
this.fire("onDOMContentLoaded", browser, data, { url: data.url });
},
fire(type, browser, bc, extra) {
if (!browser) {
return;
}
fire(type, browser, data, extra) {
let listeners = this.listeners.get(type);
if (!listeners) {
return;
@ -382,11 +463,11 @@ var WebNavigationManager = {
let details = {
browser,
frameId: data.frameId,
};
if (bc) {
details.frameId = WebNavigationFrames.getFrameId(bc);
details.parentFrameId = WebNavigationFrames.getParentFrameId(bc);
if (data.parentFrameId !== undefined) {
details.parentFrameId = data.parentFrameId;
}
for (let prop in extra) {
@ -424,13 +505,7 @@ var WebNavigation = {};
for (let event of EVENTS) {
WebNavigation[event] = {
addListener: WebNavigationManager.addListener.bind(
WebNavigationManager,
event
),
removeListener: WebNavigationManager.removeListener.bind(
WebNavigationManager,
event
),
addListener: Manager.addListener.bind(Manager, event),
removeListener: Manager.removeListener.bind(Manager, event),
};
}

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

@ -0,0 +1,408 @@
/* 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/. */
"use strict";
/* eslint-env mozilla/frame-script */
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
ChromeUtils.defineModuleGetter(
this,
"WebNavigationFrames",
"resource://gre/modules/WebNavigationFrames.jsm"
);
function loadListener(event) {
let document = event.target;
let window = document.defaultView;
let url = document.documentURI;
let frameId = WebNavigationFrames.getFrameId(window);
let parentFrameId = WebNavigationFrames.getParentFrameId(window);
sendAsyncMessage("Extension:DOMContentLoaded", {
frameId,
parentFrameId,
url,
});
}
addEventListener("DOMContentLoaded", loadListener);
addMessageListener("Extension:DisableWebNavigation", () => {
removeEventListener("DOMContentLoaded", loadListener);
});
var CreatedNavigationTargetListener = {
QueryInterface: ChromeUtils.generateQI([
"nsIObserver",
"nsISupportsWeakReference",
]),
init() {
Services.obs.addObserver(
this,
"webNavigation-createdNavigationTarget-from-js"
);
},
uninit() {
Services.obs.removeObserver(
this,
"webNavigation-createdNavigationTarget-from-js"
);
},
observe(subject, topic, data) {
if (!(subject instanceof Ci.nsIPropertyBag2)) {
return;
}
let props = subject.QueryInterface(Ci.nsIPropertyBag2);
const createdDocShell = props.getPropertyAsInterface(
"createdTabDocShell",
Ci.nsIDocShell
);
const sourceDocShell = props.getPropertyAsInterface(
"sourceTabDocShell",
Ci.nsIDocShell
);
const isSourceTabDescendant =
sourceDocShell.sameTypeRootTreeItem === docShell;
if (
docShell !== createdDocShell &&
docShell !== sourceDocShell &&
!isSourceTabDescendant
) {
// if the createdNavigationTarget is not related to this docShell
// (this docShell is not the newly created docShell, it is not the source docShell,
// and the source docShell is not a descendant of it)
// there is nothing to do here and return early.
return;
}
const isSourceTab = docShell === sourceDocShell || isSourceTabDescendant;
const sourceFrameId = WebNavigationFrames.getFrameId(
sourceDocShell.browsingContext
);
const createdOuterWindowId = sourceDocShell?.outerWindowID;
let url;
if (props.hasKey("url")) {
url = props.getPropertyAsACString("url");
}
sendAsyncMessage("Extension:CreatedNavigationTarget", {
url,
sourceFrameId,
createdOuterWindowId,
isSourceTab,
});
},
};
var FormSubmitListener = {
init() {
this.formSubmitWindows = new WeakSet();
addEventListener("DOMFormBeforeSubmit", this);
},
uninit() {
removeEventListener("DOMFormBeforeSubmit", this);
this.formSubmitWindows = new WeakSet();
},
handleEvent({ target: form }) {
this.formSubmitWindows.add(form.ownerGlobal);
},
hasAndForget: function(window) {
let has = this.formSubmitWindows.has(window);
this.formSubmitWindows.delete(window);
return has;
},
};
/**
* A generator function which iterates over a docShell tree, given a root docShell.
*
* @param {nsIDocShell} docShell - the root docShell object
* @returns {Iterator<nsIDocShell>}
*/
function iterateDocShellTree(docShell) {
return docShell.getAllDocShellsInSubtree(
docShell.typeContent,
docShell.ENUMERATE_FORWARDS
);
}
var WebProgressListener = {
init: function() {
// This WeakMap (DOMWindow -> nsIURI) keeps track of the pathname and hash
// of the previous location for all the existent docShells.
this.previousURIMap = new WeakMap();
// Populate the above previousURIMap by iterating over the docShells tree.
for (let currentDocShell of iterateDocShellTree(docShell)) {
let win = currentDocShell.domWindow;
let { currentURI } = currentDocShell.QueryInterface(Ci.nsIWebNavigation);
this.previousURIMap.set(win, currentURI);
}
// This WeakSet of DOMWindows keeps track of the attempted refresh.
this.refreshAttemptedDOMWindows = new WeakSet();
let webProgress = docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
webProgress.addProgressListener(
this,
Ci.nsIWebProgress.NOTIFY_STATE_WINDOW |
Ci.nsIWebProgress.NOTIFY_REFRESH |
Ci.nsIWebProgress.NOTIFY_LOCATION
);
},
uninit() {
if (!docShell) {
return;
}
let webProgress = docShell
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebProgress);
webProgress.removeProgressListener(this);
},
onRefreshAttempted: function onRefreshAttempted(
webProgress,
URI,
delay,
sameURI
) {
this.refreshAttemptedDOMWindows.add(webProgress.DOMWindow);
// If this function doesn't return true, the attempted refresh will be blocked.
return true;
},
onStateChange: function onStateChange(
webProgress,
request,
stateFlags,
status
) {
let { originalURI, URI: locationURI } = request.QueryInterface(
Ci.nsIChannel
);
// Prevents "about", "chrome", "resource" and "moz-extension" URI schemes to be
// reported with the resolved "file" or "jar" URIs. (see Bug 1246125 for rationale)
if (locationURI.schemeIs("file") || locationURI.schemeIs("jar")) {
let shouldUseOriginalURI =
originalURI.schemeIs("about") ||
originalURI.schemeIs("chrome") ||
originalURI.schemeIs("resource") ||
originalURI.schemeIs("moz-extension");
locationURI = shouldUseOriginalURI ? originalURI : locationURI;
}
this.sendStateChange({ webProgress, locationURI, stateFlags, status });
// Based on the docs of the webNavigation.onCommitted event, it should be raised when:
// "The document might still be downloading, but at least part of
// the document has been received"
// and for some reason we don't fire onLocationChange for the
// initial navigation of a sub-frame.
// For the above two reasons, when the navigation event is related to
// a sub-frame we process the document change here and
// then send an "Extension:DocumentChange" message to the main process,
// where it will be turned into a webNavigation.onCommitted event.
// (see Bug 1264936 and Bug 125662 for rationale)
if (
webProgress.DOMWindow.top != webProgress.DOMWindow &&
stateFlags & Ci.nsIWebProgressListener.STATE_IS_DOCUMENT
) {
this.sendDocumentChange({ webProgress, locationURI, request });
}
},
onLocationChange: function onLocationChange(
webProgress,
request,
locationURI,
flags
) {
let { DOMWindow } = webProgress;
// Get the previous URI loaded in the DOMWindow.
let previousURI = this.previousURIMap.get(DOMWindow);
// Update the URI in the map with the new locationURI.
this.previousURIMap.set(DOMWindow, locationURI);
let isSameDocument =
flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT;
// When a frame navigation doesn't change the current loaded document
// (which can be due to history.pushState/replaceState or to a changed hash in the url),
// it is reported only to the onLocationChange, for this reason
// we process the history change here and then we are going to send
// an "Extension:HistoryChange" to the main process, where it will be turned
// into a webNavigation.onHistoryStateUpdated/onReferenceFragmentUpdated event.
if (isSameDocument) {
this.sendHistoryChange({
webProgress,
previousURI,
locationURI,
request,
});
} else if (webProgress.DOMWindow.top == webProgress.DOMWindow) {
// We have to catch the document changes from top level frames here,
// where we can detect the "server redirect" transition.
// (see Bug 1264936 and Bug 125662 for rationale)
this.sendDocumentChange({ webProgress, locationURI, request });
}
},
sendStateChange({ webProgress, locationURI, stateFlags, status }) {
let data = {
requestURL: locationURI.spec,
frameId: WebNavigationFrames.getFrameId(webProgress.DOMWindow),
parentFrameId: WebNavigationFrames.getParentFrameId(
webProgress.DOMWindow
),
status,
stateFlags,
};
sendAsyncMessage("Extension:StateChange", data);
},
sendDocumentChange({ webProgress, locationURI, request }) {
let { loadType, DOMWindow } = webProgress;
let frameTransitionData = this.getFrameTransitionData({
loadType,
request,
DOMWindow,
});
let data = {
frameTransitionData,
location: locationURI ? locationURI.spec : "",
frameId: WebNavigationFrames.getFrameId(webProgress.DOMWindow),
parentFrameId: WebNavigationFrames.getParentFrameId(
webProgress.DOMWindow
),
};
sendAsyncMessage("Extension:DocumentChange", data);
},
sendHistoryChange({ webProgress, previousURI, locationURI, request }) {
let { loadType, DOMWindow } = webProgress;
let isHistoryStateUpdated = false;
let isReferenceFragmentUpdated = false;
let pathChanged = !(
previousURI && locationURI.equalsExceptRef(previousURI)
);
let hashChanged = !(previousURI && previousURI.ref == locationURI.ref);
// When the location changes but the document is the same:
// - path not changed and hash changed -> |onReferenceFragmentUpdated|
// (even if it changed using |history.pushState|)
// - path not changed and hash not changed -> |onHistoryStateUpdated|
// (only if it changes using |history.pushState|)
// - path changed -> |onHistoryStateUpdated|
if (!pathChanged && hashChanged) {
isReferenceFragmentUpdated = true;
} else if (loadType & Ci.nsIDocShell.LOAD_CMD_PUSHSTATE) {
isHistoryStateUpdated = true;
} else if (loadType & Ci.nsIDocShell.LOAD_CMD_HISTORY) {
isHistoryStateUpdated = true;
}
if (isHistoryStateUpdated || isReferenceFragmentUpdated) {
let frameTransitionData = this.getFrameTransitionData({
loadType,
request,
DOMWindow,
});
let data = {
frameTransitionData,
isHistoryStateUpdated,
isReferenceFragmentUpdated,
location: locationURI ? locationURI.spec : "",
frameId: WebNavigationFrames.getFrameId(webProgress.DOMWindow),
parentFrameId: WebNavigationFrames.getParentFrameId(
webProgress.DOMWindow
),
};
sendAsyncMessage("Extension:HistoryChange", data);
}
},
getFrameTransitionData({ loadType, request, DOMWindow }) {
let frameTransitionData = {};
if (loadType & Ci.nsIDocShell.LOAD_CMD_HISTORY) {
frameTransitionData.forward_back = true;
}
if (loadType & Ci.nsIDocShell.LOAD_CMD_RELOAD) {
frameTransitionData.reload = true;
}
if (request instanceof Ci.nsIChannel) {
if (request.loadInfo.redirectChain.length) {
frameTransitionData.server_redirect = true;
}
}
if (FormSubmitListener.hasAndForget(DOMWindow)) {
frameTransitionData.form_submit = true;
}
if (this.refreshAttemptedDOMWindows.has(DOMWindow)) {
this.refreshAttemptedDOMWindows.delete(DOMWindow);
frameTransitionData.client_redirect = true;
}
return frameTransitionData;
},
QueryInterface: ChromeUtils.generateQI([
"nsIWebProgressListener",
"nsIWebProgressListener2",
"nsISupportsWeakReference",
]),
};
var disabled = false;
WebProgressListener.init();
FormSubmitListener.init();
CreatedNavigationTargetListener.init();
addEventListener("unload", () => {
if (!disabled) {
disabled = true;
WebProgressListener.uninit();
FormSubmitListener.uninit();
CreatedNavigationTargetListener.uninit();
}
});
addMessageListener("Extension:DisableWebNavigation", () => {
if (!disabled) {
disabled = true;
WebProgressListener.uninit();
FormSubmitListener.uninit();
CreatedNavigationTargetListener.uninit();
}
});

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

@ -1,16 +0,0 @@
# -*- 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/.
Classes = [
{
'cid': '{db82286d-d649-47fb-8599-ba31673a58c5}',
'contract_ids': ['@mozilla.org/extensions/child;1'],
'type': 'mozilla::extensions::ExtensionsChild',
'constructor': 'mozilla::extensions::ExtensionsChild::GetSingleton',
'headers': ['mozilla/extensions/ExtensionsChild.h'],
'categories': {'app-startup': 'ExtensionsChild'},
},
]

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

@ -1,35 +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"
webidl BrowsingContext;
interface nsIURI;
[scriptable, uuid(5cc10dac-cab3-41dd-b4ce-55e27c43cc40)]
interface extIWebNavigation : nsISupports
{
void onDocumentChange(in BrowsingContext bc,
in jsval transitionData,
in nsIURI location);
void onHistoryChange(in BrowsingContext bc,
in jsval transitionData,
in nsIURI location,
in bool isHistoryStateUpdated,
in bool isReferenceFragmentUpdated);
void onStateChange(in BrowsingContext bc,
in nsIURI requestURI,
in nsresult status,
in unsigned long stateFlags);
void onCreatedNavigationTarget(in BrowsingContext bc,
in BrowsingContext sourceBC,
in ACString url);
void onDOMContentLoaded(in BrowsingContext bc,
in nsIURI documentURI);
};

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

@ -43,6 +43,7 @@ EXTRA_JS_MODULES += [
"ProxyChannelFilter.jsm",
"Schemas.jsm",
"WebNavigation.jsm",
"WebNavigationContent.js",
"WebNavigationFrames.jsm",
]
@ -68,12 +69,7 @@ DIRS += [
"webrequest",
]
IPDL_SOURCES += [
"PExtensions.ipdl",
]
XPIDL_SOURCES += [
"extIWebNavigation.idl",
"mozIExtensionProcessScript.idl",
]
@ -85,8 +81,6 @@ EXPORTS.mozilla = [
EXPORTS.mozilla.extensions = [
"DocumentObserver.h",
"ExtensionsChild.h",
"ExtensionsParent.h",
"MatchGlob.h",
"MatchPattern.h",
"WebExtensionContentScript.h",
@ -95,16 +89,10 @@ EXPORTS.mozilla.extensions = [
UNIFIED_SOURCES += [
"ExtensionPolicyService.cpp",
"ExtensionsChild.cpp",
"ExtensionsParent.cpp",
"MatchPattern.cpp",
"WebExtensionPolicy.cpp",
]
XPCOM_MANIFESTS += [
"components.conf",
]
FINAL_LIBRARY = "xul"

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

@ -261,7 +261,8 @@ add_task(async function webnav_transitions_props() {
win.location = CLIENT_REDIRECT_HTTPHEADER;
});
found = received.find((data) => (data.event == "onCommitted" && data.url == REDIRECTED));
found = received.find((data) => (data.event == "onCommitted" &&
data.url == CLIENT_REDIRECT_HTTPHEADER));
ok(found, "Got the onCommitted event");

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

@ -145,7 +145,10 @@ already_AddRefed<ChannelWrapper> ChannelWrapper::Get(const GlobalObject& global,
nsCOMPtr<nsIWritablePropertyBag2> props = do_QueryInterface(channel);
if (props) {
wrapper = do_GetProperty(props, CHANNELWRAPPER_PROP_KEY);
Unused << props->GetPropertyAsInterface(CHANNELWRAPPER_PROP_KEY,
NS_GET_IID(ChannelWrapper),
getter_AddRefs(wrapper));
if (wrapper) {
// Assume cached attributes may have changed at this point.
wrapper->ClearCachedAttributes();

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

@ -1,306 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
/* 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/extensions/WebNavigationContent.h"
#include "mozilla/Assertions.h"
#include "mozilla/ClearOnShutdown.h"
#include "mozilla/dom/BrowsingContext.h"
#include "mozilla/dom/ContentFrameMessageManager.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/extensions/ExtensionsChild.h"
#include "mozilla/EventListenerManager.h"
#include "mozilla/RefPtr.h"
#include "mozilla/ResultExtensions.h"
#include "mozilla/Services.h"
#include "nsCRT.h"
#include "nsDocShellLoadTypes.h"
#include "nsPIWindowRoot.h"
#include "nsIChannel.h"
#include "nsIDocShell.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsIObserverService.h"
#include "nsIPropertyBag2.h"
#include "nsIWebNavigation.h"
#include "nsIWebProgress.h"
#include "nsGlobalWindowOuter.h"
#include "nsQueryObject.h"
namespace mozilla {
namespace extensions {
/* static */
already_AddRefed<WebNavigationContent> WebNavigationContent::GetSingleton() {
static RefPtr<WebNavigationContent> sSingleton;
if (!sSingleton) {
sSingleton = new WebNavigationContent();
sSingleton->Init();
ClearOnShutdown(&sSingleton);
}
return do_AddRef(sSingleton);
}
NS_IMPL_ISUPPORTS(WebNavigationContent, nsIObserver, nsIDOMEventListener,
nsIWebProgressListener, nsISupportsWeakReference)
void WebNavigationContent::Init() {
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->AddObserver(this, "chrome-event-target-created", true);
obs->AddObserver(this, "webNavigation-createdNavigationTarget-from-js", true);
}
NS_IMETHODIMP WebNavigationContent::Observe(nsISupports* aSubject,
char const* aTopic,
char16_t const* aData) {
if (!nsCRT::strcmp(aTopic, "chrome-event-target-created")) {
// This notification is sent whenever a new window root is created, with the
// subject being an EventTarget corresponding to either an nsWindowRoot in a
// child process or an InProcessBrowserChildMessageManager in the parent.
// This is the same entry point used to register listeners for the JS window
// actor API.
if (RefPtr<dom::EventTarget> eventTarget = do_QueryObject(aSubject)) {
AttachListeners(eventTarget);
}
nsCOMPtr<nsIDocShell> docShell;
if (nsCOMPtr<nsPIWindowRoot> root = do_QueryInterface(aSubject)) {
docShell = root->GetWindow()->GetDocShell();
} else if (RefPtr<dom::ContentFrameMessageManager> mm =
do_QueryObject(aSubject)) {
docShell = mm->GetDocShell(IgnoreErrors());
}
if (docShell && docShell->GetBrowsingContext()->IsContent()) {
nsCOMPtr<nsIWebProgress> webProgress(do_GetInterface(docShell));
webProgress->AddProgressListener(this,
nsIWebProgress::NOTIFY_STATE_WINDOW |
nsIWebProgress::NOTIFY_LOCATION);
}
} else if (!nsCRT::strcmp(aTopic,
"webNavigation-createdNavigationTarget-from-js")) {
if (nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject)) {
return OnCreatedNavigationTargetFromJS(props);
}
}
return NS_OK;
}
void WebNavigationContent::AttachListeners(dom::EventTarget* aEventTarget) {
EventListenerManager* elm = aEventTarget->GetOrCreateListenerManager();
NS_ENSURE_TRUE_VOID(elm);
elm->AddEventListenerByType(this, u"DOMContentLoaded"_ns,
TrustedEventsAtCapture());
}
NS_IMETHODIMP
WebNavigationContent::HandleEvent(dom::Event* aEvent) {
nsString type;
aEvent->GetType(type);
if (type.EqualsLiteral(u"DOMContentLoaded")) {
if (RefPtr<dom::Document> doc = do_QueryObject(aEvent->GetTarget())) {
ExtensionsChild::Get().SendDOMContentLoaded(doc->GetBrowsingContext(),
doc->GetDocumentURI());
}
}
return NS_OK;
}
static dom::BrowsingContext* GetBrowsingContext(nsIWebProgress* aWebProgress) {
// FIXME: Get this via nsIWebNavigation instead.
nsCOMPtr<nsIDocShell> docShell(do_GetInterface(aWebProgress));
return docShell->GetBrowsingContext();
}
FrameTransitionData WebNavigationContent::GetFrameTransitionData(
nsIWebProgress* aWebProgress, nsIRequest* aRequest) {
FrameTransitionData result;
uint32_t loadType = 0;
Unused << aWebProgress->GetLoadType(&loadType);
if (loadType & nsIDocShell::LOAD_CMD_HISTORY) {
result.forwardBack() = true;
}
if (loadType & nsIDocShell::LOAD_CMD_RELOAD) {
result.reload() = true;
}
if (LOAD_TYPE_HAS_FLAGS(loadType, nsIWebNavigation::LOAD_FLAGS_IS_REFRESH)) {
result.clientRedirect() = true;
}
if (nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest)) {
nsCOMPtr<nsILoadInfo> loadInfo(channel->LoadInfo());
if (loadInfo->RedirectChain().Length()) {
result.serverRedirect() = true;
}
if (loadInfo->GetIsFormSubmission() &&
!(loadType & (nsIDocShell::LOAD_CMD_HISTORY |
nsIDocShell::LOAD_CMD_RELOAD))) {
result.formSubmit() = true;
}
}
return result;
}
nsresult WebNavigationContent::OnCreatedNavigationTargetFromJS(
nsIPropertyBag2* aProps) {
nsCOMPtr<nsIDocShell> createdDocShell(
do_GetProperty(aProps, u"createdTabDocShell"_ns));
nsCOMPtr<nsIDocShell> sourceDocShell(
do_GetProperty(aProps, u"sourceTabDocShell"_ns));
NS_ENSURE_ARG_POINTER(createdDocShell);
NS_ENSURE_ARG_POINTER(sourceDocShell);
dom::BrowsingContext* createdBC = createdDocShell->GetBrowsingContext();
dom::BrowsingContext* sourceBC = sourceDocShell->GetBrowsingContext();
if (createdBC->IsContent() && sourceBC->IsContent()) {
nsCString url;
Unused << aProps->GetPropertyAsACString(u"url"_ns, url);
ExtensionsChild::Get().SendCreatedNavigationTarget(createdBC, sourceBC,
url);
}
return NS_OK;
}
// nsIWebProgressListener
NS_IMETHODIMP
WebNavigationContent::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, uint32_t aStateFlags,
nsresult aStatus) {
nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest));
NS_ENSURE_TRUE(channel, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsIURI> uri;
MOZ_TRY(channel->GetURI(getter_AddRefs(uri)));
// Prevents "about", "chrome", "resource" and "moz-extension" URI schemes to
// be reported with the resolved "file" or "jar" URIs (see bug 1246125)
if (uri->SchemeIs("file") || uri->SchemeIs("jar")) {
nsCOMPtr<nsIURI> originalURI;
MOZ_TRY(channel->GetOriginalURI(getter_AddRefs(originalURI)));
// FIXME: We probably actually want NS_GetFinalChannelURI here.
if (originalURI->SchemeIs("about") || originalURI->SchemeIs("chrome") ||
originalURI->SchemeIs("resource") ||
originalURI->SchemeIs("moz-extension")) {
uri = originalURI.forget();
}
}
RefPtr<dom::BrowsingContext> bc(GetBrowsingContext(aWebProgress));
NS_ENSURE_ARG_POINTER(bc);
ExtensionsChild::Get().SendStateChange(bc, uri, aStatus, aStateFlags);
// Based on the docs of the webNavigation.onCommitted event, it should be
// raised when: "The document might still be downloading, but at least part
// of the document has been received" and for some reason we don't fire
// onLocationChange for the initial navigation of a sub-frame. For the above
// two reasons, when the navigation event is related to a sub-frame we process
// the document change here and then send an OnDocumentChange message to the
// main process, where it will be turned into a webNavigation.onCommitted
// event. (bug 1264936 and bug 125662)
if (!bc->IsTop() && aStateFlags & nsIWebProgressListener::STATE_IS_DOCUMENT) {
ExtensionsChild::Get().SendDocumentChange(
bc, GetFrameTransitionData(aWebProgress, aRequest), uri);
}
return NS_OK;
}
NS_IMETHODIMP
WebNavigationContent::OnProgressChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress) {
MOZ_ASSERT_UNREACHABLE("Listener did not request ProgressChange events");
return NS_OK;
}
NS_IMETHODIMP
WebNavigationContent::OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, nsIURI* aLocation,
uint32_t aFlags) {
RefPtr<dom::BrowsingContext> bc(GetBrowsingContext(aWebProgress));
NS_ENSURE_ARG_POINTER(bc);
// When a frame navigation doesn't change the current loaded document
// (which can be due to history.pushState/replaceState or to a changed hash in
// the url), it is reported only to the onLocationChange, for this reason we
// process the history change here and then we are going to send an
// OnHistoryChange message to the main process, where it will be turned into
// a webNavigation.onHistoryStateUpdated/onReferenceFragmentUpdated event.
if (aFlags & nsIWebProgressListener::LOCATION_CHANGE_SAME_DOCUMENT) {
uint32_t loadType = 0;
MOZ_TRY(aWebProgress->GetLoadType(&loadType));
// When the location changes but the document is the same:
// - path not changed and hash changed -> |onReferenceFragmentUpdated|
// (even if it changed using |history.pushState|)
// - path not changed and hash not changed -> |onHistoryStateUpdated|
// (only if it changes using |history.pushState|)
// - path changed -> |onHistoryStateUpdated|
bool isHistoryStateUpdated = false;
bool isReferenceFragmentUpdated = false;
if (aFlags & nsIWebProgressListener::LOCATION_CHANGE_HASHCHANGE) {
isReferenceFragmentUpdated = true;
} else if (loadType & nsIDocShell::LOAD_CMD_PUSHSTATE) {
isHistoryStateUpdated = true;
} else if (loadType & nsIDocShell::LOAD_CMD_HISTORY) {
isHistoryStateUpdated = true;
}
if (isHistoryStateUpdated || isReferenceFragmentUpdated) {
ExtensionsChild::Get().SendHistoryChange(
bc, GetFrameTransitionData(aWebProgress, aRequest), aLocation,
isHistoryStateUpdated, isReferenceFragmentUpdated);
}
} else if (bc->IsTop()) {
// We have to catch the document changes from top level frames here,
// where we can detect the "server redirect" transition.
// (bug 1264936 and bug 125662)
ExtensionsChild::Get().SendDocumentChange(
bc, GetFrameTransitionData(aWebProgress, aRequest), aLocation);
}
return NS_OK;
}
NS_IMETHODIMP
WebNavigationContent::OnStatusChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, nsresult aStatus,
const char16_t* aMessage) {
MOZ_ASSERT_UNREACHABLE("Listener did not request StatusChange events");
return NS_OK;
}
NS_IMETHODIMP
WebNavigationContent::OnSecurityChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest, uint32_t aState) {
MOZ_ASSERT_UNREACHABLE("Listener did not request SecurityChange events");
return NS_OK;
}
NS_IMETHODIMP
WebNavigationContent::OnContentBlockingEvent(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aEvent) {
MOZ_ASSERT_UNREACHABLE("Listener did not request ContentBlocking events");
return NS_OK;
}
} // namespace extensions
} // namespace mozilla

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

@ -1,57 +0,0 @@
/* -*- Mode: C++; tab-width: 2; 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_extensions_WebNavigationContent_h
#define mozilla_extensions_WebNavigationContent_h
#include "nsIDOMEventListener.h"
#include "nsIObserver.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
class nsIPropertyBag2;
class nsIRequest;
class nsIWebProgress;
namespace mozilla {
namespace dom {
class EventTarget;
} // namespace dom
namespace extensions {
class FrameTransitionData;
class WebNavigationContent final : public nsIObserver,
public nsIDOMEventListener,
public nsIWebProgressListener,
public nsSupportsWeakReference {
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
NS_DECL_NSIDOMEVENTLISTENER
NS_DECL_NSIWEBPROGRESSLISTENER
static already_AddRefed<WebNavigationContent> GetSingleton();
private:
WebNavigationContent() = default;
~WebNavigationContent() = default;
void AttachListeners(mozilla::dom::EventTarget* aEventTarget);
void Init();
FrameTransitionData GetFrameTransitionData(nsIWebProgress* aWebProgress,
nsIRequest* aRequest);
nsresult OnCreatedNavigationTargetFromJS(nsIPropertyBag2* aProps);
};
} // namespace extensions
} // namespace mozilla
#endif // defined mozilla_extensions_WebNavigationContent_h

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

@ -1,16 +0,0 @@
# -*- 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/.
Classes = [
{
'cid': '{acb22042-2b6c-427b-b550-b9f407c6fff6}',
'contract_ids': ['@mozilla.org/extensions/web-navigation-content;1'],
'type': 'mozilla::extensions::WebNavigationContent',
'constructor': 'mozilla::extensions::WebNavigationContent::GetSingleton',
'headers': ['mozilla/extensions/WebNavigationContent.h'],
'categories': {'app-startup': 'WebNavigationContent'},
},
]

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

@ -16,7 +16,6 @@ UNIFIED_SOURCES += [
"StreamFilterChild.cpp",
"StreamFilterEvents.cpp",
"StreamFilterParent.cpp",
"WebNavigationContent.cpp",
"WebRequestService.cpp",
]
@ -24,10 +23,6 @@ IPDL_SOURCES += [
"PStreamFilter.ipdl",
]
XPCOM_MANIFESTS += [
"components.conf",
]
EXPORTS.mozilla += [
"WebRequestService.h",
]
@ -39,7 +34,6 @@ EXPORTS.mozilla.extensions += [
"StreamFilterChild.h",
"StreamFilterEvents.h",
"StreamFilterParent.h",
"WebNavigationContent.h",
]
LOCAL_INCLUDES += [

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

@ -441,16 +441,10 @@ interface nsIWebProgressListener : nsISupports
* LOCATION_CHANGE_RELOAD
* This flag is on when reloading the current page, either from
* location.reload() or the browser UI.
*
* LOCATION_CHANGE_HASHCHANGE
* This flag is on for same-document location changes where only the URI's
* reference fragment has changed. This flag implies
* LOCATION_CHANGE_SAME_DOCUMENT.
*/
const unsigned long LOCATION_CHANGE_SAME_DOCUMENT = 0x00000001;
const unsigned long LOCATION_CHANGE_ERROR_PAGE = 0x00000002;
const unsigned long LOCATION_CHANGE_RELOAD = 0x00000004;
const unsigned long LOCATION_CHANGE_HASHCHANGE = 0x00000008;
/**
* Called when the location of the window being watched changes. This is not

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

@ -265,23 +265,6 @@ void nsHashPropertyBagBase::CopyFrom(nsIPropertyBag* aOther) {
}
}
nsresult nsGetProperty::operator()(const nsIID& aIID,
void** aInstancePtr) const {
nsresult rv;
if (mPropBag) {
rv = mPropBag->GetPropertyAsInterface(mPropName, aIID, aInstancePtr);
} else {
rv = NS_ERROR_NULL_POINTER;
*aInstancePtr = 0;
}
if (mErrorPtr) {
*mErrorPtr = rv;
}
return rv;
}
/*
* nsHashPropertyBag implementation.
*/

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

@ -24,9 +24,6 @@ interface nsIPropertyBag2 : nsIPropertyBag
/**
* This method returns null if the value exists, but is null.
*
* Note: C++ callers should not use this method. They should use the
* typesafe `do_GetProperty` wrapper instead.
*/
void getPropertyAsInterface (in AString prop,
in nsIIDRef iid,
@ -43,38 +40,3 @@ interface nsIPropertyBag2 : nsIPropertyBag
*/
boolean hasKey (in AString prop);
};
%{C++
#include "nsCOMPtr.h"
#include "nsAString.h"
class MOZ_STACK_CLASS nsGetProperty final : public nsCOMPtr_helper {
public:
nsGetProperty(nsIPropertyBag2* aPropBag, const nsAString& aPropName, nsresult* aError)
: mPropBag(aPropBag), mPropName(aPropName), mErrorPtr(aError) {}
virtual nsresult NS_FASTCALL operator()(const nsIID&, void**) const override;
private:
nsIPropertyBag2* MOZ_NON_OWNING_REF mPropBag;
const nsAString& mPropName;
nsresult* mErrorPtr;
};
/**
* A typesafe wrapper around nsIPropertyBag2::GetPropertyAsInterface. Similar
* to the `do_QueryInterface` family of functions, when assigned to a
* `nsCOMPtr` of a given type, attempts to query the given property to that
* type.
*
* If `aError` is passed, the return value of `GetPropertyAsInterface` is
* stored in it.
*/
inline const nsGetProperty do_GetProperty(nsIPropertyBag2* aPropBag,
const nsAString& aPropName,
nsresult* aError = 0) {
return nsGetProperty(aPropBag, aPropName, aError);
}
%}