Bug 773798 - Multi-process support for MediaStorage - Use PBlob. r=bent
authorDoug Turner <dougt@dougt.org>
Thu, 09 Aug 2012 15:41:18 -0700
changeset 105132 3664e5ab11b3981c3eb76cfe60438e64e8a22b93
parent 105131 cc583bf8519cc620daf6f957d74b8bd8dfcf074f
child 105133 ef06eb15d5208fe3b2b8b90f9d040dfb7af09c85
push idunknown
push userunknown
push dateunknown
reviewersbent
bugs773798
milestone17.0a1
Bug 773798 - Multi-process support for MediaStorage - Use PBlob. r=bent
dom/devicestorage/DeviceStorageRequestChild.cpp
dom/devicestorage/DeviceStorageRequestParent.cpp
dom/devicestorage/DeviceStorageRequestParent.h
dom/devicestorage/PDeviceStorageRequest.ipdl
dom/devicestorage/nsDeviceStorage.cpp
dom/devicestorage/nsDeviceStorage.h
dom/ipc/ContentParent.cpp
dom/ipc/PContent.ipdl
--- a/dom/devicestorage/DeviceStorageRequestChild.cpp
+++ b/dom/devicestorage/DeviceStorageRequestChild.cpp
@@ -2,16 +2,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 
 #include "DeviceStorageRequestChild.h"
 #include "nsDeviceStorage.h"
 #include "nsDOMFile.h"
