Bug 783878 - Part 2: Allow serializing remote input streams by passing the actor reference over the wire and retrieving the original stream in the parent. r=bent
authorJosh Matthews <josh@joshmatthews.net>
Fri, 21 Sep 2012 13:26:13 -0400
changeset 107798 3c77dfc193d2436e40f9dbe40558b72aa40eda31
parent 107797 e1f3deefa340ec7916607db71979d6478253f61b
child 107799 935b18138954228f73d94e7e393b3cc135616bb4
push id23509
push userryanvm@gmail.com
push dateSat, 22 Sep 2012 12:28:38 +0000
treeherdermozilla-central@b461a7cd250e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs783878
milestone18.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 783878 - Part 2: Allow serializing remote input streams by passing the actor reference over the wire and retrieving the original stream in the parent. r=bent
dom/ipc/Blob.cpp
ipc/glue/InputStreamParams.ipdlh
ipc/glue/InputStreamUtils.cpp
netwerk/protocol/ftp/PFTPChannel.ipdl
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/websocket/PWebSocket.ipdl
--- a/dom/ipc/Blob.cpp
+++ b/dom/ipc/Blob.cpp
@@ -26,34 +26,61 @@
 
 using namespace mozilla::dom;
 using namespace mozilla::dom::ipc;
 using namespace mozilla::ipc;
 
 namespace {
 
 class RemoteInputStream : public nsIInputStream,
-                          public nsISeekableStream
+                          public nsISeekableStream,
+                          public nsIIPCSerializableInputStream
 {
   mozilla::Monitor mMonitor;
   nsCOMPtr<nsIDOMBlob> mSourceBlob;
   nsCOMPtr<nsIInputStream> mStream;
   nsCOMPtr<nsISeekableStream> mSeekableStream;
+  ActorFlavorEnum mOrigin;
 
 public:
   NS_DECL_ISUPPORTS
 
-  RemoteInputStream(nsIDOMBlob* aSourceBlob)
-  : mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob)
+  RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorFlavorEnum aOrigin)
+  : mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob),
+    mOrigin(aOrigin)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aSourceBlob);
   }
 
   void
