Bug 1260982 - BlobFileImpl::GetType() should work also in workers, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Thu, 31 Mar 2016 08:32:58 +0100
changeset 291218 dcefde651ddb7528416ffe62bdb17df1afc2f2d2
parent 291217 85daafb4b11670833bc0a174ff657c1e7409af99
child 291219 d04909bc6f959de45d64fdb0143df7606d443b58
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1260982
milestone48.0a1
Bug 1260982 - BlobFileImpl::GetType() should work also in workers, r=smaug
dom/base/File.cpp
dom/base/File.h
--- a/dom/base/File.cpp
+++ b/dom/base/File.cpp
@@ -34,21 +34,24 @@
 #include "mozilla/CheckedInt.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/BlobBinding.h"
 #include "mozilla/dom/BlobSet.h"
 #include "mozilla/dom/DOMError.h"
 #include "mozilla/dom/FileBinding.h"
 #include "mozilla/dom/WorkerPrivate.h"
+#include "mozilla/dom/WorkerRunnable.h"
 #include "nsThreadUtils.h"
 
 namespace mozilla {
 namespace dom {
 
+using namespace workers;
+
 // XXXkhuey the input stream that we pass out of a File
 // can outlive the actual File object.  Thus, we must
 // ensure that the buffer underlying the stream we get
 // from NS_NewByteInputStream is held alive as long as the
 // stream is.  We do that by passing back this class instead.
 class DataOwnerAdapter final : public nsIInputStream,
                                public nsISeekableStream,
                                public nsIIPCSerializableInputStream
@@ -698,18 +701,17 @@ BlobImplBase::GetMozFullPath(nsAString& 
   if (NS_IsMainThread()) {
     if (nsContentUtils::LegacyIsCallerChromeOrNativeCode()) {
       GetMozFullPathInternal(aFileName, aRv);
     }
 
     return;
   }
 
-  workers::WorkerPrivate* workerPrivate =
-    workers::GetCurrentThreadWorkerPrivate();
+  WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
   MOZ_ASSERT(workerPrivate);
 
   if (workerPrivate->UsesSystemPrincipal()) {
     GetMozFullPathInternal(aFileName, aRv);
   }
 }
 
 void
@@ -857,27 +859,92 @@ BlobImplFile::GetSize(ErrorResult& aRv)
     }
 
     mLength = fileSize;
   }
 
   return mLength;
 }
 
+namespace {
+
+class GetTypeRunnable final : public nsRunnable
+{
+public:
+  GetTypeRunnable(WorkerPrivate* aWorkerPrivate,
+                  nsIEventTarget* aSyncLoopTarget,
+                  BlobImpl* aBlobImpl)
+    : mWorkerPrivate(aWorkerPrivate)
+    , mSyncLoopTarget(aSyncLoopTarget)
+    , mBlobImpl(aBlobImpl)
+  {
+    MOZ_ASSERT(aWorkerPrivate);
+    MOZ_ASSERT(aSyncLoopTarget);
+    MOZ_ASSERT(aBlobImpl);
+    aWorkerPrivate->AssertIsOnWorkerThread();
+  }
+
+  NS_IMETHOD
+  Run() override
+  {
+    MOZ_ASSERT(NS_IsMainThread());
+
+    nsAutoString type;
+    mBlobImpl->GetType(type);
+
+    RefPtr<MainThreadStopSyncLoopRunnable> runnable =
+      new MainThreadStopSyncLoopRunnable(mWorkerPrivate,
+                                         mSyncLoopTarget.forget(), true);
+    NS_WARN_IF(!runnable->Dispatch());
+    return NS_OK;
+  }
+
+private:
+  ~GetTypeRunnable()
+  {}
+
+  WorkerPrivate* mWorkerPrivate;
+  nsCOMPtr<nsIEventTarget> mSyncLoopTarget;
+  RefPtr<BlobImpl> mBlobImpl;
+};
+
+} // anonymous namespace
+
 void
 BlobImplFile::GetType(nsAString& aType)
 {
+  aType.Truncate();
+
   if (mContentType.IsVoid()) {
     NS_ASSERTION(mWholeFile,
                  "Should only use lazy ContentType when using the whole file");
+
+    if (!NS_IsMainThread()) {
+      WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+      if (!workerPrivate) {
+        // I have no idea in which thread this method is called. We cannot
+        // return any valid value.
+        return;
+      }
+
+      AutoSyncLoopHolder syncLoop(workerPrivate);
+
+      RefPtr<GetTypeRunnable> runnable =
+        new GetTypeRunnable(workerPrivate, syncLoop.EventTarget(), this);
+      nsresult rv = NS_DispatchToMainThread(runnable);
+      NS_WARN_IF(NS_FAILED(rv));
+
+      NS_WARN_IF(!syncLoop.Run());
+      return;
+    }
+
     nsresult rv;
     nsCOMPtr<nsIMIMEService> mimeService =
       do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
     if (NS_WARN_IF(NS_FAILED(rv))) {
-      aType.Truncate();
       return;
     }
 
     nsAutoCString mimeType;
     rv = mimeService->GetTypeFromFile(mFile, mimeType);
     if (NS_FAILED(rv)) {
       mimeType.Truncate();
     }
--- a/dom/base/File.h
+++ b/dom/base/File.h
@@ -178,16 +178,22 @@ public:
   // The returned File takes ownership of aMemoryBuffer. aMemoryBuffer will be
   // freed by free so it must be allocated by malloc or something
   // compatible with it.
   static already_AddRefed<File>
   CreateMemoryFile(nsISupports* aParent, void* aMemoryBuffer, uint64_t aLength,
                    const nsAString& aName, const nsAString& aContentType,
                    int64_t aLastModifiedDate);
 
+  // This method creates a BlobFileImpl for the new File object. This is
+  // thread-safe, cross-process, cross-thread as any other BlobImpl, but, when
+  // GetType() is called, it must dispatch a runnable to the main-thread in
+  // order to use nsIMIMEService.
+  // Would be nice if we try to avoid to use this method outside the
+  // main-thread to avoid extra runnables.
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile, bool aTemporary = false);
 
   static already_AddRefed<File>
   CreateFromFile(nsISupports* aParent, nsIFile* aFile, const nsAString& aName,
                  const nsAString& aContentType);
 
   // WebIDL methods