+#include "mozilla/dom/ipc/Blob.h"
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 DeviceStorageRequestChild::DeviceStorageRequestChild()
 {
   MOZ_COUNT_CTOR(DeviceStorageRequestChild);
@@ -23,16 +24,17 @@ DeviceStorageRequestChild::DeviceStorage
   , mFile(aFile)
 {
   MOZ_COUNT_CTOR(DeviceStorageRequestChild);
 }
 
 DeviceStorageRequestChild::~DeviceStorageRequestChild() {
   MOZ_COUNT_DTOR(DeviceStorageRequestChild);
 }
+
 bool
 DeviceStorageRequestChild::Recv__delete__(const DeviceStorageResponseValue& aValue)
 {
   switch (aValue.type()) {
 
     case DeviceStorageResponseValue::TErrorResponse:
     {
       ErrorResponse r = aValue;
@@ -45,29 +47,18 @@ DeviceStorageRequestChild::Recv__delete_
       jsval result = StringToJsval(mRequest->GetOwner(), mFile->mPath);
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TBlobResponse:
     {
       BlobResponse r = aValue;
-
-      // I am going to hell for this.  bent says he'll save me.
-      const InfallibleTArray<PRUint8> bits = r.bits();
-      void* buffer = PR_Malloc(bits.Length());
-      memcpy(buffer, (void*) bits.Elements(), bits.Length());
-
-      nsString mimeType;
-      mimeType.AssignWithConversion(r.contentType());
-
-      nsCOMPtr<nsIDOMBlob> blob = new nsDOMMemoryFile(buffer,
-                                                      bits.Length(),
-                                                      mFile->mPath,
-                                                      mimeType);
+      BlobChild* actor = static_cast<BlobChild*>(r.blobChild());
+      nsCOMPtr<nsIDOMBlob> blob = actor->GetBlob();
 
       jsval result = BlobToJsval(mRequest->GetOwner(), blob);
       mRequest->FireSuccess(result);
       break;
     }
 
     case DeviceStorageResponseValue::TEnumerationResponse:
     {
@@ -75,17 +66,17 @@ DeviceStorageRequestChild::Recv__delete_
       nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
 
       PRUint32 count = r.paths().Length();
       for (PRUint32 i = 0; i < count; i++) {
         nsCOMPtr<nsIFile> f;
         NS_NewLocalFile(r.paths()[i].fullpath(), false, getter_AddRefs(f));
 
         nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-        dsf->SetPath(r.paths()[i].path());
+        dsf->SetPath(r.paths()[i].name());
         cursor->mFiles.AppendElement(dsf);
       }
 
       nsCOMPtr<ContinueCursorEvent> event = new ContinueCursorEvent(cursor);
       NS_DispatchToMainThread(event);
       break;
     }
 
--- a/dom/devicestorage/DeviceStorageRequestParent.cpp
+++ b/dom/devicestorage/DeviceStorageRequestParent.cpp
@@ -3,16 +3,19 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "DeviceStorageRequestParent.h"
 #include "nsDOMFile.h"
 #include "nsIMIMEService.h"
 #include "nsCExternalHandlerService.h"
 #include "mozilla/unused.h"
+#include "mozilla/dom/ipc/Blob.h"
+#include "ContentParent.h"
+#include "nsProxyRelease.h"
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 DeviceStorageRequestParent::DeviceStorageRequestParent(const DeviceStorageParams& aParams)
 {
   MOZ_COUNT_CTOR(DeviceStorageRequestParent);
@@ -21,65 +24,73 @@ DeviceStorageRequestParent::DeviceStorag
     case DeviceStorageParams::TDeviceStorageAddParams:
     {
       DeviceStorageAddParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<WriteFileEvent> r = new WriteFileEvent(this, dsf, p.bits());
+
+      BlobParent* bp = static_cast<BlobParent*>(p.blobParent());
+      nsCOMPtr<nsIDOMBlob> blob = bp->GetBlob();
+
+      nsCOMPtr<nsIInputStream> stream;
+      blob->GetInternalStream(getter_AddRefs(stream));
+
+      nsRefPtr<CancelableRunnable> r = new WriteFileEvent(this, dsf, stream);
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
 
     case DeviceStorageParams::TDeviceStorageGetParams:
     {
       DeviceStorageGetParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<ReadFileEvent> r = new ReadFileEvent(this, dsf);
+      dsf->SetPath(p.name());
+      nsRefPtr<CancelableRunnable> r = new ReadFileEvent(this, dsf);
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
 
     case DeviceStorageParams::TDeviceStorageDeleteParams:
     {
       DeviceStorageDeleteParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<DeleteFileEvent> r = new DeleteFileEvent(this, dsf);
+      nsRefPtr<CancelableRunnable> r = new DeleteFileEvent(this, dsf);
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
 
     case DeviceStorageParams::TDeviceStorageEnumerationParams:
     {
       DeviceStorageEnumerationParams p = aParams;
 
       nsCOMPtr<nsIFile> f;
       NS_NewLocalFile(p.fullpath(), false, getter_AddRefs(f));
 
       nsRefPtr<DeviceStorageFile> dsf = new DeviceStorageFile(f);
-      nsRefPtr<EnumerateFileEvent> r = new EnumerateFileEvent(this, dsf, p.since());
+      nsRefPtr<CancelableRunnable> r = new EnumerateFileEvent(this, dsf, p.since());
 
       nsCOMPtr<nsIEventTarget> target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
       NS_ASSERTION(target, "Must have stream transport service");
       target->Dispatch(r, NS_DISPATCH_NORMAL);
       break;
     }
     default:
     {
@@ -89,227 +100,251 @@ DeviceStorageRequestParent::DeviceStorag
   }
 }
 
 DeviceStorageRequestParent::~DeviceStorageRequestParent()
 {
   MOZ_COUNT_DTOR(DeviceStorageRequestParent);
 }
 
+NS_IMPL_THREADSAFE_ADDREF(DeviceStorageRequestParent);
+NS_IMPL_THREADSAFE_RELEASE(DeviceStorageRequestParent);
+
+void
+DeviceStorageRequestParent::ActorDestroy(ActorDestroyReason)
+{
+  PRInt32 count = mRunnables.Length();
+  for (PRInt32 index = 0; index < count; index++) {
+    mRunnables[index]->Cancel();
+  }
+}
+
 DeviceStorageRequestParent::PostErrorEvent::PostErrorEvent(DeviceStorageRequestParent* aParent,
                                                            const char* aError)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
 {
-  mError.AssignWithConversion(aError);
+  CopyASCIItoUTF16(aError, mError);
 }
 
 DeviceStorageRequestParent::PostErrorEvent::~PostErrorEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostErrorEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostErrorEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   ErrorResponse response(mError);
   unused << mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 
 DeviceStorageRequestParent::PostSuccessEvent::PostSuccessEvent(DeviceStorageRequestParent* aParent)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
 {
 }
 
 DeviceStorageRequestParent::PostSuccessEvent::~PostSuccessEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostSuccessEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostSuccessEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   SuccessResponse response;
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::PostBlobSuccessEvent::PostBlobSuccessEvent(DeviceStorageRequestParent* aParent,
-                                                                       void* aBuffer,
+                                                                       DeviceStorageFile* aFile,
                                                                        PRUint32 aLength,
                                                                        nsACString& aMimeType)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
+  , mLength(aLength)
+  , mFile(aFile)
   , mMimeType(aMimeType)
 {
-  mBits.SetCapacity(aLength);
-  void* bits = mBits.Elements();
-  memcpy(bits, aBuffer, aLength);
 }
 
 DeviceStorageRequestParent::PostBlobSuccessEvent::~PostBlobSuccessEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostBlobSuccessEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostBlobSuccessEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  BlobResponse response(mBits, mMimeType);
+  nsString mime;
+  mime.AssignWithConversion(mMimeType);
+  CopyASCIItoUTF16(mMimeType, mime);
+
+  nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(mFile->mPath, mime, mLength, mFile->mFile);
+
+  ContentParent* cp = static_cast<ContentParent*>(mParent->Manager());
+  BlobParent* actor = cp->GetOrCreateActorForBlob(blob);
+
+  BlobResponse response;
+  response.blobParent() = actor;
+
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::PostEnumerationSuccessEvent::PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent,
                                                                                      InfallibleTArray<DeviceStorageFileValue>& aPaths)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mPaths(aPaths)
 {
 }
 
 DeviceStorageRequestParent::PostEnumerationSuccessEvent::~PostEnumerationSuccessEvent() {}
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostEnumerationSuccessEvent::Run() {
+nsresult
+DeviceStorageRequestParent::PostEnumerationSuccessEvent::CancelableRun() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   EnumerationResponse response(mPaths);
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::WriteFileEvent::WriteFileEvent(DeviceStorageRequestParent* aParent,
                                                            DeviceStorageFile* aFile,
-                                                           InfallibleTArray<PRUint8>& aBits)
-  : mParent(aParent)
+                                                           nsIInputStream* aInputStream)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
-  , mBits(aBits)
+  , mInputStream(aInputStream)
 {
 }
 
 DeviceStorageRequestParent::WriteFileEvent::~WriteFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::WriteFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::WriteFileEvent::CancelableRun()
 {
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+
   nsRefPtr<nsRunnable> r;
-  nsresult rv = mFile->Write(mBits);
+
+  if (!mInputStream) {
+    r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
+    NS_DispatchToMainThread(r);
+    return NS_OK;
+  }
+
+  nsresult rv = mFile->Write(mInputStream);
 
   if (NS_FAILED(rv)) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
   }
   else {
     r = new PostPathResultEvent(mParent, mFile->mPath);
   }
 
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 
 DeviceStorageRequestParent::DeleteFileEvent::DeleteFileEvent(DeviceStorageRequestParent* aParent,
                                                              DeviceStorageFile* aFile)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
 {
 }
 
 DeviceStorageRequestParent::DeleteFileEvent::~DeleteFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::DeleteFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::DeleteFileEvent::CancelableRun()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   mFile->mFile->Remove(true);
 
   nsRefPtr<nsRunnable> r;
 
   bool check = false;
   mFile->mFile->Exists(&check);
   if (check) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
   }
   else {
     r = new PostPathResultEvent(mParent, mFile->mPath);
   }
+
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::ReadFileEvent::ReadFileEvent(DeviceStorageRequestParent* aParent,
                                                          DeviceStorageFile* aFile)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
 {
   nsCOMPtr<nsIMIMEService> mimeService = do_GetService(NS_MIMESERVICE_CONTRACTID);
   if (mimeService) {
     nsresult rv = mimeService->GetTypeFromFile(mFile->mFile, mMimeType);
     if (NS_FAILED(rv)) {
       mMimeType.Truncate();
     }
   }
 }
 
 DeviceStorageRequestParent::ReadFileEvent::~ReadFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::ReadFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::ReadFileEvent::CancelableRun()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   nsCOMPtr<nsIRunnable> r;
   bool check = false;
   mFile->mFile->Exists(&check);
+
   if (!check) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
   PRInt64 fileSize;
   nsresult rv = mFile->mFile->GetFileSize(&fileSize);
   if (NS_FAILED(rv)) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
-  
-  PRFileDesc *fileHandle;
-  rv = mFile->mFile->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
 
-  // i am going to hell.  this is temp until bent provides seralizaiton of blobs.
-  void* buf = (void*) malloc(fileSize);
-  PRInt32 read = PR_Read(fileHandle, buf, fileSize); 
-  if (read != fileSize) {
-    r = new PostErrorEvent(mParent, POST_ERROR_EVENT_UNKNOWN);
-    NS_DispatchToMainThread(r);
-    return NS_OK;
-  }
-
-  r = new PostBlobSuccessEvent(mParent, buf, fileSize, mMimeType);
-
-  PR_Free(buf);
-  PR_Close(fileHandle);
-
+  r = new PostBlobSuccessEvent(mParent, mFile, fileSize, mMimeType);
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 DeviceStorageRequestParent::EnumerateFileEvent::EnumerateFileEvent(DeviceStorageRequestParent* aParent,
                                                                    DeviceStorageFile* aFile,
                                                                    PRUint32 aSince)
-  : mParent(aParent)
+  : CancelableRunnable(aParent)
   , mFile(aFile)
   , mSince(aSince)
 {
 }
 
 DeviceStorageRequestParent::EnumerateFileEvent::~EnumerateFileEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::EnumerateFileEvent::Run()
+nsresult
+DeviceStorageRequestParent::EnumerateFileEvent::CancelableRun()
 {
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
   nsCOMPtr<nsIRunnable> r;
   bool check = false;
   mFile->mFile->Exists(&check);
   if (!check) {
     r = new PostErrorEvent(mParent, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST);
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
@@ -318,39 +353,39 @@ DeviceStorageRequestParent::EnumerateFil
   mFile->CollectFiles(files, mSince);
 
   InfallibleTArray<DeviceStorageFileValue> values;
 
   PRUint32 count = files.Length();
   for (PRUint32 i = 0; i < count; i++) {
     nsString fullpath;
     files[i]->mFile->GetPath(fullpath);
-    DeviceStorageFileValue dsvf(fullpath, files[i]->mPath);
+    DeviceStorageFileValue dsvf(files[i]->mPath, fullpath);
     values.AppendElement(dsvf);
   }
 
   r = new PostEnumerationSuccessEvent(mParent, values);
   NS_DispatchToMainThread(r);
   return NS_OK;
 }
 
 
 DeviceStorageRequestParent::PostPathResultEvent::PostPathResultEvent(DeviceStorageRequestParent* aParent,
-                                                             const nsAString& aPath)
-  : mParent(aParent)
+                                                                     const nsAString& aPath)
+  : CancelableRunnable(aParent)
   , mPath(aPath)
 {
 }
 
 DeviceStorageRequestParent::PostPathResultEvent::~PostPathResultEvent()
 {
 }
 
-NS_IMETHODIMP
-DeviceStorageRequestParent::PostPathResultEvent::Run()
+nsresult
+DeviceStorageRequestParent::PostPathResultEvent::CancelableRun()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   SuccessResponse response;
   unused <<  mParent->Send__delete__(mParent, response);
   return NS_OK;
 }
 
--- a/dom/devicestorage/DeviceStorageRequestParent.h
+++ b/dom/devicestorage/DeviceStorageRequestParent.h
@@ -6,131 +6,172 @@
 #ifndef mozilla_dom_devicestorage_DeviceStorageRequestParent_h
 #define mozilla_dom_devicestorage_DeviceStorageRequestParent_h
 
 #include "mozilla/dom/devicestorage/PDeviceStorageRequestParent.h"
 #include "mozilla/dom/ContentChild.h"
 
 #include "nsThreadUtils.h"
 #include "nsDeviceStorage.h"
+#include "nsTArray.h"
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 class DeviceStorageRequestParent : public PDeviceStorageRequestParent
 {
 public:
   DeviceStorageRequestParent(const DeviceStorageParams& aParams);
+
+  NS_IMETHOD_(nsrefcnt) AddRef();
+  NS_IMETHOD_(nsrefcnt) Release();
+  virtual void ActorDestroy(ActorDestroyReason);
+
+protected:
   ~DeviceStorageRequestParent();
 
 private:
-  class PostErrorEvent : public nsRunnable
+  nsAutoRefCnt mRefCnt;
+
+  class CancelableRunnable : public nsRunnable
+  {
+  public:
+    CancelableRunnable(DeviceStorageRequestParent* aParent)
+      : mParent(aParent)
+      , mCanceled(false)
+    {
+      mParent->AddRunnable(this);
+    }
+
+    virtual ~CancelableRunnable() {
+    }
+
+    NS_IMETHOD Run() {
+      nsresult rv = NS_OK;
+      if (!mCanceled) {
+        rv = CancelableRun();
+        mParent->RemoveRunnable(this);
+      }
+      return rv;
+    }
+
+    void Cancel() {
+      mCanceled = true;
+    }
+
+    virtual nsresult CancelableRun() = 0;
+
+  protected:
+    nsRefPtr<DeviceStorageRequestParent> mParent;
+  private:
+    bool mCanceled;
+  };
+
+  class PostErrorEvent : public CancelableRunnable
   {
     public:
       PostErrorEvent(DeviceStorageRequestParent* aParent, const char* aError);
-      ~PostErrorEvent();
-      NS_IMETHOD Run();
+      virtual ~PostErrorEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
       nsString mError;
   };
 
-  class PostSuccessEvent : public nsRunnable
+  class PostSuccessEvent : public CancelableRunnable
   {
     public:
       PostSuccessEvent(DeviceStorageRequestParent* aParent);
-      ~PostSuccessEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-  };
-
-  class PostBlobSuccessEvent : public nsRunnable
-  {
-    public:
-      PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, void* aBuffer, PRUint32 aLength, nsACString& aMimeType);
-      ~PostBlobSuccessEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-      InfallibleTArray<PRUint8> mBits;
-      nsCString mMimeType;
-  };
-
-  class PostEnumerationSuccessEvent : public nsRunnable
-  {
-    public:
-      PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent, InfallibleTArray<DeviceStorageFileValue>& aPaths);
-      ~PostEnumerationSuccessEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-      InfallibleTArray<DeviceStorageFileValue> mPaths;
+      virtual ~PostSuccessEvent();
+      virtual nsresult CancelableRun();
   };
 
-  class WriteFileEvent : public nsRunnable
-  {
-    public:
-      WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, InfallibleTArray<PRUint8>& aBits);
-      ~WriteFileEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
-      nsRefPtr<DeviceStorageFile> mFile;
-    InfallibleTArray<PRUint8> mBits; // another copy?
-  };
-
-  class DeleteFileEvent : public nsRunnable
+  class PostBlobSuccessEvent : public CancelableRunnable
   {
     public:
-      DeleteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
-      ~DeleteFileEvent();
-      NS_IMETHOD Run();
+      PostBlobSuccessEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, PRUint32 aLength, nsACString& aMimeType);
+      virtual ~PostBlobSuccessEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
-      nsRefPtr<DeviceStorageFile> mFile;
-  };
-
-  class ReadFileEvent : public nsRunnable
-  {
-    public:
-      ReadFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
-      ~ReadFileEvent();
-      NS_IMETHOD Run();
-    private:
-      DeviceStorageRequestParent* mParent;
+      PRUint32 mLength;
       nsRefPtr<DeviceStorageFile> mFile;
       nsCString mMimeType;
   };
 
-  class EnumerateFileEvent : public nsRunnable
+  class PostEnumerationSuccessEvent : public CancelableRunnable
+  {
+    public:
+      PostEnumerationSuccessEvent(DeviceStorageRequestParent* aParent, InfallibleTArray<DeviceStorageFileValue>& aPaths);
+      virtual ~PostEnumerationSuccessEvent();
+      virtual nsresult CancelableRun();
+    private:
+      InfallibleTArray<DeviceStorageFileValue> mPaths;
+  };
+
+  class WriteFileEvent : public CancelableRunnable
+  {
+    public:
+      WriteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, nsIInputStream* aInputStream);
+      virtual ~WriteFileEvent();
+      virtual nsresult CancelableRun();
+    private:
+      nsRefPtr<DeviceStorageFile> mFile;
+      nsCOMPtr<nsIInputStream> mInputStream;
+  };
+
+  class DeleteFileEvent : public CancelableRunnable
+  {
+    public:
+      DeleteFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
+      virtual ~DeleteFileEvent();
+      virtual nsresult CancelableRun();
+    private:
+      nsRefPtr<DeviceStorageFile> mFile;
+  };
+
+  class ReadFileEvent : public CancelableRunnable
+  {
+    public:
+      ReadFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile);
+      virtual ~ReadFileEvent();
+      virtual nsresult CancelableRun();
+    private:
+      nsRefPtr<DeviceStorageFile> mFile;
+      nsCString mMimeType;
+  };
+
+  class EnumerateFileEvent : public CancelableRunnable
   {
     public:
       EnumerateFileEvent(DeviceStorageRequestParent* aParent, DeviceStorageFile* aFile, PRUint32 aSince);
-      ~EnumerateFileEvent();
-      NS_IMETHOD Run();
+      virtual ~EnumerateFileEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
       nsRefPtr<DeviceStorageFile> mFile;
       PRUint32 mSince;
   };
 
