зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
5205b46013
Коммит
ea360db963
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче