Bug 1413112 - Move WorkerLoadInfo into separate files, r=bkelly
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
#include "Principal.h"
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerDebuggerManager.h"
|
||||
#include "WorkerLoadInfo.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerScope.h"
|
||||
|
||||
@@ -22,6 +22,7 @@ class nsPIDOMWindowInner;
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class SharedWorker;
|
||||
struct WorkerLoadInfo;
|
||||
class WorkerThread;
|
||||
|
||||
class RuntimeService final : public nsIObserver
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "mozilla/dom/ChannelInfo.h"
|
||||
#include "mozilla/dom/ServiceWorkerDescriptor.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
@@ -34,23 +33,12 @@
|
||||
|
||||
#define WORKERS_SHUTDOWN_TOPIC "web-workers-shutdown"
|
||||
|
||||
class nsIContentSecurityPolicy;
|
||||
class nsIScriptContext;
|
||||
class nsIGlobalObject;
|
||||
class nsPIDOMWindowInner;
|
||||
class nsIPrincipal;
|
||||
class nsILoadGroup;
|
||||
class nsITabChild;
|
||||
class nsIChannel;
|
||||
class nsIRunnable;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
} // namespace ipc
|
||||
|
||||
namespace dom {
|
||||
|
||||
// If you change this, the corresponding list in nsIWorkerDebugger.idl needs to
|
||||
// be updated too.
|
||||
enum WorkerType
|
||||
@@ -185,117 +173,6 @@ struct JSSettings
|
||||
}
|
||||
};
|
||||
|
||||
// Implemented in WorkerPrivate.cpp
|
||||
|
||||
struct WorkerLoadInfo
|
||||
{
|
||||
// All of these should be released in WorkerPrivateParent::ForgetMainThreadObjects.
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
nsCOMPtr<nsIURI> mResolvedScriptURI;
|
||||
|
||||
// This is the principal of the global (parent worker or a window) loading
|
||||
// the worker. It can be null if we are executing a ServiceWorker, otherwise,
|
||||
// except for data: URL, it must subsumes the worker principal.
|
||||
// If we load a data: URL, mPrincipal will be a null principal.
|
||||
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
nsCOMPtr<nsIScriptContext> mScriptContext;
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
// mLoadFailedAsyncRunnable will execute on main thread if script loading
|
||||
// fails during script loading. If script loading is never started due to
|
||||
// a synchronous error, then the runnable is never executed. The runnable
|
||||
// is guaranteed to be released on the main thread.
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedAsyncRunnable;
|
||||
|
||||
class InterfaceRequestor final : public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
public:
|
||||
InterfaceRequestor(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
|
||||
void MaybeAddTabChild(nsILoadGroup* aLoadGroup);
|
||||
NS_IMETHOD GetInterface(const nsIID& aIID, void** aSink) override;
|
||||
|
||||
private:
|
||||
~InterfaceRequestor() { }
|
||||
|
||||
already_AddRefed<nsITabChild> GetAnyLiveTabChild();
|
||||
|
||||
nsCOMPtr<nsILoadContext> mLoadContext;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mOuterRequestor;
|
||||
|
||||
// Array of weak references to nsITabChild. We do not want to keep TabChild
|
||||
// actors alive for long after their ActorDestroy() methods are called.
|
||||
nsTArray<nsWeakPtr> mTabChildList;
|
||||
};
|
||||
|
||||
// Only set if we have a custom overriden load group
|
||||
RefPtr<InterfaceRequestor> mInterfaceRequestor;
|
||||
|
||||
nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||
nsCString mDomain;
|
||||
nsString mOrigin; // Derived from mPrincipal; can be used on worker thread.
|
||||
|
||||
nsString mServiceWorkerCacheName;
|
||||
Maybe<ServiceWorkerDescriptor> mServiceWorkerDescriptor;
|
||||
|
||||
Maybe<ServiceWorkerDescriptor> mParentController;
|
||||
|
||||
ChannelInfo mChannelInfo;
|
||||
nsLoadFlags mLoadFlags;
|
||||
|
||||
uint64_t mWindowID;
|
||||
|
||||
net::ReferrerPolicy mReferrerPolicy;
|
||||
bool mFromWindow;
|
||||
bool mEvalAllowed;
|
||||
bool mReportCSPViolations;
|
||||
bool mXHRParamsAllowed;
|
||||
bool mPrincipalIsSystem;
|
||||
bool mStorageAllowed;
|
||||
bool mServiceWorkersTestingInWindow;
|
||||
OriginAttributes mOriginAttributes;
|
||||
|
||||
WorkerLoadInfo();
|
||||
~WorkerLoadInfo();
|
||||
|
||||
void StealFrom(WorkerLoadInfo& aOther);
|
||||
|
||||
nsresult
|
||||
SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
|
||||
|
||||
nsresult
|
||||
GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipalOut,
|
||||
nsILoadGroup** aLoadGroupOut);
|
||||
|
||||
nsresult
|
||||
SetPrincipalFromChannel(nsIChannel* aChannel);
|
||||
|
||||
bool
|
||||
FinalChannelPrincipalIsValid(nsIChannel* aChannel);
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
bool
|
||||
PrincipalIsValid() const;
|
||||
|
||||
bool
|
||||
PrincipalURIMatchesScriptURL();
|
||||
#endif
|
||||
|
||||
bool
|
||||
ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
bool
|
||||
ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate,
|
||||
nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel);
|
||||
};
|
||||
|
||||
// All of these are implemented in RuntimeService.cpp
|
||||
|
||||
void
|
||||
|
||||
547
dom/workers/WorkerLoadInfo.cpp
Normal file
547
dom/workers/WorkerLoadInfo.cpp
Normal file
@@ -0,0 +1,547 @@
|
||||
/* -*- 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/dom/TabChild.h"
|
||||
#include "mozilla/ipc/BackgroundUtils.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/LoadContext.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIProtocolHandler.h"
|
||||
#include "nsITabChild.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace ipc;
|
||||
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
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.SwapElements(aDoomed);
|
||||
mLoadGroupToCancel.swap(aLoadGroupToCancel);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
if (mLoadGroupToCancel) {
|
||||
mLoadGroupToCancel->Cancel(NS_BINDING_ABORTED);
|
||||
mLoadGroupToCancel = nullptr;
|
||||
}
|
||||
|
||||
mDoomed.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~MainThreadReleaseRunnable()
|
||||
{ }
|
||||
};
|
||||
|
||||
// Specialize this if there's some class that has multiple nsISupports bases.
|
||||
template <class T>
|
||||
struct ISupportsBaseInfo
|
||||
{
|
||||
typedef T ISupportsBase;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(MainThreadReleaseRunnable, Runnable)
|
||||
|
||||
WorkerLoadInfo::WorkerLoadInfo()
|
||||
: mLoadFlags(nsIRequest::LOAD_NORMAL)
|
||||
, mWindowID(UINT64_MAX)
|
||||
, mReferrerPolicy(net::RP_Unset)
|
||||
, mFromWindow(false)
|
||||
, mEvalAllowed(false)
|
||||
, mReportCSPViolations(false)
|
||||
, mXHRParamsAllowed(false)
|
||||
, mPrincipalIsSystem(false)
|
||||
, mStorageAllowed(false)
|
||||
, mServiceWorkersTestingInWindow(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(WorkerLoadInfo);
|
||||
}
|
||||
|
||||
WorkerLoadInfo::~WorkerLoadInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WorkerLoadInfo);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
|
||||
{
|
||||
MOZ_ASSERT(!mBaseURI);
|
||||
aOther.mBaseURI.swap(mBaseURI);
|
||||
|
||||
MOZ_ASSERT(!mResolvedScriptURI);
|
||||
aOther.mResolvedScriptURI.swap(mResolvedScriptURI);
|
||||
|
||||
MOZ_ASSERT(!mPrincipal);
|
||||
aOther.mPrincipal.swap(mPrincipal);
|
||||
|
||||
// mLoadingPrincipal can be null if this is a ServiceWorker.
|
||||
aOther.mLoadingPrincipal.swap(mLoadingPrincipal);
|
||||
|
||||
MOZ_ASSERT(!mScriptContext);
|
||||
aOther.mScriptContext.swap(mScriptContext);
|
||||
|
||||
MOZ_ASSERT(!mWindow);
|
||||
aOther.mWindow.swap(mWindow);
|
||||
|
||||
MOZ_ASSERT(!mCSP);
|
||||
aOther.mCSP.swap(mCSP);
|
||||
|
||||
MOZ_ASSERT(!mChannel);
|
||||
aOther.mChannel.swap(mChannel);
|
||||
|
||||
MOZ_ASSERT(!mLoadGroup);
|
||||
aOther.mLoadGroup.swap(mLoadGroup);
|
||||
|
||||
MOZ_ASSERT(!mLoadFailedAsyncRunnable);
|
||||
aOther.mLoadFailedAsyncRunnable.swap(mLoadFailedAsyncRunnable);
|
||||
|
||||
MOZ_ASSERT(!mInterfaceRequestor);
|
||||
aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
|
||||
|
||||
MOZ_ASSERT(!mPrincipalInfo);
|
||||
mPrincipalInfo = aOther.mPrincipalInfo.forget();
|
||||
|
||||
mDomain = aOther.mDomain;
|
||||
mOrigin = aOther.mOrigin;
|
||||
mServiceWorkerCacheName = aOther.mServiceWorkerCacheName;
|
||||
mServiceWorkerDescriptor = aOther.mServiceWorkerDescriptor;
|
||||
mLoadFlags = aOther.mLoadFlags;
|
||||
mWindowID = aOther.mWindowID;
|
||||
mReferrerPolicy = aOther.mReferrerPolicy;
|
||||
mFromWindow = aOther.mFromWindow;
|
||||
mEvalAllowed = aOther.mEvalAllowed;
|
||||
mReportCSPViolations = aOther.mReportCSPViolations;
|
||||
mXHRParamsAllowed = aOther.mXHRParamsAllowed;
|
||||
mPrincipalIsSystem = aOther.mPrincipalIsSystem;
|
||||
mStorageAllowed = aOther.mStorageAllowed;
|
||||
mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
|
||||
mOriginAttributes = aOther.mOriginAttributes;
|
||||
mParentController = aOther.mParentController;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
|
||||
|
||||
mPrincipal = aPrincipal;
|
||||
mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
|
||||
|
||||
nsresult rv = aPrincipal->GetCsp(getter_AddRefs(mCSP));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mCSP) {
|
||||
mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
|
||||
// Set ReferrerPolicy
|
||||
bool hasReferrerPolicy = false;
|
||||
uint32_t rp = mozilla::net::RP_Unset;
|
||||
|
||||
rv = mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hasReferrerPolicy) {
|
||||
mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
|
||||
}
|
||||
} else {
|
||||
mEvalAllowed = true;
|
||||
mReportCSPViolations = false;
|
||||
}
|
||||
|
||||
mLoadGroup = aLoadGroup;
|
||||
|
||||
mPrincipalInfo = new PrincipalInfo();
|
||||
mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
|
||||
|
||||
rv = PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = nsContentUtils::GetUTFOrigin(aPrincipal, mOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WorkerLoadInfo::GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipalOut,
|
||||
nsILoadGroup** aLoadGroupOut)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChannel);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
|
||||
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;
|
||||
nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
|
||||
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;
|
||||
}
|
||||
|
||||
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 (nsContentUtils::IsSystemPrincipal(mLoadingPrincipal)) {
|
||||
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
|
||||
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;
|
||||
} else {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The principal can change, but it should still match the original
|
||||
// load group's appId and browser element flag.
|
||||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
|
||||
|
||||
channelPrincipal.forget(aPrincipalOut);
|
||||
channelLoadGroup.forget(aLoadGroupOut);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
|
||||
getter_AddRefs(principal),
|
||||
getter_AddRefs(loadGroup));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return SetPrincipalOnMainThread(principal, loadGroup);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
|
||||
getter_AddRefs(principal),
|
||||
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;
|
||||
}
|
||||
|
||||
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->GetIsSystemPrincipal()) {
|
||||
if (scheme == NS_LITERAL_CSTRING("blob")) {
|
||||
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 == NS_LITERAL_CSTRING("data") ||
|
||||
scheme == NS_LITERAL_CSTRING("blob");
|
||||
}
|
||||
|
||||
// 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 == NS_LITERAL_CSTRING("blob")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
rv = mPrincipal->GetURI(getter_AddRefs(principalURI));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_TRUE(principalURI, false);
|
||||
|
||||
bool equal = false;
|
||||
rv = principalURI->Equals(mBaseURI, &equal);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return equal;
|
||||
}
|
||||
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
|
||||
bool
|
||||
WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
nsCOMPtr<nsILoadGroup> nullLoadGroup;
|
||||
return ProxyReleaseMainThreadObjects(aWorkerPrivate, 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(mLoadingPrincipal, doomed);
|
||||
SwapToISupportsArray(mChannel, doomed);
|
||||
SwapToISupportsArray(mCSP, doomed);
|
||||
SwapToISupportsArray(mLoadGroup, doomed);
|
||||
SwapToISupportsArray(mLoadFailedAsyncRunnable, doomed);
|
||||
SwapToISupportsArray(mInterfaceRequestor, doomed);
|
||||
// Before adding anything here update kDoomedCount above!
|
||||
|
||||
MOZ_ASSERT(doomed.Length() == kDoomedCount);
|
||||
|
||||
RefPtr<MainThreadReleaseRunnable> runnable =
|
||||
new MainThreadReleaseRunnable(doomed, 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::MaybeAddTabChild(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!aLoadGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
if (!callbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITabChild> tabChild;
|
||||
callbacks->GetInterface(NS_GET_IID(nsITabChild), getter_AddRefs(tabChild));
|
||||
if (!tabChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use weak references to the tab child. Holding a strong reference will
|
||||
// not prevent an ActorDestroy() from being called on the TabChild.
|
||||
// Therefore, we should let the TabChild destroy itself as soon as possible.
|
||||
mTabChildList.AppendElement(do_GetWeakReference(tabChild));
|
||||
}
|
||||
|
||||
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 nsITabChild, then return it. Its possible,
|
||||
// though, that all of the TabChild objects have been destroyed. In that
|
||||
// case we return NS_NOINTERFACE.
|
||||
if (aIID.Equals(NS_GET_IID(nsITabChild))) {
|
||||
nsCOMPtr<nsITabChild> tabChild = GetAnyLiveTabChild();
|
||||
if (!tabChild) {
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
tabChild.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<nsITabChild>
|
||||
WorkerLoadInfo::
|
||||
InterfaceRequestor::GetAnyLiveTabChild()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Search our list of known TabChild objects for one that still exists.
|
||||
while (!mTabChildList.IsEmpty()) {
|
||||
nsCOMPtr<nsITabChild> tabChild =
|
||||
do_QueryReferent(mTabChildList.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 (tabChild && !static_cast<TabChild*>(tabChild.get())->IsDestroyed()) {
|
||||
return tabChild.forget();
|
||||
}
|
||||
|
||||
// Otherwise remove the stale weak reference and check the next one
|
||||
mTabChildList.RemoveElementAt(mTabChildList.Length() - 1);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(WorkerLoadInfo::InterfaceRequestor)
|
||||
NS_IMPL_RELEASE(WorkerLoadInfo::InterfaceRequestor)
|
||||
NS_IMPL_QUERY_INTERFACE(WorkerLoadInfo::InterfaceRequestor,
|
||||
nsIInterfaceRequestor)
|
||||
|
||||
} // worker namespace
|
||||
} // dom namespace
|
||||
} // mozilla namespace
|
||||
143
dom/workers/WorkerLoadInfo.h
Normal file
143
dom/workers/WorkerLoadInfo.h
Normal file
@@ -0,0 +1,143 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_WorkerLoadInfo_h
|
||||
#define mozilla_dom_workers_WorkerLoadInfo_h
|
||||
|
||||
#include "mozilla/dom/workers/WorkerCommon.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
class nsIChannel;
|
||||
class nsIContentSecurityPolicy;
|
||||
class nsILoadGroup;
|
||||
class nsIPrincipal;
|
||||
class nsIRunnable;
|
||||
class nsIScriptContext;
|
||||
class nsITabChild;
|
||||
class nsIURI;
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
class PrincipalInfo;
|
||||
} // namespace ipc
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
struct WorkerLoadInfo
|
||||
{
|
||||
// All of these should be released in WorkerPrivateParent::ForgetMainThreadObjects.
|
||||
nsCOMPtr<nsIURI> mBaseURI;
|
||||
nsCOMPtr<nsIURI> mResolvedScriptURI;
|
||||
|
||||
// This is the principal of the global (parent worker or a window) loading
|
||||
// the worker. It can be null if we are executing a ServiceWorker, otherwise,
|
||||
// except for data: URL, it must subsumes the worker principal.
|
||||
// If we load a data: URL, mPrincipal will be a null principal.
|
||||
nsCOMPtr<nsIPrincipal> mLoadingPrincipal;
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
|
||||
nsCOMPtr<nsIScriptContext> mScriptContext;
|
||||
nsCOMPtr<nsPIDOMWindowInner> mWindow;
|
||||
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
// mLoadFailedAsyncRunnable will execute on main thread if script loading
|
||||
// fails during script loading. If script loading is never started due to
|
||||
// a synchronous error, then the runnable is never executed. The runnable
|
||||
// is guaranteed to be released on the main thread.
|
||||
nsCOMPtr<nsIRunnable> mLoadFailedAsyncRunnable;
|
||||
|
||||
class InterfaceRequestor final : public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
public:
|
||||
InterfaceRequestor(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
|
||||
void MaybeAddTabChild(nsILoadGroup* aLoadGroup);
|
||||
NS_IMETHOD GetInterface(const nsIID& aIID, void** aSink) override;
|
||||
|
||||
private:
|
||||
~InterfaceRequestor() { }
|
||||
|
||||
already_AddRefed<nsITabChild> GetAnyLiveTabChild();
|
||||
|
||||
nsCOMPtr<nsILoadContext> mLoadContext;
|
||||
nsCOMPtr<nsIInterfaceRequestor> mOuterRequestor;
|
||||
|
||||
// Array of weak references to nsITabChild. We do not want to keep TabChild
|
||||
// actors alive for long after their ActorDestroy() methods are called.
|
||||
nsTArray<nsWeakPtr> mTabChildList;
|
||||
};
|
||||
|
||||
// Only set if we have a custom overriden load group
|
||||
RefPtr<InterfaceRequestor> mInterfaceRequestor;
|
||||
|
||||
nsAutoPtr<mozilla::ipc::PrincipalInfo> mPrincipalInfo;
|
||||
nsCString mDomain;
|
||||
nsString mOrigin; // Derived from mPrincipal; can be used on worker thread.
|
||||
|
||||
nsString mServiceWorkerCacheName;
|
||||
Maybe<ServiceWorkerDescriptor> mServiceWorkerDescriptor;
|
||||
|
||||
Maybe<ServiceWorkerDescriptor> mParentController;
|
||||
|
||||
ChannelInfo mChannelInfo;
|
||||
nsLoadFlags mLoadFlags;
|
||||
|
||||
uint64_t mWindowID;
|
||||
|
||||
net::ReferrerPolicy mReferrerPolicy;
|
||||
bool mFromWindow;
|
||||
bool mEvalAllowed;
|
||||
bool mReportCSPViolations;
|
||||
bool mXHRParamsAllowed;
|
||||
bool mPrincipalIsSystem;
|
||||
bool mStorageAllowed;
|
||||
bool mServiceWorkersTestingInWindow;
|
||||
OriginAttributes mOriginAttributes;
|
||||
|
||||
WorkerLoadInfo();
|
||||
~WorkerLoadInfo();
|
||||
|
||||
void StealFrom(WorkerLoadInfo& aOther);
|
||||
|
||||
nsresult
|
||||
SetPrincipalOnMainThread(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup);
|
||||
|
||||
nsresult
|
||||
GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipalOut,
|
||||
nsILoadGroup** aLoadGroupOut);
|
||||
|
||||
nsresult
|
||||
SetPrincipalFromChannel(nsIChannel* aChannel);
|
||||
|
||||
bool
|
||||
FinalChannelPrincipalIsValid(nsIChannel* aChannel);
|
||||
|
||||
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
bool
|
||||
PrincipalIsValid() const;
|
||||
|
||||
bool
|
||||
PrincipalURIMatchesScriptURL();
|
||||
#endif
|
||||
|
||||
bool
|
||||
ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
bool
|
||||
ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate,
|
||||
nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel);
|
||||
};
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_workers_WorkerLoadInfo_h
|
||||
@@ -17,13 +17,11 @@
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsINamed.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIScriptTimeoutHandler.h"
|
||||
#include "nsITabChild.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsITimer.h"
|
||||
@@ -45,7 +43,6 @@
|
||||
#include "mozilla/ContentEvents.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/LoadContext.h"
|
||||
#include "mozilla/Move.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/ClientManager.h"
|
||||
@@ -73,7 +70,6 @@
|
||||
#include "mozilla/dom/SimpleGlobalObject.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/dom/StructuredCloneHolder.h"
|
||||
#include "mozilla/dom/TabChild.h"
|
||||
#include "mozilla/dom/WorkerBinding.h"
|
||||
#include "mozilla/dom/WorkerDebuggerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/WorkerGlobalScopeBinding.h"
|
||||
@@ -201,28 +197,6 @@ GetAutoPtrComparator(const nsTArray<nsAutoPtr<T> >&)
|
||||
return AutoPtrComparator<T>();
|
||||
}
|
||||
|
||||
// Specialize this if there's some class that has multiple nsISupports bases.
|
||||
template <class T>
|
||||
struct ISupportsBaseInfo
|
||||
{
|
||||
typedef T ISupportsBase;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// This class is used to wrap any runnables that the worker receives via the
|
||||
// nsIEventTarget::Dispatch() method (either from NS_DispatchToCurrentThread or
|
||||
// from the worker's EventTarget).
|
||||
@@ -364,39 +338,6 @@ LogErrorToConsole(const WorkerErrorReport& aReport, uint64_t aInnerWindowId)
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
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.SwapElements(aDoomed);
|
||||
mLoadGroupToCancel.swap(aLoadGroupToCancel);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
if (mLoadGroupToCancel) {
|
||||
mLoadGroupToCancel->Cancel(NS_BINDING_ABORTED);
|
||||
mLoadGroupToCancel = nullptr;
|
||||
}
|
||||
|
||||
mDoomed.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
~MainThreadReleaseRunnable()
|
||||
{ }
|
||||
};
|
||||
|
||||
class WorkerFinishedRunnable final : public WorkerControlRunnable
|
||||
{
|
||||
WorkerPrivate* mFinishedWorker;
|
||||
@@ -1462,8 +1403,6 @@ public:
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(MainThreadReleaseRunnable, Runnable)
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(TopLevelWorkerFinishedRunnable, Runnable)
|
||||
|
||||
namespace {
|
||||
@@ -1641,347 +1580,6 @@ NS_IMPL_ISUPPORTS(WorkerEventTarget, nsIEventTarget,
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
WorkerLoadInfo::WorkerLoadInfo()
|
||||
: mLoadFlags(nsIRequest::LOAD_NORMAL)
|
||||
, mWindowID(UINT64_MAX)
|
||||
, mReferrerPolicy(net::RP_Unset)
|
||||
, mFromWindow(false)
|
||||
, mEvalAllowed(false)
|
||||
, mReportCSPViolations(false)
|
||||
, mXHRParamsAllowed(false)
|
||||
, mPrincipalIsSystem(false)
|
||||
, mStorageAllowed(false)
|
||||
, mServiceWorkersTestingInWindow(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(WorkerLoadInfo);
|
||||
}
|
||||
|
||||
WorkerLoadInfo::~WorkerLoadInfo()
|
||||
{
|
||||
MOZ_COUNT_DTOR(WorkerLoadInfo);
|
||||
}
|
||||
|
||||
void
|
||||
WorkerLoadInfo::StealFrom(WorkerLoadInfo& aOther)
|
||||
{
|
||||
MOZ_ASSERT(!mBaseURI);
|
||||
aOther.mBaseURI.swap(mBaseURI);
|
||||
|
||||
MOZ_ASSERT(!mResolvedScriptURI);
|
||||
aOther.mResolvedScriptURI.swap(mResolvedScriptURI);
|
||||
|
||||
MOZ_ASSERT(!mPrincipal);
|
||||
aOther.mPrincipal.swap(mPrincipal);
|
||||
|
||||
// mLoadingPrincipal can be null if this is a ServiceWorker.
|
||||
aOther.mLoadingPrincipal.swap(mLoadingPrincipal);
|
||||
|
||||
MOZ_ASSERT(!mScriptContext);
|
||||
aOther.mScriptContext.swap(mScriptContext);
|
||||
|
||||
MOZ_ASSERT(!mWindow);
|
||||
aOther.mWindow.swap(mWindow);
|
||||
|
||||
MOZ_ASSERT(!mCSP);
|
||||
aOther.mCSP.swap(mCSP);
|
||||
|
||||
MOZ_ASSERT(!mChannel);
|
||||
aOther.mChannel.swap(mChannel);
|
||||
|
||||
MOZ_ASSERT(!mLoadGroup);
|
||||
aOther.mLoadGroup.swap(mLoadGroup);
|
||||
|
||||
MOZ_ASSERT(!mLoadFailedAsyncRunnable);
|
||||
aOther.mLoadFailedAsyncRunnable.swap(mLoadFailedAsyncRunnable);
|
||||
|
||||
MOZ_ASSERT(!mInterfaceRequestor);
|
||||
aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
|
||||
|
||||
MOZ_ASSERT(!mPrincipalInfo);
|
||||
mPrincipalInfo = aOther.mPrincipalInfo.forget();
|
||||
|
||||
mDomain = aOther.mDomain;
|
||||
mOrigin = aOther.mOrigin;
|
||||
mServiceWorkerCacheName = aOther.mServiceWorkerCacheName;
|
||||
mServiceWorkerDescriptor = aOther.mServiceWorkerDescriptor;
|
||||
mLoadFlags = aOther.mLoadFlags;
|
||||
mWindowID = aOther.mWindowID;
|
||||
mReferrerPolicy = aOther.mReferrerPolicy;
|
||||
mFromWindow = aOther.mFromWindow;
|
||||
mEvalAllowed = aOther.mEvalAllowed;
|
||||
mReportCSPViolations = aOther.mReportCSPViolations;
|
||||
mXHRParamsAllowed = aOther.mXHRParamsAllowed;
|
||||
mPrincipalIsSystem = aOther.mPrincipalIsSystem;
|
||||
mStorageAllowed = aOther.mStorageAllowed;
|
||||
mServiceWorkersTestingInWindow = aOther.mServiceWorkersTestingInWindow;
|
||||
mOriginAttributes = aOther.mOriginAttributes;
|
||||
mParentController = aOther.mParentController;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WorkerLoadInfo::SetPrincipalOnMainThread(nsIPrincipal* aPrincipal,
|
||||
nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(aLoadGroup, aPrincipal));
|
||||
|
||||
mPrincipal = aPrincipal;
|
||||
mPrincipalIsSystem = nsContentUtils::IsSystemPrincipal(aPrincipal);
|
||||
|
||||
nsresult rv = aPrincipal->GetCsp(getter_AddRefs(mCSP));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (mCSP) {
|
||||
mCSP->GetAllowsEval(&mReportCSPViolations, &mEvalAllowed);
|
||||
// Set ReferrerPolicy
|
||||
bool hasReferrerPolicy = false;
|
||||
uint32_t rp = mozilla::net::RP_Unset;
|
||||
|
||||
rv = mCSP->GetReferrerPolicy(&rp, &hasReferrerPolicy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (hasReferrerPolicy) {
|
||||
mReferrerPolicy = static_cast<net::ReferrerPolicy>(rp);
|
||||
}
|
||||
} else {
|
||||
mEvalAllowed = true;
|
||||
mReportCSPViolations = false;
|
||||
}
|
||||
|
||||
mLoadGroup = aLoadGroup;
|
||||
|
||||
mPrincipalInfo = new PrincipalInfo();
|
||||
mOriginAttributes = nsContentUtils::GetOriginAttributes(aLoadGroup);
|
||||
|
||||
rv = PrincipalToPrincipalInfo(aPrincipal, mPrincipalInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = nsContentUtils::GetUTFOrigin(aPrincipal, mOrigin);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WorkerLoadInfo::GetPrincipalAndLoadGroupFromChannel(nsIChannel* aChannel,
|
||||
nsIPrincipal** aPrincipalOut,
|
||||
nsILoadGroup** aLoadGroupOut)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChannel);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aPrincipalOut);
|
||||
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;
|
||||
nsresult rv = ssm->GetChannelResultPrincipal(aChannel, getter_AddRefs(channelPrincipal));
|
||||
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;
|
||||
}
|
||||
|
||||
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 (nsContentUtils::IsSystemPrincipal(mLoadingPrincipal)) {
|
||||
if (!nsContentUtils::IsSystemPrincipal(channelPrincipal)) {
|
||||
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;
|
||||
} else {
|
||||
return NS_ERROR_DOM_BAD_URI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The principal can change, but it should still match the original
|
||||
// load group's appId and browser element flag.
|
||||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(channelLoadGroup, channelPrincipal));
|
||||
|
||||
channelPrincipal.forget(aPrincipalOut);
|
||||
channelLoadGroup.forget(aLoadGroupOut);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
WorkerLoadInfo::SetPrincipalFromChannel(nsIChannel* aChannel)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
|
||||
getter_AddRefs(principal),
|
||||
getter_AddRefs(loadGroup));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return SetPrincipalOnMainThread(principal, loadGroup);
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerLoadInfo::FinalChannelPrincipalIsValid(nsIChannel* aChannel)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = GetPrincipalAndLoadGroupFromChannel(aChannel,
|
||||
getter_AddRefs(principal),
|
||||
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;
|
||||
}
|
||||
|
||||
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->GetIsSystemPrincipal()) {
|
||||
if (scheme == NS_LITERAL_CSTRING("blob")) {
|
||||
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 == NS_LITERAL_CSTRING("data") ||
|
||||
scheme == NS_LITERAL_CSTRING("blob");
|
||||
}
|
||||
|
||||
// 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 == NS_LITERAL_CSTRING("blob")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
rv = mPrincipal->GetURI(getter_AddRefs(principalURI));
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
NS_ENSURE_TRUE(principalURI, false);
|
||||
|
||||
bool equal = false;
|
||||
rv = principalURI->Equals(mBaseURI, &equal);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
return equal;
|
||||
}
|
||||
#endif // MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||
|
||||
bool
|
||||
WorkerLoadInfo::ProxyReleaseMainThreadObjects(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
nsCOMPtr<nsILoadGroup> nullLoadGroup;
|
||||
return ProxyReleaseMainThreadObjects(aWorkerPrivate, 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(mLoadingPrincipal, doomed);
|
||||
SwapToISupportsArray(mChannel, doomed);
|
||||
SwapToISupportsArray(mCSP, doomed);
|
||||
SwapToISupportsArray(mLoadGroup, doomed);
|
||||
SwapToISupportsArray(mLoadFailedAsyncRunnable, doomed);
|
||||
SwapToISupportsArray(mInterfaceRequestor, doomed);
|
||||
// Before adding anything here update kDoomedCount above!
|
||||
|
||||
MOZ_ASSERT(doomed.Length() == kDoomedCount);
|
||||
|
||||
RefPtr<MainThreadReleaseRunnable> runnable =
|
||||
new MainThreadReleaseRunnable(doomed, aLoadGroupToCancel);
|
||||
return NS_SUCCEEDED(aWorkerPrivate->DispatchToMainThread(runnable.forget()));
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
class WorkerPrivateParent<Derived>::EventTarget final
|
||||
: public nsISerialEventTarget
|
||||
@@ -2038,120 +1636,6 @@ private:
|
||||
{ }
|
||||
};
|
||||
|
||||
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::MaybeAddTabChild(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!aLoadGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
if (!callbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITabChild> tabChild;
|
||||
callbacks->GetInterface(NS_GET_IID(nsITabChild), getter_AddRefs(tabChild));
|
||||
if (!tabChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use weak references to the tab child. Holding a strong reference will
|
||||
// not prevent an ActorDestroy() from being called on the TabChild.
|
||||
// Therefore, we should let the TabChild destroy itself as soon as possible.
|
||||
mTabChildList.AppendElement(do_GetWeakReference(tabChild));
|
||||
}
|
||||
|
||||
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 nsITabChild, then return it. Its possible,
|
||||
// though, that all of the TabChild objects have been destroyed. In that
|
||||
// case we return NS_NOINTERFACE.
|
||||
if (aIID.Equals(NS_GET_IID(nsITabChild))) {
|
||||
nsCOMPtr<nsITabChild> tabChild = GetAnyLiveTabChild();
|
||||
if (!tabChild) {
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
tabChild.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<nsITabChild>
|
||||
WorkerLoadInfo::
|
||||
InterfaceRequestor::GetAnyLiveTabChild()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Search our list of known TabChild objects for one that still exists.
|
||||
while (!mTabChildList.IsEmpty()) {
|
||||
nsCOMPtr<nsITabChild> tabChild =
|
||||
do_QueryReferent(mTabChildList.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 (tabChild && !static_cast<TabChild*>(tabChild.get())->IsDestroyed()) {
|
||||
return tabChild.forget();
|
||||
}
|
||||
|
||||
// Otherwise remove the stale weak reference and check the next one
|
||||
mTabChildList.RemoveElementAt(mTabChildList.Length() - 1);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(WorkerLoadInfo::InterfaceRequestor)
|
||||
NS_IMPL_RELEASE(WorkerLoadInfo::InterfaceRequestor)
|
||||
NS_IMPL_QUERY_INTERFACE(WorkerLoadInfo::InterfaceRequestor, nsIInterfaceRequestor)
|
||||
|
||||
struct WorkerPrivate::TimeoutInfo
|
||||
{
|
||||
TimeoutInfo()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define mozilla_dom_workers_workerprivate_h__
|
||||
|
||||
#include "WorkerCommon.h"
|
||||
#include "WorkerLoadInfo.h"
|
||||
|
||||
#include "js/CharacterEncoding.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "mozilla/EventListenerManager.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/Clients.h"
|
||||
#include "mozilla/dom/ClientState.h"
|
||||
#include "mozilla/dom/Console.h"
|
||||
#include "mozilla/dom/DedicatedWorkerGlobalScopeBinding.h"
|
||||
#include "mozilla/dom/DOMPrefs.h"
|
||||
@@ -34,6 +35,7 @@
|
||||
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptTimeoutHandler.h"
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
@@ -21,6 +21,7 @@ EXPORTS.mozilla.dom.workers += [
|
||||
'RuntimeService.h',
|
||||
'WorkerCommon.h',
|
||||
'WorkerDebuggerManager.h',
|
||||
'WorkerLoadInfo.h',
|
||||
]
|
||||
|
||||
# Stuff needed for the bindings, not really public though.
|
||||
@@ -49,6 +50,7 @@ UNIFIED_SOURCES += [
|
||||
'WorkerDebuggerManager.cpp',
|
||||
'WorkerHolder.cpp',
|
||||
'WorkerHolderToken.cpp',
|
||||
'WorkerLoadInfo.cpp',
|
||||
'WorkerLocation.cpp',
|
||||
'WorkerNavigator.cpp',
|
||||
'WorkerPrivate.cpp',
|
||||
|
||||
Reference in New Issue
Block a user