-  class PostPathResultEvent : public nsRunnable
+  class PostPathResultEvent : public CancelableRunnable
   {
     public:
       PostPathResultEvent(DeviceStorageRequestParent* aParent, const nsAString& aPath);
-      ~PostPathResultEvent();
-      NS_IMETHOD Run();
+      virtual ~PostPathResultEvent();
+      virtual nsresult CancelableRun();
     private:
-      DeviceStorageRequestParent* mParent;
       nsRefPtr<DeviceStorageFile> mFile;
-      InfallibleTArray<PRUint8> mBits;
       nsString mPath;
   };
 
+protected:
+  void AddRunnable(CancelableRunnable* aRunnable) {
+    mRunnables.AppendElement(aRunnable);
+  }
+  void RemoveRunnable(CancelableRunnable* aRunnable) {
+    mRunnables.RemoveElement(aRunnable);
+  }
+  nsTArray<nsRefPtr<CancelableRunnable> > mRunnables;
 };
 
 } // namespace devicestorage
 } // namespace dom
 } // namespace mozilla
 
 #endif
--- a/dom/devicestorage/PDeviceStorageRequest.ipdl
+++ b/dom/devicestorage/PDeviceStorageRequest.ipdl
@@ -1,13 +1,14 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+include protocol PBlob;
 include protocol PContent;
 
 namespace mozilla {
 namespace dom {
 namespace devicestorage {
 
 
 struct ErrorResponse
@@ -16,32 +17,28 @@ struct ErrorResponse
 };
 
 struct SuccessResponse
 {
 };
 
 struct BlobResponse
 {
-  // todo going away
-  PRUint8[] bits;
-  nsCString contentType;
+  PBlob blob;
 };
 
 struct DeviceStorageFileValue
 {
-  // todo going away
+  nsString name;
   nsString fullpath;
-  nsString path;
 };
 
 struct EnumerationResponse
 {
   DeviceStorageFileValue[] paths;
-  // todo bent PBlob
 };
 
 union DeviceStorageResponseValue
 {
   ErrorResponse;
   SuccessResponse;
   BlobResponse;
   EnumerationResponse;
--- a/dom/devicestorage/nsDeviceStorage.cpp
+++ b/dom/devicestorage/nsDeviceStorage.cpp
@@ -1,14 +1,15 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/dom/PBrowserChild.h"
+#include "mozilla/dom/ipc/Blob.h"
 #include "mozilla/dom/devicestorage/PDeviceStorageRequestChild.h"
 #include "mozilla/Attributes.h"
 #include "mozilla/dom/PContentPermissionRequestChild.h"
 
 #include "nsDeviceStorage.h"
 
 #include "nsDOMEvent.h"
 #include "nsServiceManagerUtils.h"
@@ -141,27 +142,29 @@ DeviceStorageFile::AppendRelativePath() 
   }
   mFile->AppendRelativePath(temp);
 #else
   mFile->AppendRelativePath(mPath);
 #endif
 }
 
 nsresult
-DeviceStorageFile::Write(nsIDOMBlob* aBlob)
+DeviceStorageFile::Write(nsIInputStream* aInputStream)
 {
+  if (!aInputStream) {
+    return NS_ERROR_FAILURE;
+  }
+
   nsresult rv = mFile->Create(nsIFile::NORMAL_FILE_TYPE, 00600);
   if (NS_FAILED(rv)) {
     return rv;
   }
-  nsCOMPtr<nsIInputStream> stream;
-  aBlob->GetInternalStream(getter_AddRefs(stream));
 
   PRUint32 bufSize;
-  stream->Available(&bufSize);
+  aInputStream->Available(&bufSize);
 
   nsCOMPtr<nsIOutputStream> outputStream;
   NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), mFile);
 
   if (!outputStream) {
     return NS_ERROR_FAILURE;
   }
 
