--- a/dom/media/MediaStreamTrack.cpp
+++ b/dom/media/MediaStreamTrack.cpp
@@ -39,30 +39,89 @@ MediaStreamTrackSource::ApplyConstraints
promise->MaybeReject(new MediaStreamError(
aWindow,
NS_LITERAL_STRING("OverconstrainedError"),
NS_LITERAL_STRING(""),
NS_LITERAL_STRING("")));
return promise.forget();
}
+/**
+ * PrincipalHandleListener monitors changes in PrincipalHandle of the media flowing
+ * through the MediaStreamGraph.
+ *
+ * When the main thread principal for a MediaStreamTrack changes, its principal
+ * will be set to the combination of the previous principal and the new one.
+ *
+ * As a PrincipalHandle change later happens on the MediaStreamGraph thread, we will
+ * be notified. If the latest principal on main thread matches the PrincipalHandle
+ * we just saw on MSG thread, we will set the track's principal to the new one.
+ *
+ * We know at this point that the old principal has been flushed out and data
+ * under it cannot leak to consumers.
+ *
+ * In case of multiple changes to the main thread state, the track's principal
+ * will be a combination of its old principal and all the new ones until the
+ * latest main thread principal matches the PrincipalHandle on the MSG thread.
+ */
+class MediaStreamTrack::PrincipalHandleListener : public MediaStreamTrackListener
+{
+public:
+ explicit PrincipalHandleListener(MediaStreamTrack* aTrack)
+ : mTrack(aTrack) {}
+
+ void Forget()
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+ mTrack = nullptr;
+ }
+
+ void DoNotifyPrincipalHandleChanged(const PrincipalHandle& aNewPrincipalHandle)
+ {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ if (!mTrack) {
+ return;
+ }
+
+ mTrack->NotifyPrincipalHandleChanged(aNewPrincipalHandle);
+ }
+
+ void NotifyPrincipalHandleChanged(MediaStreamGraph* aGraph,
+ const PrincipalHandle& aNewPrincipalHandle) override
+ {
+ nsCOMPtr<nsIRunnable> runnable =
+ NS_NewRunnableMethodWithArgs<StoreCopyPassByConstLRef<PrincipalHandle>>(
+ this, &PrincipalHandleListener::DoNotifyPrincipalHandleChanged, aNewPrincipalHandle);
+ aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget());
+ }
+
+protected:
+ // These fields may only be accessed on the main thread
+ MediaStreamTrack* mTrack;
+};
+
MediaStreamTrack::MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
TrackID aInputTrackID, const nsString& aLabel,
MediaStreamTrackSource* aSource)
: mOwningStream(aStream), mTrackID(aTrackID),
- mInputTrackID(aInputTrackID), mSource(aSource), mLabel(aLabel),
+ mInputTrackID(aInputTrackID), mSource(aSource),
+ mPrincipal(aSource->GetPrincipal()), mLabel(aLabel),
mEnded(false), mEnabled(true), mRemote(aSource->IsRemote()), mStopped(false)
{
if (!gMediaStreamTrackLog) {
gMediaStreamTrackLog = PR_NewLogModule("MediaStreamTrack");
}
GetSource().RegisterSink(this);
+ mPrincipalHandleListener = new PrincipalHandleListener(this);
+ AddListener(mPrincipalHandleListener);
+
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =
do_GetService("@mozilla.org/uuid-generator;1", &rv);
nsID uuid;
memset(&uuid, 0, sizeof(uuid));
if (uuidgen) {
uuidgen->GenerateUUIDInPlace(&uuid);
@@ -70,35 +129,53 @@ MediaStreamTrack::MediaStreamTrack(DOMMe
char chars[NSID_LENGTH];
uuid.ToProvidedString(chars);
mID = NS_ConvertASCIItoUTF16(chars);
}
MediaStreamTrack::~MediaStreamTrack()
{
+ Destroy();
+}
+
+void
+MediaStreamTrack::Destroy()
+{
+ if (mSource) {
+ mSource->UnregisterSink(this);
+ }
+ if (mPrincipalHandleListener) {
+ if (GetOwnedStream()) {
+ RemoveListener(mPrincipalHandleListener);
+ }
+ mPrincipalHandleListener->Forget();
+ mPrincipalHandleListener = nullptr;
+ }
}
NS_IMPL_CYCLE_COLLECTION_CLASS(MediaStreamTrack)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(MediaStreamTrack,
DOMEventTargetHelper)
+ tmp->Destroy();
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOwningStream)
- if (tmp->mSource) {
- tmp->mSource->UnregisterSink(tmp);
- }
NS_IMPL_CYCLE_COLLECTION_UNLINK(mSource)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalTrack)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(MediaStreamTrack,
DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOwningStream)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalTrack)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_ADDREF_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(MediaStreamTrack, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamTrack)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
nsPIDOMWindowInner*
@@ -172,30 +249,65 @@ MediaStreamTrack::Graph()
MediaStreamGraphImpl*
MediaStreamTrack::GraphImpl()
{
return GetOwnedStream()->GraphImpl();
}
void
-MediaStreamTrack::PrincipalChanged()
+MediaStreamTrack::SetPrincipal(nsIPrincipal* aPrincipal)
{
- LOG(LogLevel::Info, ("MediaStreamTrack %p Principal changed. Now: "
- "null=%d, codebase=%d, expanded=%d, system=%d", this,
- GetPrincipal()->GetIsNullPrincipal(),
- GetPrincipal()->GetIsCodebasePrincipal(),
- GetPrincipal()->GetIsExpandedPrincipal(),
- GetPrincipal()->GetIsSystemPrincipal()));
+ if (aPrincipal == mPrincipal) {
+ return;
+ }
+ mPrincipal = aPrincipal;
+
+ LOG(LogLevel::Info, ("MediaStreamTrack %p principal changed to %p. Now: "
+ "null=%d, codebase=%d, expanded=%d, system=%d",
+ this, mPrincipal.get(),
+ mPrincipal->GetIsNullPrincipal(),
+ mPrincipal->GetIsCodebasePrincipal(),
+ mPrincipal->GetIsExpandedPrincipal(),
+ mPrincipal->GetIsSystemPrincipal()));
for (PrincipalChangeObserver<MediaStreamTrack>* observer
: mPrincipalChangeObservers) {
observer->PrincipalChanged(this);
}
}
+void
+MediaStreamTrack::PrincipalChanged()
+{
+ mPendingPrincipal = GetSource().GetPrincipal();
+ nsCOMPtr<nsIPrincipal> newPrincipal = mPrincipal;
+ LOG(LogLevel::Info, ("MediaStreamTrack %p Principal changed on main thread "
+ "to %p (pending). Combining with existing principal %p.",
+ this, mPendingPrincipal.get(), mPrincipal.get()));
+ if (nsContentUtils::CombineResourcePrincipals(&newPrincipal,
+ mPendingPrincipal)) {
+ SetPrincipal(newPrincipal);
+ }
+}
+
+void
+MediaStreamTrack::NotifyPrincipalHandleChanged(const PrincipalHandle& aNewPrincipalHandle)
+{
+ PrincipalHandle handle(aNewPrincipalHandle);
+ LOG(LogLevel::Info, ("MediaStreamTrack %p principalHandle changed on "
+ "MediaStreamGraph thread to %p. Current principal: %p, "
+ "pending: %p",
+ this, GetPrincipalFromHandle(handle),
+ mPrincipal.get(), mPendingPrincipal.get()));
+ if (PrincipalHandleMatches(handle, mPendingPrincipal)) {
+ SetPrincipal(mPendingPrincipal);
+ mPendingPrincipal = nullptr;
+ }
+}
+
bool
MediaStreamTrack::AddPrincipalChangeObserver(
PrincipalChangeObserver<MediaStreamTrack>* aObserver)
{
return mPrincipalChangeObservers.AppendElement(aObserver) != nullptr;
}
bool
--- a/dom/media/MediaStreamTrack.h
+++ b/dom/media/MediaStreamTrack.h
@@ -71,17 +71,17 @@ public:
/**
* Get this TrackSource's principal.
*/
nsIPrincipal* GetPrincipal() const { return mPrincipal; }
/**
* Get the source's current CORSMode. If not applicable CORS_NONE is returned.
* The sink will be notified of changes to our CORSMode through
- * NotifyPrincipalChanged().
+ * PrincipalChanged().
*/
virtual CORSMode GetCORSMode() const { return CORS_NONE; }
/**
* This is used in WebRTC. A peerIdentity constrained MediaStreamTrack cannot
* be sent across the network to anything other than a peer with the provided
* identity. If this is set, then GetPrincipal() should return an instance of
* nsNullPrincipal.
@@ -205,16 +205,18 @@ class MediaStreamTrack : public DOMEvent
// some internal state, e.g., GetInputStream(), GetOwnedStream().
friend class mozilla::DOMMediaStream;
// PeerConnection and friends need to know our owning DOMStream and track id.
friend class mozilla::PeerConnectionImpl;
friend class mozilla::PeerConnectionMedia;
friend class mozilla::RemoteSourceStreamInfo;
+ class PrincipalHandleListener;
+
public:
/**
* aTrackID is the MediaStreamGraph track ID for the track in the
* MediaStream owned by aStream.
*/
MediaStreamTrack(DOMMediaStream* aStream, TrackID aTrackID,
TrackID aInputTrackID, const nsString& aLabel,
MediaStreamTrackSource* aSource);
@@ -245,17 +247,24 @@ public:
bool Ended() const { return mEnded; }
// Notifications from the MediaStreamGraph
void NotifyEnded() { mEnded = true; }
/**
* Get this track's principal.
*/
- nsIPrincipal* GetPrincipal() const { return GetSource().GetPrincipal(); }
+ nsIPrincipal* GetPrincipal() const { return mPrincipal; }
+
+ /**
+ * Called by the PrincipalHandleListener when this track's PrincipalHandle changes on
+ * the MediaStreamGraph thread. When the PrincipalHandle matches the pending
+ * principal we know that the principal change has propagated to consumers.
+ */
+ void NotifyPrincipalHandleChanged(const PrincipalHandle& aPrincipalHandle);
/**
* Get this track's CORS mode.
*/
CORSMode GetCORSMode() const { return GetSource().GetCORSMode(); }
/**
* Get this track's PeerIdentity.
@@ -326,41 +335,51 @@ public:
* Returns true if this track is connected to aPort and forwarded to aPort's
* output stream.
*/
bool IsForwardedThrough(MediaInputPort* aPort);
protected:
virtual ~MediaStreamTrack();
+ void Destroy();
+
// Returns the original DOMMediaStream's underlying input stream.
MediaStream* GetInputStream();
// Returns the owning DOMMediaStream's underlying owned stream.
ProcessedMediaStream* GetOwnedStream();
// Returns the original DOMMediaStream. If this track is a clone,
// the original track's owning DOMMediaStream is returned.
DOMMediaStream* GetInputDOMStream();
/**
+ * Sets the principal and notifies PrincipalChangeObservers if it changes.
+ */
+ void SetPrincipal(nsIPrincipal* aPrincipal);
+
+ /**
* Creates a new MediaStreamTrack with the same type, input track ID and
* source as this MediaStreamTrack.
* aTrackID is the TrackID the new track will have in its owned stream.
*/
virtual already_AddRefed<MediaStreamTrack> CloneInternal(DOMMediaStream* aOwningStream,
TrackID aTrackID) = 0;
nsTArray<PrincipalChangeObserver<MediaStreamTrack>*> mPrincipalChangeObservers;
RefPtr<DOMMediaStream> mOwningStream;
TrackID mTrackID;
TrackID mInputTrackID;
RefPtr<MediaStreamTrackSource> mSource;
RefPtr<MediaStreamTrack> mOriginalTrack;
+ nsCOMPtr<nsIPrincipal> mPrincipal;
+ nsCOMPtr<nsIPrincipal> mPendingPrincipal;
+ RefPtr<PrincipalHandleListener> mPrincipalHandleListener;
nsString mID;
nsString mLabel;
bool mEnded;
bool mEnabled;
const bool mRemote;
bool mStopped;
};