Bug 1395017. P2 - dispatch a task to the main thread to update the principal when necessary. draft
authorJW Wang <jwwang@mozilla.com>
Tue, 29 Aug 2017 17:57:00 +0800
changeset 660833 6a372c79c89af7407a34a7f76666d387b485aa64
parent 660829 d0d593a9c33aaa2c57c51bca3e97dea3aac86c8b
child 660834 a737ede09587cf3568dadd37d845ab1f23719d33
push id78568
push userjwwang@mozilla.com
push dateThu, 07 Sep 2017 17:19:47 +0000
bugs1395017
milestone57.0a1
Bug 1395017. P2 - dispatch a task to the main thread to update the principal when necessary. MozReview-Commit-ID: 7rNFyNIwT7H
dom/media/MediaCache.cpp
dom/media/MediaCache.h
dom/media/MediaResource.cpp
dom/media/MediaResource.h
--- 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.