mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Bug 1413920 - nsMultiplexInputStream should call OnInputStreamReady on close, r=smaug
This commit is contained in:
parent
afe8ac1278
commit
cc7b359311
@ -1,112 +1,11 @@
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "nsBufferedStreams.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "Helpers.h"
|
||||
|
||||
class AsyncStringStream final : public nsIAsyncInputStream
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
explicit AsyncStringStream(const nsACString& aBuffer)
|
||||
{
|
||||
NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer);
|
||||
}
|
||||
|
||||
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 NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Close() override
|
||||
{
|
||||
nsresult rv = mStream->Close();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MaybeExecCallback(mCallback, mCallbackEventTarget);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
IsNonBlocking(bool* aNonBlocking) override
|
||||
{
|
||||
return mStream->IsNonBlocking(aNonBlocking);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
CloseWithStatus(nsresult aStatus) override
|
||||
{
|
||||
return Close();
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
uint32_t aFlags, uint32_t aRequestedCount,
|
||||
nsIEventTarget* aEventTarget) override
|
||||
{
|
||||
if (aFlags & nsIAsyncInputStream::WAIT_CLOSURE_ONLY) {
|
||||
mCallback = aCallback;
|
||||
mCallbackEventTarget = aEventTarget;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MaybeExecCallback(aCallback, aEventTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
MaybeExecCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget)
|
||||
{
|
||||
if (!aCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> callback = aCallback;
|
||||
nsCOMPtr<nsIAsyncInputStream> self = this;
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
||||
"AsyncWait", [callback, self]() { callback->OnInputStreamReady(self); });
|
||||
|
||||
if (aEventTarget) {
|
||||
aEventTarget->Dispatch(r.forget());
|
||||
} else {
|
||||
r->Run();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
~AsyncStringStream() = default;
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mCallbackEventTarget;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(AsyncStringStream, nsIAsyncInputStream, nsIInputStream)
|
||||
|
||||
// Helper function for creating a AsyncStringStream
|
||||
// Helper function for creating a testing::AsyncStringStream
|
||||
already_AddRefed<nsBufferedInputStream>
|
||||
CreateStream(uint32_t aSize, nsCString& aBuffer)
|
||||
{
|
||||
@ -115,7 +14,7 @@ CreateStream(uint32_t aSize, nsCString& aBuffer)
|
||||
aBuffer.BeginWriting()[i] = i % 10;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = new AsyncStringStream(aBuffer);
|
||||
nsCOMPtr<nsIInputStream> stream = new testing::AsyncStringStream(aBuffer);
|
||||
|
||||
RefPtr<nsBufferedInputStream> bis = new nsBufferedInputStream();
|
||||
bis->Init(stream, aSize);
|
||||
|
@ -255,8 +255,6 @@ nsMultiplexInputStream::Close()
|
||||
}
|
||||
}
|
||||
|
||||
mAsyncWaitCallback = nullptr;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
@ -130,4 +131,88 @@ InputStreamCallback::OnInputStreamReady(nsIAsyncInputStream* aStream)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
AsyncStringStream::AsyncStringStream(const nsACString& aBuffer)
|
||||
{
|
||||
NS_NewCStringInputStream(getter_AddRefs(mStream), aBuffer);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncStringStream::Available(uint64_t* aLength)
|
||||
{
|
||||
return mStream->Available(aLength);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncStringStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount)
|
||||
{
|
||||
return mStream->Read(aBuffer, aCount, aReadCount);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncStringStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
uint32_t aCount, uint32_t *aResult)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncStringStream::Close()
|
||||
{
|
||||
nsresult rv = mStream->Close();
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
MaybeExecCallback(mCallback, mCallbackEventTarget);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncStringStream::IsNonBlocking(bool* aNonBlocking)
|
||||
{
|
||||
return mStream->IsNonBlocking(aNonBlocking);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncStringStream::CloseWithStatus(nsresult aStatus)
|
||||
{
|
||||
return Close();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
AsyncStringStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
uint32_t aFlags, uint32_t aRequestedCount,
|
||||
nsIEventTarget* aEventTarget)
|
||||
{
|
||||
if (aFlags & nsIAsyncInputStream::WAIT_CLOSURE_ONLY) {
|
||||
mCallback = aCallback;
|
||||
mCallbackEventTarget = aEventTarget;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
MaybeExecCallback(aCallback, aEventTarget);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
AsyncStringStream::MaybeExecCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget)
|
||||
{
|
||||
if (!aCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> callback = aCallback;
|
||||
nsCOMPtr<nsIAsyncInputStream> self = this;
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(
|
||||
"AsyncWait", [callback, self]() { callback->OnInputStreamReady(self); });
|
||||
|
||||
if (aEventTarget) {
|
||||
aEventTarget->Dispatch(r.forget());
|
||||
} else {
|
||||
r->Run();
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(AsyncStringStream, nsIAsyncInputStream, nsIInputStream)
|
||||
|
||||
} // namespace testing
|
||||
|
@ -7,9 +7,11 @@
|
||||
#ifndef __Helpers_h
|
||||
#define __Helpers_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIAsyncOutputStream.h"
|
||||
#include "nsString.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
#include <stdint.h>
|
||||
|
||||
@ -68,6 +70,28 @@ public:
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
};
|
||||
|
||||
class AsyncStringStream final : public nsIAsyncInputStream
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> mStream;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIASYNCINPUTSTREAM
|
||||
|
||||
explicit AsyncStringStream(const nsACString& aBuffer);
|
||||
|
||||
private:
|
||||
~AsyncStringStream() = default;
|
||||
|
||||
void
|
||||
MaybeExecCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget);
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mCallbackEventTarget;
|
||||
};
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // __Helpers_h
|
||||
|
@ -5,12 +5,13 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIInputStream.h"
|
||||
#include "nsIMultiplexInputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsStringStream.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "Helpers.h"
|
||||
|
||||
TEST(MultiplexInputStream, Seek_SET)
|
||||
{
|
||||
@ -101,3 +102,114 @@ TEST(MultiplexInputStream, Seek_SET)
|
||||
ASSERT_EQ((uint64_t)buf2.Length() - 6 + buf3.Length(), length);
|
||||
ASSERT_EQ(0, strncmp(readBuf, "The qu", count));
|
||||
}
|
||||
|
||||
already_AddRefed<nsIInputStream>
|
||||
CreateStreamHelper()
|
||||
{
|
||||
nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
|
||||
do_CreateInstance("@mozilla.org/io/multiplex-input-stream;1");
|
||||
|
||||
nsCString buf1;
|
||||
buf1.AssignLiteral("Hello");
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream1 = new testing::AsyncStringStream(buf1);
|
||||
multiplexStream->AppendStream(inputStream1);
|
||||
|
||||
nsCString buf2;
|
||||
buf2.AssignLiteral(" ");
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream2 = new testing::AsyncStringStream(buf2);
|
||||
multiplexStream->AppendStream(inputStream2);
|
||||
|
||||
nsCString buf3;
|
||||
buf3.AssignLiteral("World!");
|
||||
|
||||
nsCOMPtr<nsIInputStream> inputStream3 = new testing::AsyncStringStream(buf3);
|
||||
multiplexStream->AppendStream(inputStream3);
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream(do_QueryInterface(multiplexStream));
|
||||
return stream.forget();
|
||||
}
|
||||
|
||||
// AsyncWait - without EventTarget
|
||||
TEST(TestMultiplexInputStream, AsyncWait_withoutEventTarget) {
|
||||
nsCOMPtr<nsIInputStream> is = CreateStreamHelper();
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> ais = do_QueryInterface(is);
|
||||
ASSERT_TRUE(!!ais);
|
||||
|
||||
RefPtr<testing::InputStreamCallback> cb =
|
||||
new testing::InputStreamCallback();
|
||||
|
||||
ASSERT_EQ(NS_OK, ais->AsyncWait(cb, 0, 0, nullptr));
|
||||
ASSERT_FALSE(cb->Called());
|
||||
|
||||
// Eventually it is called.
|
||||
MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil([&]() { return cb->Called(); }));
|
||||
ASSERT_TRUE(cb->Called());
|
||||
}
|
||||
|
||||
// AsyncWait - with EventTarget
|
||||
TEST(TestMultiplexInputStream, AsyncWait_withEventTarget) {
|
||||
nsCOMPtr<nsIInputStream> is = CreateStreamHelper();
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> ais = do_QueryInterface(is);
|
||||
ASSERT_TRUE(!!ais);
|
||||
|
||||
RefPtr<testing::InputStreamCallback> cb =
|
||||
new testing::InputStreamCallback();
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
|
||||
ASSERT_EQ(NS_OK, ais->AsyncWait(cb, 0, 0, thread));
|
||||
|
||||
ASSERT_FALSE(cb->Called());
|
||||
|
||||
// Eventually it is called.
|
||||
MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil([&]() { return cb->Called(); }));
|
||||
ASSERT_TRUE(cb->Called());
|
||||
}
|
||||
|
||||
// AsyncWait - without EventTarget - closureOnly
|
||||
TEST(TestMultiplexInputStream, AsyncWait_withoutEventTarget_closureOnly) {
|
||||
nsCOMPtr<nsIInputStream> is = CreateStreamHelper();
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> ais = do_QueryInterface(is);
|
||||
ASSERT_TRUE(!!ais);
|
||||
|
||||
RefPtr<testing::InputStreamCallback> cb =
|
||||
new testing::InputStreamCallback();
|
||||
|
||||
ASSERT_EQ(NS_OK, ais->AsyncWait(cb, nsIAsyncInputStream::WAIT_CLOSURE_ONLY,
|
||||
0, nullptr));
|
||||
ASSERT_FALSE(cb->Called());
|
||||
|
||||
ais->CloseWithStatus(NS_ERROR_FAILURE);
|
||||
ASSERT_FALSE(cb->Called());
|
||||
|
||||
// Eventually it is called.
|
||||
MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil([&]() { return cb->Called(); }));
|
||||
ASSERT_TRUE(cb->Called());
|
||||
}
|
||||
|
||||
// AsyncWait - withEventTarget - closureOnly
|
||||
TEST(TestMultiplexInputStream, AsyncWait_withEventTarget_closureOnly) {
|
||||
nsCOMPtr<nsIInputStream> is = CreateStreamHelper();
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> ais = do_QueryInterface(is);
|
||||
ASSERT_TRUE(!!ais);
|
||||
|
||||
RefPtr<testing::InputStreamCallback> cb =
|
||||
new testing::InputStreamCallback();
|
||||
nsCOMPtr<nsIThread> thread = do_GetCurrentThread();
|
||||
|
||||
ASSERT_EQ(NS_OK, ais->AsyncWait(cb, nsIAsyncInputStream::WAIT_CLOSURE_ONLY,
|
||||
0, thread));
|
||||
|
||||
ASSERT_FALSE(cb->Called());
|
||||
ais->CloseWithStatus(NS_ERROR_FAILURE);
|
||||
ASSERT_FALSE(cb->Called());
|
||||
|
||||
// Eventually it is called.
|
||||
MOZ_ALWAYS_TRUE(mozilla::SpinEventLoopUntil([&]() { return cb->Called(); }));
|
||||
ASSERT_TRUE(cb->Called());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user