Backout rev 509957c7a9f9 (bug 1456986). r=me a=ryanvm

This commit is contained in:
Ben Kelly 2018-05-08 07:38:53 -07:00
parent 17a7546f6b
commit 363fb9cea0
6 changed files with 62 additions and 158 deletions

View File

@ -17,7 +17,6 @@
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ServiceWorkerGlobalScopeBinding.h"
#include "mozilla/dom/WorkerPrivate.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#ifdef XP_WIN
#undef PostMessage
@ -148,42 +147,7 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
return;
}
nsPIDOMWindowInner* window = GetOwner();
if (NS_WARN_IF(!window || !window->GetExtantDoc())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
ServiceWorkerManager::LocalizeAndReportToAllClients(
mDescriptor.Scope(), "ServiceWorkerPostMessageStorageError",
nsTArray<nsString> { NS_ConvertUTF8toUTF16(mDescriptor.Scope()) });
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
Maybe<ClientInfo> clientInfo = window->GetClientInfo();
Maybe<ClientState> clientState = window->GetClientState();
if (NS_WARN_IF(clientInfo.isNothing() || clientState.isNothing())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
aRv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
&transferable);
if (aRv.Failed()) {
return;
}
ipc::StructuredCloneData data;
data.Write(aCx, aMessage, transferable, aRv);
if (aRv.Failed()) {
return;
}
mInner->PostMessage(Move(data), clientInfo.ref(), clientState.ref());
mInner->PostMessage(GetParentObject(), aCx, aMessage, aTransferable, aRv);
}

View File

