virtual bool MainThreadRun() override { AssertIsOnMainThread(); // Initialise an AutoJSAPI with the target window. AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(mBackingStore->GetParentObject()))) { mRv.Throw(NS_ERROR_UNEXPECTED); return true; } JSContext* cx = jsapi.cx(); JS::Rooted<JS::Value> value(cx); if (!mObjBuffer.read(cx, &value)) { JS_ClearPendingException(cx); mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return true; } nsRefPtr<Promise> promise = mBackingStore->Add(cx, value, mId, mRevisionId, mRv); promise->AppendNativeHandler(mPromiseWorkerProxy); return true; }
// static nsresult AsyncConnectionHelper::ConvertCloneBufferToJSVal( JSContext* aCx, JSAutoStructuredCloneBuffer& aBuffer, jsval* aResult) { NS_ASSERTION(aCx, "Null context!"); NS_ASSERTION(aResult, "Null pointer!"); JSAutoRequest ar(aCx); if (aBuffer.data()) { JSBool ok = aBuffer.read(aResult, aCx); aBuffer.clear(aCx); if (!ok) { NS_ERROR("Failed to decode!"); return NS_ERROR_DOM_DATA_CLONE_ERR; } } else { *aResult = JSVAL_VOID; } return NS_OK; }
/* * General-purpose structured-cloning utility for cases where the structured * clone buffer is only used in stack-scope (that is to say, the buffer does * not escape from this function). The stack-scoping allows us to pass * references to various JSObjects directly in certain situations without * worrying about lifetime issues. * * This function assumes that |cx| is already entered the compartment we want * to clone to, and that |val| may not be same-compartment with cx. When the * function returns, |val| is set to the result of the clone. */ bool StackScopedClone(JSContext *cx, StackScopedCloneOptions &options, MutableHandleValue val) { JSAutoStructuredCloneBuffer buffer; StackScopedCloneData data(cx, &options); { // For parsing val we have to enter its compartment. // (unless it's a primitive) Maybe<JSAutoCompartment> ac; if (val.isObject()) { ac.construct(cx, &val.toObject()); } else if (val.isString() && !JS_WrapValue(cx, val)) { return false; } if (!buffer.write(cx, val, &gStackScopedCloneCallbacks, &data)) return false; } // Now recreate the clones in the target compartment. return buffer.read(cx, val, &gStackScopedCloneCallbacks, &data); }
NS_IMETHODIMP PostMessageRunnable::Run() { MOZ_ASSERT(mPort); // Ensure that the buffer is freed even if we fail to post the message JSAutoStructuredCloneBuffer buffer; buffer.adopt(mMessage, mMessageLen); mMessage = nullptr; mMessageLen = 0; // Get the JSContext for the target window nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(mPort->GetOwner()); NS_ENSURE_STATE(sgo); nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext(); AutoPushJSContext cx(scriptContext ? scriptContext->GetNativeContext() : nsContentUtils::GetSafeJSContext()); MOZ_ASSERT(cx); // Deserialize the structured clone data JS::Rooted<JS::Value> messageData(cx); { StructuredCloneInfo scInfo; scInfo.mEvent = this; scInfo.mPort = mPort; if (!buffer.read(cx, messageData.address(), &kPostMessageCallbacks, &scInfo)) { return NS_ERROR_DOM_DATA_CLONE_ERR; } } // Create the event nsIDocument* doc = mPort->GetOwner()->GetExtantDoc(); if (!doc) { return NS_OK; } ErrorResult error; nsRefPtr<nsDOMEvent> event = doc->CreateEvent(NS_LITERAL_STRING("MessageEvent"), error); if (error.Failed()) { return NS_OK; } nsCOMPtr<nsIDOMMessageEvent> message = do_QueryInterface(event); nsresult rv = message->InitMessageEvent(NS_LITERAL_STRING("message"), false /* non-bubbling */, true /* cancelable */, messageData, EmptyString(), EmptyString(), mPort->GetOwner()); if (NS_FAILED(rv)) { return NS_OK; } message->SetTrusted(true); bool status; mPort->DispatchEvent(event, &status); return status ? NS_OK : NS_ERROR_FAILURE; }