Bug 1339710 - SlicedInputStream should be an nsIIPCSerializableInputStream, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 22 Feb 2017 09:41:05 +0100
changeset 373241 8d14d2a3ec606e2e661a1572c2c0c22a90593ff4
parent 373240 e3b42bc5273c59b8dd1057f518ce32159b665ca1
child 373242 78926e4f66c2187759eeaf5d933c4a5956bd0ce2
push id10863
push userjlorenzo@mozilla.com
push dateMon, 06 Mar 2017 23:02:23 +0000
treeherdermozilla-aurora@0931190cd725 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1339710
milestone54.0a1
Bug 1339710 - SlicedInputStream should be an nsIIPCSerializableInputStream, r=smaug
ipc/glue/InputStreamParams.ipdlh
ipc/glue/InputStreamUtils.cpp
xpcom/io/SlicedInputStream.cpp
xpcom/io/SlicedInputStream.h
--- a/ipc/glue/InputStreamParams.ipdlh
+++ b/ipc/glue/InputStreamParams.ipdlh
@@ -59,27 +59,37 @@ struct RemoteInputStreamParams
 // XXX This may only be used for same-process inter-thread communication! The
 //     value should be reinterpret_cast'd to nsIInputStream. It carries a
 //     reference.
 struct SameProcessInputStreamParams
 {
   intptr_t addRefedInputStream;
 };
 
+struct SlicedInputStreamParams
+{
+  InputStreamParams stream;
+  uint64_t start;
+  uint64_t length;
+  uint64_t curPos;
+  bool closed;
+};
+
 union InputStreamParams
 {
   StringInputStreamParams;
   FileInputStreamParams;
   PartialFileInputStreamParams;
   TemporaryFileInputStreamParams;
   BufferedInputStreamParams;
   MIMEInputStreamParams;
   MultiplexInputStreamParams;
   RemoteInputStreamParams;
   SameProcessInputStreamParams;
+  SlicedInputStreamParams;
 };
 
 union OptionalInputStreamParams
 {
   void_t;
   InputStreamParams;
 };
 
--- a/ipc/glue/InputStreamUtils.cpp
+++ b/ipc/glue/InputStreamUtils.cpp
@@ -17,16 +17,17 @@
 #include "nsID.h"
 #include "nsIXULRuntime.h"
 #include "nsMIMEInputStream.h"
 #include "nsMultiplexInputStream.h"
 #include "nsNetCID.h"
 #include "nsStringStream.h"
 #include "nsTemporaryFileInputStream.h"
 #include "nsXULAppAPI.h"
