1089 lines
36 KiB
C++
1089 lines
36 KiB
C++
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* 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 <utility>
|
|
|
|
#include "TestCommon.h"
|
|
#include "gtest/gtest.h"
|
|
#include "Http2WebTransportSession.h"
|
|
#include "Http2WebTransportStream.h"
|
|
#include "nsString.h"
|
|
#include "nsTArray.h"
|
|
#include "mozilla/gtest/MozAssertions.h"
|
|
#include "mozilla/Queue.h"
|
|
#include "mozilla/net/NeqoHttp3Conn.h"
|
|
#include "Capsule.h"
|
|
#include "CapsuleEncoder.h"
|
|
#include "CapsuleParser.h"
|
|
#include "nsIWebTransport.h"
|
|
#include "nsStreamUtils.h"
|
|
#include "nsThreadUtils.h"
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::net;
|
|
|
|
class MockWebTransportClient : public CapsuleIOHandler {
|
|
public:
|
|
NS_INLINE_DECL_REFCOUNTING(MockWebTransportClient, override)
|
|
|
|
explicit MockWebTransportClient(Http2WebTransportInitialSettings aSettings)
|
|
: mSession(new Http2WebTransportSessionImpl(this, aSettings)),
|
|
mParser(MakeUnique<CapsuleParser>(mSession)) {}
|
|
|
|
Http2WebTransportSessionImpl* Session() { return mSession; }
|
|
|
|
void HasCapsuleToSend() override {
|
|
mSession->PrepareCapsulesToSend(mOutCapsules);
|
|
}
|
|
|
|
void SetSentFin() override { mSetSentFinCalled = true; }
|
|
|
|
void StartReading() override { mStartReadingCalled = true; }
|
|
|
|
void OnCapsuleParseFailure(nsresult aError) override {
|
|
mOnParseFailureCalled = true;
|
|
}
|
|
|
|
void ProcessInputCapsules(
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>>&& aCapsules) {
|
|
while (!aCapsules.IsEmpty()) {
|
|
UniquePtr<CapsuleEncoder> capsule = aCapsules.Pop();
|
|
auto buffer = capsule->GetBuffer();
|
|
mParser->ProcessCapsuleData(buffer.Elements(), buffer.Length());
|
|
}
|
|
}
|
|
|
|
void ProcessOutput() {
|
|
mSession->PrepareCapsulesToSend(mOutCapsules);
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>> queue(std::move(mOutCapsules));
|
|
while (!queue.IsEmpty()) {
|
|
UniquePtr<CapsuleEncoder> encoder = queue.Pop();
|
|
auto metadata = encoder->GetStreamMetadata();
|
|
if (metadata) {
|
|
mSession->OnStreamDataSent(StreamId(metadata->mID),
|
|
metadata->mDataSize);
|
|
}
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
}
|
|
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>> GetOutCapsules() {
|
|
return std::move(mOutCapsules);
|
|
}
|
|
|
|
void Done() {
|
|
mParser = nullptr;
|
|
mSession->Close(NS_OK);
|
|
mSession = nullptr;
|
|
}
|
|
|
|
// State tracking
|
|
bool mSetSentFinCalled = false;
|
|
bool mStartReadingCalled = false;
|
|
bool mOnParseFailureCalled = false;
|
|
|
|
private:
|
|
~MockWebTransportClient() = default;
|
|
|
|
RefPtr<Http2WebTransportSessionImpl> mSession;
|
|
UniquePtr<CapsuleParser> mParser;
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>> mOutCapsules;
|
|
};
|
|
|
|
class MockWebTransportServer : public CapsuleParser::Listener {
|
|
public:
|
|
NS_INLINE_DECL_REFCOUNTING(MockWebTransportServer, override)
|
|
|
|
explicit MockWebTransportServer()
|
|
: mParser(MakeUnique<CapsuleParser>(this)) {}
|
|
|
|
bool OnCapsule(Capsule&& aCapsule) override {
|
|
mReceivedCapsules.AppendElement(std::move(aCapsule));
|
|
return true;
|
|
}
|
|
void OnCapsuleParseFailure(nsresult aError) override {
|
|
MOZ_RELEASE_ASSERT(false);
|
|
}
|
|
|
|
nsTArray<Capsule> GetReceivedCapsules() {
|
|
return std::move(mReceivedCapsules);
|
|
}
|
|
|
|
void ProcessInputCapsules(
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>>&& aCapsules) {
|
|
while (!aCapsules.IsEmpty()) {
|
|
UniquePtr<CapsuleEncoder> capsule = aCapsules.Pop();
|
|
auto buffer = capsule->GetBuffer();
|
|
mParser->ProcessCapsuleData(buffer.Elements(), buffer.Length());
|
|
}
|
|
}
|
|
|
|
void SendWebTransportMaxStreamsCapsule(uint64_t aLimit, bool aBidi) {
|
|
Capsule capsule = Capsule::WebTransportMaxStreams(aLimit, aBidi);
|
|
UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
|
|
encoder->EncodeCapsule(capsule);
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
|
|
void SendWebTransportStreamDataCapsule(uint64_t aID, bool aFin,
|
|
nsTArray<uint8_t>&& aData) {
|
|
Capsule capsule =
|
|
Capsule::WebTransportStreamData(aID, aFin, std::move(aData));
|
|
UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
|
|
encoder->EncodeCapsule(capsule);
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
|
|
void SendWebTransportMaxStreamDataCapsule(uint64_t aLimit, uint64_t aID) {
|
|
Capsule capsule = Capsule::WebTransportMaxStreamData(aLimit, aID);
|
|
UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
|
|
encoder->EncodeCapsule(capsule);
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
|
|
void SendWebTransportMaxDataCapsule(uint64_t aLimit) {
|
|
Capsule capsule = Capsule::WebTransportMaxData(aLimit);
|
|
UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
|
|
encoder->EncodeCapsule(capsule);
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
|
|
void SendWebTransportStopSendingCapsule(uint64_t aError, uint64_t aID) {
|
|
Capsule capsule = Capsule::WebTransportStopSending(aError, aID);
|
|
UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
|
|
encoder->EncodeCapsule(capsule);
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
|
|
void SendWebTransportResetStreamCapsule(uint64_t aError, uint64_t aSize,
|
|
uint64_t aID) {
|
|
Capsule capsule = Capsule::WebTransportResetStream(aError, aSize, aID);
|
|
UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
|
|
encoder->EncodeCapsule(capsule);
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
|
|
void SendDatagramCapsule(nsTArray<uint8_t>&& aPayload) {
|
|
Capsule capsule = Capsule::WebTransportDatagram(std::move(aPayload));
|
|
UniquePtr<CapsuleEncoder> encoder = MakeUnique<CapsuleEncoder>();
|
|
encoder->EncodeCapsule(capsule);
|
|
mOutCapsules.Push(std::move(encoder));
|
|
}
|
|
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>> GetOutCapsules() {
|
|
return std::move(mOutCapsules);
|
|
}
|
|
|
|
void Done() { mParser = nullptr; }
|
|
|
|
private:
|
|
~MockWebTransportServer() = default;
|
|
|
|
UniquePtr<CapsuleParser> mParser;
|
|
nsTArray<Capsule> mReceivedCapsules;
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>> mOutCapsules;
|
|
};
|
|
|
|
// TODO: will be used when testing incoming streams.
|
|
class MockWebTransportSessionEventListener
|
|
: public WebTransportSessionEventListener,
|
|
public WebTransportSessionEventListenerInternal {
|
|
public:
|
|
NS_DECL_THREADSAFE_ISUPPORTS
|
|
NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENER
|
|
NS_DECL_WEBTRANSPORTSESSIONEVENTLISTENERINTERNAL
|
|
|
|
MockWebTransportSessionEventListener() {}
|
|
nsTArray<RefPtr<WebTransportStreamBase>> TakeIncomingStreams() {
|
|
return std::move(mIncomingStreams);
|
|
}
|
|
nsTArray<uint8_t> mReceivedDatagrams;
|
|
|
|
Maybe<std::pair<uint64_t, nsresult>> TakeStopSending() {
|
|
return std::move(mStopSending);
|
|
}
|
|
|
|
Maybe<std::pair<uint64_t, nsresult>> TakeReset() { return std::move(mReset); }
|
|
|
|
private:
|
|
virtual ~MockWebTransportSessionEventListener() = default;
|
|
|
|
nsTArray<RefPtr<WebTransportStreamBase>> mIncomingStreams;
|
|
Maybe<std::pair<uint64_t, nsresult>> mStopSending;
|
|
Maybe<std::pair<uint64_t, nsresult>> mReset;
|
|
};
|
|
|
|
NS_IMPL_ISUPPORTS(MockWebTransportSessionEventListener,
|
|
WebTransportSessionEventListener,
|
|
WebTransportSessionEventListenerInternal)
|
|
|
|
NS_IMETHODIMP
|
|
MockWebTransportSessionEventListener::OnSessionReadyInternal(
|
|
WebTransportSessionBase* aSession) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
MockWebTransportSessionEventListener::OnIncomingStreamAvailableInternal(
|
|
WebTransportStreamBase* aStream) {
|
|
mIncomingStreams.AppendElement(RefPtr{aStream});
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
MockWebTransportSessionEventListener::OnIncomingBidirectionalStreamAvailable(
|
|
nsIWebTransportBidirectionalStream* aStream) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
MockWebTransportSessionEventListener::OnIncomingUnidirectionalStreamAvailable(
|
|
nsIWebTransportReceiveStream* aStream) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
MockWebTransportSessionEventListener::OnSessionReady(uint64_t ready) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
MockWebTransportSessionEventListener::OnSessionClosed(
|
|
bool aCleanly, uint32_t aStatus, const nsACString& aReason) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP MockWebTransportSessionEventListener::OnDatagramReceivedInternal(
|
|
nsTArray<uint8_t>&& aData) {
|
|
mReceivedDatagrams = std::move(aData);
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP MockWebTransportSessionEventListener::OnDatagramReceived(
|
|
const nsTArray<uint8_t>& aData) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP MockWebTransportSessionEventListener::OnMaxDatagramSize(
|
|
uint64_t aSize) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
MockWebTransportSessionEventListener::OnOutgoingDatagramOutCome(
|
|
uint64_t aId, WebTransportSessionEventListener::DatagramOutcome aOutCome) {
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP MockWebTransportSessionEventListener::OnStopSending(
|
|
uint64_t aStreamId, nsresult aError) {
|
|
mStopSending = Some(std::pair<uint64_t, nsresult>(aStreamId, aError));
|
|
return NS_OK;
|
|
}
|
|
|
|
NS_IMETHODIMP MockWebTransportSessionEventListener::OnResetReceived(
|
|
uint64_t aStreamId, nsresult aError) {
|
|
mReset = Some(std::pair<uint64_t, nsresult>(aStreamId, aError));
|
|
return NS_OK;
|
|
}
|
|
|
|
static void ServerProcessCapsules(MockWebTransportServer* aServer,
|
|
MockWebTransportClient* aClient) {
|
|
aClient->ProcessOutput();
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>> outCapsules =
|
|
aClient->GetOutCapsules();
|
|
aServer->ProcessInputCapsules(std::move(outCapsules));
|
|
}
|
|
|
|
static void ClientProcessCapsules(MockWebTransportServer* aServer,
|
|
MockWebTransportClient* aClient) {
|
|
mozilla::Queue<UniquePtr<CapsuleEncoder>> outCapsules =
|
|
aServer->GetOutCapsules();
|
|
aClient->ProcessInputCapsules(std::move(outCapsules));
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, CloseSessionCapsule)
|
|
{
|
|
RefPtr<MockWebTransportClient> client =
|
|
new MockWebTransportClient(Http2WebTransportInitialSettings());
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
nsCString reason("test");
|
|
client->Session()->CloseSession(42, "test"_ns);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
CloseWebTransportSessionCapsule& parsedCapsule =
|
|
received[0].GetCloseWebTransportSessionCapsule();
|
|
ASSERT_EQ(parsedCapsule.mStatus, 42u);
|
|
ASSERT_EQ(parsedCapsule.mReason, reason);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, CreateOutgoingStream)
|
|
{
|
|
RefPtr<MockWebTransportClient> client =
|
|
new MockWebTransportClient(Http2WebTransportInitialSettings());
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> bidiStream;
|
|
auto callback =
|
|
[&](Result<RefPtr<WebTransportStreamBase>, nsresult>&& aResult) {
|
|
if (aResult.isErr()) {
|
|
return;
|
|
}
|
|
bidiStream = aResult.unwrap();
|
|
};
|
|
client->Session()->CreateOutgoingBidirectionalStream(std::move(callback));
|
|
ASSERT_TRUE(bidiStream == nullptr);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
// Creating a stream is blocked, we should see a
|
|
// WebTransportStreamsBlockedCapsule from the client.
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamsBlockedCapsule& streamsBlocked =
|
|
received[0].GetWebTransportStreamsBlockedCapsule();
|
|
ASSERT_EQ(streamsBlocked.mLimit, 0u);
|
|
ASSERT_EQ(streamsBlocked.mBidi, true);
|
|
|
|
server->SendWebTransportMaxStreamsCapsule(1, true);
|
|
ClientProcessCapsules(server, client);
|
|
ASSERT_TRUE(bidiStream != nullptr);
|
|
|
|
RefPtr<WebTransportStreamBase> unidiStream;
|
|
auto callback1 =
|
|
[&](Result<RefPtr<WebTransportStreamBase>, nsresult>&& aResult) {
|
|
if (aResult.isErr()) {
|
|
return;
|
|
}
|
|
unidiStream = aResult.unwrap();
|
|
};
|
|
client->Session()->CreateOutgoingUnidirectionalStream(std::move(callback1));
|
|
ASSERT_TRUE(unidiStream == nullptr);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamsBlockedCapsule& streamsBlocked1 =
|
|
received[0].GetWebTransportStreamsBlockedCapsule();
|
|
ASSERT_EQ(streamsBlocked1.mLimit, 0u);
|
|
ASSERT_EQ(streamsBlocked1.mBidi, false);
|
|
|
|
server->SendWebTransportMaxStreamsCapsule(1, false);
|
|
ClientProcessCapsules(server, client);
|
|
ASSERT_TRUE(unidiStream != nullptr);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
static void CreateTestData(uint32_t aNumBytes, nsTArray<uint8_t>& aDataOut) {
|
|
static constexpr const char kSampleText[] =
|
|
"{\"type\":\"message\",\"id\":42,\"payload\":\"The quick brown fox jumps "
|
|
"over the lazy dog.\"}";
|
|
static constexpr uint32_t kSampleTextLen = sizeof(kSampleText) - 1;
|
|
|
|
aDataOut.SetCapacity(aNumBytes);
|
|
|
|
while (aNumBytes > 0) {
|
|
uint32_t chunkSize = std::min(kSampleTextLen, aNumBytes);
|
|
aDataOut.AppendElements(reinterpret_cast<const uint8_t*>(kSampleText),
|
|
chunkSize);
|
|
aNumBytes -= chunkSize;
|
|
}
|
|
}
|
|
|
|
static void ValidateData(nsTArray<uint8_t>& aInput,
|
|
nsTArray<uint8_t>& aExpectedData) {
|
|
ASSERT_EQ(aExpectedData.Length(), aInput.Length());
|
|
for (size_t i = 0; i < aExpectedData.Length(); i++) {
|
|
ASSERT_EQ(aExpectedData[i], aInput[i]);
|
|
}
|
|
}
|
|
|
|
static void ValidateData(nsIInputStream* aStream,
|
|
nsTArray<uint8_t>& aExpectedData) {
|
|
nsTArray<uint8_t> outputData;
|
|
nsresult rv = NS_ConsumeStream(aStream, UINT32_MAX, outputData);
|
|
ASSERT_NS_SUCCEEDED(rv);
|
|
ValidateData(outputData, aExpectedData);
|
|
}
|
|
|
|
static std::pair<nsCOMPtr<nsIAsyncOutputStream>, nsCOMPtr<nsIAsyncInputStream>>
|
|
CreateStreamAndSendData(WebTransportStreamBase* aStream,
|
|
const nsTArray<uint8_t>& aData) {
|
|
nsCOMPtr<nsIAsyncOutputStream> writer;
|
|
nsCOMPtr<nsIAsyncInputStream> reader;
|
|
aStream->GetWriterAndReader(getter_AddRefs(writer), getter_AddRefs(reader));
|
|
|
|
uint32_t numWritten = 0;
|
|
Unused << writer->Write((const char*)aData.Elements(), aData.Length(),
|
|
&numWritten);
|
|
NS_ProcessPendingEvents(nullptr);
|
|
return std::make_pair(writer, reader);
|
|
}
|
|
|
|
static void ValidateStreamCapsule(MockWebTransportServer* aServer,
|
|
nsTArray<uint8_t>& aExpectedData,
|
|
bool aExpectBidi) {
|
|
nsTArray<Capsule> received = aServer->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamDataCapsule& streamData =
|
|
received[0].GetWebTransportStreamDataCapsule();
|
|
StreamId id(streamData.mID);
|
|
ASSERT_TRUE(id.IsClientInitiated());
|
|
ASSERT_EQ(id.IsBiDi(), aExpectBidi);
|
|
ValidateData(streamData.mData, aExpectedData);
|
|
}
|
|
|
|
static already_AddRefed<WebTransportStreamBase> CreateOutgoingStream(
|
|
MockWebTransportClient* aClient, bool aBidi = true) {
|
|
RefPtr<WebTransportStreamBase> stream;
|
|
auto callback =
|
|
[&](Result<RefPtr<WebTransportStreamBase>, nsresult>&& aResult) {
|
|
if (aResult.isErr()) {
|
|
return;
|
|
}
|
|
stream = aResult.unwrap();
|
|
MOZ_RELEASE_ASSERT(stream);
|
|
};
|
|
if (aBidi) {
|
|
aClient->Session()->CreateOutgoingBidirectionalStream(std::move(callback));
|
|
} else {
|
|
aClient->Session()->CreateOutgoingUnidirectionalStream(std::move(callback));
|
|
}
|
|
return stream.forget();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, OutgoingUniStream)
|
|
{
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxData = 1024;
|
|
settings.mInitialMaxStreamsUni = 1;
|
|
settings.mInitialMaxStreamDataUni = 512;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
// Try to create bidi stream (should fail and trigger streams-blocked capsule)
|
|
RefPtr<WebTransportStreamBase> bidiStream;
|
|
client->Session()->CreateOutgoingBidirectionalStream([&](auto&& aResult) {
|
|
if (aResult.isOk()) {
|
|
bidiStream = aResult.unwrap();
|
|
}
|
|
});
|
|
ASSERT_TRUE(bidiStream == nullptr);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
{
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
auto& capsule = received[0].GetWebTransportStreamsBlockedCapsule();
|
|
ASSERT_EQ(capsule.mLimit, 0u);
|
|
ASSERT_TRUE(capsule.mBidi);
|
|
}
|
|
|
|
// Create unidirectional stream and send data
|
|
RefPtr<WebTransportStreamBase> unidiStream =
|
|
CreateOutgoingStream(client, false);
|
|
ASSERT_TRUE(unidiStream != nullptr);
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(512, inputData);
|
|
CreateStreamAndSendData(unidiStream, inputData);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
ValidateStreamCapsule(server, inputData, /* aExpectBidi = */ false);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, OutgoingBidiStream)
|
|
{
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxData = 1024;
|
|
settings.mInitialMaxStreamsUni = 1;
|
|
settings.mInitialMaxStreamsBidi = 1;
|
|
settings.mInitialMaxStreamDataBidi = 512;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(bidiStream != nullptr);
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(512, inputData);
|
|
CreateStreamAndSendData(bidiStream, inputData);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
ValidateStreamCapsule(server, inputData, /* aExpectBidi = */ true);
|
|
|
|
// Echo back from server
|
|
nsTArray<uint8_t> echo;
|
|
echo.AppendElements(inputData.Elements(), inputData.Length());
|
|
StreamId id = StreamId::From(0);
|
|
server->SendWebTransportStreamDataCapsule(id, false, std::move(echo));
|
|
ClientProcessCapsules(server, client);
|
|
|
|
nsCOMPtr<nsIAsyncInputStream> reader;
|
|
nsCOMPtr<nsIAsyncOutputStream> writer;
|
|
bidiStream->GetWriterAndReader(getter_AddRefs(writer),
|
|
getter_AddRefs(reader));
|
|
uint64_t available = 0;
|
|
Unused << reader->Available(&available);
|
|
EXPECT_EQ(available, inputData.Length());
|
|
|
|
ValidateData(reader, inputData);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, IncomingBidiStream)
|
|
{
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialLocalMaxStreamsBidi = 1;
|
|
settings.mInitialLocalMaxStreamDataBidi = 512;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportSessionEventListener> listener =
|
|
new MockWebTransportSessionEventListener();
|
|
client->Session()->SetWebTransportSessionEventListener(listener);
|
|
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(512, inputData);
|
|
nsTArray<uint8_t> cloned(inputData.Clone());
|
|
|
|
server->SendWebTransportStreamDataCapsule(1, false, std::move(cloned));
|
|
|
|
ClientProcessCapsules(server, client);
|
|
|
|
nsTArray<RefPtr<WebTransportStreamBase>> streams =
|
|
listener->TakeIncomingStreams();
|
|
ASSERT_EQ(streams.Length(), 1u);
|
|
|
|
nsCOMPtr<nsIAsyncOutputStream> writer;
|
|
nsCOMPtr<nsIAsyncInputStream> reader;
|
|
RefPtr<WebTransportStreamBase> stream = streams[0];
|
|
stream->GetWriterAndReader(getter_AddRefs(writer), getter_AddRefs(reader));
|
|
|
|
ValidateData(reader, inputData);
|
|
|
|
cloned = inputData.Clone();
|
|
server->SendWebTransportStreamDataCapsule(5, false, std::move(cloned));
|
|
|
|
ClientProcessCapsules(server, client);
|
|
streams = listener->TakeIncomingStreams();
|
|
ASSERT_EQ(streams.Length(), 0u);
|
|
|
|
client->Session()->OnStreamClosed(
|
|
static_cast<Http2WebTransportStream*>(stream.get()));
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
cloned = inputData.Clone();
|
|
server->SendWebTransportStreamDataCapsule(5, false, std::move(cloned));
|
|
|
|
ClientProcessCapsules(server, client);
|
|
streams = listener->TakeIncomingStreams();
|
|
ASSERT_EQ(streams.Length(), 1u);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, StreamDataSenderFlowControl)
|
|
{
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxData = 1024;
|
|
settings.mInitialMaxStreamsBidi = 1;
|
|
settings.mInitialMaxStreamDataBidi = 100;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(bidiStream != nullptr);
|
|
|
|
nsCOMPtr<nsIAsyncOutputStream> writer;
|
|
nsCOMPtr<nsIAsyncInputStream> reader;
|
|
bidiStream->GetWriterAndReader(getter_AddRefs(writer),
|
|
getter_AddRefs(reader));
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(100, inputData);
|
|
uint32_t numWritten = 0;
|
|
Unused << writer->Write((const char*)inputData.Elements(), inputData.Length(),
|
|
&numWritten);
|
|
|
|
NS_ProcessPendingEvents(nullptr);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamDataCapsule& streamData =
|
|
received[0].GetWebTransportStreamDataCapsule();
|
|
|
|
StreamId id(streamData.mID);
|
|
ASSERT_TRUE(id.IsClientInitiated());
|
|
ASSERT_TRUE(id.IsBiDi());
|
|
ValidateData(streamData.mData, inputData);
|
|
|
|
numWritten = 0;
|
|
Unused << writer->Write((const char*)inputData.Elements(), inputData.Length(),
|
|
&numWritten);
|
|
|
|
NS_ProcessPendingEvents(nullptr);
|
|
ServerProcessCapsules(server, client);
|
|
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamDataBlockedCapsule& blocked =
|
|
received[0].GetWebTransportStreamDataBlockedCapsule();
|
|
StreamId receivedId(blocked.mID);
|
|
ASSERT_EQ(id, receivedId);
|
|
ASSERT_EQ(blocked.mLimit, 100u);
|
|
|
|
server->SendWebTransportMaxStreamDataCapsule(300, id);
|
|
ClientProcessCapsules(server, client);
|
|
|
|
Unused << writer->Write((const char*)inputData.Elements(), inputData.Length(),
|
|
&numWritten);
|
|
|
|
NS_ProcessPendingEvents(nullptr);
|
|
ServerProcessCapsules(server, client);
|
|
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamDataCapsule& streamData1 =
|
|
received[0].GetWebTransportStreamDataCapsule();
|
|
ASSERT_EQ(streamData1.mData.Length(), 200u);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, StreamDataSenderFlowControlMaxData)
|
|
{
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxData = 100;
|
|
settings.mInitialMaxStreamsBidi = 1;
|
|
settings.mInitialMaxStreamDataBidi = 100;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(bidiStream != nullptr);
|
|
|
|
nsCOMPtr<nsIAsyncOutputStream> writer;
|
|
nsCOMPtr<nsIAsyncInputStream> reader;
|
|
bidiStream->GetWriterAndReader(getter_AddRefs(writer),
|
|
getter_AddRefs(reader));
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(100, inputData);
|
|
uint32_t numWritten = 0;
|
|
Unused << writer->Write((const char*)inputData.Elements(), inputData.Length(),
|
|
&numWritten);
|
|
|
|
NS_ProcessPendingEvents(nullptr);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamDataCapsule& streamData =
|
|
received[0].GetWebTransportStreamDataCapsule();
|
|
|
|
StreamId id(streamData.mID);
|
|
ASSERT_TRUE(id.IsClientInitiated());
|
|
ASSERT_TRUE(id.IsBiDi());
|
|
ValidateData(streamData.mData, inputData);
|
|
|
|
numWritten = 0;
|
|
Unused << writer->Write((const char*)inputData.Elements(), inputData.Length(),
|
|
&numWritten);
|
|
|
|
NS_ProcessPendingEvents(nullptr);
|
|
ServerProcessCapsules(server, client);
|
|
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 2u);
|
|
|
|
WebTransportDataBlockedCapsule& sessionDataBlocked =
|
|
received[0].GetWebTransportDataBlockedCapsule();
|
|
ASSERT_EQ(sessionDataBlocked.mLimit, 100u);
|
|
|
|
WebTransportStreamDataBlockedCapsule& blocked =
|
|
received[1].GetWebTransportStreamDataBlockedCapsule();
|
|
StreamId receivedId(blocked.mID);
|
|
ASSERT_EQ(id, receivedId);
|
|
ASSERT_EQ(blocked.mLimit, 100u);
|
|
|
|
server->SendWebTransportMaxStreamDataCapsule(500, id);
|
|
ClientProcessCapsules(server, client);
|
|
|
|
Unused << writer->Write((const char*)inputData.Elements(), inputData.Length(),
|
|
&numWritten);
|
|
|
|
NS_ProcessPendingEvents(nullptr);
|
|
ServerProcessCapsules(server, client);
|
|
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 0u);
|
|
|
|
server->SendWebTransportMaxDataCapsule(1024);
|
|
ClientProcessCapsules(server, client);
|
|
|
|
Unused << writer->Write((const char*)inputData.Elements(), inputData.Length(),
|
|
&numWritten);
|
|
|
|
NS_ProcessPendingEvents(nullptr);
|
|
ServerProcessCapsules(server, client);
|
|
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStreamDataCapsule& streamData1 =
|
|
received[0].GetWebTransportStreamDataCapsule();
|
|
ASSERT_EQ(streamData1.mData.Length(), 300u);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
static void CheckFc(ReceiverFlowControlBase& aFc, uint64_t aConsumed,
|
|
uint64_t aRetired) {
|
|
MOZ_RELEASE_ASSERT(aFc.Consumed() == aConsumed);
|
|
MOZ_RELEASE_ASSERT(aFc.Retired() == aRetired);
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, ReceiverFlowControl)
|
|
{
|
|
const uint32_t FC_SIZE = 1024;
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxStreamsBidi = 2;
|
|
settings.mInitialLocalMaxStreamDataBidi = FC_SIZE * 3 / 4;
|
|
settings.mInitialLocalMaxData = FC_SIZE;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> s1 = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(s1 != nullptr);
|
|
|
|
RefPtr<WebTransportStreamBase> s2 = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(s2 != nullptr);
|
|
|
|
CheckFc(client->Session()->ReceiverFc(), 0, 0);
|
|
CheckFc(*s1->ReceiverFc(), 0, 0);
|
|
CheckFc(*s2->ReceiverFc(), 0, 0);
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(FC_SIZE / 4, inputData);
|
|
|
|
StreamId id = StreamId::From(0);
|
|
server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
|
|
|
|
CreateTestData(FC_SIZE / 4, inputData);
|
|
StreamId id1 = StreamId::From(4);
|
|
server->SendWebTransportStreamDataCapsule(id1, false, std::move(inputData));
|
|
|
|
ClientProcessCapsules(server, client);
|
|
|
|
CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
|
|
CheckFc(*s1->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
|
|
CheckFc(*s2->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
|
|
|
|
CreateTestData(FC_SIZE / 4, inputData);
|
|
server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
|
|
|
|
ClientProcessCapsules(server, client);
|
|
|
|
CheckFc(client->Session()->ReceiverFc(), FC_SIZE * 3 / 4, FC_SIZE * 3 / 4);
|
|
CheckFc(*s1->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
|
|
CheckFc(*s2->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, ReceiverFlowControl1)
|
|
{
|
|
const uint32_t FC_SIZE = 1024;
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxStreamsBidi = 1;
|
|
settings.mInitialLocalMaxStreamDataBidi = FC_SIZE / 2;
|
|
settings.mInitialLocalMaxData = FC_SIZE;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> bidiStream = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(bidiStream != nullptr);
|
|
|
|
nsCOMPtr<nsIAsyncOutputStream> writer;
|
|
nsCOMPtr<nsIAsyncInputStream> reader;
|
|
bidiStream->GetWriterAndReader(getter_AddRefs(writer),
|
|
getter_AddRefs(reader));
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(FC_SIZE / 4, inputData);
|
|
|
|
StreamId id = StreamId::From(0);
|
|
server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
|
|
ClientProcessCapsules(server, client);
|
|
|
|
uint64_t available = 0;
|
|
Unused << reader->Available(&available);
|
|
EXPECT_EQ(available, FC_SIZE / 4);
|
|
|
|
nsTArray<uint8_t> outputData;
|
|
nsresult rv = NS_ConsumeStream(reader, UINT32_MAX, outputData);
|
|
ASSERT_NS_SUCCEEDED(rv);
|
|
|
|
CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
|
|
CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 4, FC_SIZE / 4);
|
|
|
|
CreateTestData(1, inputData);
|
|
server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
|
|
ClientProcessCapsules(server, client);
|
|
|
|
CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 4 + 1, FC_SIZE / 4 + 1);
|
|
CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 4 + 1, FC_SIZE / 4 + 1);
|
|
|
|
available = 0;
|
|
Unused << reader->Available(&available);
|
|
EXPECT_EQ(available, 1u);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportMaxStreamDataCapsule& capsule =
|
|
received[0].GetWebTransportMaxStreamDataCapsule();
|
|
ASSERT_EQ(capsule.mID, 0u);
|
|
ASSERT_EQ(capsule.mLimit, FC_SIZE * 3 / 4 + 1);
|
|
|
|
CreateTestData(FC_SIZE / 4 - 1, inputData);
|
|
server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
|
|
ClientProcessCapsules(server, client);
|
|
|
|
CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
|
|
CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 2, FC_SIZE / 2);
|
|
|
|
CreateTestData(1, inputData);
|
|
server->SendWebTransportStreamDataCapsule(id, false, std::move(inputData));
|
|
ClientProcessCapsules(server, client);
|
|
|
|
CheckFc(client->Session()->ReceiverFc(), FC_SIZE / 2 + 1, FC_SIZE / 2 + 1);
|
|
CheckFc(*bidiStream->ReceiverFc(), FC_SIZE / 2 + 1, FC_SIZE / 2 + 1);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportMaxDataCapsule& maxData =
|
|
received[0].GetWebTransportMaxDataCapsule();
|
|
ASSERT_EQ(maxData.mMaxDataSize, FC_SIZE * 3 / 2 + 1);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, StreamStopSending)
|
|
{
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxStreamsUni = 1;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> uniStream =
|
|
CreateOutgoingStream(client, false);
|
|
ASSERT_TRUE(uniStream != nullptr);
|
|
|
|
uniStream->SendStopSending(0);
|
|
ServerProcessCapsules(server, client);
|
|
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportStopSendingCapsule& stopSending =
|
|
received[0].GetWebTransportStopSendingCapsule();
|
|
ASSERT_EQ(stopSending.mID, uniStream->WebTransportStreamId());
|
|
ASSERT_EQ(stopSending.mErrorCode, 0u);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, StreamOnStopSending)
|
|
{
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxStreamsUni = 1;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportSessionEventListener> listener =
|
|
new MockWebTransportSessionEventListener();
|
|
client->Session()->SetWebTransportSessionEventListener(listener);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> uniStream =
|
|
CreateOutgoingStream(client, false);
|
|
ASSERT_TRUE(uniStream != nullptr);
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(512, inputData);
|
|
CreateStreamAndSendData(uniStream, inputData);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
server->SendWebTransportStopSendingCapsule(0,
|
|
uniStream->WebTransportStreamId());
|
|
ClientProcessCapsules(server, client);
|
|
|
|
auto stopSending = listener->TakeStopSending();
|
|
ASSERT_TRUE(stopSending);
|
|
ASSERT_EQ(stopSending->first, uniStream->WebTransportStreamId());
|
|
ASSERT_EQ(stopSending->second, NS_ERROR_WEBTRANSPORT_CODE_BASE);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, StreamReset)
|
|
{
|
|
const uint32_t TOTAL_SIZE = 1024;
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxStreamsBidi = 1;
|
|
settings.mInitialMaxStreamDataBidi = TOTAL_SIZE;
|
|
settings.mInitialMaxData = TOTAL_SIZE;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportSessionEventListener> listener =
|
|
new MockWebTransportSessionEventListener();
|
|
client->Session()->SetWebTransportSessionEventListener(listener);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> stream = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(stream != nullptr);
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(TOTAL_SIZE / 4, inputData);
|
|
CreateStreamAndSendData(stream, inputData);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
inputData.Clear();
|
|
CreateTestData(TOTAL_SIZE / 4, inputData);
|
|
CreateStreamAndSendData(stream, inputData);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 2u);
|
|
|
|
stream->Reset(0);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
received = server->GetReceivedCapsules();
|
|
ASSERT_EQ(received.Length(), 1u);
|
|
|
|
WebTransportResetStreamCapsule& reset =
|
|
received[0].GetWebTransportResetStreamCapsule();
|
|
ASSERT_EQ(reset.mID, stream->WebTransportStreamId());
|
|
ASSERT_EQ(reset.mErrorCode, 0u);
|
|
ASSERT_EQ(reset.mReliableSize, TOTAL_SIZE / 2);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, StreamResetReliableSize)
|
|
{
|
|
const uint32_t TOTAL_SIZE = 1024;
|
|
Http2WebTransportInitialSettings settings;
|
|
settings.mInitialMaxStreamsBidi = 1;
|
|
settings.mInitialMaxStreamDataBidi = TOTAL_SIZE;
|
|
settings.mInitialMaxData = TOTAL_SIZE;
|
|
RefPtr<MockWebTransportClient> client = new MockWebTransportClient(settings);
|
|
RefPtr<MockWebTransportSessionEventListener> listener =
|
|
new MockWebTransportSessionEventListener();
|
|
client->Session()->SetWebTransportSessionEventListener(listener);
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
|
|
RefPtr<WebTransportStreamBase> stream = CreateOutgoingStream(client);
|
|
ASSERT_TRUE(stream != nullptr);
|
|
|
|
nsTArray<uint8_t> inputData;
|
|
CreateTestData(TOTAL_SIZE / 4, inputData);
|
|
auto streams = CreateStreamAndSendData(stream, inputData);
|
|
|
|
ServerProcessCapsules(server, client);
|
|
|
|
server->SendWebTransportStreamDataCapsule(stream->WebTransportStreamId(),
|
|
false, std::move(inputData));
|
|
CreateTestData(TOTAL_SIZE / 4, inputData);
|
|
server->SendWebTransportStreamDataCapsule(stream->WebTransportStreamId(),
|
|
false, std::move(inputData));
|
|
|
|
server->SendWebTransportResetStreamCapsule(0, TOTAL_SIZE / 2,
|
|
stream->WebTransportStreamId());
|
|
ClientProcessCapsules(server, client);
|
|
|
|
auto reset = listener->TakeReset();
|
|
ASSERT_TRUE(reset);
|
|
ASSERT_EQ(reset->first, stream->WebTransportStreamId());
|
|
ASSERT_EQ(reset->second, NS_ERROR_WEBTRANSPORT_CODE_BASE);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|
|
|
|
TEST(TestHttp2WebTransport, SendAndReceiveDatagram)
|
|
{
|
|
RefPtr<MockWebTransportClient> client =
|
|
new MockWebTransportClient(Http2WebTransportInitialSettings());
|
|
RefPtr<MockWebTransportServer> server = new MockWebTransportServer();
|
|
RefPtr<MockWebTransportSessionEventListener> listener =
|
|
new MockWebTransportSessionEventListener();
|
|
client->Session()->SetWebTransportSessionEventListener(listener);
|
|
|
|
nsTArray<uint8_t> mockData, expectedData;
|
|
CreateTestData(512, mockData);
|
|
expectedData.AppendElements(mockData);
|
|
|
|
// Send datagram from client to server
|
|
client->Session()->SendDatagram(std::move(mockData), 1);
|
|
ServerProcessCapsules(server, client);
|
|
|
|
// Verify the server received the correct datagram capsule
|
|
nsTArray<Capsule> received = server->GetReceivedCapsules();
|
|
WebTransportDatagramCapsule& parsedCapsule =
|
|
received[0].GetWebTransportDatagramCapsule();
|
|
ValidateData(parsedCapsule.mPayload, expectedData);
|
|
|
|
// Echo and verify the received datagram payload back to the client
|
|
server->SendDatagramCapsule(std::move(parsedCapsule.mPayload));
|
|
ClientProcessCapsules(server, client);
|
|
ValidateData(listener->mReceivedDatagrams, expectedData);
|
|
|
|
client->Done();
|
|
server->Done();
|
|
}
|