Bug 1434553 - Implement nsIInputStreamLength and nsIAsyncInputStreamLength - part 6 - nsMIMEInputStream exposes nsIInputStreamLength, r=mayhmer

This commit is contained in:
Andrea Marchesini 2018-05-23 07:12:35 +02:00
Родитель 958612bfaf
Коммит f0fb8aa183
4 изменённых файлов: 347 добавлений и 6 удалений

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

@ -13,6 +13,7 @@
#include "nsCOMPtr.h"
#include "nsComponentManagerUtils.h"
#include "nsIAsyncInputStream.h"
#include "nsIInputStreamLength.h"
#include "nsIHttpHeaderVisitor.h"
#include "nsIMIMEInputStream.h"
#include "nsISeekableStream.h"
@ -32,7 +33,10 @@ class nsMIMEInputStream : public nsIMIMEInputStream,
public nsISeekableStream,
public nsIIPCSerializableInputStream,
public nsIAsyncInputStream,
public nsIInputStreamCallback
public nsIInputStreamCallback,
public nsIInputStreamLength,
public nsIAsyncInputStreamLength,
public nsIInputStreamLengthCallback
{
virtual ~nsMIMEInputStream() = default;
@ -46,6 +50,9 @@ public:
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
NS_DECL_NSIASYNCINPUTSTREAM
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSIINPUTSTREAMLENGTH
NS_DECL_NSIASYNCINPUTSTREAMLENGTH
NS_DECL_NSIINPUTSTREAMLENGTHCALLBACK
private:
@ -62,6 +69,8 @@ private:
bool IsAsyncInputStream() const;
bool IsIPCSerializable() const;
bool IsInputStreamLength() const;
bool IsAsyncInputStreamLength() const;
nsTArray<HeaderEntry> mHeaders;
@ -72,6 +81,9 @@ private:
// This is protected by mutex.
nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
// This is protected by mutex.
nsCOMPtr<nsIInputStreamLengthCallback> mAsyncInputStreamLengthCallback;
};
NS_IMPL_ADDREF(nsMIMEInputStream)
@ -91,6 +103,12 @@ NS_INTERFACE_MAP_BEGIN(nsMIMEInputStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
IsAsyncInputStream())
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIMIMEInputStream)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLength,
IsInputStreamLength())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStreamLength,
IsAsyncInputStreamLength())
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLengthCallback,
IsAsyncInputStreamLength())
NS_IMPL_QUERY_CLASSINFO(nsMIMEInputStream)
NS_INTERFACE_MAP_END
@ -392,6 +410,54 @@ nsMIMEInputStream::ExpectedSerializedLength()
return serializable ? serializable->ExpectedSerializedLength() : Nothing();
}
NS_IMETHODIMP
nsMIMEInputStream::Length(int64_t* aLength)
{
nsCOMPtr<nsIInputStreamLength> stream = do_QueryInterface(mStream);
if (NS_WARN_IF(!stream)) {
return NS_ERROR_FAILURE;
}
return stream->Length(aLength);
}
NS_IMETHODIMP
nsMIMEInputStream::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback,
nsIEventTarget* aEventTarget)
{
nsCOMPtr<nsIAsyncInputStreamLength> stream = do_QueryInterface(mStream);
if (NS_WARN_IF(!stream)) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIInputStreamLengthCallback> callback = aCallback ? this : nullptr;
{
MutexAutoLock lock(mMutex);
mAsyncInputStreamLengthCallback = aCallback;
}
return stream->AsyncLengthWait(callback, aEventTarget);
}
NS_IMETHODIMP
nsMIMEInputStream::OnInputStreamLengthReady(nsIAsyncInputStreamLength* aStream,
int64_t aLength)
{
nsCOMPtr<nsIInputStreamLengthCallback> callback;
{
MutexAutoLock lock(mMutex);
// We have been canceled in the meanwhile.
if (!mAsyncInputStreamLengthCallback) {
return NS_OK;
}
callback.swap(mAsyncInputStreamLengthCallback);
}
MOZ_ASSERT(callback);
return callback->OnInputStreamLengthReady(this, aLength);
}
bool
nsMIMEInputStream::IsAsyncInputStream() const
{
@ -410,3 +476,17 @@ nsMIMEInputStream::IsIPCSerializable() const
nsCOMPtr<nsIIPCSerializableInputStream> serializable = do_QueryInterface(mStream);
return !!serializable;
}
bool
nsMIMEInputStream::IsInputStreamLength() const
{
nsCOMPtr<nsIInputStreamLength> stream = do_QueryInterface(mStream);
return !!stream;
}
bool
nsMIMEInputStream::IsAsyncInputStreamLength() const
{
nsCOMPtr<nsIAsyncInputStreamLength> stream = do_QueryInterface(mStream);
return !!stream;
}

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