@@ -170,17 +173,17 @@ DeviceStorageFile::Write(nsIDOMBlob* aBl
                              outputStream,
                              4096*4);
 
   if (!bufferedOutputStream) {
     return NS_ERROR_FAILURE;
   }
 
   PRUint32 wrote;
-  bufferedOutputStream->WriteFrom(stream, bufSize, &wrote);
+  bufferedOutputStream->WriteFrom(aInputStream, bufSize, &wrote);
   bufferedOutputStream->Close();
   outputStream->Close();
   if (bufSize != wrote) {
     return NS_ERROR_FAILURE;
   }
   return NS_OK;
 }
 
@@ -527,17 +530,16 @@ public:
     else {
       mError.Append(NS_LITERAL_STRING("null path"));
     }
   }
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
     mRequest->FireError(mError);
     mRequest = nullptr;
     return NS_OK;
   }
 
 private:
   nsRefPtr<DOMRequest> mRequest;
   nsString mError;
@@ -555,17 +557,16 @@ ContinueCursorEvent::ContinueCursorEvent
 
 ContinueCursorEvent::~ContinueCursorEvent() {}
 
 NS_IMETHODIMP
 ContinueCursorEvent::Run() {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   jsval val;
-
   nsDOMDeviceStorageCursor* cursor = static_cast<nsDOMDeviceStorageCursor*>(mRequest.get());
   if (cursor->mFiles.Length() == 0) {
     val = JSVAL_NULL;
   }
   else {
     nsRefPtr<DeviceStorageFile> file = cursor->mFiles[0];
     cursor->mFiles.RemoveElementAt(0);
 
@@ -813,17 +814,20 @@ public:
     }
 
   ~WriteFileEvent() {}
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
-    nsresult rv = mFile->Write(mBlob);
+    nsCOMPtr<nsIInputStream> stream;
+    mBlob->GetInternalStream(getter_AddRefs(stream));
+
+    nsresult rv = mFile->Write(stream);
 
     if (NS_FAILED(rv)) {
       mFile->mFile->Remove(false);
 
       nsCOMPtr<PostErrorEvent> event = new PostErrorEvent(mRequest,
                                                           POST_ERROR_EVENT_UNKNOWN,
                                                           mFile);
       NS_DispatchToMainThread(event);
@@ -854,17 +858,16 @@ public:
 
   ~ReadFileEvent() {}
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
     nsRefPtr<nsRunnable> r;
-
     if (!mFile->mEditable) {
       bool check = false;
       mFile->mFile->Exists(&check);
       if (!check) {
         r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST, mFile);
       }
     }
 
@@ -898,17 +901,17 @@ public:
 
     mFile->mFile->Remove(true);
 
     nsRefPtr<nsRunnable> r;
 
     bool check = false;
     mFile->mFile->Exists(&check);
     if (check) {
-      r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_UNKNOWN, mFile);
+      r = new PostErrorEvent(mRequest, POST_ERROR_EVENT_FILE_DOES_NOT_EXIST, mFile);
     }
     else {
       r = new PostResultEvent(mRequest, mFile->mPath);
     }
     NS_DispatchToMainThread(r);
     return NS_OK;
   }
 
