Commit da0a8f05 authored by Andrea Marchesini's avatar Andrea Marchesini
Browse files

Bug 1421094 - Make nsBufferedStream cloneable, r=smaug

parent 5b3cbf1d
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -293,6 +293,7 @@ NS_INTERFACE_MAP_BEGIN(nsBufferedInputStream)
    NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream, IsIPCSerializable())
    NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream, IsAsyncInputStream())
    NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback, IsAsyncInputStream())
    NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream, IsCloneableInputStream())
    NS_IMPL_QUERY_CLASSINFO(nsBufferedInputStream)
NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)

@@ -641,6 +642,13 @@ nsBufferedInputStream::IsAsyncInputStream() const
    return !!stream;
}

bool
nsBufferedInputStream::IsCloneableInputStream() const
{
    nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mStream);
    return !!stream;
}

NS_IMETHODIMP
nsBufferedInputStream::CloseWithStatus(nsresult aStatus)
{
@@ -695,6 +703,50 @@ nsBufferedInputStream::GetData(nsIInputStream **aResult)
    return NS_OK;
}

// nsICloneableInputStream interface

NS_IMETHODIMP
nsBufferedInputStream::GetCloneable(bool* aCloneable)
{
  *aCloneable = false;

  // If we don't have the buffer, the inputStream has been already closed.
  // If mBufferStartOffset is not 0, the stream has been seeked or read.
  // In both case the cloning is not supported.
  if (!mBuffer || mBufferStartOffset) {
    return NS_OK;
  }

  nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mStream);

  // GetCloneable is infallible.
  NS_ENSURE_TRUE(stream, NS_OK);

  return stream->GetCloneable(aCloneable);
}

NS_IMETHODIMP
nsBufferedInputStream::Clone(nsIInputStream** aResult)
{
  if (!mBuffer || mBufferStartOffset) {
    return NS_ERROR_FAILURE;
  }

  nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mStream);
  NS_ENSURE_TRUE(stream, NS_ERROR_FAILURE);

  nsCOMPtr<nsIInputStream> clonedStream;
  nsresult rv = stream->Clone(getter_AddRefs(clonedStream));
  NS_ENSURE_SUCCESS(rv, rv);

  nsCOMPtr<nsIBufferedInputStream> bis = new nsBufferedInputStream();
  rv = bis->Init(clonedStream, mBufferSize);
  NS_ENSURE_SUCCESS(rv, rv);

  bis.forget(aResult);
  return NS_OK;
}

////////////////////////////////////////////////////////////////////////////////
// nsBufferedOutputStream

+5 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "nsCOMPtr.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsICloneableInputStream.h"

////////////////////////////////////////////////////////////////////////////////

@@ -65,7 +66,8 @@ class nsBufferedInputStream : public nsBufferedStream,
                              public nsIStreamBufferAccess,
                              public nsIIPCSerializableInputStream,
                              public nsIAsyncInputStream,
                              public nsIInputStreamCallback
                              public nsIInputStreamCallback,
                              public nsICloneableInputStream
{
public:
    NS_DECL_ISUPPORTS_INHERITED
@@ -75,6 +77,7 @@ public:
    NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
    NS_DECL_NSIASYNCINPUTSTREAM
    NS_DECL_NSIINPUTSTREAMCALLBACK
    NS_DECL_NSICLONEABLEINPUTSTREAM

    nsBufferedInputStream() : nsBufferedStream() {}

@@ -90,6 +93,7 @@ protected:

    bool IsIPCSerializable() const;
    bool IsAsyncInputStream() const;
    bool IsCloneableInputStream() const;

    NS_IMETHOD Fill() override;
    NS_IMETHOD Flush() override { return NS_OK; } // no-op for input streams
+50 −12
Original line number Diff line number Diff line
@@ -40,6 +40,54 @@ TEST(CloneInputStream, CloneableInput)
  testing::ConsumeAndValidateStream(clone, inputString);
}

class NonCloneableInputStream final : public nsIInputStream
{
public:
  NS_DECL_THREADSAFE_ISUPPORTS

  explicit NonCloneableInputStream(already_AddRefed<nsIInputStream> aInputStream)
    : mStream(aInputStream)
  {}

  NS_IMETHOD
  Available(uint64_t* aLength) override
  {
    return mStream->Available(aLength);
  }

  NS_IMETHOD
  Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount) override
  {
    return mStream->Read(aBuffer, aCount, aReadCount);
  }

  NS_IMETHOD
  ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
               uint32_t aCount, uint32_t *aResult) override
  {
    return mStream->ReadSegments(aWriter, aClosure, aCount, aResult);
  }

  NS_IMETHOD
  Close() override
  {
    return mStream->Close();
  }

  NS_IMETHOD
  IsNonBlocking(bool* aNonBlocking) override
  {
    return mStream->IsNonBlocking(aNonBlocking);
  }

private:
  ~NonCloneableInputStream() = default;

  nsCOMPtr<nsIInputStream> mStream;
};

NS_IMPL_ISUPPORTS(NonCloneableInputStream, nsIInputStream)

TEST(CloneInputStream, NonCloneableInput_NoFallback)
{
  nsTArray<char> inputData;
@@ -50,12 +98,7 @@ TEST(CloneInputStream, NonCloneableInput_NoFallback)
  nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString);
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  // Take advantage of nsBufferedInputStream being non-cloneable right
  // now.  If this changes in the future, then we need a different stream
  // type in this test.
  nsCOMPtr<nsIInputStream> stream;
  rv = NS_NewBufferedInputStream(getter_AddRefs(stream), base.forget(), 4096);
  ASSERT_TRUE(NS_SUCCEEDED(rv));
  nsCOMPtr<nsIInputStream> stream = new NonCloneableInputStream(base.forget());

  nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(stream);
  ASSERT_TRUE(cloneable == nullptr);
@@ -78,12 +121,7 @@ TEST(CloneInputStream, NonCloneableInput_Fallback)
  nsresult rv = NS_NewCStringInputStream(getter_AddRefs(base), inputString);
  ASSERT_TRUE(NS_SUCCEEDED(rv));

  // Take advantage of nsBufferedInputStream being non-cloneable right
  // now.  If this changes in the future, then we need a different stream
  // type in this test.
  nsCOMPtr<nsIInputStream> stream;
  rv = NS_NewBufferedInputStream(getter_AddRefs(stream), base.forget(), 4096);
  ASSERT_TRUE(NS_SUCCEEDED(rv));
  nsCOMPtr<nsIInputStream> stream = new NonCloneableInputStream(base.forget());

  nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(stream);
  ASSERT_TRUE(cloneable == nullptr);