@ -0,0 +1,260 @@
#include "gtest/gtest.h"
#include "Helpers.h"
#include "nsCOMPtr.h"
#include "nsIPipe.h"
#include "nsStreamUtils.h"
#include "nsString.h"
#include "nsStringStream.h"
#include "nsIMIMEInputStream.h"
using mozilla::GetCurrentThreadSerialEventTarget;
using mozilla::SpinEventLoopUntil;
namespace {
class SeekableLengthInputStream final : public testing::LengthInputStream
, public nsISeekableStream
{
public:
SeekableLengthInputStream(const nsACString& aBuffer,
bool aIsInputStreamLength,
bool aIsAsyncInputStreamLength,
nsresult aLengthRv = NS_OK,
bool aNegativeValue = false)
: testing::LengthInputStream(aBuffer, aIsInputStreamLength,
aIsAsyncInputStreamLength, aLengthRv,
aNegativeValue)
{}
NS_DECL_ISUPPORTS_INHERITED
NS_IMETHOD
Seek(int32_t aWhence, int64_t aOffset) override
{
MOZ_CRASH("This method should not be called.");
return NS_ERROR_FAILURE;
}
NS_IMETHOD
Tell(int64_t* aResult) override
{
MOZ_CRASH("This method should not be called.");
return NS_ERROR_FAILURE;
}
NS_IMETHOD
SetEOF() override
{
MOZ_CRASH("This method should not be called.");
return NS_ERROR_FAILURE;
}
private:
~SeekableLengthInputStream() = default;
};
NS_IMPL_ISUPPORTS_INHERITED(SeekableLengthInputStream,
testing::LengthInputStream,
nsISeekableStream)
} // anonymous
// nsIInputStreamLength && nsIAsyncInputStreamLength
TEST(TestNsMIMEInputStream, QIInputStreamLength) {
nsCString buf;
buf.AssignLiteral("Hello world");
for (int i = 0; i < 4; i++) {
nsCOMPtr<nsIInputStream> mis;
{
RefPtr<SeekableLengthInputStream> stream =
new SeekableLengthInputStream(buf, i % 2, i > 1);
nsresult rv;
nsCOMPtr<nsIMIMEInputStream> m(
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
ASSERT_EQ(NS_OK, rv);
rv = m->SetData(stream);
ASSERT_EQ(NS_OK, rv);
mis = do_QueryInterface(m);
ASSERT_TRUE(!!mis);
}
{
nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(mis);
ASSERT_EQ(!!(i % 2), !!qi);
}
{
nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(mis);
ASSERT_EQ(i > 1, !!qi);
}
}
}
TEST(TestNsMIMEInputStream, InputStreamLength) {
nsCString buf;
buf.AssignLiteral("Hello world");
nsCOMPtr<nsIInputStream> mis;
{
RefPtr<SeekableLengthInputStream> stream =
new SeekableLengthInputStream(buf, true, false);
nsresult rv;
nsCOMPtr<nsIMIMEInputStream> m(
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
ASSERT_EQ(NS_OK, rv);
rv = m->SetData(stream);
ASSERT_EQ(NS_OK, rv);
mis = do_QueryInterface(m);
ASSERT_TRUE(!!mis);
}
nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(mis);
ASSERT_TRUE(!!qi);
int64_t size;
nsresult rv = qi->Length(&size);
ASSERT_EQ(NS_OK, rv);
ASSERT_EQ(buf.Length(), size);
}
TEST(TestNsMIMEInputStream, NegativeInputStreamLength) {
nsCString buf;
buf.AssignLiteral("Hello world");
nsCOMPtr<nsIInputStream> mis;
{
RefPtr<SeekableLengthInputStream> stream =
new SeekableLengthInputStream(buf, true, false, NS_OK, true);
nsresult rv;
nsCOMPtr<nsIMIMEInputStream> m(
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
ASSERT_EQ(NS_OK, rv);
rv = m->SetData(stream);
ASSERT_EQ(NS_OK, rv);
mis = do_QueryInterface(m);
ASSERT_TRUE(!!mis);
}
nsCOMPtr<nsIInputStreamLength> qi = do_QueryInterface(mis);
ASSERT_TRUE(!!qi);
int64_t size;
nsresult rv = qi->Length(&size);
ASSERT_EQ(NS_OK, rv);
ASSERT_EQ(-1, size);
}
TEST(TestNsMIMEInputStream, AsyncInputStreamLength) {
nsCString buf;
buf.AssignLiteral("Hello world");
nsCOMPtr<nsIInputStream> mis;
{
RefPtr<SeekableLengthInputStream> stream =
new SeekableLengthInputStream(buf, false, true);
nsresult rv;
nsCOMPtr<nsIMIMEInputStream> m(
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
ASSERT_EQ(NS_OK, rv);
rv = m->SetData(stream);
ASSERT_EQ(NS_OK, rv);
mis = do_QueryInterface(m);
ASSERT_TRUE(!!mis);
}
nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(mis);
ASSERT_TRUE(!!qi);
RefPtr<testing::LengthCallback> callback = new testing::LengthCallback();
nsresult rv = qi->AsyncLengthWait(callback, GetCurrentThreadSerialEventTarget());
ASSERT_EQ(NS_OK, rv);
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback->Called(); }));
ASSERT_EQ(buf.Length(), callback->Size());
}
TEST(TestNsMIMEInputStream, NegativeAsyncInputStreamLength) {
nsCString buf;
buf.AssignLiteral("Hello world");
nsCOMPtr<nsIInputStream> mis;
{
RefPtr<SeekableLengthInputStream> stream =
new SeekableLengthInputStream(buf, false, true, NS_OK, true);
nsresult rv;
nsCOMPtr<nsIMIMEInputStream> m(
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
ASSERT_EQ(NS_OK, rv);
rv = m->SetData(stream);
ASSERT_EQ(NS_OK, rv);
mis = do_QueryInterface(m);
ASSERT_TRUE(!!mis);
}
nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(mis);
ASSERT_TRUE(!!qi);
RefPtr<testing::LengthCallback> callback = new testing::LengthCallback();
nsresult rv = qi->AsyncLengthWait(callback, GetCurrentThreadSerialEventTarget());
ASSERT_EQ(NS_OK, rv);
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback->Called(); }));
ASSERT_EQ(-1, callback->Size());
}
TEST(TestNsMIMEInputStream, AbortLengthCallback) {
nsCString buf;
buf.AssignLiteral("Hello world");
nsCOMPtr<nsIInputStream> mis;
{
RefPtr<SeekableLengthInputStream> stream =
new SeekableLengthInputStream(buf, false, true, NS_OK, true);
nsresult rv;
nsCOMPtr<nsIMIMEInputStream> m(
do_CreateInstance("@mozilla.org/network/mime-input-stream;1", &rv));
ASSERT_EQ(NS_OK, rv);
rv = m->SetData(stream);
ASSERT_EQ(NS_OK, rv);
mis = do_QueryInterface(m);
ASSERT_TRUE(!!mis);
}
nsCOMPtr<nsIAsyncInputStreamLength> qi = do_QueryInterface(mis);
ASSERT_TRUE(!!qi);
RefPtr<testing::LengthCallback> callback1 = new testing::LengthCallback();
nsresult rv = qi->AsyncLengthWait(callback1, GetCurrentThreadSerialEventTarget());
ASSERT_EQ(NS_OK, rv);
RefPtr<testing::LengthCallback> callback2 = new testing::LengthCallback();
rv = qi->AsyncLengthWait(callback2, GetCurrentThreadSerialEventTarget());
ASSERT_EQ(NS_OK, rv);
MOZ_ALWAYS_TRUE(SpinEventLoopUntil([&]() { return callback2->Called(); }));
ASSERT_TRUE(!callback1->Called());
ASSERT_EQ(-1, callback2->Size());
}

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

@ -8,6 +8,7 @@ UNIFIED_SOURCES += [
'TestBufferedInputStream.cpp',
'TestHeaders.cpp',
'TestHttpAuthUtils.cpp',
'TestMIMEInputStream.cpp',
'TestMozURL.cpp',
'TestPartiallySeekableInputStream.cpp',
'TestProtocolProxyService.cpp',

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

@ -95,7 +95,7 @@ private:
};
// This class implements a simple nsIInputStreamLength stream.
class LengthInputStream final : public nsIInputStream
class LengthInputStream : public nsIInputStream
, public nsIInputStreamLength
, public nsIAsyncInputStreamLength
{
@ -180,8 +180,8 @@ public:
return aEventTarget->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
}
private:
~LengthInputStream() {}
protected:
virtual ~LengthInputStream() = default;
};
class LengthCallback final : public nsIInputStreamLengthCallback