@@ -1048,44 +1051,40 @@ public:
     switch(mRequestType) {
       case DEVICE_STORAGE_REQUEST_WRITE:
       {
         if (!mBlob) {
           return NS_ERROR_FAILURE;
         }
 
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
-          PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
 
-          nsCOMPtr<nsIInputStream> stream;
-          mBlob->GetInternalStream(getter_AddRefs(stream));
-
-          InfallibleTArray<PRUint8> bits;
-          PRUint32 bufSize, numRead;
+	  BlobChild* actor = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mBlob);
+	  if (!actor) {
+	    return NS_ERROR_FAILURE;
+	  }
 
-          stream->Available(&bufSize);
-          bits.SetCapacity(bufSize);
+          DeviceStorageAddParams params;
+	  params.blobChild() = actor;
+	  params.name() = mFile->mPath;
+	  params.fullpath() = fullpath;
 
-          void* buffer = (void*) bits.Elements();
-
-          stream->Read((char*)buffer, bufSize, &numRead);
-
-          DeviceStorageAddParams params(fullpath, bits);
+          PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
           ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
         r = new WriteFileEvent(mBlob, mFile, mRequest);
         break;
       }
 
       case DEVICE_STORAGE_REQUEST_READ:
       {
         if (XRE_GetProcessType() != GeckoProcessType_Default) {
           PDeviceStorageRequestChild* child = new DeviceStorageRequestChild(mRequest, mFile);
-          DeviceStorageGetParams params(fullpath);
+          DeviceStorageGetParams params(mFile->mPath, fullpath);
           ContentChild::GetSingleton()->SendPDeviceStorageRequestConstructor(child, params);
           return NS_OK;
         }
 
         r = new ReadFileEvent(mFile, mRequest);
         break;
       }
 
