// 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;
}
bool
WorkerMessagePort::MaybeDispatchEvent(
                                JSContext* aCx,
                                JSAutoStructuredCloneBuffer& aBuffer,
                                nsTArray<nsCOMPtr<nsISupports>>& aClonedObjects)
{
  if (mClosed) {
    NS_WARNING("Not going to ever run this event!");
    aBuffer.clear();
    aClonedObjects.Clear();
    return true;
  }

  if (!mStarted) {
    // Queue the message for later.
    MessageInfo* info = mQueuedMessages.AppendElement();
    info->mBuffer.swap(aBuffer);
    info->mClonedObjects.SwapElements(aClonedObjects);
    return true;
  }

  // Go ahead and dispatch the event.
  JS::Rooted<JSObject*> target(aCx, GetJSObject());
  return DispatchMessageEvent(aCx, target, aBuffer, aClonedObjects);
}
Esempio n. 3
0
  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;
  }
Esempio n. 4
0
static bool
Serialize(JSContext *cx, unsigned argc, jsval *vp)
{
    CallArgs args = CallArgsFromVp(argc, vp);

    JSAutoStructuredCloneBuffer clonebuf;
    if (!clonebuf.write(cx, args.get(0), args.get(1)))
        return false;

    RootedObject obj(cx, CloneBufferObject::Create(cx, &clonebuf));
    if (!obj)
        return false;

    args.rval().setObject(*obj);
    return true;
}
bool
WriteStructuredClone(JSContext* aCx, JS::Handle<JS::Value> aSource,
                     JSAutoStructuredCloneBuffer& aBuffer,
                     StructuredCloneClosure& aClosure)
{
  return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure);
}
Esempio n. 6
0
    static jobject CloneInstance(JNIEnv* env, jobject instance) {
        NativeJSContainer* const container = FromInstance(env, instance);
        if (!container || !container->EnsureObject(env)) {
            return nullptr;
        }
        JSContext* const cx = container->mThreadContext;
        JS::RootedObject object(cx, container->mJSObject);
        MOZ_ASSERT(object);

        JSAutoStructuredCloneBuffer buffer;
        if (!buffer.write(cx, JS::RootedValue(cx, JS::ObjectValue(*object)))) {
            AndroidBridge::ThrowException(env,
                "java/lang/UnsupportedOperationException",
                "Cannot serialize object");
            return nullptr;
        }
        return CreateInstance(env, new NativeJSContainer(cx, Move(buffer)));
    }
void
ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
                                 const Optional<Sequence<JS::Value>>& aTransferable,
                                 ErrorResult& aRv)
{
  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
  MOZ_ASSERT(workerPrivate);
  workerPrivate->AssertIsOnWorkerThread();

  JS::Rooted<JS::Value> transferable(aCx, JS::UndefinedValue());
  if (aTransferable.WasPassed()) {
    const Sequence<JS::Value>& realTransferable = aTransferable.Value();

    JS::HandleValueArray elements =
      JS::HandleValueArray::fromMarkedLocation(realTransferable.Length(),
                                               realTransferable.Elements());

    JSObject* array = JS_NewArrayObject(aCx, elements);
    if (!array) {
      aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
      return;
    }

    transferable.setObject(*array);
  }

  const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false);

  WorkerStructuredCloneClosure closure;

  JSAutoStructuredCloneBuffer buffer;
  if (!buffer.write(aCx, aMessage, transferable, callbacks, &closure)) {
    aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
    return;
  }

  nsRefPtr<ServiceWorkerClientPostMessageRunnable> runnable =
    new ServiceWorkerClientPostMessageRunnable(mWindowId, Move(buffer),
                                               closure);
  nsresult rv = NS_DispatchToMainThread(runnable);
  if (NS_FAILED(rv)) {
    aRv.Throw(NS_ERROR_FAILURE);
  }
}
Esempio n. 8
0
/*
 * 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);
}
Esempio n. 9
0
  DataStoreAddRunnable(WorkerPrivate* aWorkerPrivate,
                       const nsMainThreadPtrHandle<DataStore>& aBackingStore,
                       Promise* aWorkerPromise,
                       JSContext* aCx,
                       JS::Handle<JS::Value> aObj,
                       const Optional<StringOrUnsignedLong>& aId,
                       const nsAString& aRevisionId,
                       ErrorResult& aRv)
    : DataStoreProxyRunnable(aWorkerPrivate, aBackingStore, aWorkerPromise)
    , mId(aId)
    , mRevisionId(aRevisionId)
    , mRv(aRv)
  {
    MOZ_ASSERT(aWorkerPrivate);
    aWorkerPrivate->AssertIsOnWorkerThread();

    // This needs to be structured cloned while it's still on the worker thread.
    if (!mObjBuffer.write(aCx, aObj)) {
      JS_ClearPendingException(aCx);
      mRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
    }
  }
Esempio n. 10
0
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;
}