mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 21:01:08 +00:00
Bug 1713748 - Partition WebSocket nsWSAdmissionManager queue. r=timhuang,nhnt11
Differential Revision: https://phabricator.services.mozilla.com/D119534
This commit is contained in:
parent
a5e65da4cb
commit
f97e49d85c
@ -537,7 +537,7 @@ var PushServiceWebSocket = {
|
||||
try {
|
||||
// Grab a wakelock before we open the socket to ensure we don't go to
|
||||
// sleep before connection the is opened.
|
||||
this._ws.asyncOpen(uri, uri.spec, 0, this._wsListener, null);
|
||||
this._ws.asyncOpen(uri, uri.spec, {}, 0, this._wsListener, null);
|
||||
this._currentState = STATE_WAITING_FOR_WS_START;
|
||||
} catch (e) {
|
||||
console.error(
|
||||
|
@ -42,7 +42,7 @@ MockWebSocketParent.prototype = {
|
||||
return this._originalURI;
|
||||
},
|
||||
|
||||
asyncOpen(uri, origin, windowId, listener, context) {
|
||||
asyncOpen(uri, origin, originAttributes, windowId, listener, context) {
|
||||
this._listener = listener;
|
||||
this._context = context;
|
||||
waterfall(() => this._listener.onStart(this._context));
|
||||
|
@ -250,7 +250,7 @@ MockWebSocket.prototype = {
|
||||
return this._originalURI;
|
||||
},
|
||||
|
||||
asyncOpen(uri, origin, windowId, listener, context) {
|
||||
asyncOpen(uri, origin, originAttributes, windowId, listener, context) {
|
||||
this._listener = listener;
|
||||
this._context = context;
|
||||
waterfall(() => this._listener.onStart(this._context));
|
||||
|
@ -1213,7 +1213,7 @@ class AsyncOpenRunnable final : public WebSocketMainThreadRunnable {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> principal = doc->NodePrincipal();
|
||||
nsCOMPtr<nsIPrincipal> principal = doc->PartitionedPrincipal();
|
||||
if (!principal) {
|
||||
mErrorCode = NS_ERROR_FAILURE;
|
||||
return true;
|
||||
@ -1233,8 +1233,9 @@ class AsyncOpenRunnable final : public WebSocketMainThreadRunnable {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aTopLevelWorkerPrivate && !aTopLevelWorkerPrivate->GetWindow());
|
||||
|
||||
mErrorCode = mImpl->AsyncOpen(aTopLevelWorkerPrivate->GetPrincipal(), 0,
|
||||
nullptr, ""_ns, nullptr);
|
||||
mErrorCode =
|
||||
mImpl->AsyncOpen(aTopLevelWorkerPrivate->GetPartitionedPrincipal(), 0,
|
||||
nullptr, ""_ns, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1256,6 +1257,7 @@ already_AddRefed<WebSocket> WebSocket::ConstructorCommon(
|
||||
const nsACString& aNegotiatedExtensions, ErrorResult& aRv) {
|
||||
MOZ_ASSERT_IF(!aTransportProvider, aNegotiatedExtensions.IsEmpty());
|
||||
nsCOMPtr<nsIPrincipal> principal;
|
||||
nsCOMPtr<nsIPrincipal> partitionedPrincipal;
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
if (NS_WARN_IF(!global)) {
|
||||
@ -1272,7 +1274,8 @@ already_AddRefed<WebSocket> WebSocket::ConstructorCommon(
|
||||
}
|
||||
|
||||
principal = scriptPrincipal->GetPrincipal();
|
||||
if (!principal) {
|
||||
partitionedPrincipal = scriptPrincipal->PartitionedPrincipal();
|
||||
if (!principal || !partitionedPrincipal) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
@ -1420,6 +1423,7 @@ already_AddRefed<WebSocket> WebSocket::ConstructorCommon(
|
||||
|
||||
if (NS_IsMainThread()) {
|
||||
MOZ_ASSERT(principal);
|
||||
MOZ_ASSERT(partitionedPrincipal);
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> ownerWindow = do_QueryInterface(global);
|
||||
|
||||
@ -1437,8 +1441,9 @@ already_AddRefed<WebSocket> WebSocket::ConstructorCommon(
|
||||
}
|
||||
}
|
||||
|
||||
aRv = webSocket->mImpl->AsyncOpen(principal, windowID, aTransportProvider,
|
||||
aNegotiatedExtensions, std::move(stack));
|
||||
aRv = webSocket->mImpl->AsyncOpen(partitionedPrincipal, windowID,
|
||||
aTransportProvider, aNegotiatedExtensions,
|
||||
std::move(stack));
|
||||
} else {
|
||||
MOZ_ASSERT(!aTransportProvider && aNegotiatedExtensions.IsEmpty(),
|
||||
"not yet implemented");
|
||||
@ -1748,7 +1753,9 @@ nsresult WebSocketImpl::AsyncOpen(
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
rv = mChannel->AsyncOpen(uri, asciiOrigin, aInnerWindowID, this, nullptr);
|
||||
rv = mChannel->AsyncOpenNative(uri, asciiOrigin,
|
||||
aPrincipal->OriginAttributesRef(),
|
||||
aInnerWindowID, this, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return NS_ERROR_CONTENT_BLOCKED;
|
||||
}
|
||||
|
@ -716,6 +716,11 @@ class WorkerPrivate final : public RelativeTimeline {
|
||||
return mLoadInfo.mLoadingPrincipal;
|
||||
}
|
||||
|
||||
nsIPrincipal* GetPartitionedPrincipal() const {
|
||||
AssertIsOnMainThread();
|
||||
return mLoadInfo.mPartitionedPrincipal;
|
||||
}
|
||||
|
||||
const nsAString& OriginNoSuffix() const { return mLoadInfo.mOriginNoSuffix; }
|
||||
|
||||
const nsACString& Origin() const { return mLoadInfo.mOrigin; }
|
||||
|
@ -10445,6 +10445,12 @@
|
||||
value: false
|
||||
mirror: always
|
||||
|
||||
# Partition the websocket pending connection queue by OriginAttributes.
|
||||
- name: privacy.partition.network_state.ws_connection_queue
|
||||
type: RelaxedAtomicBool
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
# The global switch to control the URL query sting stripping which strips query
|
||||
# parameters from loading URIs to prevent bounce (redirect) tracking.
|
||||
- name: privacy.query_stripping.enabled
|
||||
|
@ -29,6 +29,7 @@ parent:
|
||||
// Forwarded methods corresponding to methods on nsIWebSocketChannel
|
||||
async AsyncOpen(nsIURI aURI,
|
||||
nsCString aOrigin,
|
||||
OriginAttributes aOriginAttributes,
|
||||
uint64_t aInnerWindowID,
|
||||
nsCString aProtocol,
|
||||
bool aSecure,
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/MathAlgorithms.h"
|
||||
#include "mozilla/StaticPrefs_privacy.h"
|
||||
#include "mozilla/Utf8.h"
|
||||
#include "mozilla/net/WebSocketEventService.h"
|
||||
|
||||
@ -317,10 +318,11 @@ class nsWSAdmissionManager {
|
||||
|
||||
// If there is already another WS channel connecting to this IP address,
|
||||
// defer BeginOpen and mark as waiting in queue.
|
||||
bool found = (sManager->IndexOf(ws->mAddress) >= 0);
|
||||
bool found = (sManager->IndexOf(ws->mAddress, ws->mOriginSuffix) >= 0);
|
||||
|
||||
// Always add ourselves to queue, even if we'll connect immediately
|
||||
UniquePtr<nsOpenConn> newdata(new nsOpenConn(ws->mAddress, ws));
|
||||
UniquePtr<nsOpenConn> newdata(
|
||||
new nsOpenConn(ws->mAddress, ws->mOriginSuffix, ws));
|
||||
sManager->mQueue.AppendElement(std::move(newdata));
|
||||
|
||||
if (found) {
|
||||
@ -357,7 +359,7 @@ class nsWSAdmissionManager {
|
||||
// Check for queued connections to same host.
|
||||
// Note: still need to check for failures, since next websocket with same
|
||||
// host may have different port
|
||||
sManager->ConnectNext(aChannel->mAddress);
|
||||
sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
|
||||
}
|
||||
|
||||
// Called every time a websocket channel ends its session (including going
|
||||
@ -409,7 +411,7 @@ class nsWSAdmissionManager {
|
||||
LOG(("Websocket: changing state to NOT_CONNECTING"));
|
||||
aChannel->mConnecting = NOT_CONNECTING;
|
||||
if (wasNotQueued) {
|
||||
sManager->ConnectNext(aChannel->mAddress);
|
||||
sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -447,20 +449,22 @@ class nsWSAdmissionManager {
|
||||
|
||||
class nsOpenConn {
|
||||
public:
|
||||
nsOpenConn(nsCString& addr, WebSocketChannel* channel)
|
||||
: mAddress(addr), mChannel(channel) {
|
||||
nsOpenConn(nsCString& addr, nsCString& originSuffix,
|
||||
WebSocketChannel* channel)
|
||||
: mAddress(addr), mOriginSuffix(originSuffix), mChannel(channel) {
|
||||
MOZ_COUNT_CTOR(nsOpenConn);
|
||||
}
|
||||
MOZ_COUNTED_DTOR(nsOpenConn)
|
||||
|
||||
nsCString mAddress;
|
||||
nsCString mOriginSuffix;
|
||||
WebSocketChannel* mChannel;
|
||||
};
|
||||
|
||||
void ConnectNext(nsCString& hostName) {
|
||||
void ConnectNext(nsCString& hostName, nsCString& originSuffix) {
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
|
||||
int32_t index = IndexOf(hostName);
|
||||
int32_t index = IndexOf(hostName, originSuffix);
|
||||
if (index >= 0) {
|
||||
WebSocketChannel* chan = mQueue[index]->mChannel;
|
||||
|
||||
@ -481,9 +485,15 @@ class nsWSAdmissionManager {
|
||||
}
|
||||
}
|
||||
|
||||
int32_t IndexOf(nsCString& aStr) {
|
||||
int32_t IndexOf(nsCString& aAddress, nsCString& aOriginSuffix) {
|
||||
for (uint32_t i = 0; i < mQueue.Length(); i++) {
|
||||
if (aStr == (mQueue[i])->mAddress) return i;
|
||||
bool isPartitioned =
|
||||
StaticPrefs::privacy_partition_network_state() &&
|
||||
StaticPrefs::privacy_partition_network_state_ws_connection_queue();
|
||||
if (aAddress == (mQueue[i])->mAddress &&
|
||||
(!isPartitioned || aOriginSuffix == (mQueue[i])->mOriginSuffix)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@ -3241,11 +3251,28 @@ WebSocketChannel::GetSecurityInfo(nsISupports** aSecurityInfo) {
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketChannel::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
uint64_t aInnerWindowID,
|
||||
nsIWebSocketListener* aListener,
|
||||
nsISupports* aContext) {
|
||||
nsISupports* aContext, JSContext* aCx) {
|
||||
OriginAttributes attrs;
|
||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
return AsyncOpenNative(aURI, aOrigin, attrs, aInnerWindowID, aListener,
|
||||
aContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketChannel::AsyncOpenNative(nsIURI* aURI, const nsACString& aOrigin,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t aInnerWindowID,
|
||||
nsIWebSocketListener* aListener,
|
||||
nsISupports* aContext) {
|
||||
LOG(("WebSocketChannel::AsyncOpen() %p\n", this));
|
||||
|
||||
aOriginAttributes.CreateSuffix(mOriginSuffix);
|
||||
|
||||
if (!NS_IsMainThread()) {
|
||||
MOZ_ASSERT(false, "not main thread");
|
||||
LOG(("WebSocketChannel::AsyncOpen() called off the main thread"));
|
||||
|
@ -92,8 +92,14 @@ class WebSocketChannel : public BaseWebSocketChannel,
|
||||
// nsIWebSocketChannel methods BaseWebSocketChannel didn't implement for us
|
||||
//
|
||||
NS_IMETHOD AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
|
||||
uint64_t aWindowID, nsIWebSocketListener* aListener,
|
||||
nsISupports* aContext) override;
|
||||
JS::HandleValue aOriginAttributes, uint64_t aWindowID,
|
||||
nsIWebSocketListener* aListener, nsISupports* aContext,
|
||||
JSContext* aCx) override;
|
||||
NS_IMETHOD AsyncOpenNative(nsIURI* aURI, const nsACString& aOrigin,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t aWindowID,
|
||||
nsIWebSocketListener* aListener,
|
||||
nsISupports* aContext) override;
|
||||
NS_IMETHOD Close(uint16_t aCode, const nsACString& aReason) override;
|
||||
NS_IMETHOD SendMsg(const nsACString& aMsg) override;
|
||||
NS_IMETHOD SendBinaryMsg(const nsACString& aMsg) override;
|
||||
@ -207,6 +213,8 @@ class WebSocketChannel : public BaseWebSocketChannel,
|
||||
// then to IP address (unless we're leaving DNS resolution to a proxy server)
|
||||
nsCString mAddress;
|
||||
int32_t mPort; // WS server port
|
||||
// Secondary key for the connection queue. Used by nsWSAdmissionManager.
|
||||
nsCString mOriginSuffix;
|
||||
|
||||
// Used for off main thread access to the URI string.
|
||||
nsCString mHost;
|
||||
|
@ -458,9 +458,23 @@ void WebSocketChannelChild::SetupNeckoTarget() {
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketChannelChild::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
uint64_t aInnerWindowID,
|
||||
nsIWebSocketListener* aListener,
|
||||
nsISupports* aContext) {
|
||||
nsISupports* aContext, JSContext* aCx) {
|
||||
OriginAttributes attrs;
|
||||
if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
return AsyncOpenNative(aURI, aOrigin, attrs, aInnerWindowID, aListener,
|
||||
aContext);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WebSocketChannelChild::AsyncOpenNative(
|
||||
nsIURI* aURI, const nsACString& aOrigin,
|
||||
const OriginAttributes& aOriginAttributes, uint64_t aInnerWindowID,
|
||||
nsIWebSocketListener* aListener, nsISupports* aContext) {
|
||||
LOG(("WebSocketChannelChild::AsyncOpen() %p\n", this));
|
||||
|
||||
MOZ_ASSERT(NS_IsMainThread(), "not main thread");
|
||||
@ -511,10 +525,11 @@ WebSocketChannelChild::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
|
||||
|
||||
gNeckoChild->SendPWebSocketConstructor(
|
||||
this, browserChild, IPC::SerializedLoadContext(this), mSerial);
|
||||
if (!SendAsyncOpen(uri, nsCString(aOrigin), aInnerWindowID, mProtocol,
|
||||
mEncrypted, mPingInterval, mClientSetPingInterval,
|
||||
mPingResponseTimeout, mClientSetPingTimeout, loadInfoArgs,
|
||||
transportProvider, mNegotiatedExtensions)) {
|
||||
if (!SendAsyncOpen(uri, nsCString(aOrigin), aOriginAttributes, aInnerWindowID,
|
||||
mProtocol, mEncrypted, mPingInterval,
|
||||
mClientSetPingInterval, mPingResponseTimeout,
|
||||
mClientSetPingTimeout, loadInfoArgs, transportProvider,
|
||||
mNegotiatedExtensions)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
|
@ -32,8 +32,14 @@ class WebSocketChannelChild final : public BaseWebSocketChannel,
|
||||
// nsIWebSocketChannel methods BaseWebSocketChannel didn't implement for us
|
||||
//
|
||||
NS_IMETHOD AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
|
||||
JS::HandleValue aOriginAttributes,
|
||||
uint64_t aInnerWindowID, nsIWebSocketListener* aListener,
|
||||
nsISupports* aContext) override;
|
||||
nsISupports* aContext, JSContext* aCx) override;
|
||||
NS_IMETHOD AsyncOpenNative(nsIURI* aURI, const nsACString& aOrigin,
|
||||
const OriginAttributes& aOriginAttributes,
|
||||
uint64_t aInnerWindowID,
|
||||
nsIWebSocketListener* aListener,
|
||||
nsISupports* aContext) override;
|
||||
NS_IMETHOD Close(uint16_t code, const nsACString& reason) override;
|
||||
NS_IMETHOD SendMsg(const nsACString& aMsg) override;
|
||||
NS_IMETHOD SendBinaryMsg(const nsACString& aMsg) override;
|
||||
|
@ -47,7 +47,8 @@ mozilla::ipc::IPCResult WebSocketChannelParent::RecvDeleteSelf() {
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult WebSocketChannelParent::RecvAsyncOpen(
|
||||
nsIURI* aURI, const nsCString& aOrigin, const uint64_t& aInnerWindowID,
|
||||
nsIURI* aURI, const nsCString& aOrigin,
|
||||
const OriginAttributes& aOriginAttributes, const uint64_t& aInnerWindowID,
|
||||
const nsCString& aProtocol, const bool& aSecure,
|
||||
const uint32_t& aPingInterval, const bool& aClientSetPingInterval,
|
||||
const uint32_t& aPingTimeout, const bool& aClientSetPingTimeout,
|
||||
@ -118,7 +119,8 @@ mozilla::ipc::IPCResult WebSocketChannelParent::RecvAsyncOpen(
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
rv = mChannel->AsyncOpen(uri, aOrigin, aInnerWindowID, this, nullptr);
|
||||
rv = mChannel->AsyncOpenNative(uri, aOrigin, aOriginAttributes,
|
||||
aInnerWindowID, this, nullptr);
|
||||
if (NS_FAILED(rv)) goto fail;
|
||||
|
||||
return IPC_OK();
|
||||
|
@ -39,7 +39,8 @@ class WebSocketChannelParent : public PWebSocketParent,
|
||||
|
||||
private:
|
||||
mozilla::ipc::IPCResult RecvAsyncOpen(
|
||||
nsIURI* aURI, const nsCString& aOrigin, const uint64_t& aInnerWindowID,
|
||||
nsIURI* aURI, const nsCString& aOrigin,
|
||||
const OriginAttributes& aOriginAttributes, const uint64_t& aInnerWindowID,
|
||||
const nsCString& aProtocol, const bool& aSecure,
|
||||
const uint32_t& aPingInterval, const bool& aClientSetPingInterval,
|
||||
const uint32_t& aPingTimeout, const bool& aClientSetPingTimeout,
|
||||
|
@ -19,6 +19,10 @@ webidl Node;
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIContentPolicy.idl"
|
||||
|
||||
|
||||
|
||||
[ref] native OriginAttributes(const mozilla::OriginAttributes);
|
||||
|
||||
/**
|
||||
* Low-level websocket API: handles network protocol.
|
||||
*
|
||||
@ -128,15 +132,26 @@ interface nsIWebSocketChannel : nsISupports
|
||||
*
|
||||
* @param aURI the uri of the websocket protocol - may be redirected
|
||||
* @param aOrigin the uri of the originating resource
|
||||
* @param aOriginAttributes attributes of the originating resource.
|
||||
* @param aInnerWindowID the inner window ID
|
||||
* @param aListener the nsIWebSocketListener implementation
|
||||
* @param aContext an opaque parameter forwarded to aListener's methods
|
||||
*/
|
||||
[must_use] void asyncOpen(in nsIURI aURI,
|
||||
in ACString aOrigin,
|
||||
in unsigned long long aInnerWindowID,
|
||||
in nsIWebSocketListener aListener,
|
||||
in nsISupports aContext);
|
||||
[implicit_jscontext]
|
||||
void asyncOpen(in nsIURI aURI,
|
||||
in ACString aOrigin,
|
||||
in jsval aOriginAttributes,
|
||||
in unsigned long long aInnerWindowID,
|
||||
in nsIWebSocketListener aListener,
|
||||
in nsISupports aContext);
|
||||
|
||||
[must_use]
|
||||
void asyncOpenNative(in nsIURI aURI,
|
||||
in ACString aOrigin,
|
||||
in OriginAttributes aOriginAttributes,
|
||||
in unsigned long long aInnerWindowID,
|
||||
in nsIWebSocketListener aListener,
|
||||
in nsISupports aContext);
|
||||
|
||||
/*
|
||||
* Close the websocket connection for writing - no more calls to sendMsg
|
||||
|
@ -164,8 +164,9 @@ static int FuzzingRunNetworkWebsocket(const uint8_t* data, size_t size) {
|
||||
|
||||
gWebSocketListener = new FuzzingWebSocketListener();
|
||||
|
||||
rv =
|
||||
gWebSocketChannel->AsyncOpen(url, spec, 0, gWebSocketListener, nullptr);
|
||||
OriginAttributes attrs;
|
||||
rv = gWebSocketChannel->AsyncOpenNative(url, spec, attrs, 0,
|
||||
gWebSocketListener, nullptr);
|
||||
|
||||
if (rv == NS_OK) {
|
||||
FUZZING_LOG(("Successful call to AsyncOpen"));
|
||||
|
@ -72,6 +72,6 @@ function run_test() {
|
||||
Ci.nsIContentPolicy.TYPE_WEBSOCKET
|
||||
);
|
||||
|
||||
chan.asyncOpen(uri, url, 0, listener, null);
|
||||
chan.asyncOpen(uri, url, {}, 0, listener, null);
|
||||
do_test_pending();
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ function run_test() {
|
||||
);
|
||||
|
||||
var uri = Services.io.newURI(url);
|
||||
chan.asyncOpen(uri, url, 0, listener, null);
|
||||
chan.asyncOpen(uri, url, {}, 0, listener, null);
|
||||
do_test_pending();
|
||||
} catch (x) {
|
||||
dump("throwing " + x);
|
||||
|
@ -83,7 +83,7 @@ add_task(async function open_wss_when_h3_is_active() {
|
||||
var wsListener = new WebSocketListener();
|
||||
await new Promise(resolve => {
|
||||
wsListener.finish = resolve;
|
||||
chan.asyncOpen(uri, wssUri, 0, wsListener, null);
|
||||
chan.asyncOpen(uri, wssUri, {}, 0, wsListener, null);
|
||||
});
|
||||
|
||||
// Try to use https protocol, it should sttill use HTTP/3
|
||||
|
Loading…
Reference in New Issue
Block a user