Bug 1339710 - SlicedInputStream should be an nsIIPCSerializableInputStream, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 22 Feb 2017 09:41:05 +0100
changeset 344214 8d14d2a3ec606e2e661a1572c2c0c22a90593ff4
parent 344213 e3b42bc5273c59b8dd1057f518ce32159b665ca1
child 344215 78926e4f66c2187759eeaf5d933c4a5956bd0ce2
push id31402
push usercbook@mozilla.com
push dateWed, 22 Feb 2017 13:33:50 +0000
treeherdermozilla-central@f5372cb6c3c7 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1339710
milestone54.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 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;
 };