forked from mirrors/gecko-dev
Backed out changeset 455ce831c73c (bug 1876575) Backed out changeset 4fa3fbf3a3ae (bug 1876575) Backed out changeset ac4c41cb3b67 (bug 1876575) Backed out changeset 15e06d10788e (bug 1876575) Backed out changeset dcd6bbea816a (bug 1876575) Backed out changeset cc547125fda9 (bug 1876574)
508 lines
17 KiB
C++
508 lines
17 KiB
C++
/* -*- 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 "WorkerLoadInfo.h"
|
|
#include "WorkerPrivate.h"
|
|
|
|
#include "mozilla/BasePrincipal.h"
|
|
#include "mozilla/dom/nsCSPUtils.h"
|
|
#include "mozilla/dom/BrowserChild.h"
|
|
#include "mozilla/dom/ReferrerInfo.h"
|
|
#include "mozilla/ipc/BackgroundUtils.h"
|
|
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
|
#include "mozilla/LoadContext.h"
|
|
#include "mozilla/StorageAccess.h"
|
|
#include "mozilla/StoragePrincipalHelper.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsIContentSecurityPolicy.h"
|
|
#include "nsICookieJarSettings.h"
|
|
#include "nsINetworkInterceptController.h"
|
|
#include "nsIProtocolHandler.h"
|
|
#include "nsIReferrerInfo.h"
|
|
#include "nsIBrowserChild.h"
|
|
#include "nsScriptSecurityManager.h"
|
|
#include "nsNetUtil.h"
|
|
|
|
namespace mozilla {
|
|
|
|
using namespace ipc;
|
|
|
|
namespace dom {
|
|
|
|
namespace {
|
|
|
|
class MainThreadReleaseRunnable final : public Runnable {
|
|
nsTArray<nsCOMPtr<nsISupports>> mDoomed;
|
|
nsCOMPtr<nsILoadGroup> mLoadGroupToCancel;
|
|
|
|
public:
|
|
MainThreadReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>>&& aDoomed,
|
|
nsCOMPtr<nsILoadGroup>&& aLoadGroupToCancel)
|
|
: mozilla::Runnable("MainThreadReleaseRunnable"),
|
|
mDoomed(std::move(aDoomed)),
|
|
mLoadGroupToCancel(std::move(aLoadGroupToCancel)) {}
|
|
|
|
NS_INLINE_DECL_REFCOUNTING_INHERITED(MainThreadReleaseRunnable, Runnable)
|
|
|
|
NS_IMETHOD
|
|
Run() override {
|
|
if (mLoadGroupToCancel) {
|
|
mLoadGroupToCancel->CancelWithReason(
|
|
NS_BINDING_ABORTED, "WorkerLoadInfo::MainThreadReleaseRunnable"_ns);
|
|
mLoadGroupToCancel = nullptr;
|
|
}
|
|
|
|
mDoomed.Clear();
|
|
return NS_OK;
|
|
}
|
|
|
|
private:
|
|
~MainThreadReleaseRunnable() = default;
|
|
};
|
|
|
|
// Specialize this if there's some class that has multiple nsISupports bases.
|
|
template <class T>
|
|
struct ISupportsBaseInfo {
|
|
using ISupportsBase = T;
|
|
};
|
|
|
|
template <template <class> class SmartPtr, class T>
|
|
inline void SwapToISupportsArray(SmartPtr<T>& aSrc,
|
|
nsTArray<nsCOMPtr<nsISupports>>& aDest) {
|
|
nsCOMPtr<nsISupports>* dest = aDest.AppendElement();
|
|
|
|
T* raw = nullptr;
|
|
aSrc.swap(raw);
|
|
|
|
nsISupports* rawSupports =
|
|
static_cast<typename ISupportsBaseInfo<T>::ISupportsBase*>(raw);
|
|
dest->swap(rawSupports);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
WorkerLoadInfoData::WorkerLoadInfoData()
|
|
: mLoadFlags(nsIRequest::LOAD_NORMAL),
|
|
mWindowID(UINT64_MAX),
|
|
mAssociatedBrowsingContextID(0),
|
|
mReferrerInfo(new ReferrerInfo(nullptr)),
|
|
mFromWindow(false),
|
|
mEvalAllowed(false),
|
|
mReportEvalCSPViolations(false),
|
|
mWasmEvalAllowed(false),
|
|
mReportWasmEvalCSPViolations(false),
|
|
mXHRParamsAllowed(false),
|
|
mWatchedByDevTools(false),
|
|
mStorageAccess(StorageAccess::eDeny),
|
|
mUseRegularPrincipal(false),
|
|
mUsingStorageAccess(false),
|
|
mServiceWorkersTestingInWindow(false),
|
|
mShouldResistFingerprinting(false),
|
|
mIsThirdPartyContextToTopWindow(true),
|
|
mSecureContext(eNotSet) {}
|
|
|
|
nsresult WorkerLoadInfo::SetPrincipalsAndCSPOnMainThread(
|
|
nsIPrincipal* aPrincipal, nsIPrincipal* aPartitionedPrincipal,
|
|
nsILoadGroup* aLoadGroup, nsIContentSecurityPolicy* aCsp) {
|
|
AssertIsOnMainThread();
|
|
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
|
|
|
|
mPrincipal = aPrincipal;
|
|
mPartitionedPrincipal = aPartitionedPrincipal;
|
|
|
|
mCSP = aCsp;
|
|
|
|
if (mCSP) {
|
|
mCSP->GetAllowsEval(&mReportEvalCSPViolations, &mEvalAllowed);
|
|
mCSP->GetAllowsWasmEval(&mReportWasmEvalCSPViolations, &mWasmEvalAllowed);
|
|
mCSPInfo = MakeUnique<CSPInfo>();
|
|
nsresult rv = CSPToCSPInfo(aCsp, mCSPInfo.get());
|
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
|
return rv;
|
|
}
|
|
} else {
|
|
mEvalAllowed = true;
|
|
mReportEvalCSPViolations = false;
|
|
mWasmEvalAllowed = true;
|
|
mReportWasmEvalCSPViolations = false;
|
|
}
|
|
|
|
mLoadGroup = aLoadGroup;
|
|
|
|
mPrincipalInfo = MakeUnique<PrincipalInfo>();
|
|
mPartitionedPrincipalInfo = MakeUnique<PrincipalInfo>();
|
|
StoragePrincipalHelper::GetRegularPrincipalOriginAttributes(
|
|
aLoadGroup, mOriginAttributes);
|
|
|
|
nsresult rv = PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo.get());
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (aPrincipal->Equals(aPartitionedPrincipal)) {
|
|
*mPartitionedPrincipalInfo = *mPrincipalInfo;
|
|
} else {
|
|
mPartitionedPrincipalInfo = MakeUnique<PrincipalInfo>();
|
|
rv = PrincipalToPrincipalInfo(aPartitionedPrincipal,
|
|
mPartitionedPrincipalInfo.get());
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult WorkerLoadInfo::GetPrincipalsAndLoadGroupFromChannel(
|
|
nsIChannel* aChannel, nsIPrincipal** aPrincipalOut,
|
|
nsIPrincipal** aPartitionedPrincipalOut, nsILoadGroup** aLoadGroupOut) {
|
|
AssertIsOnMainThread();
|
|
MOZ_DIAGNOSTIC_ASSERT(aChannel);
|
|
MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
|
|
MOZ_DIAGNOSTIC_ASSERT(aPartitionedPrincipalOut);
|
|
MOZ_DIAGNOSTIC_ASSERT(aLoadGroupOut);
|
|
|
|
// Initial triggering principal should be set
|
|
NS_ENSURE_TRUE(mLoadingPrincipal, NS_ERROR_DOM_INVALID_STATE_ERR);
|
|
|
|
nsIScriptSecurityManager* ssm = nsContentUtils::GetSecurityManager();
|
|
MOZ_DIAGNOSTIC_ASSERT(ssm);
|
|
|
|
nsCOMPtr<nsIPrincipal> channelPrincipal;
|
|
nsCOMPtr<nsIPrincipal> channelPartitionedPrincipal;
|
|
nsresult rv = ssm->GetChannelResultPrincipals(
|
|
aChannel, getter_AddRefs(channelPrincipal),
|
|
getter_AddRefs(channelPartitionedPrincipal));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Every time we call GetChannelResultPrincipal() it will return a different
|
|
// null principal for a data URL. We don't want to change the worker's
|
|
// principal again, though. Instead just keep the original null principal we
|
|
// first got from the channel.
|
|
//
|
|
// Note, we don't do this by setting principalToInherit on the channel's
|
|
// load info because we don't yet have the first null principal when we
|
|
// create the channel.
|
|
if (mPrincipal && mPrincipal->GetIsNullPrincipal() &&
|
|
channelPrincipal->GetIsNullPrincipal()) {
|
|
channelPrincipal = mPrincipal;
|
|
channelPartitionedPrincipal = mPrincipal;
|
|
}
|
|
|
|
nsCOMPtr<nsILoadGroup> channelLoadGroup;
|
|
rv = aChannel->GetLoadGroup(getter_AddRefs(channelLoadGroup));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
MOZ_ASSERT(channelLoadGroup);
|
|
|
|
// If the loading principal is the system principal then the channel
|
|
// principal must also be the system principal (we do not allow chrome
|
|
// code to create workers with non-chrome scripts, and if we ever decide
|
|
// to change this we need to make sure we don't always set
|
|
// mPrincipalIsSystem to true in WorkerPrivate::GetLoadInfo()). Otherwise
|
|
// this channel principal must be same origin with the load principal (we
|
|
// check again here in case redirects changed the location of the script).
|
|
if (mLoadingPrincipal->IsSystemPrincipal()) {
|
|
if (!channelPrincipal->IsSystemPrincipal()) {
|
|
nsCOMPtr<nsIURI> finalURI;
|
|
rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(finalURI));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// See if this is a resource URI. Since JSMs usually come from
|
|
// resource:// URIs we're currently considering all URIs with the
|
|
// URI_IS_UI_RESOURCE flag as valid for creating privileged workers.
|
|
bool isResource;
|
|
rv = NS_URIChainHasFlags(finalURI, nsIProtocolHandler::URI_IS_UI_RESOURCE,
|
|
&isResource);
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
if (isResource) {
|
|
// Assign the system principal to the resource:// worker only if it
|
|
// was loaded from code using the system principal.
|
|
channelPrincipal = mLoadingPrincipal;
|
|
channelPartitionedPrincipal = mLoadingPrincipal;
|
|
} else {
|
|
return NS_ERROR_DOM_BAD_URI;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The principal can change, but it should still match the original
|
|
// load group's browser element flag.
|
|
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
|
|
|
|
channelPrincipal.forget(aPrincipalOut);
|
|
channelPartitionedPrincipal.forget(aPartitionedPrincipalOut);
|
|
channelLoadGroup.forget(aLoadGroupOut);
|
|
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult WorkerLoadInfo::SetPrincipalsAndCSPFromChannel(nsIChannel* aChannel) {
|
|
AssertIsOnMainThread();
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
nsCOMPtr<nsIPrincipal> partitionedPrincipal;
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
nsresult rv = GetPrincipalsAndLoadGroupFromChannel(
|
|
aChannel, getter_AddRefs(principal), getter_AddRefs(partitionedPrincipal),
|
|
getter_AddRefs(loadGroup));
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
// Workers themselves can have their own CSP - Workers of an opaque origin
|
|
// however inherit the CSP of the document that spawned the worker.
|
|
nsCOMPtr<nsIContentSecurityPolicy> csp;
|
|
if (CSP_ShouldResponseInheritCSP(aChannel)) {
|
|
nsCOMPtr<nsILoadInfo> loadinfo = aChannel->LoadInfo();
|
|
csp = loadinfo->GetCsp();
|
|
}
|
|
return SetPrincipalsAndCSPOnMainThread(principal, partitionedPrincipal,
|
|
loadGroup, csp);
|
|
}
|
|
|
|
bool WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel) {
|
|
AssertIsOnMainThread();
|
|
|
|
nsCOMPtr<nsIPrincipal> principal;
|
|
nsCOMPtr<nsIPrincipal> partitionedPrincipal;
|
|
nsCOMPtr<nsILoadGroup> loadGroup;
|
|
nsresult rv = GetPrincipalsAndLoadGroupFromChannel(
|
|
aChannel, getter_AddRefs(principal), getter_AddRefs(partitionedPrincipal),
|
|
getter_AddRefs(loadGroup));
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
// Verify that the channel is still a null principal. We don't care
|
|
// if these are the exact same null principal object, though. From
|
|
// the worker's perspective its the same effect.
|
|
if (principal->GetIsNullPrincipal() && mPrincipal->GetIsNullPrincipal()) {
|
|
return true;
|
|
}
|
|
|
|
// Otherwise we require exact equality. Redirects can happen, but they
|
|
// are not allowed to change our principal.
|
|
if (principal->Equals(mPrincipal)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
|
bool WorkerLoadInfo::PrincipalIsValid() const {
|
|
return mPrincipal && mPrincipalInfo &&
|
|
mPrincipalInfo->type() != PrincipalInfo::T__None &&
|
|
mPrincipalInfo->type() <= PrincipalInfo::T__Last &&
|
|
mPartitionedPrincipal && mPartitionedPrincipalInfo &&
|
|
mPartitionedPrincipalInfo->type() != PrincipalInfo::T__None &&
|
|
mPartitionedPrincipalInfo->type() <= PrincipalInfo::T__Last;
|
|
}
|
|
|
|
bool WorkerLoadInfo::PrincipalURIMatchesScriptURL() {
|
|
AssertIsOnMainThread();
|
|
|
|
nsAutoCString scheme;
|
|
nsresult rv = mBaseURI->GetScheme(scheme);
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
// A system principal must either be a blob URL or a resource JSM.
|
|
if (mPrincipal->IsSystemPrincipal()) {
|
|
if (scheme == "blob"_ns) {
|
|
return true;
|
|
}
|
|
|
|
bool isResource = false;
|
|
nsresult rv = NS_URIChainHasFlags(
|
|
mBaseURI, nsIProtocolHandler::URI_IS_UI_RESOURCE, &isResource);
|
|
NS_ENSURE_SUCCESS(rv, false);
|
|
|
|
return isResource;
|
|
}
|
|
|
|
// A null principal can occur for a data URL worker script or a blob URL
|
|
// worker script from a sandboxed iframe.
|
|
if (mPrincipal->GetIsNullPrincipal()) {
|
|
return scheme == "data"_ns || scheme == "blob"_ns;
|
|
}
|
|
|
|
// The principal for a blob: URL worker script does not have a matching URL.
|
|
// This is likely a bug in our referer setting logic, but exempt it for now.
|
|
// This is another reason we should fix bug 1340694 so that referer does not
|
|
// depend on the principal URI.
|
|
if (scheme == "blob"_ns) {
|
|
return true;
|
|
}
|
|
|
|
if (mPrincipal->IsSameOrigin(mBaseURI)) {
|
|
return true;
|
|
}
|
|
|
|
// If strict file origin policy is in effect, local files will always fail
|
|
// IsSameOrigin unless they are identical. Explicitly check file origin
|
|
// policy, in that case.
|
|
|
|
bool allowsRelaxedOriginPolicy = false;
|
|
rv = mPrincipal->AllowsRelaxStrictFileOriginPolicy(
|
|
mBaseURI, &allowsRelaxedOriginPolicy);
|
|
|
|
if (nsScriptSecurityManager::GetStrictFileOriginPolicy() &&
|
|
NS_URIIsLocalFile(mBaseURI) &&
|
|
(NS_SUCCEEDED(rv) && allowsRelaxedOriginPolicy)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
|
|
|
bool WorkerLoadInfo::ProxyReleaseMainThreadObjects(
|
|
WorkerPrivate* aWorkerPrivate) {
|
|
nsCOMPtr<nsILoadGroup> nullLoadGroup;
|
|
return ProxyReleaseMainThreadObjects(aWorkerPrivate,
|
|
std::move(nullLoadGroup));
|
|
}
|
|
|
|
bool WorkerLoadInfo::ProxyReleaseMainThreadObjects(
|
|
WorkerPrivate* aWorkerPrivate,
|
|
nsCOMPtr<nsILoadGroup>&& aLoadGroupToCancel) {
|
|
static const uint32_t kDoomedCount = 11;
|
|
nsTArray<nsCOMPtr<nsISupports>> doomed(kDoomedCount);
|
|
|
|
SwapToISupportsArray(mWindow, doomed);
|
|
SwapToISupportsArray(mScriptContext, doomed);
|
|
SwapToISupportsArray(mBaseURI, doomed);
|
|
SwapToISupportsArray(mResolvedScriptURI, doomed);
|
|
SwapToISupportsArray(mPrincipal, doomed);
|
|
SwapToISupportsArray(mPartitionedPrincipal, doomed);
|
|
SwapToISupportsArray(mLoadingPrincipal, doomed);
|
|
SwapToISupportsArray(mChannel, doomed);
|
|
SwapToISupportsArray(mCSP, doomed);
|
|
SwapToISupportsArray(mLoadGroup, doomed);
|
|
SwapToISupportsArray(mInterfaceRequestor, doomed);
|
|
// Before adding anything here update kDoomedCount above!
|
|
|
|
MOZ_ASSERT(doomed.Length() == kDoomedCount);
|
|
|
|
RefPtr<MainThreadReleaseRunnable> runnable = new MainThreadReleaseRunnable(
|
|
std::move(doomed), std::move(aLoadGroupToCancel));
|
|
return NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(runnable.forget()));
|
|
}
|
|
|
|
WorkerLoadInfo::InterfaceRequestor::InterfaceRequestor(
|
|
nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(aPrincipal);
|
|
|
|
// Look for an existing LoadContext. This is optional and it's ok if
|
|
// we don't find one.
|
|
nsCOMPtr<nsILoadContext> baseContext;
|
|
if (aLoadGroup) {
|
|
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
|
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
|
if (callbacks) {
|
|
callbacks->GetInterface(NS_GET_IID(nsILoadContext),
|
|
getter_AddRefs(baseContext));
|
|
}
|
|
mOuterRequestor = callbacks;
|
|
}
|
|
|
|
mLoadContext = new LoadContext(aPrincipal, baseContext);
|
|
}
|
|
|
|
void WorkerLoadInfo::InterfaceRequestor::MaybeAddBrowserChild(
|
|
nsILoadGroup* aLoadGroup) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
if (!aLoadGroup) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
|
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
|
if (!callbacks) {
|
|
return;
|
|
}
|
|
|
|
nsCOMPtr<nsIBrowserChild> browserChild;
|
|
callbacks->GetInterface(NS_GET_IID(nsIBrowserChild),
|
|
getter_AddRefs(browserChild));
|
|
if (!browserChild) {
|
|
return;
|
|
}
|
|
|
|
// Use weak references to the tab child. Holding a strong reference will
|
|
// not prevent an ActorDestroy() from being called on the BrowserChild.
|
|
// Therefore, we should let the BrowserChild destroy itself as soon as
|
|
// possible.
|
|
mBrowserChildList.AppendElement(do_GetWeakReference(browserChild));
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
WorkerLoadInfo::InterfaceRequestor::GetInterface(const nsIID& aIID,
|
|
void** aSink) {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
MOZ_ASSERT(mLoadContext);
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
|
|
nsCOMPtr<nsILoadContext> ref = mLoadContext;
|
|
ref.forget(aSink);
|
|
return NS_OK;
|
|
}
|
|
|
|
// If we still have an active nsIBrowserChild, then return it. Its possible,
|
|
// though, that all of the BrowserChild objects have been destroyed. In that
|
|
// case we return NS_NOINTERFACE.
|
|
if (aIID.Equals(NS_GET_IID(nsIBrowserChild))) {
|
|
nsCOMPtr<nsIBrowserChild> browserChild = GetAnyLiveBrowserChild();
|
|
if (!browserChild) {
|
|
return NS_NOINTERFACE;
|
|
}
|
|
browserChild.forget(aSink);
|
|
return NS_OK;
|
|
}
|
|
|
|
if (aIID.Equals(NS_GET_IID(nsINetworkInterceptController)) &&
|
|
mOuterRequestor) {
|
|
// If asked for the network intercept controller, ask the outer requestor,
|
|
// which could be the docshell.
|
|
return mOuterRequestor->GetInterface(aIID, aSink);
|
|
}
|
|
|
|
return NS_NOINTERFACE;
|
|
}
|
|
|
|
already_AddRefed<nsIBrowserChild>
|
|
WorkerLoadInfo::InterfaceRequestor::GetAnyLiveBrowserChild() {
|
|
MOZ_ASSERT(NS_IsMainThread());
|
|
|
|
// Search our list of known BrowserChild objects for one that still exists.
|
|
while (!mBrowserChildList.IsEmpty()) {
|
|
nsCOMPtr<nsIBrowserChild> browserChild =
|
|
do_QueryReferent(mBrowserChildList.LastElement());
|
|
|
|
// Does this tab child still exist? If so, return it. We are done. If the
|
|
// PBrowser actor is no longer useful, don't bother returning this tab.
|
|
if (browserChild &&
|
|
!static_cast<BrowserChild*>(browserChild.get())->IsDestroyed()) {
|
|
return browserChild.forget();
|
|
}
|
|
|
|
// Otherwise remove the stale weak reference and check the next one
|
|
mBrowserChildList.RemoveLastElement();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
NS_IMPL_ADDREF(WorkerLoadInfo::InterfaceRequestor)
|
|
NS_IMPL_RELEASE(WorkerLoadInfo::InterfaceRequestor)
|
|
NS_IMPL_QUERY_INTERFACE(WorkerLoadInfo::InterfaceRequestor,
|
|
nsIInterfaceRequestor)
|
|
|
|
WorkerLoadInfo::WorkerLoadInfo() { MOZ_COUNT_CTOR(WorkerLoadInfo); }
|
|
|
|
WorkerLoadInfo::WorkerLoadInfo(WorkerLoadInfo&& aOther) noexcept
|
|
: WorkerLoadInfoData(std::move(aOther)) {
|
|
MOZ_COUNT_CTOR(WorkerLoadInfo);
|
|
}
|
|
|
|
WorkerLoadInfo::~WorkerLoadInfo() { MOZ_COUNT_DTOR(WorkerLoadInfo); }
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|