Automatic update from web-platform-tests WebRTC: scope Interop 2026 subtests in four tests (#59869) Scope these subtests by inserting/removing `if (rest)` / `if (interop2026)` guards in place around the existing subtest bodies — no subtest body is moved, reordered, or reindented: * webrtc/RTCConfiguration-iceServers.html: scope `with invalid turn url should throw SyntaxError` to interop-2026 (the `config_test` helper generates both the `new RTCPeerConnection(config) - ...` and `setConfiguration(config) - ...` subtests). * webrtc/RTCError.html: scope `RTCError httpRequestStatusCode should not be supported.` to interop-2026. * webrtc/RTCRtpParameters-codec.html: scope `Stats output-rtp should match the selected codec in simulcast usecase on a video sender` to interop-2026. * webrtc/RTCSctpTransport-maxChannels.html: scope `Sctp transport has null maxChannels and maxMessageSize in have-local-offer` and `... in have-remote-offer` to rest only. Part of Interop 2026 WebRTC focus area scoping; see https://github.com/w3c/webrtc-pc/issues/3100. No `<meta name="variant">` declarations are changed, so URLs as seen on wpt.fyi remain stable. -- wpt-commits: 1d51a07a56b08957df1469f34359e96db3de2bcf wpt-pr: 59869
450 lines
15 KiB
HTML
450 lines
15 KiB
HTML
<!doctype html>
|
|
<meta charset=utf-8>
|
|
<meta name="variant" content="?interop-2026">
|
|
<meta name="variant" content="?rest">
|
|
<title>RTCConfiguration iceServers</title>
|
|
<script src='/resources/testharness.js'></script>
|
|
<script src='/resources/testharnessreport.js'></script>
|
|
<script src='RTCConfiguration-helper.js'></script>
|
|
<script>
|
|
'use strict';
|
|
const rest = !new URLSearchParams(location.search).has("interop-2026");
|
|
const interop2026 = !new URLSearchParams(location.search).has("rest");
|
|
|
|
// Test is based on the following editor's draft:
|
|
// https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
|
|
|
|
// The following helper function is called from
|
|
// RTCConfiguration-helper.js:
|
|
// config_test
|
|
|
|
/*
|
|
4.3.2. Interface Definition
|
|
[Constructor(optional RTCConfiguration configuration)]
|
|
interface RTCPeerConnection : EventTarget {
|
|
...
|
|
};
|
|
|
|
4.2.1. RTCConfiguration Dictionary
|
|
dictionary RTCConfiguration {
|
|
sequence<RTCIceServer> iceServers = [];
|
|
...
|
|
};
|
|
|
|
4.2.4. RTCIceServer Dictionary
|
|
dictionary RTCIceServer {
|
|
required (DOMString or sequence<DOMString>) urls;
|
|
DOMString username;
|
|
DOMString credential;
|
|
};
|
|
*/
|
|
// RFC 8489 limits the length of the TURN username to 509 bytes:
|
|
// https://datatracker.ietf.org/doc/html/rfc8489#section-14.3
|
|
const kUsernameOfMaxPermittedLength = 'a'.repeat(509);
|
|
|
|
if (rest) {
|
|
test(() => {
|
|
const pc = new RTCPeerConnection();
|
|
assert_array_equals(pc.getConfiguration().iceServers, []);
|
|
}, 'new RTCPeerConnection() should have default configuration.iceServers of []');
|
|
|
|
config_test(makePc => {
|
|
makePc({});
|
|
}, '{} should succeed');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_js(TypeError, () =>
|
|
makePc({ iceServers: null }));
|
|
}, '{ iceServers: null } should throw TypeError');
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: undefined });
|
|
assert_array_equals(pc.getConfiguration().iceServers, []);
|
|
}, '{ iceServers: undefined } should succeed');
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [] });
|
|
assert_array_equals(pc.getConfiguration().iceServers, []);
|
|
}, '{ iceServers: [] } should succeed');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_js(TypeError, () =>
|
|
makePc({ iceServers: [null] }));
|
|
}, '{ iceServers: [null] } should throw TypeError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_js(TypeError, () =>
|
|
makePc({ iceServers: [undefined] }));
|
|
}, '{ iceServers: [undefined] } should throw TypeError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_js(TypeError, () =>
|
|
makePc({ iceServers: [{}] }));
|
|
}, '{ iceServers: [{}] } should throw TypeError');
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [{
|
|
urls: 'stun:stun1.example.net'
|
|
}] });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 1);
|
|
|
|
const server = iceServers[0];
|
|
assert_array_equals(server.urls, ['stun:stun1.example.net']);
|
|
|
|
}, `with stun server should succeed`);
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [{
|
|
urls: ['stun:stun1.example.net']
|
|
}] });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 1);
|
|
|
|
const server = iceServers[0];
|
|
assert_array_equals(server.urls, ['stun:stun1.example.net']);
|
|
|
|
}, `with stun server array should succeed`);
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [{
|
|
urls: ['stun:stun1.example.net', 'stun:stun2.example.net']
|
|
}] });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 1);
|
|
|
|
const server = iceServers[0];
|
|
assert_array_equals(server.urls, ['stun:stun1.example.net', 'stun:stun2.example.net']);
|
|
|
|
}, `with 2 stun servers should succeed`);
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [{
|
|
urls: 'turn:turn.example.org',
|
|
username: 'user',
|
|
credential: 'cred'
|
|
}] });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 1);
|
|
|
|
const server = iceServers[0];
|
|
assert_array_equals(server.urls, ['turn:turn.example.org']);
|
|
assert_equals(server.username, 'user');
|
|
assert_equals(server.credential, 'cred');
|
|
|
|
}, `with turn server, username, credential should succeed`);
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [{
|
|
urls: 'turns:turn.example.org',
|
|
username: '',
|
|
credential: 'cred'
|
|
}] });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 1);
|
|
|
|
const server = iceServers[0];
|
|
assert_array_equals(server.urls, ['turns:turn.example.org']);
|
|
assert_equals(server.username, '');
|
|
assert_equals(server.credential, 'cred');
|
|
|
|
}, `with turns server and empty string username should succeed`);
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [{
|
|
urls: 'turn:turn.example.org',
|
|
username: '',
|
|
credential: 'cred'
|
|
}] });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 1);
|
|
|
|
const server = iceServers[0];
|
|
assert_array_equals(server.urls, ['turn:turn.example.org']);
|
|
assert_equals(server.username, '');
|
|
assert_equals(server.credential, 'cred');
|
|
|
|
}, `with turn server and empty string username should succeed`);
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [{
|
|
urls: ['turns:turn.example.org', 'turn:turn.example.net'],
|
|
username: 'user',
|
|
credential: 'cred'
|
|
}] });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 1);
|
|
|
|
const server = iceServers[0];
|
|
assert_array_equals(server.urls, ['turns:turn.example.org', 'turn:turn.example.net']);
|
|
assert_equals(server.username, 'user');
|
|
assert_equals(server.credential, 'cred');
|
|
|
|
}, `with one turns server, one turn server, username, credential should succeed`);
|
|
|
|
config_test(makePc => {
|
|
assert_equals(kUsernameOfMaxPermittedLength.length, 509);
|
|
const pc = makePc({ iceServers: [{
|
|
urls: 'turn:turn.example.net',
|
|
username: kUsernameOfMaxPermittedLength,
|
|
credential: 'cred'
|
|
}] });
|
|
}, `with a turn server and a username of 509 characters should succeed`);
|
|
|
|
/*
|
|
4.3.2. To set a configuration
|
|
11.4. If scheme name is turn or turns, and either of server.username or
|
|
server.credential are omitted, then throw an InvalidAccessError.
|
|
*/
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turn:turn.example.net'
|
|
}] }));
|
|
}, 'with turn server and no credentials should throw InvalidAccessError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turn:turn.example.net',
|
|
username: 'user'
|
|
}] }));
|
|
}, 'with turn server and only username should throw InvalidAccessError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turn:turn.example.net',
|
|
credential: 'cred'
|
|
}] }));
|
|
}, 'with turn server and only credential should throw InvalidAccessError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turns:turn.example.net'
|
|
}] }));
|
|
}, 'with turns server and no credentials should throw InvalidAccessError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turns:turn.example.net',
|
|
username: 'user'
|
|
}] }));
|
|
}, 'with turns server and only username should throw InvalidAccessError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turns:turn.example.net',
|
|
credential: 'cred'
|
|
}] }));
|
|
}, 'with turns server and only credential should throw InvalidAccessError');
|
|
}
|
|
if (interop2026) {
|
|
config_test(makePc => {
|
|
assert_equals(kUsernameOfMaxPermittedLength.length, 509);
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turns:turn.example.net',
|
|
username: kUsernameOfMaxPermittedLength + 'a',
|
|
credential: 'cred'
|
|
}] }));
|
|
}, `with a turn server and a username of 510 characters throw InvalidAccessError`);
|
|
}
|
|
if (rest) {
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turn:turn.example.net',
|
|
username: 'user',
|
|
credential: ''
|
|
}] }));
|
|
}, `with a turn server and an empty credential throw InvalidAccessError`);
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom('InvalidAccessError', () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turns:turn.example.net',
|
|
username: 'user',
|
|
credential: ''
|
|
}] }));
|
|
}, `with a turns server and an empty credential throw InvalidAccessError`);
|
|
|
|
/*
|
|
4.3.2. To set a configuration
|
|
11.3. For each url in server.urls parse url and obtain scheme name.
|
|
- If the scheme name is not implemented by the browser, throw a SyntaxError.
|
|
- or if parsing based on the syntax defined in [ RFC7064] and [RFC7065] fails,
|
|
throw a SyntaxError.
|
|
|
|
[RFC7064] URI Scheme for the Session Traversal Utilities for NAT (STUN) Protocol
|
|
3.1. URI Scheme Syntax
|
|
stunURI = scheme ":" host [ ":" port ]
|
|
scheme = "stun" / "stuns"
|
|
|
|
[RFC7065] Traversal Using Relays around NAT (TURN) Uniform Resource Identifiers
|
|
3.1. URI Scheme Syntax
|
|
turnURI = scheme ":" host [ ":" port ]
|
|
[ "?transport=" transport ]
|
|
scheme = "turn" / "turns"
|
|
transport = "udp" / "tcp" / transport-ext
|
|
transport-ext = 1*unreserved
|
|
*/
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{
|
|
urls: ''
|
|
}] }));
|
|
}, 'with "" url should throw SyntaxError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{
|
|
urls: ['stun:stun1.example.net', '']
|
|
}] }));
|
|
}, 'with ["stun:stun1.example.net", ""] url should throw SyntaxError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'relative-url'
|
|
}] }));
|
|
}, 'with relative url should throw SyntaxError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'http://example.com'
|
|
}] }));
|
|
}, 'with http url should throw SyntaxError');
|
|
|
|
}
|
|
if (interop2026) {
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'turn://example.org/foo?x=y'
|
|
// `username` and `credential` are not passed because the invalid url
|
|
// should be rejected before the check for those arguments.
|
|
}] }));
|
|
}, 'with invalid turn url should throw SyntaxError');
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{
|
|
urls: 'stun://example.org/foo?x=y'
|
|
}] }));
|
|
}, 'with invalid stun url should throw SyntaxError');
|
|
}
|
|
if (rest) {
|
|
// RFC 7064/7065 define STUN/TURN URI syntax as:
|
|
// stunURI = scheme ":" host [ ":" port ]
|
|
// turnURI = scheme ":" host [ ":" port ] [ "?transport=" transport ]
|
|
// No authority (//), path, fragment, or userinfo is permitted.
|
|
// According to webrtc-pc, only "transport=udp" and "transport=tcp" are valid
|
|
// query values for TURN/TURNS, and other transport strings should result in
|
|
// SyntaxError.
|
|
[
|
|
{ urls: 'stun:',
|
|
desc: 'stun url with no host or port' },
|
|
{ urls: 'stun::8191',
|
|
desc: 'stun url with port but no host' },
|
|
{ urls: 'turn:',
|
|
desc: 'turn url with no host or port' },
|
|
{ urls: 'turn::8191',
|
|
desc: 'turn url with port but no host' },
|
|
{ urls: 'stun:example.org:131071',
|
|
desc: 'stun url with too large a port' },
|
|
{ urls: 'turn:example.org:131071',
|
|
desc: 'turn url with too large a port' },
|
|
{ urls: 'stun:2001:4860:4860::8888',
|
|
desc: 'stun url with IPv6 and no brackets' },
|
|
{ urls: 'turn:2001:4860:4860::8888',
|
|
desc: 'turn url with IPv6 and no brackets' },
|
|
{ urls: 'stun:::ffff:192.0.2.128',
|
|
desc: 'stun url with IPv4-mapped IPv6 and no brackets' },
|
|
{ urls: 'turn:::ffff:192.0.2.128',
|
|
desc: 'turn url with IPv4-mapped IPv6 and no brackets' },
|
|
{ urls: 'stun:example.org#frag',
|
|
desc: 'stun url with fragment' },
|
|
{ urls: 'turn:example.org#frag',
|
|
desc: 'turn url with fragment' },
|
|
{ urls: 'stun:user@example.org',
|
|
desc: 'stun url with userinfo' },
|
|
{ urls: 'turn:user@example.org',
|
|
desc: 'turn url with userinfo' },
|
|
{ urls: 'stun:example.org/',
|
|
desc: 'stun url with /' },
|
|
{ urls: 'turn:example.org/',
|
|
desc: 'turn url with /' },
|
|
{ urls: 'stun:example.org\\',
|
|
desc: 'stun url with \\' },
|
|
{ urls: 'turn:example.org\\',
|
|
desc: 'turn url with \\' },
|
|
{ urls: 'stun:example.org/path',
|
|
desc: 'stun url with path' },
|
|
{ urls: 'turn:example.org/path',
|
|
desc: 'turn url with path' },
|
|
{ urls: 'stun:example.org\\path',
|
|
desc: 'stun url with \\path' },
|
|
{ urls: 'turn:example.org\\path',
|
|
desc: 'turn url with \\path' },
|
|
{ urls: 'stun:example.org?foo=bar',
|
|
desc: 'stun url with query' },
|
|
{ urls: 'stun:example.org?transport=udp',
|
|
desc: 'stun url with transport query' },
|
|
{ urls: 'turn:example.org?foo=bar',
|
|
desc: 'turn url with non-transport query' },
|
|
{ urls: 'turn:example.org?transport=datachannel',
|
|
desc: 'turn url with invalid transport' },
|
|
{ urls: 'turn:example.org?transport=',
|
|
desc: 'turn url with empty transport query' },
|
|
].forEach(({ urls, desc }) =>
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{ urls }] }));
|
|
}, `with ${desc} should throw SyntaxError`));
|
|
|
|
config_test(makePc => {
|
|
assert_throws_dom("SyntaxError", () =>
|
|
makePc({ iceServers: [{
|
|
urls: []
|
|
}] }));
|
|
}, `with empty urls should throw SyntaxError`);
|
|
|
|
test(() => {
|
|
const pc = new RTCPeerConnection({ iceServers: [{
|
|
urls: 'stun:stun1.example.net'
|
|
}] });
|
|
let config = pc.getConfiguration();
|
|
assert_equals(config.iceServers.length, 1);
|
|
pc.setConfiguration({});
|
|
config = pc.getConfiguration();
|
|
assert_equals(config.iceServers.length, 0);
|
|
}, `setConfiguration(config) - without iceServers removes ice servers`);
|
|
|
|
config_test(makePc => {
|
|
const pc = makePc({ iceServers: [...Array(32)].map((_, i) => ({
|
|
urls: `stun:stun${i+1}.example.net`
|
|
})) });
|
|
|
|
const { iceServers } = pc.getConfiguration();
|
|
assert_equals(iceServers.length, 32);
|
|
|
|
for (let i = 0; i < 32; i++) {
|
|
const server = iceServers[i];
|
|
assert_array_equals(server.urls, [`stun:stun${i+1}.example.net`]);
|
|
}
|
|
}, `with 32 ice servers must succeed`);
|
|
}
|
|
</script>
|