Bug 1203680 P5 Make ServiceWorkerManager ensure channel upload stream is cloneable. r=nsm
authorBen Kelly <ben@wanderview.com>
Tue, 15 Sep 2015 10:15:45 -0700
changeset 262616 52093388544adaa41d3abfe0413d60763a7f1a7d
parent 262615 0c0bfeb70612ef41aa093eb0158b840fc7ad1115
child 262617 46dc7055da667e7ccd5fa97262de7ff2674ebd03
push id15198
push userkwierso@gmail.com
push dateWed, 16 Sep 2015 00:21:31 +0000
treeherderfx-team@dbfddd6efb5d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnsm
bugs1203680
milestone43.0a1
Bug 1203680 P5 Make ServiceWorkerManager ensure channel upload stream is cloneable. r=nsm
dom/workers/ServiceWorkerManager.cpp
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -3862,16 +3862,92 @@ private:
       }
 
       MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
     }
     return true;
   }
 };
 
+namespace {
+
+class ContinueDispatchFetchEventRunnable : public nsRunnable
+{
+  WorkerPrivate* mWorkerPrivate;
+  nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
+  nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
+  nsAutoPtr<ServiceWorkerClientInfo> mClientInfo;
+  bool mIsReload;
+public:
+  ContinueDispatchFetchEventRunnable(WorkerPrivate* aWorkerPrivate,
+                                     nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
+                                     nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
+                                     nsAutoPtr<ServiceWorkerClientInfo>& aClientInfo,
+                                     bool aIsReload)
+    : mWorkerPrivate(aWorkerPrivate)
+    , mChannel(aChannel)
+    , mServiceWorker(aServiceWorker)
+    , mClientInfo(aClientInfo)
+    , mIsReload(aIsReload)
+  {
+  }
+
+  void
+  HandleError()
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+    NS_WARNING("Unexpected error while dispatching fetch event!");
+    DebugOnly<nsresult> rv = mChannel->ResetInterception();
+    NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to resume intercepted network request");
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsCOMPtr<nsIChannel> channel;
+    nsresult rv = mChannel->GetChannel(getter_AddRefs(channel));
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    // The channel might have encountered an unexpected error while ensuring
+    // the upload stream is cloneable.  Check here and reset the interception
+    // if that happens.
+    nsresult status;
+    rv = channel->GetStatus(&status);
+    if (NS_WARN_IF(NS_FAILED(rv) || NS_FAILED(status))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    nsRefPtr<FetchEventRunnable> event =
+      new FetchEventRunnable(mWorkerPrivate, mChannel, mServiceWorker,
+                             mClientInfo, mIsReload);
+    rv = event->Init();
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    AutoJSAPI jsapi;
+    jsapi.Init();
+    if (NS_WARN_IF(!event->Dispatch(jsapi.cx()))) {
+      HandleError();
+      return NS_OK;
+    }
+
+    return NS_OK;
+  }
+};
+
+} // anonymous namespace
+
 NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor)
 
 void
 ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttributes,
                                          nsIDocument* aDoc,
                                          nsIInterceptedChannel* aChannel,
                                          bool aIsReload,
                                          ErrorResult& aRv)
@@ -3935,31 +4011,38 @@ ServiceWorkerManager::DispatchFetchEvent
 
   nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
     new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
 
   nsRefPtr<ServiceWorker> sw = static_cast<ServiceWorker*>(serviceWorker.get());
   nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
     new nsMainThreadPtrHolder<ServiceWorker>(sw));
 
-  // clientInfo is null if we don't have a controlled document
-  nsRefPtr<FetchEventRunnable> event =
-    new FetchEventRunnable(sw->GetWorkerPrivate(), handle, serviceWorkerHandle,
-                           clientInfo, aIsReload);
-  aRv = event->Init();
+  nsCOMPtr<nsIRunnable> continueRunnable =
+    new ContinueDispatchFetchEventRunnable(sw->GetWorkerPrivate(), handle,
+                                           serviceWorkerHandle, clientInfo,
+                                           aIsReload);
+
+  nsCOMPtr<nsIChannel> innerChannel;
+  aRv = aChannel->GetChannel(getter_AddRefs(innerChannel));
   if (NS_WARN_IF(aRv.Failed())) {
     return;
   }
 
-  AutoJSAPI api;
-  api.Init();
-  if (NS_WARN_IF(!event->Dispatch(api.cx()))) {
-    aRv.Throw(NS_ERROR_FAILURE);
+  nsCOMPtr<nsIUploadChannel2> uploadChannel = do_QueryInterface(innerChannel);
+
+  // If there is no upload stream, then continue immediately
+  if (!uploadChannel) {
+    MOZ_ALWAYS_TRUE(NS_SUCCEEDED(continueRunnable->Run()));
     return;
   }
+
+  // Otherwise, ensure the upload stream can be cloned directly.  This may
+  // require some async copying, so provide a callback.
+  aRv = uploadChannel->EnsureUploadStreamIsCloneable(continueRunnable);
 }
 
 bool
 ServiceWorkerManager::IsAvailable(const OriginAttributes& aOriginAttributes,
                                   nsIURI* aURI)
 {
   MOZ_ASSERT(aURI);