Bug 1235183. Part 4 - create channel asynchronously. r=cpearce
authorJW Wang <jwwang@mozilla.com>
Fri, 24 Jun 2016 13:45:01 +0800
changeset 343128 d80a90575e2d88ceaa07dfa30ed750fbbf798acd
parent 343127 f03f55222c0d865d6be327882f237d6ce5d6cbf8
child 343129 9eea8021987aa665a474355d3c3e072a71b32999
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce
bugs1235183
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1235183. Part 4 - create channel asynchronously. r=cpearce MozReview-Commit-ID: 9JVuHhhMFoa
dom/html/HTMLMediaElement.cpp
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -464,18 +464,21 @@ void HTMLMediaElement::ReportLoadError(c
                                   aParams,
                                   aParamCount);
 }
 
 class HTMLMediaElement::ChannelLoader final {
 public:
   NS_INLINE_DECL_REFCOUNTING(ChannelLoader);
 
-  nsresult Load(HTMLMediaElement* aElement)
+  void LoadInternal(HTMLMediaElement* aElement)
   {
+    if (mCancelled) {
+      return;
+    }
 
     // determine what security checks need to be performed in AsyncOpen2().
     nsSecurityFlags securityFlags = aElement->ShouldCheckAllowOrigin()
       ? nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS :
         nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_INHERITS;
 
     if (aElement->GetCORSMode() == CORS_USE_CREDENTIALS) {
       securityFlags |= nsILoadInfo::SEC_COOKIES_INCLUDE;
@@ -506,17 +509,19 @@ public:
                                 loadGroup,
                                 nullptr,   // aCallbacks
                                 nsICachingChannel::LOAD_BYPASS_LOCAL_CACHE_IF_BUSY |
                                 nsIChannel::LOAD_MEDIA_SNIFFER_OVERRIDES_CONTENT_TYPE |
                                 nsIChannel::LOAD_CLASSIFY_URI |
                                 nsIChannel::LOAD_CALL_CONTENT_SNIFFERS);
 
     if (NS_FAILED(rv)) {
-      return rv;
+      // Notify load error so the element will try next resource candidate.
+      aElement->NotifyLoadError();
+      return;
     }
 
     // This is a workaround and it will be fix in bug 1264230.
     nsCOMPtr<nsILoadInfo> loadInfo = channel->GetLoadInfo();
     if (loadInfo) {
       NeckoOriginAttributes originAttrs;
       NS_GetOriginAttributes(channel, originAttrs);
       loadInfo->SetOriginAttributes(originAttrs);
@@ -540,37 +545,50 @@ public:
       hc->SetRequestHeader(NS_LITERAL_CSTRING("Range"),
                            NS_LITERAL_CSTRING("bytes=0-"),
                            false);
       aElement->SetRequestHeaders(hc);
     }
 
     rv = channel->AsyncOpen2(loadListener);
     if (NS_FAILED(rv)) {
-      return rv;
+      // Notify load error so the element will try next resource candidate.
+      aElement->NotifyLoadError();
+      return;
     }
 
     // Else the channel must be open and starting to download. If it encounters
     // a non-catastrophic failure, it will set a new task to continue loading
     // another candidate.  It's safe to set it as mChannel now.
     mChannel = channel;
 
     // loadListener will be unregistered either on shutdown or when
     // OnStartRequest for the channel we just opened fires.
     nsContentUtils::RegisterShutdownObserver(loadListener);
-    return NS_OK;
+  }
+
+  nsresult Load(HTMLMediaElement* aElement)
+  {
+    // Per bug 1235183 comment 8, we can't spin the event loop from stable
+    // state. Defer NS_NewChannel() to a new regular runnable.
+    return NS_DispatchToMainThread(NewRunnableMethod<HTMLMediaElement*>(
+      this, &ChannelLoader::LoadInternal, aElement));
   }
 
   void Cancel()
   {
-    mChannel->Cancel(NS_BINDING_ABORTED);
-    mChannel = nullptr;
+    mCancelled = true;
+    if (mChannel) {
+      mChannel->Cancel(NS_BINDING_ABORTED);
+      mChannel = nullptr;
+    }
   }
 
   void Done() {
+    MOZ_ASSERT(mChannel);
     // Decoder successfully created, the decoder now owns the MediaResource
     // which owns the channel.
     mChannel = nullptr;
   }
 
   nsresult Redirect(nsIChannel* aChannel,
                     nsIChannel* aNewChannel,
                     uint32_t aFlags)
@@ -604,16 +622,18 @@ private:
   {
     MOZ_ASSERT(!mChannel);
   }
   // Holds a reference to the first channel we open to the media resource.
   // Once the decoder is created, control over the channel passes to the
   // decoder, and we null out this reference. We must store this in case
   // we need to cancel the channel before control of it passes to the decoder.
   nsCOMPtr<nsIChannel> mChannel;
+
+  bool mCancelled = false;
 };
 
 NS_IMPL_ADDREF_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
 NS_IMPL_RELEASE_INHERITED(HTMLMediaElement, nsGenericHTMLElement)
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLMediaElement)
 
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLMediaElement, nsGenericHTMLElement)