Backed out 11 changesets (bug 1681529) for mochitest failures at test_reload_large_postdata.html. CLOSED TREE

Backed out changeset f1f988155c82 (bug 1681529)
Backed out changeset f0ba367de05e (bug 1681529)
Backed out changeset dbea9952ec79 (bug 1681529)
Backed out changeset 6e185ec2c4a4 (bug 1681529)
Backed out changeset d0b11c08666a (bug 1681529)
Backed out changeset f2515096b378 (bug 1681529)
Backed out changeset ecd8c3b8fdb4 (bug 1681529)
Backed out changeset 7ea2e9cc8bad (bug 1681529)
Backed out changeset dbc85d0bffaf (bug 1681529)
Backed out changeset f0893f544219 (bug 1681529)
Backed out changeset 91979e21aa8e (bug 1681529)
This commit is contained in:
Brindusan Cristian 2021-02-02 22:02:59 +02:00
Родитель 83c6b7fa71
Коммит cbdb020883
20 изменённых файлов: 38 добавлений и 1063 удалений

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

@ -1,46 +0,0 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80 ft=javascript: */
"use strict";
const BinaryInputStream = CC(
"@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream"
);
Cu.importGlobalProperties(["URLSearchParams"]);
function readStream(inputStream) {
let available = 0;
let result = [];
while ((available = inputStream.available()) > 0) {
result.push(inputStream.readBytes(available));
}
return result.join("");
}
function handleRequest(request, response) {
let rv = (() => {
try {
if (request.method != "POST") {
return "ERROR: not a POST request";
}
let body = new URLSearchParams(
readStream(new BinaryInputStream(request.bodyInputStream))
);
return body.get("payload").length;
} catch (e) {
return "ERROR: Exception: " + e;
}
})();
response.setHeader("Content-Type", "text/html", false);
response.setHeader("Cache-Control", "no-cache", false);
response.write(`<!DOCTYPE HTML>
<script>
let rv = (${JSON.stringify(rv)});
opener.postMessage(rv, "*");
</script>
`);
}

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

@ -119,6 +119,3 @@ skip-if = true # This was disabled for a few years now anyway, bug 1677544
[test_triggeringprincipal_iframe_iframe_window_open.html]
[test_contentpolicy_block_window.html]
[test_rate_limit_location_change.html]
[test_reload_large_postdata.html]
support-files =
file_reload_large_postdata.sjs

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

@ -1,61 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<form id="form" action="file_reload_large_postdata.sjs" target="_blank" rel="opener" method="POST">
<input id="input" name="payload" type="hidden" value=""/>
</form>
<pre id="test">
<script>
// This is derived from `kTooLargeStream` in `IPCStreamUtils.cpp`.
const kTooLargeStream = 1024 * 1024;
function waitForPopup(expected) {
return new Promise(resolve => {
addEventListener("message", evt => {
info("got message!");
is(evt.source.opener, window, "the event source's opener should be this window");
is(evt.data, expected, "got the expected data from the popup");
resolve(evt.source);
}, { once: true });
});
}
add_task(async function() {
await SpecialPowers.pushPrefEnv({"set": [["dom.confirm_repost.testing.always_accept", true]]});
let form = document.getElementById("form");
let input = document.getElementById("input");
// Create a very large value to include in the post payload. This should
// ensure that the value isn't sent directly over IPC, and is instead sent as
// an async inputstream.
let payloadSize = kTooLargeStream;
let popupReady = waitForPopup(payloadSize);
input.value = "A".repeat(payloadSize);
form.submit();
let popup = await popupReady;
try {
let popupReady2 = waitForPopup(payloadSize);
info("reloading popup");
popup.location.reload();
let popup2 = await popupReady2;
is(popup, popup2);
} finally {
popup.close();
}
});
// The .sjs server can time out processing the 1mb payload in debug builds.
requestLongerTimeout(2);
</script>
</pre>
</body>
</html>

5
dom/cache/CacheStreamControlChild.cpp поставляемый
Просмотреть файл