--- a/dom/devicestorage/nsDeviceStorage.h
+++ b/dom/devicestorage/nsDeviceStorage.h
@@ -48,18 +48,18 @@ public:
   void SetPath(const nsAString& aPath);
   void SetEditable(bool aEditable);
 
   NS_DECL_ISUPPORTS
 
   // we want to make sure that the names of file can't reach
   // outside of the type of storage the user asked for.
   bool IsSafePath();
-  
-  nsresult Write(nsIDOMBlob* blob);
+
+  nsresult Write(nsIInputStream* aInputStream);
   nsresult Write(InfallibleTArray<PRUint8>& bits);
   void CollectFiles(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRUint64 aSince = 0);
   void collectFilesInternal(nsTArray<nsRefPtr<DeviceStorageFile> > &aFiles, PRUint64 aSince, nsAString& aRootPath);
 
 private:
   void NormalizeFilePath();
   void AppendRelativePath();
 };
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -957,23 +957,26 @@ ContentParent::DeallocPBrowser(PBrowserP
     TabParent* parent = static_cast<TabParent*>(frame);
     NS_RELEASE(parent);
     return true;
 }
 
 PDeviceStorageRequestParent*
 ContentParent::AllocPDeviceStorageRequest(const DeviceStorageParams& aParams)
 {
-  return new DeviceStorageRequestParent(aParams);
+  DeviceStorageRequestParent* result = new DeviceStorageRequestParent(aParams);
+  NS_ADDREF(result);
+  return result;
 }
 
 bool
 ContentParent::DeallocPDeviceStorageRequest(PDeviceStorageRequestParent* doomed)
 {
-  delete doomed;
+  DeviceStorageRequestParent *parent = static_cast<DeviceStorageRequestParent*>(doomed);
+  NS_RELEASE(parent);
   return true;
 }
 
 PBlobParent*
 ContentParent::AllocPBlob(const BlobConstructorParams& aParams)
 {
   return BlobParent::Create(aParams);
 }
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -68,22 +68,24 @@ struct FontListEntry {
     PRUint16  weight;
     PRInt16   stretch;
     PRUint8   italic;
     PRUint8   index;
 };
 
 struct DeviceStorageAddParams
 {
+  PBlob blob;
+  nsString name;
   nsString fullpath;
-  PRUint8[] bits;
 };
 
 struct DeviceStorageGetParams
 {
+  nsString name;
   nsString fullpath;
 };
 
 struct DeviceStorageDeleteParams
 {
   nsString fullpath;
 };