Bug 1395017. P2 - dispatch a task to the main thread to update the principal when necessary.
MozReview-Commit-ID: 7rNFyNIwT7H
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -1867,43 +1867,35 @@ MediaCacheStream::NotifyDataStarted(int6
mChannelOffset = aOffset;
if (mStreamLength >= 0) {
// If we started reading at a certain offset, then for sure
// the stream is at least that long.
mStreamLength = std::max(mStreamLength, mChannelOffset);
}
}
-bool
+void
MediaCacheStream::UpdatePrincipal(nsIPrincipal* aPrincipal)
{
- return nsContentUtils::CombineResourcePrincipals(&mPrincipal, aPrincipal);
+ MOZ_ASSERT(NS_IsMainThread());
+ MediaCache::ResourceStreamIterator iter(mMediaCache, mResourceID);
+ while (MediaCacheStream* stream = iter.Next()) {
+ if (nsContentUtils::CombineResourcePrincipals(&stream->mPrincipal,
+ aPrincipal)) {
+ stream->mClient->CacheClientNotifyPrincipalChanged();
+ }
+ }
}
void
-MediaCacheStream::NotifyDataReceived(int64_t aSize, const char* aData,
- nsIPrincipal* aPrincipal)
+MediaCacheStream::NotifyDataReceived(int64_t aSize, const char* aData)
{
// This might happen off the main thread.
MOZ_DIAGNOSTIC_ASSERT(!mClosed);
- // Update principals before putting the data in the cache. This is important,
- // we want to make sure all principals are updated before any consumer
- // can see the new data.
- // We do this without holding the cache monitor, in case the client wants
- // to do something that takes a lock.
- {
- MediaCache::ResourceStreamIterator iter(mMediaCache, mResourceID);
- while (MediaCacheStream* stream = iter.Next()) {
- if (stream->UpdatePrincipal(aPrincipal)) {
- stream->mClient->CacheClientNotifyPrincipalChanged();
- }
- }
- }
-
ReentrantMonitorAutoEnter mon(mMediaCache->GetReentrantMonitor());
int64_t size = aSize;
const char* data = aData;
LOG("Stream %p DataReceived at %" PRId64 " count=%" PRId64,
this, mChannelOffset, aSize);
// We process the data one block (or part of a block) at a time
--- a/dom/media/MediaCache.h
+++ b/dom/media/MediaCache.h
@@ -256,18 +256,17 @@ public:
// time by the client, not just after a CacheClientSeek.
void NotifyDataStarted(int64_t aOffset);
// Notifies the cache that data has been received. The stream already
// knows the offset because data is received in sequence and
// the starting offset is known via NotifyDataStarted or because
// the cache requested the offset in
// ChannelMediaResource::CacheClientSeek, or because it defaulted to 0.
// We pass in the principal that was used to load this data.
- void NotifyDataReceived(int64_t aSize, const char* aData,
- nsIPrincipal* aPrincipal);
+ void NotifyDataReceived(int64_t aSize, const char* aData);
// Notifies the cache that the current bytes should be written to disk.
// Called on the main thread.
void FlushPartialBlock();
// Notifies the cache that the channel has closed with the given status.
void NotifyDataEnded(nsresult aStatus);
// Notifies the stream that the channel is reopened. The stream should
// reset variables such as |mDidNotifyDataEnded|.
@@ -343,16 +342,20 @@ public:
// 'Read' for argument and return details.
nsresult ReadAt(int64_t aOffset, char* aBuffer,
uint32_t aCount, uint32_t* aBytes);
void ThrottleReadahead(bool bThrottle);
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
+ // Update mPrincipal for all streams of the same resource given that data has
+ // been received from aPrincipal
+ void UpdatePrincipal(nsIPrincipal* aPrincipal);
+
private:
friend class MediaCache;
/**
* A doubly-linked list of blocks. Add/Remove/Get methods are all
* constant time. We declare this here so that a stream can contain a
* BlockList of its read-ahead blocks. Blocks are referred to by index
* into the MediaCache::mIndex array.
@@ -420,18 +423,16 @@ private:
// This method assumes that the cache monitor is held and can be called on
// any thread.
int64_t GetNextCachedDataInternal(int64_t aOffset);
// Writes |mPartialBlock| to disk.
// Used by |NotifyDataEnded| and |FlushPartialBlock|.
// If |aNotifyAll| is true, this function will wake up readers who may be
// waiting on the media cache monitor. Called on the main thread only.
void FlushPartialBlockInternal(bool aNotify, ReentrantMonitorAutoEnter& aReentrantMonitor);
- // Update mPrincipal given that data has been received from aPrincipal
- bool UpdatePrincipal(nsIPrincipal* aPrincipal);
// Instance of MediaCache to use with this MediaCacheStream.
RefPtr<MediaCache> mMediaCache;
// These fields are main-thread-only.
ChannelMediaResource* mClient;
nsCOMPtr<nsIPrincipal> mPrincipal;
// Set to true when MediaCache::Update() has finished while this stream
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -441,76 +441,71 @@ ChannelMediaResource::OnChannelRedirect(
uint32_t aFlags)
{
mChannel = aNew;
mSuspendAgent.NotifyChannelOpened(mChannel);
return SetupChannelHeaders();
}
nsresult
-ChannelMediaResource::CopySegmentToCache(nsIPrincipal* aPrincipal,
- const char* aFromSegment,
+ChannelMediaResource::CopySegmentToCache(const char* aFromSegment,
uint32_t aCount,
uint32_t* aWriteCount)
{
// Keep track of where we're up to.
LOG("CopySegmentToCache at mOffset [%" PRId64 "] add "
"[%d] bytes for decoder[%p]",
mOffset, aCount, mCallback.get());
mOffset += aCount;
- mCacheStream.NotifyDataReceived(aCount, aFromSegment, aPrincipal);
+ mCacheStream.NotifyDataReceived(aCount, aFromSegment);
*aWriteCount = aCount;
return NS_OK;
}
-
-struct CopySegmentClosure {
- nsCOMPtr<nsIPrincipal> mPrincipal;
- ChannelMediaResource* mResource;
-};
-
nsresult
ChannelMediaResource::CopySegmentToCache(nsIInputStream* aInStream,
- void* aClosure,
+ void* aResource,
const char* aFromSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t* aWriteCount)
{
- CopySegmentClosure* closure = static_cast<CopySegmentClosure*>(aClosure);
- return closure->mResource->CopySegmentToCache(
- closure->mPrincipal, aFromSegment, aCount, aWriteCount);
+ ChannelMediaResource* res = static_cast<ChannelMediaResource*>(aResource);
+ return res->CopySegmentToCache(aFromSegment, aCount, aWriteCount);
}
nsresult
ChannelMediaResource::OnDataAvailable(nsIRequest* aRequest,
nsIInputStream* aStream,
uint32_t aCount)
{
// This might happen off the main thread.
NS_ASSERTION(mChannel.get() == aRequest, "Wrong channel!");
+ bool isMainThread = NS_IsMainThread();
+ if (isMainThread) {
+ // Update the principal now if we are already on the main thread. Otherwise
+ // we will dispatch a runnable to do it.
+ UpdatePrincipal();
+ }
+
RefPtr<ChannelMediaResource> self = this;
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
- "ChannelMediaResource::OnDataAvailable",
- [self, aCount]() { self->mChannelStatistics.AddBytes(aCount); });
+ "ChannelMediaResource::OnDataAvailable", [self, aCount, isMainThread]() {
+ self->mChannelStatistics.AddBytes(aCount);
+ if (!isMainThread) {
+ self->UpdatePrincipal();
+ }
+ });
mCallback->AbstractMainThread()->Dispatch(r.forget());
- CopySegmentClosure closure;
- nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
- if (secMan && mChannel) {
- secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(closure.mPrincipal));
- }
- closure.mResource = this;
-
uint32_t count = aCount;
while (count > 0) {
uint32_t read;
- nsresult rv = aStream->ReadSegments(CopySegmentToCache, &closure, count,
- &read);
+ nsresult rv = aStream->ReadSegments(CopySegmentToCache, this, count, &read);
if (NS_FAILED(rv))
return rv;
NS_ASSERTION(read > 0, "Read 0 bytes while data was available?");
count -= read;
}
return NS_OK;
}
@@ -624,17 +619,18 @@ nsresult ChannelMediaResource::Close()
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
CloseChannel();
mCacheStream.Close();
return NS_OK;
}
-already_AddRefed<nsIPrincipal> ChannelMediaResource::GetCurrentPrincipal()
+already_AddRefed<nsIPrincipal>
+ChannelMediaResource::GetCurrentPrincipal()
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
nsCOMPtr<nsIPrincipal> principal = mCacheStream.GetCurrentPrincipal();
return principal.forget();
}
bool ChannelMediaResource::CanClone()
@@ -874,16 +870,28 @@ void
ChannelMediaResource::CacheClientNotifyPrincipalChanged()
{
NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
mCallback->NotifyPrincipalChanged();
}
void
+ChannelMediaResource::UpdatePrincipal()
+{
+ MOZ_ASSERT(NS_IsMainThread());
+ nsCOMPtr<nsIPrincipal> principal;
+ nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
+ if (secMan && mChannel) {
+ secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
+ mCacheStream.UpdatePrincipal(principal);
+ }
+}
+
+void
ChannelMediaResource::CacheClientNotifySuspendedStatusChanged()
{
NS_ASSERTION(NS_IsMainThread(), "Don't call on non-main thread");
mCallback->NotifySuspendedStatusChanged(IsSuspendedByCache());
}
nsresult
ChannelMediaResource::CacheClientSeek(int64_t aOffset, bool aResume)
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -541,34 +541,35 @@ protected:
// Opens the channel, using an HTTP byte range request to start at mOffset
// if possible. Main thread only.
nsresult OpenChannel(nsIStreamListener** aStreamListener);
nsresult RecreateChannel();
// Add headers to HTTP request. Main thread only.
nsresult SetupChannelHeaders();
// Closes the channel. Main thread only.
void CloseChannel();
+ // Update the principal for the resource. Main thread only.
+ void UpdatePrincipal();
// Parses 'Content-Range' header and returns results via parameters.
// Returns error if header is not available, values are not parse-able or
// values are out of range.
nsresult ParseContentRangeHeader(nsIHttpChannel * aHttpChan,
int64_t& aRangeStart,
int64_t& aRangeEnd,
int64_t& aRangeTotal);
static nsresult CopySegmentToCache(nsIInputStream* aInStream,
- void* aClosure,
+ void* aResource,
const char* aFromSegment,
uint32_t aToOffset,
uint32_t aCount,
uint32_t* aWriteCount);
- nsresult CopySegmentToCache(nsIPrincipal* aPrincipal,
- const char* aFromSegment,
+ nsresult CopySegmentToCache(const char* aFromSegment,
uint32_t aCount,
uint32_t* aWriteCount);
// Main thread access only
int64_t mOffset;
RefPtr<Listener> mListener;
// When this flag is set, if we get a network error we should silently
// reopen the stream.