зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1434553 - Implement nsIInputStreamLength and nsIAsyncInputStreamLength - part 6 - nsMIMEInputStream exposes nsIInputStreamLength, r=mayhmer
This commit is contained in:
Родитель
958612bfaf
Коммит
f0fb8aa183
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче