Bug 2007202: Make a scriptable interface for WebTransport stats data for xpcshell tests r=necko-reviewers,valentin
Differential Revision: https://phabricator.services.mozilla.com/D324954
This commit is contained in:
committed by
rjesup@mozilla.com
parent
dd81880e29
commit
11452663c1
@@ -675,12 +675,16 @@ NS_IMETHODIMP
|
||||
WebTransportParent::OnSessionClosed(const bool aCleanly,
|
||||
const uint32_t aErrorCode,
|
||||
const nsACString& aReason,
|
||||
WebTransportStatsData* aStats) {
|
||||
nsIWebTransportSessionStats* aStats) {
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
MOZ_ASSERT(mOwningEventTarget);
|
||||
MOZ_ASSERT(!mOwningEventTarget->IsOnCurrentThread());
|
||||
|
||||
WebTransportStatsData* rawStats = nullptr;
|
||||
MOZ_ALWAYS_SUCCEEDS(aStats->GetRawStats(&rawStats));
|
||||
MOZ_ASSERT(rawStats);
|
||||
|
||||
// currently we just know if session was closed gracefully or not.
|
||||
// we need better error propagation from lower-levels of http3
|
||||
// webtransport session and it's subsequent error mapping to DOM.
|
||||
@@ -714,7 +718,7 @@ WebTransportParent::OnSessionClosed(const bool aCleanly,
|
||||
LOG(("[%p] NotifyRemoteClosed to be called later", this));
|
||||
// NotifyRemoteClosed needs to wait until mResolver is invoked.
|
||||
mExecuteAfterResolverCallback = [self = RefPtr{this}, aCleanly,
|
||||
aErrorCode, statsData = *aStats,
|
||||
aErrorCode, statsData = *rawStats,
|
||||
reason = nsCString{aReason}]() {
|
||||
self->NotifyRemoteClosed(aCleanly, aErrorCode, reason, statsData);
|
||||
};
|
||||
@@ -726,7 +730,7 @@ WebTransportParent::OnSessionClosed(const bool aCleanly,
|
||||
// stream associated with the CONNECT request that initiated
|
||||
// transport.[[Session]] is in the "Data Recvd" state. [QUIC]
|
||||
// XXX not calculated yet
|
||||
NotifyRemoteClosed(aCleanly, aErrorCode, aReason, *aStats);
|
||||
NotifyRemoteClosed(aCleanly, aErrorCode, aReason, *rawStats);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@@ -998,15 +1002,19 @@ NS_IMETHODIMP WebTransportParent::OnMaxDatagramSize(uint64_t aSize) {
|
||||
// duration of this synchronous call, or null if stats could not be gathered.
|
||||
// We copy the data into the resolver before returning.
|
||||
NS_IMETHODIMP WebTransportParent::OnStatsAvailable(
|
||||
WebTransportStatsData* aStats) {
|
||||
nsIWebTransportSessionStats* aStats) {
|
||||
MOZ_ASSERT(mSocketThread->IsOnCurrentThread());
|
||||
WebTransportStatsData* rawStats = nullptr;
|
||||
if (aStats) {
|
||||
MOZ_ALWAYS_SUCCEEDS(aStats->GetRawStats(&rawStats));
|
||||
}
|
||||
if (rawStats) {
|
||||
LOG(
|
||||
("Stats available: bytesSent=%llu, bytesReceived=%llu, minRtt=%f, "
|
||||
"smoothedRtt=%f",
|
||||
(unsigned long long)aStats->bytesSent(),
|
||||
(unsigned long long)aStats->bytesReceived(), aStats->minRtt(),
|
||||
aStats->smoothedRtt()));
|
||||
(unsigned long long)rawStats->bytesSent(),
|
||||
(unsigned long long)rawStats->bytesReceived(), rawStats->minRtt(),
|
||||
rawStats->smoothedRtt()));
|
||||
} else {
|
||||
LOG(("Stats unavailable"));
|
||||
}
|
||||
@@ -1018,7 +1026,7 @@ NS_IMETHODIMP WebTransportParent::OnStatsAvailable(
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
ResolvePendingGetStats(aStats ? Some(*aStats) : Nothing());
|
||||
ResolvePendingGetStats(rawStats ? Some(*rawStats) : Nothing());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,9 @@ void Http2WebTransportSessionImpl::GetStats() {
|
||||
// so getStats()'s Promise settles instead of staying pending forever.
|
||||
if (RefPtr<WebTransportSessionEventListener> listener = GetListener()) {
|
||||
mozilla::dom::WebTransportStatsData stats;
|
||||
listener->OnStatsAvailable(&stats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(stats);
|
||||
listener->OnStatsAvailable(statsWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -338,7 +338,9 @@ void Http3WebTransportSession::Close(nsresult aResult) {
|
||||
LOG(("Http3WebTransportSession::Close %p", this));
|
||||
if (RefPtr<WebTransportSessionEventListener> listener = TakeListener()) {
|
||||
mozilla::dom::WebTransportStatsData emptyStats;
|
||||
listener->OnSessionClosed(NS_SUCCEEDED(aResult), 0, ""_ns, &emptyStats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(emptyStats);
|
||||
listener->OnSessionClosed(NS_SUCCEEDED(aResult), 0, ""_ns, statsWrapper);
|
||||
}
|
||||
if (mTransaction) {
|
||||
mTransaction->Close(aResult);
|
||||
@@ -379,7 +381,9 @@ void Http3WebTransportSession::OnSessionClosed(bool aCleanly, uint32_t aStatus,
|
||||
}
|
||||
if (RefPtr<WebTransportSessionEventListener> listener = TakeListener()) {
|
||||
// Use cached stats captured at close time
|
||||
listener->OnSessionClosed(aCleanly, aStatus, aReason, &mCachedStats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(mCachedStats);
|
||||
listener->OnSessionClosed(aCleanly, aStatus, aReason, statsWrapper);
|
||||
}
|
||||
mRecvState = RECV_DONE;
|
||||
mSendState = SEND_DONE;
|
||||
@@ -410,7 +414,9 @@ void Http3WebTransportSession::CloseSession(uint32_t aStatus,
|
||||
// Notify listener with cached stats before clearing it
|
||||
RefPtr<WebTransportSessionEventListener> listener = GetListener();
|
||||
if (listener) {
|
||||
listener->OnSessionClosed(true, mStatus, mReason, &mCachedStats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(mCachedStats);
|
||||
listener->OnSessionClosed(true, mStatus, mReason, statsWrapper);
|
||||
}
|
||||
|
||||
mSession->ConnectSlowConsumer(this);
|
||||
@@ -624,7 +630,9 @@ void Http3WebTransportSession::GetStats() {
|
||||
return;
|
||||
}
|
||||
|
||||
listener->OnStatsAvailable(&stats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(stats);
|
||||
listener->OnStatsAvailable(statsWrapper);
|
||||
}
|
||||
|
||||
void Http3WebTransportSession::GetNegotiatedProtocol(nsACString& aProtocol) {
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
namespace mozilla::net {
|
||||
|
||||
NS_IMPL_ISUPPORTS(WebTransportSessionStatsWrapper, nsIWebTransportSessionStats)
|
||||
|
||||
NS_IMETHODIMP WebTransportSessionStatsWrapper::GetRawStats(
|
||||
mozilla::dom::WebTransportStatsData** aStats) {
|
||||
*aStats = &mStats;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void WebTransportSessionBase::SetWebTransportSessionEventListener(
|
||||
WebTransportSessionEventListener* listener) {
|
||||
MutexAutoLock lock(mListenerLock);
|
||||
|
||||
@@ -8,7 +8,9 @@
|
||||
#include <functional>
|
||||
|
||||
#include "mozilla/Mutex.h"
|
||||
#include "mozilla/dom/PWebTransport.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsIWebTransport.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class WebTransportSessionEventListener;
|
||||
@@ -18,6 +20,27 @@ namespace mozilla::net {
|
||||
class WebTransportStreamBase;
|
||||
class Http3WebTransportSession;
|
||||
|
||||
// Wraps a WebTransportStatsData snapshot so it can be passed through the
|
||||
// scriptable WebTransportSessionEventListener::OnSessionClosed/
|
||||
// OnStatsAvailable methods; the raw data itself is only accessible to
|
||||
// native (C++) consumers via the noscript GetRawStats().
|
||||
class WebTransportSessionStatsWrapper final
|
||||
: public nsIWebTransportSessionStats {
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
explicit WebTransportSessionStatsWrapper(
|
||||
const mozilla::dom::WebTransportStatsData& aStats)
|
||||
: mStats(aStats) {}
|
||||
|
||||
NS_IMETHOD GetRawStats(mozilla::dom::WebTransportStatsData** aStats) override;
|
||||
|
||||
private:
|
||||
~WebTransportSessionStatsWrapper() = default;
|
||||
|
||||
mozilla::dom::WebTransportStatsData mStats;
|
||||
};
|
||||
|
||||
class WebTransportSessionBase {
|
||||
public:
|
||||
NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
|
||||
|
||||
@@ -102,8 +102,11 @@ nsresult WebTransportSessionProxy::AsyncConnectWithClient(
|
||||
auto cleanup = MakeScopeExit([self = RefPtr<WebTransportSessionProxy>(this)] {
|
||||
MutexAutoLock lock(self->mMutex);
|
||||
mozilla::dom::WebTransportStatsData stats; // Zero-initialized
|
||||
self->mListener->OnSessionClosed(false, 0, ""_ns,
|
||||
&stats); // TODO: find a better error.
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(stats);
|
||||
self->mListener->OnSessionClosed(
|
||||
false, 0, ""_ns,
|
||||
statsWrapper); // TODO: find a better error.
|
||||
self->mChannel = nullptr;
|
||||
self->mListener = nullptr;
|
||||
self->ChangeState(WebTransportSessionProxyState::DONE);
|
||||
@@ -385,7 +388,9 @@ WebTransportSessionProxy::GetStats() {
|
||||
|
||||
// If we're using cached stats, call OnStatsAvailable directly
|
||||
if (useCachedStats) {
|
||||
return OnStatsAvailable(&cachedStats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(cachedStats);
|
||||
return OnStatsAvailable(statsWrapper);
|
||||
}
|
||||
|
||||
if (!OnSocketThread()) {
|
||||
@@ -868,7 +873,9 @@ WebTransportSessionProxy::OnStartRequest(nsIRequest* aRequest) {
|
||||
}
|
||||
if (listener) {
|
||||
mozilla::dom::WebTransportStatsData stats; // Zero-initialized
|
||||
listener->OnSessionClosed(false, closeStatus, reason, &stats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(stats);
|
||||
listener->OnSessionClosed(false, closeStatus, reason, statsWrapper);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -954,9 +961,12 @@ WebTransportSessionProxy::OnStopRequest(nsIRequest* aRequest,
|
||||
listener->OnSessionReady(sessionId);
|
||||
} else {
|
||||
mozilla::dom::WebTransportStatsData stats; // Zero-initialized
|
||||
listener->OnSessionClosed(false, closeStatus, reason,
|
||||
&stats); // TODO: find a better error.
|
||||
// Currently error code 0 is used.
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(stats);
|
||||
listener->OnSessionClosed(
|
||||
false, closeStatus, reason,
|
||||
statsWrapper); // TODO: find a better error.
|
||||
// Currently error code 0 is used.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1208,9 +1218,9 @@ WebTransportSessionProxy::OnSessionReady(uint64_t ready) {
|
||||
// duration of this synchronous call. We copy the data immediately to cache it
|
||||
// and when capturing it in lambdas for deferred execution.
|
||||
NS_IMETHODIMP
|
||||
WebTransportSessionProxy::OnSessionClosed(
|
||||
bool aCleanly, uint32_t aStatus, const nsACString& aReason,
|
||||
mozilla::dom::WebTransportStatsData* aStats) {
|
||||
WebTransportSessionProxy::OnSessionClosed(bool aCleanly, uint32_t aStatus,
|
||||
const nsACString& aReason,
|
||||
nsIWebTransportSessionStats* aStats) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
MutexAutoLock lock(mMutex);
|
||||
LOG(
|
||||
@@ -1218,10 +1228,14 @@ WebTransportSessionProxy::OnSessionClosed(
|
||||
"mStopRequestCalled=%d",
|
||||
this, mState, mStopRequestCalled));
|
||||
|
||||
mozilla::dom::WebTransportStatsData* rawStats = nullptr;
|
||||
MOZ_ALWAYS_SUCCEEDS(aStats->GetRawStats(&rawStats));
|
||||
MOZ_ASSERT(rawStats);
|
||||
|
||||
// Cache stats (spec requirement for GetStats after close)
|
||||
if (!mHasCachedStats) {
|
||||
mHasCachedStats = true;
|
||||
mCachedStats = *aStats;
|
||||
mCachedStats = *rawStats;
|
||||
}
|
||||
|
||||
// Since OnSessionReady on the listener is called on the main thread,
|
||||
@@ -1232,8 +1246,10 @@ WebTransportSessionProxy::OnSessionClosed(
|
||||
mPendingEvents.AppendElement([self = RefPtr{this}, status(aStatus),
|
||||
closeReason(std::move(closeReason)),
|
||||
cleanly(aCleanly),
|
||||
stats = *aStats]() mutable {
|
||||
(void)self->OnSessionClosed(cleanly, status, closeReason, &stats);
|
||||
stats = *rawStats]() mutable {
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(stats);
|
||||
(void)self->OnSessionClosed(cleanly, status, closeReason, statsWrapper);
|
||||
});
|
||||
return NS_OK;
|
||||
}
|
||||
@@ -1305,8 +1321,9 @@ void WebTransportSessionProxy::OnStatsAvailableInternal(
|
||||
return;
|
||||
}
|
||||
if (aStats) {
|
||||
mozilla::dom::WebTransportStatsData stats = *aStats;
|
||||
listener->OnStatsAvailable(&stats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(*aStats);
|
||||
listener->OnStatsAvailable(statsWrapper);
|
||||
} else {
|
||||
listener->OnStatsAvailable(nullptr);
|
||||
}
|
||||
@@ -1314,20 +1331,24 @@ void WebTransportSessionProxy::OnStatsAvailableInternal(
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebTransportSessionProxy::OnStatsAvailable(
|
||||
mozilla::dom::WebTransportStatsData* aStats) {
|
||||
nsIWebTransportSessionStats* aStats) {
|
||||
MOZ_ASSERT(OnSocketThread(), "not on socket thread");
|
||||
mozilla::dom::WebTransportStatsData* rawStats = nullptr;
|
||||
if (aStats) {
|
||||
MOZ_ALWAYS_SUCCEEDS(aStats->GetRawStats(&rawStats));
|
||||
}
|
||||
if (rawStats) {
|
||||
LOG(("WebTransportSessionProxy::OnStatsAvailable %p - bytesSent=%" PRIu64
|
||||
", bytesReceived=%" PRIu64 ", minRtt=%f, smoothedRtt=%f",
|
||||
this, aStats->bytesSent(), aStats->bytesReceived(), aStats->minRtt(),
|
||||
aStats->smoothedRtt()));
|
||||
this, rawStats->bytesSent(), rawStats->bytesReceived(),
|
||||
rawStats->minRtt(), rawStats->smoothedRtt()));
|
||||
} else {
|
||||
LOG(("WebTransportSessionProxy::OnStatsAvailable %p - stats unavailable",
|
||||
this));
|
||||
}
|
||||
|
||||
Maybe<mozilla::dom::WebTransportStatsData> stats =
|
||||
aStats ? Some(*aStats) : Nothing();
|
||||
rawStats ? Some(*rawStats) : Nothing();
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
@@ -1336,9 +1357,9 @@ WebTransportSessionProxy::OnStatsAvailable(
|
||||
// the socket thread here.
|
||||
MOZ_ASSERT(mTarget->IsOnCurrentThread());
|
||||
// Cache stats for use after connection is closed (spec requirement).
|
||||
if (aStats) {
|
||||
if (rawStats) {
|
||||
mHasCachedStats = true;
|
||||
mCachedStats = *aStats;
|
||||
mCachedStats = *rawStats;
|
||||
}
|
||||
if (!mTarget->IsOnCurrentThread()) {
|
||||
return mTarget->Dispatch(
|
||||
@@ -1402,7 +1423,9 @@ void WebTransportSessionProxy::CallOnSessionClosed() MOZ_REQUIRES(mMutex) {
|
||||
if (listener) {
|
||||
// Don't invoke the callback under the lock.
|
||||
MutexAutoUnlock unlock(mMutex);
|
||||
listener->OnSessionClosed(cleanly, closeStatus, reason, &stats);
|
||||
nsCOMPtr<nsIWebTransportSessionStats> statsWrapper =
|
||||
new WebTransportSessionStatsWrapper(stats);
|
||||
listener->OnSessionClosed(cleanly, closeStatus, reason, statsWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -106,16 +106,24 @@ interface nsIWebTransport : nsISupports {
|
||||
[noscript] void retargetTo(in nsIEventTarget aTarget);
|
||||
};
|
||||
|
||||
// Wraps a WebTransportStatsData snapshot so it can be passed through a
|
||||
// scriptable interface. The raw data is only accessible to native (C++)
|
||||
// consumers, since WebTransportStatsData itself is not scriptable.
|
||||
[builtinclass, scriptable, uuid(bd8549d7-002f-4032-96a4-19430399d081)]
|
||||
interface nsIWebTransportSessionStats : nsISupports {
|
||||
[noscript] readonly attribute WebTransportStatsDataPtr rawStats;
|
||||
};
|
||||
|
||||
// Events related to a WebTransport session.
|
||||
[scriptable, uuid(0e3cb269-f318-43c8-959e-897f57894b71)]
|
||||
interface WebTransportSessionEventListener : nsISupports {
|
||||
// This is used to let the consumer of nsIWebTransport know that the
|
||||
// underlying WebTransportSession object is ready to use.
|
||||
void onSessionReady(in uint64_t aSessionId);
|
||||
[noscript] void onSessionClosed(in boolean aCleanly,
|
||||
in uint32_t aErrorCode,
|
||||
in ACString aReason,
|
||||
in WebTransportStatsDataPtr aStats);
|
||||
void onSessionClosed(in boolean aCleanly,
|
||||
in uint32_t aErrorCode,
|
||||
in ACString aReason,
|
||||
in nsIWebTransportSessionStats aStats);
|
||||
void onDraining();
|
||||
|
||||
// When a new stream has been received.
|
||||
@@ -141,7 +149,7 @@ interface WebTransportSessionEventListener : nsISupports {
|
||||
in WebTransportSessionEventListener_DatagramOutcome aOutCome);
|
||||
|
||||
// aStats is null if stats could not be gathered for this session.
|
||||
[noscript] void onStatsAvailable(in WebTransportStatsDataPtr aStats);
|
||||
void onStatsAvailable(in nsIWebTransportSessionStats aStats);
|
||||
};
|
||||
|
||||
[uuid(8fb30aa9-5163-4eb3-81f3-371e1ccb5b0e)]
|
||||
|
||||
@@ -251,7 +251,7 @@ MockWebTransportSessionEventListener::OnSessionReady(uint64_t ready) {
|
||||
NS_IMETHODIMP
|
||||
MockWebTransportSessionEventListener::OnSessionClosed(
|
||||
bool aCleanly, uint32_t aStatus, const nsACString& aReason,
|
||||
mozilla::dom::WebTransportStatsData* aStats) {
|
||||
nsIWebTransportSessionStats* aStats) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ NS_IMETHODIMP MockWebTransportSessionEventListener::OnResetReceived(
|
||||
}
|
||||
|
||||
NS_IMETHODIMP MockWebTransportSessionEventListener::OnStatsAvailable(
|
||||
mozilla::dom::WebTransportStatsData* aStats) {
|
||||
nsIWebTransportSessionStats* aStats) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user