@ -20,10 +20,6 @@ class nsIGlobalObject;
namespace mozilla {
namespace dom {
namespace ipc {
class StructuredCloneData;
} // namespace ipc
#define NS_DOM_SERVICEWORKER_IID \
{0xd42e0611, 0x3647, 0x4319, {0xae, 0x05, 0x19, 0x89, 0x59, 0xba, 0x99, 0x5e}}
@ -58,9 +54,10 @@ public:
RemoveServiceWorker(ServiceWorker* aWorker) = 0;
virtual void
PostMessage(ipc::StructuredCloneData&& aData,
const ClientInfo& aClientInfo,
const ClientState& aClientState) = 0;
PostMessage(nsIGlobalObject* aGlobal,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) = 0;
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
};

View File

@ -256,13 +256,38 @@ ServiceWorkerInfo::RemoveServiceWorker(ServiceWorker* aWorker)
}
void
ServiceWorkerInfo::PostMessage(ipc::StructuredCloneData&& aData,
const ClientInfo& aClientInfo,
const ClientState& aClientState)
ServiceWorkerInfo::PostMessage(nsIGlobalObject* aGlobal,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv)
{
mServiceWorkerPrivate->SendMessageEvent(Move(aData),
ClientInfoAndState(aClientInfo.ToIPC(),
aClientState.ToIPC()));
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
if (NS_WARN_IF(!window || !window->GetExtantDoc())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
auto storageAllowed = nsContentUtils::StorageAllowedForWindow(window);
if (storageAllowed != nsContentUtils::StorageAccess::eAllow) {
ServiceWorkerManager::LocalizeAndReportToAllClients(
Scope(), "ServiceWorkerPostMessageStorageError",
nsTArray<nsString> { NS_ConvertUTF8toUTF16(Scope()) });
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return;
}
Maybe<ClientInfo> clientInfo = window->GetClientInfo();
Maybe<ClientState> clientState = window->GetClientState();
if (NS_WARN_IF(clientInfo.isNothing() || clientState.isNothing())) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
aRv = mServiceWorkerPrivate->SendMessageEvent(aCx, aMessage, aTransferable,
ClientInfoAndState(clientInfo.ref().ToIPC(),
clientState.ref().ToIPC()));
}
void

View File

@ -17,7 +17,6 @@
namespace mozilla {
namespace dom {
class ClientInfoAndState;
class ServiceWorkerPrivate;
/*
@ -86,9 +85,10 @@ private:
RemoveServiceWorker(ServiceWorker* aWorker) override;
virtual void
PostMessage(ipc::StructuredCloneData&& aData,
const ClientInfo& aClientInfo,
const ClientState& aClientState) override;
PostMessage(nsIGlobalObject* aGlobal,
JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
ErrorResult& aRv) override;
public:
NS_DECL_ISUPPORTS

View File

@ -23,7 +23,6 @@
#include "nsStreamUtils.h"
#include "nsStringStream.h"
#include "mozilla/Assertions.h"
#include "mozilla/JSObjectHolder.h"
#include "mozilla/dom/Client.h"
#include "mozilla/dom/ClientIPCTypes.h"
#include "mozilla/dom/DOMPrefs.h"
@ -34,12 +33,10 @@
#include "mozilla/dom/PromiseNativeHandler.h"
#include "mozilla/dom/PushEventBinding.h"
#include "mozilla/dom/RequestBinding.h"
#include "mozilla/dom/StructuredCloneHolder.h"
#include "mozilla/dom/WorkerDebugger.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/dom/WorkerRunnable.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/dom/ipc/StructuredCloneData.h"
#include "mozilla/Unused.h"
using namespace mozilla;
@ -215,24 +212,6 @@ ServiceWorkerPrivate::CheckScriptEvaluation(LifeCycleEventCallback* aScriptEvalu
return NS_OK;
}
JSObject*
ServiceWorkerPrivate::GetOrCreateSandbox(JSContext* aCx)
{
AssertIsOnMainThread();
if (!mSandbox) {
nsIXPConnect* xpc = nsContentUtils::XPConnect();
JS::Rooted<JSObject*> sandbox(aCx);
nsresult rv = xpc->CreateSandbox(aCx, mInfo->Principal(), sandbox.address());
NS_ENSURE_SUCCESS(rv, nullptr);
mSandbox = new JSObjectHolder(aCx, sandbox);
}
return mSandbox->GetJSObject();
}
namespace {
enum ExtendableEventResult {
@ -521,17 +500,17 @@ public:
};
class SendMessageEventRunnable final : public ExtendableEventWorkerRunnable
, public StructuredCloneHolder
{
StructuredCloneHolder mData;
const ClientInfoAndState mClientInfoAndState;
public:
SendMessageEventRunnable(WorkerPrivate* aWorkerPrivate,
KeepAliveToken* aKeepAliveToken,
StructuredCloneHolder&& aData,
const ClientInfoAndState& aClientInfoAndState)
: ExtendableEventWorkerRunnable(aWorkerPrivate, aKeepAliveToken)
, mData(Move(aData))
, StructuredCloneHolder(CloningSupported, TransferringSupported,
StructuredCloneScope::SameProcessDifferentThread)
, mClientInfoAndState(aClientInfoAndState)
{
MOZ_ASSERT(NS_IsMainThread());
@ -543,13 +522,13 @@ public:
JS::Rooted<JS::Value> messageData(aCx);
nsCOMPtr<nsIGlobalObject> sgo = aWorkerPrivate->GlobalScope();
ErrorResult rv;
mData.Read(sgo, aCx, &messageData, rv);
Read(sgo, aCx, &messageData, rv);
if (NS_WARN_IF(rv.Failed())) {
return true;
}
Sequence<OwningNonNull<MessagePort>> ports;
if (!mData.TakeTransferredPortsAsSequence(ports)) {
if (!TakeTransferredPortsAsSequence(ports)) {
return true;
}
@ -584,82 +563,35 @@ public:
} // anonymous namespace
nsresult
ServiceWorkerPrivate::SendMessageEvent(ipc::StructuredCloneData&& aData,
ServiceWorkerPrivate::SendMessageEvent(JSContext* aCx,
JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
const ClientInfoAndState& aClientInfoAndState)
{
MOZ_ASSERT(NS_IsMainThread());
ErrorResult rv;
// Ideally we would simply move the StructuredCloneData to the
// SendMessageEventRunnable, but we cannot because it uses non-threadsafe
// ref-counting. The following gnarly code unpacks the IPC-friendly
// StructuredCloneData and re-packs it into the thread-friendly
// StructuredCloneHolder. In the future we should remove this and make
// it easier to simple move the data to the other thread. See bug 1458936.
AutoSafeJSContext cx;
JSObject* sandbox = GetOrCreateSandbox(cx);
NS_ENSURE_TRUE(sandbox, NS_ERROR_FAILURE);
JS::Rooted<JSObject*> global(cx, sandbox);
NS_ENSURE_TRUE(sandbox, NS_ERROR_FAILURE);
// The CreateSandbox call returns a proxy to the actual sandbox object. We
// don't need a proxy here.
global = js::UncheckedUnwrap(global);
JSAutoCompartment ac(cx, global);
JS::Rooted<JS::Value> messageData(cx);
aData.Read(cx, &messageData, rv);
if (rv.Failed()) {
ErrorResult rv(SpawnWorkerIfNeeded(MessageEvent));
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
Sequence<OwningNonNull<MessagePort>> ports;
if (!aData.TakeTransferredPortsAsSequence(ports)) {
return NS_ERROR_FAILURE;
}
JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedHandleValue);
JS::Rooted<JSObject*> array(cx, JS_NewArrayObject(cx, ports.Length()));
NS_ENSURE_TRUE(array, NS_ERROR_OUT_OF_MEMORY);
for (uint32_t i = 0; i < ports.Length(); ++i) {
JS::Rooted<JS::Value> value(cx);
if (!GetOrCreateDOMReflector(cx, ports[i], &value)) {
JS_ClearPendingException(cx);
return NS_ERROR_FAILURE;
}
if (!JS_DefineElement(cx, array, i, value, JSPROP_ENUMERATE)) {
return NS_ERROR_OUT_OF_MEMORY;
}
}
JS::Rooted<JS::Value> transferable(cx);
transferable.setObject(*array);
StructuredCloneHolder holder(StructuredCloneHolder::CloningSupported,
StructuredCloneHolder::TransferringSupported,
JS::StructuredCloneScope::SameProcessDifferentThread);
holder.Write(cx, messageData, transferable, JS::CloneDataPolicy(), rv);
if (rv.Failed()) {
return rv.StealNSResult();
}
// Now that the re-packing is complete, send a runnable to the service worker
// thread.
rv = SpawnWorkerIfNeeded(MessageEvent);
rv = nsContentUtils::CreateJSValueFromSequenceOfObject(aCx, aTransferable,
&transferable);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
RefPtr<KeepAliveToken> token = CreateEventKeepAliveToken();
RefPtr<SendMessageEventRunnable> runnable =
new SendMessageEventRunnable(mWorkerPrivate, token, Move(holder),
aClientInfoAndState);
new SendMessageEventRunnable(mWorkerPrivate, token, aClientInfoAndState);
runnable->Write(aCx, aMessage, transferable, JS::CloneDataPolicy(), rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
if (!runnable->Dispatch()) {
return NS_ERROR_FAILURE;
}

View File

@ -16,9 +16,6 @@
class nsIInterceptedChannel;
namespace mozilla {
class JSObjectHolder;
namespace dom {
class ClientInfoAndState;
@ -26,10 +23,6 @@ class KeepAliveToken;
class ServiceWorkerInfo;
class ServiceWorkerRegistrationInfo;
namespace ipc {
class StructuredCloneData;
} // namespace ipc
class LifeCycleEventCallback : public Runnable
{
public:
@ -89,7 +82,8 @@ public:
explicit ServiceWorkerPrivate(ServiceWorkerInfo* aInfo);
nsresult
SendMessageEvent(ipc::StructuredCloneData&& aData,
SendMessageEvent(JSContext* aCx, JS::Handle<JS::Value> aMessage,
const Sequence<JSObject*>& aTransferable,
const ClientInfoAndState& aClientInfoAndState);
// This is used to validate the worker script and continue the installation
@ -205,9 +199,6 @@ private:
already_AddRefed<KeepAliveToken>
CreateEventKeepAliveToken();
JSObject*
GetOrCreateSandbox(JSContext* aCx);
// The info object owns us. It is possible to outlive it for a brief period
// of time if there are pending waitUntil promises, in which case it
// will be null and |SpawnWorkerIfNeeded| will always fail.
@ -224,11 +215,6 @@ private:
// worker a grace period after each event.
RefPtr<KeepAliveToken> mIdleKeepAliveToken;
// Sandbox global used to re-pack structured clone data before sending
// to the service worker thread. Ideally we would remove this and just
// make StructuredCloneData thread safe enough to pass to the worker thread.
RefPtr<JSObjectHolder> mSandbox;
uint64_t mDebuggerCount;
uint64_t mTokenCount;