Files
tubestation/dom/media/webrtc/jsapi/RTCRtpScriptTransform.cpp
Andrew Sutherland 7ac66a7a4b Bug 1858809 - Enforce Worker::PostEventWithOptions invariants. r=bwc,dom-worker-reviewers,smaug
Under debug/fuzzing builds WorkerRunnable will assert in its constructor
if passed a null WorkerPrivate.  While there is no runtime problem under
non-debug builds, it is a reasonable invariant for us to have until we
are able to eliminate to turn all of this into normal runnables.

`RTCRtpScriptTransform::Constructor` currently can get into this situation
where the method is invoked but the Worker is in a closing / terminated
state.  The spec has a "FIXME" to specify what to do in this situation.

This patch implements an early return with an error based on adding a new
`Worker::IsEligibleForMessaging` which is analogous to
`nsIGlobalObject::IsEligibleForMessaging`.  This is potentially
observable since JS getters or proxies passed to the constructor as the
`options` arg will not be serialized in this case, but it is not a
secret to the inherently same-origin Worker whether the Worker is
closing; the same information is available via WebLocks among other
methods.  I chose the simplest path here given the absence of any spec
language or even an issue on the repo that I can see.

Differential Revision: https://phabricator.services.mozilla.com/D205779
2024-04-10 01:38:36 +00:00

101 lines
3.5 KiB
C++

/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=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 https://mozilla.org/MPL/2.0/. */
#include "RTCRtpScriptTransform.h"
#include "libwebrtcglue/FrameTransformerProxy.h"
#include "jsapi/RTCTransformEventRunnable.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/Worker.h"
#include "mozilla/dom/RTCRtpScriptTransformBinding.h"
#include "mozilla/dom/MessagePortBinding.h"
#include "mozilla/Logging.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/RefPtr.h"
#include "nsPIDOMWindow.h"
#include "nsContentUtils.h"
#include "nsCOMPtr.h"
#include "nsDebug.h"
#include "ErrorList.h"
#include "nsWrapperCache.h"
#include "nsISupports.h"
#include "nsCycleCollectionParticipant.h"
#include "js/RootingAPI.h"
namespace mozilla::dom {
LazyLogModule gScriptTransformLog("RTCRtpScriptTransform");
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(RTCRtpScriptTransform, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(RTCRtpScriptTransform)
NS_IMPL_CYCLE_COLLECTING_RELEASE(RTCRtpScriptTransform)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(RTCRtpScriptTransform)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
already_AddRefed<RTCRtpScriptTransform> RTCRtpScriptTransform::Constructor(
const GlobalObject& aGlobal, Worker& aWorker,
JS::Handle<JS::Value> aOptions,
const Optional<Sequence<JSObject*>>& aTransfer, ErrorResult& aRv) {
nsCOMPtr<nsPIDOMWindowInner> ownerWindow =
do_QueryInterface(aGlobal.GetAsSupports());
if (NS_WARN_IF(!ownerWindow)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
// The spec currently fails to describe what to do when the worker is closing
// or closed; the following placeholder text can be found in the spec at:
// https://w3c.github.io/webrtc-encoded-transform/#dom-rtcrtpscripttransform-rtcrtpscripttransform
//
// > FIXME: Describe error handling (worker closing flag true at
// > RTCRtpScriptTransform creation time. And worker being terminated while
// > transform is processing data).
//
// Because our worker runnables do not like to be pointed at a nonexistant
// worker, we throw in this case.
if (!aWorker.IsEligibleForMessaging()) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
auto newTransform = MakeRefPtr<RTCRtpScriptTransform>(ownerWindow);
RefPtr<RTCTransformEventRunnable> runnable =
new RTCTransformEventRunnable(aWorker, &newTransform->GetProxy());
if (aTransfer.WasPassed()) {
aWorker.PostEventWithOptions(aGlobal.Context(), aOptions, aTransfer.Value(),
runnable, aRv);
} else {
StructuredSerializeOptions transferOptions;
aWorker.PostEventWithOptions(aGlobal.Context(), aOptions,
transferOptions.mTransfer, runnable, aRv);
}
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return newTransform.forget();
}
RTCRtpScriptTransform::RTCRtpScriptTransform(nsPIDOMWindowInner* aWindow)
: mWindow(aWindow), mProxy(new FrameTransformerProxy) {}
RTCRtpScriptTransform::~RTCRtpScriptTransform() {
mProxy->ReleaseScriptTransformer();
}
JSObject* RTCRtpScriptTransform::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return RTCRtpScriptTransform_Binding::Wrap(aCx, this, aGivenProto);
}
} // namespace mozilla::dom
#undef LOGTAG