Bug 1634436 - Make DecryptingInputStream implement nsICloneableInputStream. r=dom-workers-and-storage-reviewers,janv

Differential Revision: https://phabricator.services.mozilla.com/D75815
This commit is contained in:
Simon Giesecke 2020-06-17 15:04:29 +00:00
Родитель 5205b46013
Коммит ea360db963
4 изменённых файлов: 132 добавлений и 21 удалений

Просмотреть файл

@ -15,6 +15,8 @@ NS_IMPL_RELEASE(DecryptingInputStreamBase);
NS_INTERFACE_MAP_BEGIN(DecryptingInputStreamBase)
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
mBaseCloneableInputStream || !mBaseStream)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END
@ -26,6 +28,13 @@ DecryptingInputStreamBase::DecryptingInputStreamBase(
MOZ_ASSERT(seekableStream &&
SameCOMIdentity(mBaseStream->get(), seekableStream));
mBaseSeekableStream.init(WrapNotNullUnchecked(seekableStream));
const nsCOMPtr<nsICloneableInputStream> cloneableInputStream =
do_QueryInterface(mBaseStream->get());
if (cloneableInputStream &&
SameCOMIdentity(mBaseStream->get(), cloneableInputStream)) {
mBaseCloneableInputStream.init(WrapNotNullUnchecked(cloneableInputStream));
}
}
NS_IMETHODIMP DecryptingInputStreamBase::Read(char* aBuf, uint32_t aCount,
@ -44,6 +53,11 @@ NS_IMETHODIMP DecryptingInputStreamBase::SetEOF() {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP DecryptingInputStreamBase::GetCloneable(bool* aCloneable) {
*aCloneable = true;
return NS_OK;
}
size_t DecryptingInputStreamBase::PlainLength() const {
MOZ_ASSERT(mNextByte <= mPlainBytes);
return mPlainBytes - mNextByte;

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/InitializedOnce.h"
#include "nsCOMPtr.h"
#include "nsICloneableInputStream.h"
#include "nsIInputStream.h"
#include "nsISeekableStream.h"
@ -17,7 +18,8 @@
namespace mozilla::dom::quota {
class DecryptingInputStreamBase : public nsIInputStream,
public nsISeekableStream {
public nsISeekableStream,
public nsICloneableInputStream {
public:
NS_DECL_THREADSAFE_ISUPPORTS
@ -26,6 +28,9 @@ class DecryptingInputStreamBase : public nsIInputStream,
NS_IMETHOD SetEOF() final;
using nsICloneableInputStream::GetCloneable;
NS_IMETHOD GetCloneable(bool* aCloneable) final;
protected:
DecryptingInputStreamBase(MovingNotNull<nsCOMPtr<nsIInputStream>> aBaseStream,
size_t aBlockSize);
@ -40,6 +45,8 @@ class DecryptingInputStreamBase : public nsIInputStream,
InitializedOnce<const NotNull<nsCOMPtr<nsIInputStream>>> mBaseStream;
LazyInitializedOnce<const NotNull<nsISeekableStream*>> mBaseSeekableStream;
LazyInitializedOnce<const NotNull<nsICloneableInputStream*>>
mBaseCloneableInputStream;
// Number of bytes of plain data in mBuffer.
size_t mPlainBytes = 0;
@ -74,6 +81,8 @@ class DecryptingInputStream final : public DecryptingInputStreamBase {
NS_IMETHOD Seek(int32_t aWhence, int64_t aOffset) override;
NS_IMETHOD Clone(nsIInputStream** _retval) override;
private:
~DecryptingInputStream();

Просмотреть файл

@ -418,6 +418,32 @@ NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Seek(const int32_t aWhence,
return NS_OK;
}
template <typename CipherStrategy>
NS_IMETHODIMP DecryptingInputStream<CipherStrategy>::Clone(
nsIInputStream** _retval) {
if (!mBaseStream) {
return NS_BASE_STREAM_CLOSED;
}
if (!(*mBaseCloneableInputStream)->GetCloneable()) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIInputStream> clonedStream;
nsresult rv =
(*mBaseCloneableInputStream)->Clone(getter_AddRefs(clonedStream));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
*_retval =
MakeAndAddRef<DecryptingInputStream>(WrapNotNull(std::move(clonedStream)),
mBlockSize, mCipherStrategy, mKey)
.take();
return NS_OK;
}
} // namespace mozilla::dom::quota
#endif

Просмотреть файл

@ -24,7 +24,9 @@ namespace mozilla::dom::quota {
// Similar to ArrayBufferInputStream from netwerk/base/ArrayBufferInputStream.h,
// but this is initialized from a Span on construction, rather than lazily from
// a JS ArrayBuffer.
class ArrayBufferInputStream : public nsIInputStream, public nsISeekableStream {
class ArrayBufferInputStream : public nsIInputStream,
public nsISeekableStream,
public nsICloneableInputStream {
public:
explicit ArrayBufferInputStream(mozilla::Span<const uint8_t> aData);
@ -32,6 +34,7 @@ class ArrayBufferInputStream : public nsIInputStream, public nsISeekableStream {
NS_DECL_NSIINPUTSTREAM
NS_DECL_NSITELLABLESTREAM
NS_DECL_NSISEEKABLESTREAM
NS_DECL_NSICLONEABLEINPUTSTREAM
private:
virtual ~ArrayBufferInputStream() = default;
@ -48,6 +51,7 @@ NS_IMPL_RELEASE(ArrayBufferInputStream);
NS_INTERFACE_MAP_BEGIN(ArrayBufferInputStream)
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
NS_INTERFACE_MAP_END
@ -177,6 +181,18 @@ NS_IMETHODIMP ArrayBufferInputStream::SetEOF() {
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP ArrayBufferInputStream::GetCloneable(bool* aCloneable) {
*aCloneable = true;
return NS_OK;
}
NS_IMETHODIMP ArrayBufferInputStream::Clone(nsIInputStream** _retval) {
*_retval = MakeAndAddRef<ArrayBufferInputStream>(
AsBytes(Span{mArrayBuffer.get(), mBufferLength}))
.take();
return NS_OK;
}
} // namespace mozilla::dom::quota
using namespace mozilla;
@ -300,16 +316,17 @@ static void WriteTestData(nsCOMPtr<nsIOutputStream>&& aBaseOutputStream,
EXPECT_EQ(NS_OK, outStream->Close());
}
template <typename CipherStrategy, typename ExtraChecks>
static void ReadTestData(
MovingNotNull<nsCOMPtr<nsIInputStream>>&& aBaseInputStream,
const Span<const uint8_t> aExpectedData, const size_t aReadChunkSize,
const size_t aBlockSize, const CipherStrategy& aCipherStrategy,
const typename CipherStrategy::KeyType& aKey,
const ExtraChecks& aExtraChecks) {
auto inStream = MakeSafeRefPtr<DecryptingInputStream<CipherStrategy>>(
std::move(aBaseInputStream), aBlockSize, aCipherStrategy, aKey);
template <typename CipherStrategy>
static void NoExtraChecks(DecryptingInputStream<CipherStrategy>& aInputStream,
Span<const uint8_t> aExpectedData,
Span<const uint8_t> aRemainder) {}
template <typename CipherStrategy,
typename ExtraChecks = decltype(NoExtraChecks<CipherStrategy>)>
static void ReadTestData(
DecryptingInputStream<CipherStrategy>& aDecryptingInputStream,
const Span<const uint8_t> aExpectedData, const size_t aReadChunkSize,
const ExtraChecks& aExtraChecks = NoExtraChecks<CipherStrategy>) {
auto readData = nsTArray<uint8_t>();
readData.SetLength(aReadChunkSize);
for (auto remainder = aExpectedData; !remainder.IsEmpty();) {
@ -318,27 +335,39 @@ static void ReadTestData(
remainder = newExpectedRemainder;
uint32_t read;
EXPECT_EQ(NS_OK,
inStream->Read(reinterpret_cast<char*>(readData.Elements()),
currentExpected.Length(), &read));
EXPECT_EQ(NS_OK, aDecryptingInputStream.Read(
reinterpret_cast<char*>(readData.Elements()),
currentExpected.Length(), &read));
EXPECT_EQ(currentExpected.Length(), read);
EXPECT_EQ(currentExpected,
Span{readData}.First(currentExpected.Length()).AsConst());
aExtraChecks(*inStream, aExpectedData, remainder);
aExtraChecks(aDecryptingInputStream, aExpectedData, remainder);
}
// Expect EOF.
uint32_t read;
EXPECT_EQ(NS_OK, inStream->Read(reinterpret_cast<char*>(readData.Elements()),
readData.Length(), &read));
EXPECT_EQ(NS_OK, aDecryptingInputStream.Read(
reinterpret_cast<char*>(readData.Elements()),
readData.Length(), &read));
EXPECT_EQ(0u, read);
}
template <typename CipherStrategy>
static void NoExtraChecks(DecryptingInputStream<CipherStrategy>& aInputStream,
Span<const uint8_t> aExpectedData,
Span<const uint8_t> aRemainder) {}
template <typename CipherStrategy,
typename ExtraChecks = decltype(NoExtraChecks<CipherStrategy>)>
static auto ReadTestData(
MovingNotNull<nsCOMPtr<nsIInputStream>>&& aBaseInputStream,
const Span<const uint8_t> aExpectedData, const size_t aReadChunkSize,
const size_t aBlockSize, const CipherStrategy& aCipherStrategy,
const typename CipherStrategy::KeyType& aKey,
const ExtraChecks& aExtraChecks = NoExtraChecks<CipherStrategy>) {
auto inStream = MakeSafeRefPtr<DecryptingInputStream<CipherStrategy>>(
std::move(aBaseInputStream), aBlockSize, aCipherStrategy, aKey);
ReadTestData(*inStream, aExpectedData, aReadChunkSize, aExtraChecks);
return inStream;
}
// XXX Change to return the buffer instead.
template <typename CipherStrategy,
@ -457,6 +486,39 @@ TEST_P(ParametrizedCryptTest, DummyCipherStrategy_Available) {
});
}
TEST_P(ParametrizedCryptTest, DummyCipherStrategy_Clone) {
using CipherStrategy = DummyCipherStrategy;
const CipherStrategy cipherStrategy;
const TestParams& testParams = GetParam();
// XXX Add deduction guide for RefPtr from already_AddRefed
const auto baseOutputStream =
WrapNotNull(RefPtr<dom::quota::MemoryOutputStream>{
dom::quota::MemoryOutputStream::Create(2048)});
const auto data = MakeTestData(testParams.DataSize());
WriteTestData(nsCOMPtr<nsIOutputStream>{baseOutputStream.get()}, Span{data},
testParams.EffectiveWriteChunkSize(), testParams.BlockSize(),
cipherStrategy, CipherStrategy::KeyType{},
testParams.FlushMode());
const auto baseInputStream =
MakeRefPtr<ArrayBufferInputStream>(baseOutputStream->Data());
const auto inStream = ReadTestData(
WrapNotNull(nsCOMPtr<nsIInputStream>{baseInputStream}), Span{data},
testParams.EffectiveReadChunkSize(), testParams.BlockSize(),
cipherStrategy, CipherStrategy::KeyType{});
nsCOMPtr<nsIInputStream> clonedInputStream;
EXPECT_EQ(NS_OK, inStream->Clone(getter_AddRefs(clonedInputStream)));
ReadTestData(
static_cast<DecryptingInputStream<CipherStrategy>&>(*clonedInputStream),
Span{data}, testParams.EffectiveReadChunkSize());
}
// XXX This test is actually only parametrized on the block size.
TEST_P(ParametrizedCryptTest, DummyCipherStrategy_IncompleteBlock) {
using CipherStrategy = DummyCipherStrategy;