+#include "SlicedInputStream.h"
 
 using namespace mozilla::dom;
 
 namespace {
 
 NS_DEFINE_CID(kStringInputStreamCID, NS_STRINGINPUTSTREAM_CID);
 NS_DEFINE_CID(kFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID);
 NS_DEFINE_CID(kPartialFileInputStreamCID, NS_PARTIALLOCALFILEINPUTSTREAM_CID);
@@ -143,16 +144,20 @@ DeserializeInputStream(const InputStream
 
       stream = dont_AddRef(
         reinterpret_cast<nsIInputStream*>(params.addRefedInputStream()));
       MOZ_ASSERT(stream);
 
       return stream.forget();
     }
 
+    case InputStreamParams::TSlicedInputStreamParams:
+      serializable = new SlicedInputStream();
+      break;
+
     default:
       MOZ_ASSERT(false, "Unknown params!");
       return nullptr;
   }
 
   MOZ_ASSERT(serializable);
 
   if (!serializable->Deserialize(aParams, aFileDescriptors)) {
--- a/xpcom/io/SlicedInputStream.cpp
+++ b/xpcom/io/SlicedInputStream.cpp
@@ -1,69 +1,96 @@
 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 /* 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 "SlicedInputStream.h"
+#include "mozilla/ipc/InputStreamUtils.h"
 #include "nsISeekableStream.h"
 #include "nsStreamUtils.h"
 
+using namespace mozilla::ipc;
+
 NS_IMPL_ADDREF(SlicedInputStream);
 NS_IMPL_RELEASE(SlicedInputStream);
 
 NS_INTERFACE_MAP_BEGIN(SlicedInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
-                                     mWeakCloneableInputStream)
+                                     mWeakCloneableInputStream || !mInputStream)
+  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
+                                     mWeakIPCSerializableInputStream || !mInputStream)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
 NS_INTERFACE_MAP_END
 
 SlicedInputStream::SlicedInputStream(nsIInputStream* aInputStream,
                                      uint64_t aStart, uint64_t aLength)
   : mWeakCloneableInputStream(nullptr)
+  , mWeakIPCSerializableInputStream(nullptr)
   , mStart(aStart)
   , mLength(aLength)
   , mCurPos(0)
   , mClosed(false)
 {
   MOZ_ASSERT(aInputStream);
   SetSourceStream(aInputStream);
 }
 
+SlicedInputStream::SlicedInputStream()
+  : mWeakCloneableInputStream(nullptr)
+  , mWeakIPCSerializableInputStream(nullptr)
+  , mStart(0)
+  , mLength(0)
+  , mCurPos(0)
+  , mClosed(false)
+{}
+
 SlicedInputStream::~SlicedInputStream()
 {}
 
 void
 SlicedInputStream::SetSourceStream(nsIInputStream* aInputStream)
 {
+  MOZ_ASSERT(!mInputStream);
   MOZ_ASSERT(aInputStream);
 
   mInputStream = aInputStream;
 
   nsCOMPtr<nsICloneableInputStream> cloneableStream =
     do_QueryInterface(aInputStream);
   if (cloneableStream && SameCOMIdentity(aInputStream, cloneableStream)) {
     mWeakCloneableInputStream = cloneableStream;
   }
+
+  nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
+    do_QueryInterface(aInputStream);
+  if (serializableStream &&
+      SameCOMIdentity(aInputStream, serializableStream)) {
+    mWeakIPCSerializableInputStream = serializableStream;
+  }
 }
 
 NS_IMETHODIMP
 SlicedInputStream::Close()
 {
+  NS_ENSURE_STATE(mInputStream);
+
   mClosed = true;
   return NS_OK;
 }
 
 // nsIInputStream interface
 
 NS_IMETHODIMP
 SlicedInputStream::Available(uint64_t* aLength)
 {
+  NS_ENSURE_STATE(mInputStream);
+
   if (mClosed) {
     return NS_BASE_STREAM_CLOSED;
   }
 
   nsresult rv = mInputStream->Available(aLength);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
@@ -86,16 +113,18 @@ SlicedInputStream::Read(char* aBuffer, u
 {
   return ReadSegments(NS_CopySegmentToBuffer, aBuffer, aCount, aReadCount);
 }
 
 NS_IMETHODIMP
 SlicedInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
                                 uint32_t aCount, uint32_t *aResult)
 {
+  NS_ENSURE_STATE(mInputStream);
+
   uint32_t result;
 
   if (!aResult) {
     aResult = &result;
   }
 
   *aResult = 0;
 
@@ -161,33 +190,37 @@ SlicedInputStream::ReadSegments(nsWriteS
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SlicedInputStream::IsNonBlocking(bool* aNonBlocking)
 {
+  NS_ENSURE_STATE(mInputStream);
   return mInputStream->IsNonBlocking(aNonBlocking);
 }
 
 // nsICloneableInputStream interface
 
 NS_IMETHODIMP
 SlicedInputStream::GetCloneable(bool* aCloneable)
 {
-  MOZ_ASSERT(mWeakCloneableInputStream);
+  NS_ENSURE_STATE(mInputStream);
+  NS_ENSURE_STATE(mWeakCloneableInputStream);
+
   *aCloneable = true;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 SlicedInputStream::Clone(nsIInputStream** aResult)
 {
-  MOZ_ASSERT(mWeakCloneableInputStream);
+  NS_ENSURE_STATE(mInputStream);
+  NS_ENSURE_STATE(mWeakCloneableInputStream);
 
   nsCOMPtr<nsIInputStream> clonedStream;
   nsresult rv = mWeakCloneableInputStream->Clone(getter_AddRefs(clonedStream));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return rv;
   }
 
   nsCOMPtr<nsIInputStream> sis =
@@ -197,32 +230,98 @@ SlicedInputStream::Clone(nsIInputStream*
   return NS_OK;
 }
 
 // nsIAsyncInputStream interface
 
 NS_IMETHODIMP
 SlicedInputStream::CloseWithStatus(nsresult aStatus)
 {
+  NS_ENSURE_STATE(mInputStream);
+
   nsCOMPtr<nsIAsyncInputStream> asyncStream =
     do_QueryInterface(mInputStream);
   if (!asyncStream) {
     return NS_ERROR_FAILURE;
   }
 
   return asyncStream->CloseWithStatus(aStatus);
 }
 
 NS_IMETHODIMP
 SlicedInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
                              uint32_t aFlags,
                              uint32_t aRequestedCount,
                              nsIEventTarget* aEventTarget)
 {
+  NS_ENSURE_STATE(mInputStream);
+
   nsCOMPtr<nsIAsyncInputStream> asyncStream =
     do_QueryInterface(mInputStream);
   if (!asyncStream) {
     return NS_ERROR_FAILURE;
   }
 
   return asyncStream->AsyncWait(aCallback, aFlags, aRequestedCount,
                                 aEventTarget);
 }
+
+// nsIIPCSerializableInputStream
+
+void
+SlicedInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
+                             FileDescriptorArray& aFileDescriptors)
+{
+  MOZ_ASSERT(mInputStream);
+  MOZ_ASSERT(mWeakIPCSerializableInputStream);
+
+  SlicedInputStreamParams params;
+  SerializeInputStream(mInputStream, params.stream(), aFileDescriptors);
+  params.start() = mStart;
+  params.length() = mLength;
+  params.curPos() = mCurPos;
+  params.closed() = mClosed;
+
+  aParams = params;
+}
+
+bool
+SlicedInputStream::Deserialize(const mozilla::ipc::InputStreamParams& aParams,
+                               const FileDescriptorArray& aFileDescriptors)
+{
+  MOZ_ASSERT(!mInputStream);
+  MOZ_ASSERT(!mWeakIPCSerializableInputStream);
+
+  if (aParams.type() !=
+      InputStreamParams::TSlicedInputStreamParams) {
+    NS_ERROR("Received unknown parameters from the other process!");
+    return false;
+  }
+
+  const SlicedInputStreamParams& params =
+    aParams.get_SlicedInputStreamParams();
+
+  nsCOMPtr<nsIInputStream> stream =
+    DeserializeInputStream(params.stream(), aFileDescriptors);
+  if (!stream) {
+    NS_WARNING("Deserialize failed!");
+    return false;
+  }
+
+  SetSourceStream(stream);
+
+  mStart = params.start();
+  mLength = params.length();
+  mCurPos = params.curPos();
+  mClosed = params.closed();
+
+  return true;
+}
+
+mozilla::Maybe<uint64_t>
+SlicedInputStream::ExpectedSerializedLength()
+{
+  if (!mInputStream || !mWeakIPCSerializableInputStream) {
+    return mozilla::Nothing();
+  }
+
+  return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
+}
--- a/xpcom/io/SlicedInputStream.h
+++ b/xpcom/io/SlicedInputStream.h
@@ -5,52 +5,59 @@
 
 #ifndef SlicedInputStream_h
 #define SlicedInputStream_h
 
 #include "mozilla/Attributes.h"
 #include "nsCOMPtr.h"
 #include "nsIAsyncInputStream.h"
 #include "nsICloneableInputStream.h"
+#include "nsIIPCSerializableInputStream.h"
 
 // A wrapper for a slice of an underlying input stream.
 
 class SlicedInputStream final : public nsIAsyncInputStream
                               , public nsICloneableInputStream
+                              , public nsIIPCSerializableInputStream
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIINPUTSTREAM
+  NS_DECL_NSIASYNCINPUTSTREAM
   NS_DECL_NSICLONEABLEINPUTSTREAM
-  NS_DECL_NSIASYNCINPUTSTREAM
+  NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
 
   // Create an input stream whose data comes from a slice of aInputStream.  The
   // slice begins at aStart bytes beyond aInputStream's current position, and
   // extends for a maximum of aLength bytes.  If aInputStream contains fewer
   // than aStart bytes, reading from SlicedInputStream returns no data.  If
   // aInputStream contains more than aStart bytes, but fewer than aStart +
   // aLength bytes, reading from SlicedInputStream returns as many bytes as can
   // be consumed from aInputStream after reading aLength bytes.
   //
   // aInputStream should not be read from after constructing a
   // SlicedInputStream wrapper around it.
 
   SlicedInputStream(nsIInputStream* aInputStream,
                     uint64_t aStart, uint64_t aLength);
 
+  // This CTOR is meant to be used just for IPC.
+  SlicedInputStream();
+
 private:
   ~SlicedInputStream();
 
   void
   SetSourceStream(nsIInputStream* aInputStream);
 
   nsCOMPtr<nsIInputStream> mInputStream;
 
-  // Raw pointer because this is just QI of mInputStream.
+  // Raw pointers because these are just QI of mInputStream.
   nsICloneableInputStream* mWeakCloneableInputStream;
+  nsIIPCSerializableInputStream* mWeakIPCSerializableInputStream;
 
   uint64_t mStart;
   uint64_t mLength;
   uint64_t mCurPos;
 
   bool mClosed;
 };