Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Errors

//
// Simple WebTransport test
//
/* import-globals-from head_webtransport.js */
"use strict";
var h3Port;
var host;
var { setTimeout } = ChromeUtils.importESModule(
);
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("network.dns.localDomains");
Services.prefs.clearUserPref("network.webtransport.datagrams.enabled");
Services.prefs.clearUserPref(
"network.http.http3.alt-svc-mapping-for-testing"
);
});
add_task(async function setup() {
await http3_setup_tests("h3");
Services.prefs.setBoolPref("network.webtransport.datagrams.enabled", true);
h3Port = Services.env.get("MOZHTTP3_PORT");
Assert.notEqual(h3Port, null);
Assert.notEqual(h3Port, "");
host = "foo.example.com:" + h3Port;
});
function makeChan(url) {
let chan = NetUtil.newChannel({
uri: url,
loadUsingSystemPrincipal: true,
contentPolicyType: Ci.nsIContentPolicy.TYPE_DOCUMENT,
}).QueryInterface(Ci.nsIHttpChannel);
chan.loadFlags = Ci.nsIChannel.LOAD_INITIAL_DOCUMENT_URI;
return chan;
}
function channelOpenPromise(chan, flags) {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async resolve => {
function finish(req, buffer) {
resolve([req, buffer]);
}
let internal = chan.QueryInterface(Ci.nsIHttpChannelInternal);
internal.setWaitForHTTPSSVCRecord();
chan.asyncOpen(new ChannelListener(finish, null, flags));
});
}
function bytesFromString(str) {
return new TextEncoder().encode(str);
}
add_task(async function test_wt_datagram() {
let webTransport = NetUtil.newWebTransport();
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
let pReady = new Promise(resolve => {
listener.ready = resolve;
});
let pSize = new Promise(resolve => {
listener.onMaxDatagramSize = resolve;
});
let pOutcome = new Promise(resolve => {
listener.onDatagramOutcome = resolve;
});
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/success`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
await pReady;
webTransport.getMaxDatagramSize();
let size = await pSize;
info("max size:" + size);
let rawData = new Uint8Array(size);
rawData.fill(42);
webTransport.sendDatagram(rawData, 1);
let { id, outcome } = await pOutcome;
Assert.equal(id, 1);
Assert.equal(outcome, Ci.WebTransportSessionEventListener.SENT);
let chan = makeChan(`https://${host}/get_webtransport_datagram`);
let [req, buffer] = await channelOpenPromise(chan);
Assert.equal(req.protocolVersion, "h3");
Assert.deepEqual(bytesFromString(buffer), rawData);
webTransport.getMaxDatagramSize();
size = await pSize;
info("max size:" + size);
rawData = new Uint8Array(size + 1);
webTransport.sendDatagram(rawData, 2);
pOutcome = new Promise(resolve => {
listener.onDatagramOutcome = resolve;
});
({ id, outcome } = await pOutcome);
Assert.equal(id, 2);
Assert.equal(
outcome,
Ci.WebTransportSessionEventListener.DROPPED_TOO_MUCH_DATA
);
webTransport.closeSession(0, "");
});
add_task(async function test_connect_wt() {
let webTransport = NetUtil.newWebTransport();
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.ready = resolve;
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/success`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
webTransport.closeSession(0, "");
});
add_task(async function test_redirect_wt() {
let webTransport = NetUtil.newWebTransport();
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.closed = resolve;
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/redirect`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
});
add_task(async function test_reject() {
let webTransport = NetUtil.newWebTransport();
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.closed = resolve;
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/reject`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
});
async function test_closed(path) {
let webTransport = NetUtil.newWebTransport();
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
let pReady = new Promise(resolve => {
listener.ready = resolve;
});
let pClose = new Promise(resolve => {
listener.closed = resolve;
});
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}${path}`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
await pReady;
await pClose;
}
add_task(async function test_closed_0ms() {
await test_closed("/closeafter0ms");
});
add_task(async function test_closed_100ms() {
await test_closed("/closeafter100ms");
});
add_task(async function test_wt_stream_create() {
let webTransport = NetUtil.newWebTransport().QueryInterface(
Ci.nsIWebTransport
);
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.ready = resolve;
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/success`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
await streamCreatePromise(webTransport, true);
await streamCreatePromise(webTransport, false);
webTransport.closeSession(0, "");
});
add_task(async function test_wt_stream_send_and_stats() {
let webTransport = NetUtil.newWebTransport().QueryInterface(
Ci.nsIWebTransport
);
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.ready = resolve;
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/success`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
let stream = await streamCreatePromise(webTransport, false);
let outputStream = stream.outputStream;
let data = "1234567890ABC";
outputStream.write(data, data.length);
// We need some time to send the packet out.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(resolve => setTimeout(resolve, 2000));
let stats = await sendStreamStatsPromise(stream);
Assert.equal(stats.bytesSent, data.length);
webTransport.closeSession(0, "");
});
add_task(async function test_wt_receive_stream_and_stats() {
let webTransport = NetUtil.newWebTransport().QueryInterface(
Ci.nsIWebTransport
);
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
let pReady = new Promise(resolve => {
listener.ready = resolve;
});
let pStreamReady = new Promise(resolve => {
listener.streamAvailable = resolve;
});
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/create_unidi_stream_and_hello`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
await pReady;
let stream = await pStreamReady;
let data = await new Promise(resolve => {
let handler = new inputStreamReader().QueryInterface(
Ci.nsIInputStreamCallback
);
handler.finish = resolve;
let inputStream = stream.inputStream;
inputStream.asyncWait(handler, 0, 0, Services.tm.currentThread);
});
info("data: " + data);
Assert.equal(data, "qwerty");
let stats = await receiveStreamStatsPromise(stream);
Assert.equal(stats.bytesReceived, data.length);
stream.sendStopSending(0);
webTransport.closeSession(0, "");
});
add_task(async function test_wt_outgoing_bidi_stream() {
let webTransport = NetUtil.newWebTransport().QueryInterface(
Ci.nsIWebTransport
);
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.ready = resolve;
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/success`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
let stream = await streamCreatePromise(webTransport, true);
let outputStream = stream.outputStream;
let data = "1234567";
outputStream.write(data, data.length);
let received = await new Promise(resolve => {
let handler = new inputStreamReader().QueryInterface(
Ci.nsIInputStreamCallback
);
handler.finish = resolve;
let inputStream = stream.inputStream;
inputStream.asyncWait(handler, 0, 0, Services.tm.currentThread);
});
info("received: " + received);
Assert.equal(received, data);
let stats = await sendStreamStatsPromise(stream);
Assert.equal(stats.bytesSent, data.length);
stats = await receiveStreamStatsPromise(stream);
Assert.equal(stats.bytesReceived, data.length);
webTransport.closeSession(0, "");
});
add_task(async function test_wt_incoming_bidi_stream() {
let webTransport = NetUtil.newWebTransport().QueryInterface(
Ci.nsIWebTransport
);
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
let pReady = new Promise(resolve => {
listener.ready = resolve;
});
let pStreamReady = new Promise(resolve => {
listener.streamAvailable = resolve;
});
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/create_bidi_stream`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
await pReady;
let stream = await pStreamReady;
let outputStream = stream.outputStream;
let data = "12345678";
outputStream.write(data, data.length);
let received = await new Promise(resolve => {
let handler = new inputStreamReader().QueryInterface(
Ci.nsIInputStreamCallback
);
handler.finish = resolve;
let inputStream = stream.inputStream;
inputStream.asyncWait(handler, 0, 0, Services.tm.currentThread);
});
info("received: " + received);
Assert.equal(received, data);
let stats = await sendStreamStatsPromise(stream);
Assert.equal(stats.bytesSent, data.length);
stats = await receiveStreamStatsPromise(stream);
Assert.equal(stats.bytesReceived, data.length);
webTransport.closeSession(0, "");
});
async function createWebTransportAndConnect() {
let webTransport = NetUtil.newWebTransport();
await new Promise(resolve => {
let listener = new WebTransportListener().QueryInterface(
Ci.WebTransportSessionEventListener
);
listener.ready = resolve;
webTransport.asyncConnect(
NetUtil.newURI(`https://${host}/success`),
true,
[],
Services.scriptSecurityManager.getSystemPrincipal(),
Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_SEC_CONTEXT_IS_NULL,
listener
);
});
return webTransport;
}
add_task(async function test_multple_webtransport_connnection() {
let webTransports = [];
for (let i = 0; i < 3; i++) {
let transport = await createWebTransportAndConnect();
webTransports.push(transport);
}
let first = webTransports[0];
await streamCreatePromise(first, true);
for (let i = 0; i < 3; i++) {
webTransports[i].closeSession(0, "");
}
});