+  Serialize(InputStreamParams& aParams)
+  {
+    nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mSourceBlob);
+    MOZ_ASSERT(remote);
+
+    if (mOrigin == Parent) {
+      aParams = RemoteInputStreamParams(
+        static_cast<PBlobParent*>(remote->GetPBlob()), nullptr);
+    } else {
+      aParams = RemoteInputStreamParams(
+        nullptr, static_cast<PBlobChild*>(remote->GetPBlob()));
+    }
+  }
+
+  bool
+  Deserialize(const InputStreamParams& aParams)
+  {
+    // See InputStreamUtils.cpp to see how deserialization of a
+    // RemoteInputStream is special-cased.
+    MOZ_NOT_REACHED("RemoteInputStream should never be deserialized");
+    return false;
+  }
+
+  void
   SetStream(nsIInputStream* aStream)
   {
     MOZ_ASSERT(NS_IsMainThread());
     MOZ_ASSERT(aStream);
 
     nsCOMPtr<nsIInputStream> stream = aStream;
     nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
 
@@ -229,16 +256,17 @@ private:
   }
 };
 
 NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream)
 NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream)
 
 NS_INTERFACE_MAP_BEGIN(RemoteInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
+  NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
 NS_INTERFACE_MAP_END
 
 template <ActorFlavorEnum ActorFlavor>
 class InputStreamActor : public BlobTraits<ActorFlavor>::StreamType
 {
   nsRefPtr<RemoteInputStream> mRemoteStream;
@@ -416,17 +444,18 @@ private:
     void
     RunInternal(bool aNotify)
     {
       MOZ_ASSERT(NS_IsMainThread());
       MOZ_ASSERT(mActor);
       MOZ_ASSERT(!mInputStream);
       MOZ_ASSERT(!mDone);
 
-      nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mSourceBlob);
+      nsRefPtr<RemoteInputStream> stream = new RemoteInputStream(mSourceBlob,
+                                                                 ActorFlavor);
 
       StreamActorType* streamActor = new StreamActorType(stream);
       if (mActor->SendPBlobStreamConstructor(streamActor)) {
         stream.swap(mInputStream);
       }
 
       mActor = nullptr;
 
--- a/ipc/glue/InputStreamParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -1,15 +1,16 @@
 /* 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 "ipc/IPCMessageUtils.h";
 
 using mozilla::void_t;
+include protocol PBlob;
 
 namespace mozilla {
 namespace ipc {
 
 struct StringInputStreamParams
 {
   nsCString data;
 };
@@ -31,24 +32,30 @@ struct PartialFileInputStreamParams
 struct MultiplexInputStreamParams
 {
   InputStreamParams[] streams;
   uint32_t currentStream;
   nsresult status;
   bool startedReadingCurrent;
 };
 
+struct RemoteInputStreamParams
+{
+  PBlob remoteBlob;
+};
+
 union InputStreamParams
 {
   StringInputStreamParams;
   FileInputStreamParams;
   PartialFileInputStreamParams;
   BufferedInputStreamParams;
   MIMEInputStreamParams;
   MultiplexInputStreamParams;
+  RemoteInputStreamParams;
 };
 
 union OptionalInputStreamParams
 {
   void_t;
   InputStreamParams;
 };
 
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -2,26 +2,32 @@
  * 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 "InputStreamUtils.h"
 
 #include "nsIIPCSerializableInputStream.h"
 
 #include "mozilla/Assertions.h"
+#include "mozilla/dom/ipc/Blob.h"
 #include "nsComponentManagerUtils.h"
 #include "nsDebug.h"
 #include "nsID.h"
+#include "nsIDOMFile.h"
+#include "nsIXULRuntime.h"
 #include "nsMIMEInputStream.h"
 #include "nsMultiplexInputStream.h"
 #include "nsNetCID.h"
 #include "nsStringStream.h"
 #include "nsThreadUtils.h"
+#include "nsXULAppAPI.h"
 
 using namespace mozilla::ipc;
+using mozilla::dom::BlobChild;
+using mozilla::dom::BlobParent;
 
 namespace {
 
 NS_DEFINE_CID(kStringInputStreamCID, NS_STRINGINPUTSTREAM_CID);
 NS_DEFINE_CID(kFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID);
 NS_DEFINE_CID(kPartialFileInputStreamCID, NS_PARTIALLOCALFILEINPUTSTREAM_CID);
 NS_DEFINE_CID(kBufferedInputStreamCID, NS_BUFFEREDINPUTSTREAM_CID);
 NS_DEFINE_CID(kMIMEInputStreamCID, NS_MIMEINPUTSTREAM_CID);
@@ -95,16 +101,39 @@ DeserializeInputStream(const InputStream
     case InputStreamParams::TMIMEInputStreamParams:
       serializable = do_CreateInstance(kMIMEInputStreamCID);
       break;
 
     case InputStreamParams::TMultiplexInputStreamParams:
       serializable = do_CreateInstance(kMultiplexInputStreamCID);
       break;
 
+    // When the input stream already exists in this process, all we need to do
+    // is retrieve the original instead of sending any data over the wire.
+    case InputStreamParams::TRemoteInputStreamParams: {
+      nsCOMPtr<nsIDOMBlob> domBlob;
+      const RemoteInputStreamParams& params =
+          aParams.get_RemoteInputStreamParams();
+
+      domBlob = params.remoteBlobParent() ?
+          static_cast<BlobParent*>(params.remoteBlobParent())->GetBlob() :
+          static_cast<BlobChild*>(params.remoteBlobChild())->GetBlob();
+
+      MOZ_ASSERT(domBlob, "Invalid blob contents");
+
+      // If fetching the internal stream fails, we ignore it and return a
+      // null stream.
+      nsCOMPtr<nsIInputStream> stream;
+      nsresult rv = domBlob->GetInternalStream(getter_AddRefs(stream));
+      if (NS_FAILED(rv) || !stream) {
+        NS_WARNING("Couldn't obtain a valid stream from the blob");
+      }
+      return stream.forget();
+    }
+
     default:
       MOZ_ASSERT(false, "Unknown params!");
       return nullptr;
   }
 
   MOZ_ASSERT(serializable);
 
   if (!serializable->Deserialize(aParams)) {
--- a/netwerk/protocol/ftp/PFTPChannel.ipdl
+++ b/netwerk/protocol/ftp/PFTPChannel.ipdl
@@ -4,16 +4,18 @@
 /* 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 PNecko;
 include InputStreamParams;
 include URIParams;
 
+include protocol PBlob; //FIXME: bug #792908
+
 include "SerializedLoadContext.h";
 
 using IPC::SerializedLoadContext;
 using PRTime;
 
 namespace mozilla {
 namespace net {
 
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -4,16 +4,18 @@
 /* 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 PNecko;
 include InputStreamParams;
 include URIParams;
 
+include protocol PBlob; //FIXME: bug #792908
+
 include "mozilla/net/PHttpChannelParams.h";
 include "mozilla/net/NeckoMessageUtils.h";
 include "prio.h";
 include "SerializedLoadContext.h";
 
 using RequestHeaderTuples;
 using nsHttpHeaderArray;
 using nsHttpResponseHead;
--- a/netwerk/protocol/websocket/PWebSocket.ipdl
+++ b/netwerk/protocol/websocket/PWebSocket.ipdl
@@ -5,16 +5,18 @@
  * 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 PNecko;
 include protocol PBrowser;
 include InputStreamParams;
 include URIParams;
 
+include protocol PBlob; //FIXME: bug #792908
+
 include "SerializedLoadContext.h";
 using IPC::SerializedLoadContext;
 
 namespace mozilla {
 namespace net {
 
 async protocol PWebSocket
 {