@ -108,9 +108,8 @@ void CacheStreamControlChild::OpenStream(const nsID& aId,
SendOpenStream(aId)->Then(
GetCurrentSerialEventTarget(), __func__,
[aResolver,
holder = holder.clonePtr()](const Maybe<IPCStream>& aOptionalStream) {
nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aOptionalStream);
aResolver(std::move(stream));
holder = holder.clonePtr()](RefPtr<nsIInputStream>&& aOptionalStream) {
aResolver(nsCOMPtr<nsIInputStream>(std::move(aOptionalStream)));
},
[aResolver, holder = holder.clonePtr()](ResponseRejectReason&& aReason) {
aResolver(nullptr);

10
dom/cache/CacheStreamControlParent.cpp поставляемый
Просмотреть файл

@ -109,14 +109,8 @@ mozilla::ipc::IPCResult CacheStreamControlParent::RecvOpenStream(
const nsID& aStreamId, OpenStreamResolver&& aResolver) {
NS_ASSERT_OWNINGTHREAD(CacheStreamControlParent);
OpenStream(aStreamId, [aResolver, self = RefPtr{this}](
nsCOMPtr<nsIInputStream>&& aStream) {
AutoIPCStream autoStream;
if (self->CanSend() && autoStream.Serialize(aStream, self->Manager())) {
aResolver(autoStream.TakeOptionalValue());
} else {
aResolver(Nothing());
}
OpenStream(aStreamId, [aResolver](nsCOMPtr<nsIInputStream>&& aStream) {
aResolver(aStream);
});
return IPC_OK();

4
dom/cache/PCacheStreamControl.ipdl поставляемый
Просмотреть файл

@ -6,9 +6,9 @@ include protocol PBackground;
include protocol PFileDescriptorSet;
include protocol PChildToParentStream;
include protocol PParentToChildStream;
include IPCStream;
using struct nsID from "nsID.h";
using refcounted class nsIInputStream from "mozilla/ipc/IPCStreamUtils.h";
namespace mozilla {
namespace dom {
@ -19,7 +19,7 @@ refcounted protocol PCacheStreamControl
manager PBackground;
parent:
async OpenStream(nsID aStreamId) returns(IPCStream? aStream);
async OpenStream(nsID aStreamId) returns(nsIInputStream aStream);
async NoteClosed(nsID aStreamId);
child:

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

@ -15,9 +15,9 @@ namespace mozilla {
template <typename M>
/* static */
already_AddRefed<RemoteLazyInputStreamParent>
RemoteLazyInputStreamParent::CreateCommon(nsIInputStream* aInputStream,
uint64_t aSize, uint64_t aChildID,
nsresult* aRv, M* aManager) {
RemoteLazyInputStreamParent::Create(nsIInputStream* aInputStream,
uint64_t aSize, uint64_t aChildID,
nsresult* aRv, M* aManager) {
MOZ_ASSERT(aInputStream);
MOZ_ASSERT(aRv);
@ -59,14 +59,10 @@ RemoteLazyInputStreamParent::Create(const nsID& aID, uint64_t aSize,
return nullptr;
}
/* static */
already_AddRefed<RemoteLazyInputStreamParent>
RemoteLazyInputStreamParent::Create(nsIInputStream* aInputStream,
uint64_t aSize, uint64_t aChildID,
nsresult* aRv,
mozilla::ipc::PBackgroundParent* aManager) {
return CreateCommon(aInputStream, aSize, aChildID, aRv, aManager);
}
template already_AddRefed<RemoteLazyInputStreamParent>
RemoteLazyInputStreamParent::Create<mozilla::ipc::PBackgroundParent>(
nsIInputStream*, uint64_t, uint64_t, nsresult*,
mozilla::ipc::PBackgroundParent*);
/* static */
already_AddRefed<RemoteLazyInputStreamParent>
@ -85,27 +81,16 @@ RemoteLazyInputStreamParent::Create(const nsID& aID, uint64_t aSize,
return nullptr;
}
/* static */
already_AddRefed<RemoteLazyInputStreamParent>
RemoteLazyInputStreamParent::Create(
nsIInputStream* aInputStream, uint64_t aSize, uint64_t aChildID,
nsresult* aRv, mozilla::net::SocketProcessParent* aManager) {
return CreateCommon(aInputStream, aSize, aChildID, aRv, aManager);
}
template already_AddRefed<RemoteLazyInputStreamParent>
RemoteLazyInputStreamParent::CreateCommon<mozilla::net::SocketProcessParent>(
RemoteLazyInputStreamParent::Create<mozilla::net::SocketProcessParent>(
nsIInputStream*, uint64_t, uint64_t, nsresult*,
mozilla::net::SocketProcessParent*);
/* static */
already_AddRefed<RemoteLazyInputStreamParent>
RemoteLazyInputStreamParent::Create(nsIInputStream* aInputStream,
uint64_t aSize, uint64_t aChildID,
nsresult* aRv,
mozilla::dom::ContentParent* aManager) {
return CreateCommon(aInputStream, aSize, aChildID, aRv, aManager);
}
template already_AddRefed<RemoteLazyInputStreamParent>
RemoteLazyInputStreamParent::Create<dom::ContentParent>(nsIInputStream*,
uint64_t, uint64_t,
nsresult*,
dom::ContentParent*);
RemoteLazyInputStreamParent::RemoteLazyInputStreamParent(
const nsID& aID, uint64_t aSize, dom::ContentParent* aManager)

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

@ -38,17 +38,10 @@ class RemoteLazyInputStreamParent final : public PRemoteLazyInputStreamParent {
// The size of the inputStream must be passed as argument in order to avoid
// the use of nsIInputStream::Available() which could open a fileDescriptor in
// case the stream is a nsFileStream.
template <typename M>
static already_AddRefed<RemoteLazyInputStreamParent> Create(
nsIInputStream* aInputStream, uint64_t aSize, uint64_t aChildID,
nsresult* aRv, mozilla::dom::ContentParent* aManager);
static already_AddRefed<RemoteLazyInputStreamParent> Create(
nsIInputStream* aInputStream, uint64_t aSize, uint64_t aChildID,
nsresult* aRv, mozilla::ipc::PBackgroundParent* aManager);
static already_AddRefed<RemoteLazyInputStreamParent> Create(
nsIInputStream* aInputStream, uint64_t aSize, uint64_t aChildID,
nsresult* aRv, mozilla::net::SocketProcessParent* aManager);
nsresult* aRv, M* aManager);
static already_AddRefed<RemoteLazyInputStreamParent> Create(
const nsID& aID, uint64_t aSize,
@ -77,11 +70,6 @@ class RemoteLazyInputStreamParent final : public PRemoteLazyInputStreamParent {
bool HasValidStream() const;
private:
template <typename M>
static already_AddRefed<RemoteLazyInputStreamParent> CreateCommon(
nsIInputStream* aInputStream, uint64_t aSize, uint64_t aChildID,
nsresult* aRv, M* aManager);
RemoteLazyInputStreamParent(const nsID& aID, uint64_t aSize,
mozilla::dom::ContentParent* aManager);

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

@ -330,30 +330,26 @@ void IPCStreamDestination::SetLength(int64_t aLength) {
mLengthSet = true;
#endif
mLength = aLength;
if (aLength != -1) {
nsCOMPtr<nsIInputStream> finalStream;
finalStream = new InputStreamLengthWrapper(mReader.forget(), aLength);
mReader = do_QueryInterface(finalStream);
MOZ_ASSERT(mReader);
}
}
already_AddRefed<nsIInputStream> IPCStreamDestination::TakeReader() {
MOZ_ASSERT(mReader);
MOZ_ASSERT(!mDelayedStartInputStream);
nsCOMPtr<nsIAsyncInputStream> reader{mReader.forget()};
if (mDelayedStart) {
mDelayedStartInputStream =
new DelayedStartInputStream(this, std::move(reader));
reader = mDelayedStartInputStream;
MOZ_ASSERT(reader);
new DelayedStartInputStream(this, std::move(mReader));
RefPtr<nsIAsyncInputStream> inputStream = mDelayedStartInputStream;
return inputStream.forget();
}
if (mLength != -1) {
MOZ_ASSERT(mLengthSet);
nsCOMPtr<nsIInputStream> finalStream =
new InputStreamLengthWrapper(reader.forget(), mLength);
reader = do_QueryInterface(finalStream);
MOZ_ASSERT(reader);
}
return reader.forget();
return mReader.forget();
}
bool IPCStreamDestination::IsOnOwningThread() const {

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

@ -80,7 +80,6 @@ class IPCStreamDestination {
// away. If that happens, the reading of data will not be possible anymore.
class DelayedStartInputStream;
RefPtr<DelayedStartInputStream> mDelayedStartInputStream;
int64_t mLength = -1;
nsCOMPtr<nsIThread> mOwningThread;
bool mDelayedStart;

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

@ -7,7 +7,6 @@
#include "IPCStreamUtils.h"
#include "nsIIPCSerializableInputStream.h"
#include "mozIRemoteLazyInputStream.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/ContentChild.h"
@ -18,8 +17,6 @@
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/net/SocketProcessChild.h"
#include "mozilla/net/SocketProcessParent.h"
#include "mozilla/InputStreamLengthHelper.h"
#include "mozilla/RemoteLazyInputStreamParent.h"
#include "mozilla/Unused.h"
#include "nsNetCID.h"
#include "BackgroundParentImpl.h"
@ -43,8 +40,6 @@ bool SerializeInputStreamWithFdsChild(nsIIPCSerializableInputStream* aStream,
MOZ_RELEASE_ASSERT(aStream);
MOZ_ASSERT(aManager);
// If you change this size, please also update the payload size in
// test_reload_large_postdata.html.
const uint64_t kTooLargeStream = 1024 * 1024;
uint32_t sizeUsed = 0;
@ -133,55 +128,6 @@ bool SerializeInputStream(nsIInputStream* aStream, IPCStream& aValue,
return true;
}
template <typename M>
bool SerializeLazyInputStream(nsIInputStream* aStream, IPCStream& aValue,
M* aManager) {
MOZ_ASSERT(aStream);
MOZ_ASSERT(aManager);
MOZ_ASSERT(XRE_IsParentProcess());
// avoid creating a loop between processes by accessing the underlying input
// stream.
nsCOMPtr<nsIInputStream> stream = aStream;
if (nsCOMPtr<mozIRemoteLazyInputStream> remoteLazyInputStream =
do_QueryInterface(stream)) {
stream = remoteLazyInputStream->GetInternalStream();
if (NS_WARN_IF(!stream)) {
return false;
}
}
uint64_t childID = 0;
if constexpr (std::is_same_v<dom::ContentParent, M>) {
childID = aManager->ChildID();
} else if constexpr (std::is_base_of_v<PBackgroundParent, M>) {
childID = BackgroundParent::GetChildID(aManager);
}
int64_t length = -1;
if (!InputStreamLengthHelper::GetSyncLength(stream, &length)) {
length = -1;
}
nsresult rv = NS_OK;
RefPtr<RemoteLazyInputStreamParent> actor =
RemoteLazyInputStreamParent::Create(aStream, length, childID, &rv,
aManager);
if (NS_WARN_IF(NS_FAILED(rv))) {
return false;
}
if (!aManager->SendPRemoteLazyInputStreamConstructor(actor, actor->ID(),
actor->Size())) {
return false;
}
aValue.stream() = RemoteLazyInputStreamParams(actor);
aValue.optionalFds() = void_t();
return true;
}
template <typename M>
bool SerializeInputStreamChild(nsIInputStream* aStream, M* aManager,
IPCStream* aValue,
@ -221,16 +167,6 @@ bool SerializeInputStreamParent(nsIInputStream* aStream, M* aManager,
MOZ_ASSERT(aManager);
MOZ_ASSERT(aValue || aOptionalValue);
// When requesting a delayed start stream from the parent process, serialize
// it as a remote lazy stream to avoid bloating payloads.
if (aDelayedStart && XRE_IsParentProcess()) {
if (aValue) {
return SerializeLazyInputStream(aStream, *aValue, aManager);
}
return SerializeLazyInputStream(aStream, aOptionalValue->ref(), aManager);
}
nsCOMPtr<nsIIPCSerializableInputStream> serializable =
do_QueryInterface(aStream);
@ -551,7 +487,7 @@ Maybe<IPCStream>& AutoIPCStream::TakeOptionalValue() {
void IPDLParamTraits<nsIInputStream*>::Write(IPC::Message* aMsg,
IProtocol* aActor,
nsIInputStream* aParam) {
auto autoStream = MakeRefPtr<HoldIPCStream>(/* aDelayedStart */ true);
auto autoStream = MakeRefPtr<HoldIPCStream>();
bool ok = false;
bool found = false;

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

@ -200,8 +200,6 @@ class HoldIPCStream final : public AutoIPCStream {
public:
NS_INLINE_DECL_REFCOUNTING(HoldIPCStream)
using AutoIPCStream::AutoIPCStream;
private:
~HoldIPCStream() = default;
};

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

@ -14,7 +14,6 @@
#include "ipc/IPCMessageUtils.h"
#include "mozilla/Mutex.h"
#include "mozilla/SeekableStreamWrapper.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
@ -404,6 +403,9 @@ bool nsMIMEInputStream::Deserialize(
const MIMEInputStreamParams& params = aParams.get_MIMEInputStreamParams();
const Maybe<InputStreamParams>& wrappedParams = params.optionalStream();
mHeaders = params.headers().Clone();
mStartedReading = params.startedReading();
if (wrappedParams.isSome()) {
nsCOMPtr<nsIInputStream> stream;
stream = InputStreamHelper::DeserializeInputStream(wrappedParams.ref(),
@ -413,23 +415,9 @@ bool nsMIMEInputStream::Deserialize(
return false;
}
// nsMIMEInputStream requires that the underlying data stream be seekable,
// as is checked in `SetData`. Ensure that the stream we deserialized is
// seekable before using it.
nsCOMPtr<nsIInputStream> seekable;
nsresult rv = mozilla::SeekableStreamWrapper::MaybeWrap(
stream.forget(), getter_AddRefs(seekable));
if (NS_FAILED(rv)) {
NS_WARNING("Failed to ensure wrapped input stream is seekable");
return false;
}
MOZ_ALWAYS_SUCCEEDS(SetData(seekable));
mStream = stream;
}
mHeaders = params.headers().Clone();
mStartedReading = params.startedReading();
return true;
}

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

@ -1,492 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 "mozilla/SeekableStreamWrapper.h"
#include "mozilla/InputStreamLengthHelper.h"
#include "nsStreamUtils.h"
namespace mozilla {
/* static */
nsresult SeekableStreamWrapper::MaybeWrap(
already_AddRefed<nsIInputStream> aOriginal, nsIInputStream** aResult) {
// First, check if the original stream is already seekable.
nsCOMPtr<nsIInputStream> original(aOriginal);
if (nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(original)) {
original.forget(aResult);
return NS_OK;
}
// If the original stream was not seekable, clone it. This may create a
// replacement stream using `nsPipe` if the original stream was not cloneable.
nsCOMPtr<nsIInputStream> clone;
nsCOMPtr<nsIInputStream> replacement;
nsresult rv = NS_CloneInputStream(original, getter_AddRefs(clone),
getter_AddRefs(replacement));
if (NS_FAILED(rv)) {
return rv;
}
if (replacement) {
original = replacement.forget();
}
// Our replacement or original must be cloneable if `NS_CloneInputStream`
// succeeded.
nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(original);
MOZ_DIAGNOSTIC_ASSERT(cloneable && cloneable->GetCloneable(),
"Result of NS_CloneInputStream must be cloneable");
nsCOMPtr<nsIAsyncInputStream> stream =
new SeekableStreamWrapper(cloneable, clone);
stream.forget(aResult);
return NS_OK;
}
template <typename T>
nsCOMPtr<T> SeekableStreamWrapper::StreamAs() {
MutexAutoLock lock(mMutex);
if constexpr (std::is_same_v<T, nsIInputStream>) {
return nsCOMPtr<T>(mCurrent);
} else {
return nsCOMPtr<T>(do_QueryInterface(mCurrent));
}
}
// nsIInputStream
NS_IMETHODIMP
SeekableStreamWrapper::Close() {
auto stream = StreamAs<nsIInputStream>();
NS_ENSURE_STATE(stream);
nsresult rv1 = stream->Close();
nsresult rv2 = NS_ERROR_NOT_IMPLEMENTED;
if (nsCOMPtr<nsIInputStream> original = do_QueryInterface(mOriginal)) {
rv2 = original->Close();
}
return NS_FAILED(rv1) ? rv1 : rv2;
}
NS_IMETHODIMP
SeekableStreamWrapper::Available(uint64_t* aLength) {
auto stream = StreamAs<nsIInputStream>();
NS_ENSURE_STATE(stream);
return stream->Available(aLength);
}
NS_IMETHODIMP
SeekableStreamWrapper::Read(char* aBuffer, uint32_t aCount,
uint32_t* aReadCount) {
auto stream = StreamAs<nsIInputStream>();
NS_ENSURE_STATE(stream);
return stream->Read(aBuffer, aCount, aReadCount);
}
namespace {
struct WriterClosure {
nsIInputStream* mStream;
nsWriteSegmentFun mInnerFun;
void* mInnerClosure;
};
static nsresult WriterCb(nsIInputStream* aInStream, void* aClosure,
const char* aFromSegment, uint32_t aToOffset,
uint32_t aCount, uint32_t* aWriteCount) {
auto* closure = static_cast<WriterClosure*>(aClosure);
return (closure->mInnerFun)(closure->mStream, closure->mInnerClosure,
aFromSegment, aToOffset, aCount, aWriteCount);
}
} // namespace
NS_IMETHODIMP
SeekableStreamWrapper::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
uint32_t aCount, uint32_t* aResult) {
auto stream = StreamAs<nsIInputStream>();
NS_ENSURE_STATE(stream);
WriterClosure innerClosure{static_cast<nsIAsyncInputStream*>(this), aWriter,
aClosure};
return stream->ReadSegments(WriterCb, &innerClosure, aCount, aResult);
}
NS_IMETHODIMP
SeekableStreamWrapper::IsNonBlocking(bool* aNonBlocking) {
auto stream = StreamAs<nsIInputStream>();
NS_ENSURE_STATE(stream);
return stream->IsNonBlocking(aNonBlocking);
}
// nsICloneableInputStream
NS_IMETHODIMP
SeekableStreamWrapper::GetCloneable(bool* aCloneable) {
auto stream = StreamAs<nsICloneableInputStream>();
NS_ENSURE_STATE(stream);
return stream->GetCloneable(aCloneable);
}
NS_IMETHODIMP
SeekableStreamWrapper::Clone(nsIInputStream** aResult) {
NS_ENSURE_STATE(mOriginal);
NS_ENSURE_STATE(mOriginal->GetCloneable());
nsCOMPtr<nsIInputStream> originalClone;
nsresult rv = mOriginal->Clone(getter_AddRefs(originalClone));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsICloneableInputStream> newOriginal =
do_QueryInterface(originalClone);
if (!newOriginal || !newOriginal->GetCloneable()) {
return NS_ERROR_FAILURE;
}
auto cloneable = StreamAs<nsICloneableInputStream>();
if (!cloneable || !cloneable->GetCloneable()) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIInputStream> newClone;
rv = cloneable->Clone(getter_AddRefs(newClone));
if (NS_FAILED(rv)) {
return rv;
}
nsCOMPtr<nsIAsyncInputStream> result =
new SeekableStreamWrapper(newOriginal, newClone);
result.forget(aResult);
return NS_OK;
}
// nsIAsyncInputStream
NS_IMETHODIMP
SeekableStreamWrapper::CloseWithStatus(nsresult aStatus) {
auto stream = StreamAs<nsIAsyncInputStream>();
NS_ENSURE_STATE(stream);
nsresult rv1 = stream->CloseWithStatus(aStatus);
nsresult rv2 = NS_ERROR_NOT_IMPLEMENTED;
if (nsCOMPtr<nsIAsyncInputStream> original = do_QueryInterface(mOriginal)) {
rv2 = original->CloseWithStatus(aStatus);
}
return NS_FAILED(rv1) ? rv1 : rv2;
}
class AsyncWaitCallback final : public nsIInputStreamCallback {
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINPUTSTREAMCALLBACK
public:
AsyncWaitCallback(nsIInputStreamCallback* aCallback,
nsIAsyncInputStream* aStream)
: mCallback(aCallback), mStream(aStream) {}
private:
~AsyncWaitCallback() = default;
nsCOMPtr<nsIInputStreamCallback> mCallback;
nsCOMPtr<nsIAsyncInputStream> mStream;
};
NS_IMPL_ISUPPORTS(AsyncWaitCallback, nsIInputStreamCallback)
NS_IMETHODIMP
AsyncWaitCallback::OnInputStreamReady(nsIAsyncInputStream*) {
return mCallback->OnInputStreamReady(mStream);
}
NS_IMETHODIMP
SeekableStreamWrapper::AsyncWait(nsIInputStreamCallback* aCallback,
uint32_t aFlags, uint32_t aRequestedCount,
nsIEventTarget* aEventTarget) {
auto stream = StreamAs<nsIAsyncInputStream>();
NS_ENSURE_TRUE(stream, NS_ERROR_NOT_IMPLEMENTED);
nsCOMPtr<nsIInputStreamCallback> callback;
if (aCallback) {
callback = new AsyncWaitCallback(aCallback, this);
}
return stream->AsyncWait(callback, aFlags, aRequestedCount, aEventTarget);
}
// nsITellableStream
NS_IMETHODIMP
SeekableStreamWrapper::Tell(int64_t* aResult) {
auto stream = StreamAs<nsITellableStream>();
NS_ENSURE_STATE(stream);
return stream->Tell(aResult);
}
// nsISeekableStream
NS_IMETHODIMP
SeekableStreamWrapper::Seek(int32_t aWhence, int64_t aOffset) {
// Check if our original stream has already been closed, in which case we
// can't seek anymore.
nsCOMPtr<nsIInputStream> original = do_QueryInterface(mOriginal);
uint64_t ignored = 0;
nsresult rv = original->Available(&ignored);
if (NS_FAILED(rv)) {
return rv;
}
int64_t offset = aOffset;
nsCOMPtr<nsIInputStream> origin;
switch (aWhence) {
// With NS_SEEK_SET, offset relative to our original stream.
case NS_SEEK_SET:
break;
// With NS_SEEK_CUR, if the offset is positive, perform it relative to our
// current stream, otherwise perform it relative to the original stream,
// offset by the result of `Tell`-ing our current stream.
case NS_SEEK_CUR: {
auto current = StreamAs<nsIInputStream>();
if (offset >= 0) {
origin = current.forget();
break;
}
nsCOMPtr<nsITellableStream> tellable = do_QueryInterface(current);
if (!tellable) {
return NS_ERROR_NOT_IMPLEMENTED;
}
int64_t cur = 0;
rv = tellable->Tell(&cur);
if (NS_FAILED(rv)) {
return rv;
}
offset += cur;
break;
}
// We have no way of knowing what the end of the stream is, so we can't
// implement this right now.
case NS_SEEK_END:
return NS_ERROR_NOT_IMPLEMENTED;
}
if (offset < 0) {
NS_WARNING("cannot seek before beginning of stream");
return NS_ERROR_INVALID_ARG;
}
// If we aren't starting from our existing stream, clone a new stream from
// `mOriginal`.
if (!origin) {
rv = mOriginal->Clone(getter_AddRefs(origin));
if (NS_FAILED(rv)) {
return rv;
}
}
MOZ_ASSERT(origin);
// If we have an offset from our origin to read to, use `ReadSegments` with
// `NS_DiscardSegment` to read to that point in the stream.
if (offset > 0) {
uint64_t available = 0;
rv = origin->Available(&available);
if (NS_FAILED(rv)) {
return rv;
}
if (available < uint64_t(offset)) {
// The current implementation of Seek cannot handle seeking into
// unavailable data, whether that's because it's past the end of the input
// stream, or the data isn't available yet.
NS_WARNING("cannot seek past the end of the currently avaliable data");
return NS_ERROR_INVALID_ARG;
}
// Discard segments from the input stream.
uint32_t written = 0;
rv = origin->ReadSegments(NS_DiscardSegment, nullptr, offset, &written);
if (NS_FAILED(rv)) {
return rv;
}
if (written != offset) {
return NS_BASE_STREAM_WOULD_BLOCK;
}
}
// Actually swap out our `nsIInputStream`.
nsCOMPtr<nsIInputStream> toClose;
{
MutexAutoLock lock(mMutex);
if (mCurrent != origin) {
toClose = mCurrent.forget();
mCurrent = origin.forget();
}
MOZ_ASSERT(mCurrent);
}
if (toClose) {
toClose->Close();
}
return NS_OK;
}
NS_IMETHODIMP
SeekableStreamWrapper::SetEOF() { return NS_ERROR_NOT_IMPLEMENTED; }
// nsIInputStreamLength
NS_IMETHODIMP
SeekableStreamWrapper::Length(int64_t* aLength) {
auto stream = StreamAs<nsIInputStreamLength>();
NS_ENSURE_STATE(stream);
return stream->Length(aLength);
}
// nsIAsyncInputStreamLength
class AsyncLengthCallback final : public nsIInputStreamLengthCallback {
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINPUTSTREAMLENGTHCALLBACK
public:
AsyncLengthCallback(nsIInputStreamLengthCallback* aCallback,
nsIAsyncInputStreamLength* aStream)
: mCallback(aCallback), mStream(aStream) {}
private:
~AsyncLengthCallback() = default;
nsCOMPtr<nsIInputStreamLengthCallback> mCallback;
nsCOMPtr<nsIAsyncInputStreamLength> mStream;
};
NS_IMPL_ISUPPORTS(AsyncLengthCallback, nsIInputStreamLengthCallback)
NS_IMETHODIMP
AsyncLengthCallback::OnInputStreamLengthReady(nsIAsyncInputStreamLength*,
int64_t aLength) {
return mCallback->OnInputStreamLengthReady(mStream, aLength);
}
NS_IMETHODIMP
SeekableStreamWrapper::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback,
nsIEventTarget* aEventTarget) {
auto stream = StreamAs<nsIAsyncInputStreamLength>();
NS_ENSURE_TRUE(stream, NS_ERROR_NOT_IMPLEMENTED);
nsCOMPtr<nsIInputStreamLengthCallback> callback;
if (aCallback) {
callback = new AsyncLengthCallback(aCallback, this);
}
return stream->AsyncLengthWait(callback, aEventTarget);
}
// nsIIPCSerializableInputStream
void SeekableStreamWrapper::Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ParentToChildStreamActorManager* aManager) {
SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
aSizeUsed, aManager);
}
void SeekableStreamWrapper::Serialize(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed,
mozilla::ipc::ChildToParentStreamActorManager* aManager) {
SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
aSizeUsed, aManager);
}
template <typename M>
void SeekableStreamWrapper::SerializeInternal(
mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
// Stream serialization methods generally do not respect the current seek
// offset when serializing, as is seen in nsStringStream::Serialize. As
// `StreamAs` may be nullptr and requires acquiring the mutex, instead
// serialize `mOriginal` into our pipe.
//
// Don't serialize context about this being a SeekableStreamWrapper, as the
// specific interfaces a stream implements, such as nsISeekableStream, are not
// preserved over IPC.
MOZ_ASSERT(IsIPCSerializableInputStream());
nsCOMPtr<nsIInputStream> original = do_QueryInterface(mOriginal);
mozilla::ipc::InputStreamHelper::SerializeInputStream(
original, aParams, aFileDescriptors, aDelayedStart, aMaxSize, aSizeUsed,
aManager);
}
bool SeekableStreamWrapper::Deserialize(
const mozilla::ipc::InputStreamParams& aParams,
const FileDescriptorArray& aFileDescriptors) {
MOZ_CRASH("This method should never be called!");
return false;
}
// nsIBufferedInputStream
NS_IMETHODIMP
SeekableStreamWrapper::Init(nsIInputStream*, uint32_t) {
MOZ_CRASH(
"SeekableStreamWrapper should never be initialized with "
"nsIBufferedInputStream::Init!\n");
}
NS_IMETHODIMP
SeekableStreamWrapper::GetData(nsIInputStream** aResult) {
auto stream = StreamAs<nsIBufferedInputStream>();
NS_ENSURE_STATE(stream);
return stream->GetData(aResult);
}
// nsISupports
bool SeekableStreamWrapper::IsAsyncInputStream() {
nsCOMPtr<nsIAsyncInputStream> stream(do_QueryInterface(mOriginal));
return stream;
}
bool SeekableStreamWrapper::IsInputStreamLength() {
nsCOMPtr<nsIInputStreamLength> stream(do_QueryInterface(mOriginal));
return stream;
}
bool SeekableStreamWrapper::IsAsyncInputStreamLength() {
nsCOMPtr<nsIAsyncInputStreamLength> stream(do_QueryInterface(mOriginal));
return stream;
}
bool SeekableStreamWrapper::IsIPCSerializableInputStream() {
nsCOMPtr<nsIIPCSerializableInputStream> stream(do_QueryInterface(mOriginal));
return stream;
}
bool SeekableStreamWrapper::IsBufferedInputStream() {
nsCOMPtr<nsIBufferedInputStream> stream(do_QueryInterface(mOriginal));
return stream;
}
NS_IMPL_ADDREF(SeekableStreamWrapper)
NS_IMPL_RELEASE(SeekableStreamWrapper)
NS_INTERFACE_MAP_BEGIN(SeekableStreamWrapper)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAsyncInputStream)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsIInputStream, nsIAsyncInputStream)
NS_INTERFACE_MAP_ENTRY(nsITellableStream)
NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream, IsAsyncInputStream())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLength,
IsInputStreamLength())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStreamLength,
IsAsyncInputStreamLength())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
IsIPCSerializableInputStream())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIBufferedInputStream,
IsBufferedInputStream())
NS_INTERFACE_MAP_END
} // namespace mozilla

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

@ -1,91 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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/. */
#ifndef mozilla_SeekableStreamWrapper_h
#define mozilla_SeekableStreamWrapper_h
#include "mozilla/Assertions.h"
#include "mozilla/Mutex.h"
#include "nsCOMPtr.h"
#include "nsIAsyncInputStream.h"
#include "nsISeekableStream.h"
#include "nsICloneableInputStream.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsIInputStreamLength.h"
#include "nsIBufferedStreams.h"
namespace mozilla {
// Adapter class which converts an input stream implementing
// `nsICloneableInputStream`, such as `nsPipe`, into a stream implementing
// `nsISeekableStream`. This is done by keeping a clone of the original unwound
// input stream to allow rewinding the stream back to its original position.
class SeekableStreamWrapper final : public nsIAsyncInputStream,
public nsISeekableStream,
public nsICloneableInputStream,
public nsIInputStreamLength,
public nsIAsyncInputStreamLength,
public nsIIPCSerializableInputStream,
public nsIBufferedInputStream {
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
NS_DECL_NSIASYNCINPUTSTREAM
NS_DECL_NSITELLABLESTREAM
NS_DECL_NSISEEKABLESTREAM
NS_DECL_NSICLONEABLEINPUTSTREAM
NS_DECL_NSIINPUTSTREAMLENGTH
NS_DECL_NSIASYNCINPUTSTREAMLENGTH
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
NS_DECL_NSIBUFFEREDINPUTSTREAM
public:
/**
* This function returns a nsIInputStream which is known to implement
* nsISeekableStream. This will return |aSource| if it already implements
* nsISeekableStream, and will wrap it if it does not.
*
* If the original stream implements `nsICloneableInputStream`, this will be
* used to implement the rewinding functionality necessary for
* `nsISeekableStream`, otherwise it will be copied into a `nsPipe`.
*/
static nsresult MaybeWrap(already_AddRefed<nsIInputStream> aOriginal,
nsIInputStream** aResult);
private:
SeekableStreamWrapper(nsICloneableInputStream* aOriginal,
nsIInputStream* aCurrent)
: mOriginal(aOriginal), mCurrent(aCurrent) {
MOZ_ASSERT(mOriginal->GetCloneable());
}
~SeekableStreamWrapper() = default;
template <typename T>
nsCOMPtr<T> StreamAs();
template <typename M>
void SerializeInternal(mozilla::ipc::InputStreamParams& aParams,
FileDescriptorArray& aFileDescriptors,
bool aDelayedStart, uint32_t aMaxSize,
uint32_t* aSizeUsed, M* aManager);
bool IsAsyncInputStream();
bool IsInputStreamLength();
bool IsAsyncInputStreamLength();
bool IsIPCSerializableInputStream();
bool IsBufferedInputStream();
// mOriginal is immutable after creation, and is not guarded by `mMutex`.
nsCOMPtr<nsICloneableInputStream> mOriginal;
// This mutex guards `mCurrent`.
Mutex mMutex{"SeekableStreamWrapper"};
nsCOMPtr<nsIInputStream> mCurrent;
};
} // namespace mozilla
#endif // mozilla_SeekableStreamWrapper_h

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

@ -94,7 +94,6 @@ EXPORTS.mozilla += [
"InputStreamLengthHelper.h",
"InputStreamLengthWrapper.h",
"NonBlockingAsyncInputStream.h",
"SeekableStreamWrapper.h",
"SlicedInputStream.h",
"SnappyCompressOutputStream.h",
"SnappyFrameUtils.h",
@ -129,7 +128,6 @@ UNIFIED_SOURCES += [
"nsStringStream.cpp",
"nsUnicharInputStream.cpp",
"nsWildCard.cpp",
"SeekableStreamWrapper.cpp",
"SlicedInputStream.cpp",
"SnappyCompressOutputStream.cpp",
"SnappyFrameUtils.cpp",

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

@ -188,13 +188,6 @@ class nsPipeInputStream final : public nsIAsyncInputStream,
// A version of Status() that doesn't acquire the monitor.
nsresult Status(const ReentrantMonitorAutoEnter& ev) const;
// The status of this input stream, ignoring the status of the underlying
// monitor. If this status is errored, the input stream has either already
// been removed from the pipe, or will be removed from the pipe shortly.
nsresult InputStatus(const ReentrantMonitorAutoEnter&) const {
return mInputStatus;
}
private:
virtual ~nsPipeInputStream();
@ -974,10 +967,7 @@ nsresult nsPipe::CloneInputStream(nsPipeInputStream* aOriginal,
nsIInputStream** aCloneOut) {
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
RefPtr<nsPipeInputStream> ref = new nsPipeInputStream(*aOriginal);
// don't add clones of closed pipes to mInputList.
if (NS_SUCCEEDED(ref->InputStatus(mon))) {
mInputList.AppendElement(ref);
}
mInputList.AppendElement(ref);
nsCOMPtr<nsIAsyncInputStream> upcast = std::move(ref);
upcast.forget(aCloneOut);
return NS_OK;

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

@ -62,9 +62,7 @@ class LengthStream final : public nsIInputStreamLength,
NS_IMETHOD AsyncLengthWait(nsIInputStreamLengthCallback* aCallback,
nsIEventTarget* aEventTarget) override {
if (aCallback) {
aCallback->OnInputStreamLengthReady(this, mLength);
}
aCallback->OnInputStreamLengthReady(this, mLength);
return NS_OK;
}

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

@ -1,200 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 <stdlib.h>
#include "gtest/gtest.h"
#include "Helpers.h"
#include "mozilla/SeekableStreamWrapper.h"
#include "nsIPipe.h"
static void NewSeekablePipe(nsIInputStream** aReader,
nsIOutputStream** aWriter) {
nsCOMPtr<nsIAsyncInputStream> reader;
nsCOMPtr<nsIAsyncOutputStream> writer;
nsresult rv =
NS_NewPipe2(getter_AddRefs(reader), getter_AddRefs(writer), true, true);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(reader);
EXPECT_FALSE(seekable);
nsCOMPtr<nsIInputStream> wrapped;
rv = mozilla::SeekableStreamWrapper::MaybeWrap(do_AddRef(reader),
getter_AddRefs(wrapped));
ASSERT_TRUE(NS_SUCCEEDED(rv));
wrapped.forget(aReader);
writer.forget(aWriter);
}
TEST(SeekableStreamWrapper, NoWrap)
{
nsTArray<char> inputData;
testing::CreateData(4096, inputData);
nsDependentCSubstring inputString(inputData.Elements(), inputData.Length());
nsCOMPtr<nsIInputStream> stream;
nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), inputString);
ASSERT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsIInputStream> wrapped;
rv = mozilla::SeekableStreamWrapper::MaybeWrap(do_AddRef(stream),
getter_AddRefs(wrapped));
ASSERT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(stream, wrapped);
testing::ConsumeAndValidateStream(wrapped, inputString);
}
TEST(SeekableStreamWrapper, WrapPipe)
{
nsCOMPtr<nsIInputStream> reader;
nsCOMPtr<nsIOutputStream> writer;
NewSeekablePipe(getter_AddRefs(reader), getter_AddRefs(writer));
nsTArray<char> inputData;
testing::CreateData(1024, inputData);
uint32_t numWritten = 0;
nsresult rv =
writer->Write(inputData.Elements(), inputData.Length(), &numWritten);
EXPECT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(numWritten, 1024u);
nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(reader);
ASSERT_TRUE(seekable);
nsCOMPtr<nsICloneableInputStream> cloneable = do_QueryInterface(reader);
ASSERT_TRUE(cloneable);
ASSERT_TRUE(cloneable->GetCloneable());
nsCOMPtr<nsIInputStream> clone1;
rv = cloneable->Clone(getter_AddRefs(clone1));
ASSERT_TRUE(NS_SUCCEEDED(rv));
ASSERT_TRUE(clone1);
// Check that we can read the first 512 bytes.
{
char buf[512];
uint32_t numRead = 0;
rv = reader->Read(buf, 512, &numRead);
EXPECT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(numRead, 512u);
EXPECT_EQ(mozilla::Span(inputData).First(512), mozilla::Span(buf));
}
// Check that we can read the second 512 bytes.
{
char buf[512];
uint32_t numRead = 0;
rv = reader->Read(buf, 512, &numRead);
EXPECT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(numRead, 512u);
EXPECT_EQ(mozilla::Span(inputData).Last(512), mozilla::Span(buf));
}
// Should be at the end of the pipe
{
char buf[1];
uint32_t numRead = 0;
rv = reader->Read(buf, 1, &numRead);
EXPECT_EQ(rv, NS_BASE_STREAM_WOULD_BLOCK);
}
// Re-read the second 512 bytes by seeking back.
{
rv = seekable->Seek(nsISeekableStream::NS_SEEK_CUR, -512);
EXPECT_TRUE(NS_SUCCEEDED(rv));
char buf[512];
uint32_t numRead = 0;
rv = reader->Read(buf, 512, &numRead);
EXPECT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(numRead, 512u);
EXPECT_EQ(mozilla::Span(inputData).Last(512), mozilla::Span(buf));
}
// Re-read the last 256 bytes by seeking absolutely
{
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 768);
EXPECT_TRUE(NS_SUCCEEDED(rv));
char buf[256];
uint32_t numRead = 0;
rv = reader->Read(buf, 256, &numRead);
EXPECT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(numRead, 256u);
EXPECT_EQ(mozilla::Span(inputData).Last(256), mozilla::Span(buf));
}
// Double-check that we haven't impacted our clone
{
char buf[1024];
uint32_t numRead = 0;
rv = clone1->Read(buf, 1024, &numRead);
EXPECT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(numRead, 1024u);
EXPECT_EQ(mozilla::Span(inputData), mozilla::Span(buf));
}
// The clone should no longer be seekable once closed.
rv = clone1->Close();
EXPECT_TRUE(NS_SUCCEEDED(rv));
nsCOMPtr<nsISeekableStream> clone1Seekable(do_QueryInterface(clone1));
rv = clone1Seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
EXPECT_TRUE(NS_FAILED(rv));
// Should still be open
{
uint64_t available = 0;
rv = reader->Available(&available);
EXPECT_TRUE(NS_SUCCEEDED(rv));
EXPECT_EQ(available, uint64_t(0));
}
// Close the original output stream
rv = writer->Close();
EXPECT_TRUE(NS_SUCCEEDED(rv));
// Should be closed
{
uint64_t available = 0;
rv = reader->Available(&available);
EXPECT_EQ(rv, NS_BASE_STREAM_CLOSED);
}
// Seeing back to the beginning should re-open the stream which had reached
// the end.
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
EXPECT_TRUE(NS_SUCCEEDED(rv));
testing::ConsumeAndValidateStream(reader, inputData);
}
TEST(SeekableStreamWrapper, Interfaces)
{
nsCOMPtr<nsIInputStream> reader;
nsCOMPtr<nsIOutputStream> writer;
NewSeekablePipe(getter_AddRefs(reader), getter_AddRefs(writer));
nsCOMPtr<nsIAsyncInputStream> readerType1 = do_QueryInterface(reader);
EXPECT_TRUE(readerType1);
nsCOMPtr<nsITellableStream> readerType2 = do_QueryInterface(reader);
EXPECT_TRUE(readerType2);
nsCOMPtr<nsISeekableStream> readerType3 = do_QueryInterface(reader);
EXPECT_TRUE(readerType3);
nsCOMPtr<nsICloneableInputStream> readerType4 = do_QueryInterface(reader);
EXPECT_TRUE(readerType4);
nsCOMPtr<nsIBufferedInputStream> readerType5 = do_QueryInterface(reader);
EXPECT_TRUE(readerType5);
}

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

@ -39,7 +39,6 @@ UNIFIED_SOURCES += [
"TestRacingServiceManager.cpp",
"TestRecursiveMutex.cpp",
"TestRWLock.cpp",
"TestSeekableStreamWrapper.cpp",
"TestSegmentedBuffer.cpp",
"TestSlicedInputStream.cpp",
"TestSmallArrayLRUCache.cpp",