RTCConfiguration-iceServers.html (11471B)
1 <!doctype html> 2 <meta charset=utf-8> 3 <title>RTCConfiguration iceServers</title> 4 <script src='/resources/testharness.js'></script> 5 <script src='/resources/testharnessreport.js'></script> 6 <script src='RTCConfiguration-helper.js'></script> 7 <script> 8 'use strict'; 9 10 // Test is based on the following editor's draft: 11 // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html 12 13 // The following helper function is called from 14 // RTCConfiguration-helper.js: 15 // config_test 16 17 /* 18 4.3.2. Interface Definition 19 [Constructor(optional RTCConfiguration configuration)] 20 interface RTCPeerConnection : EventTarget { 21 ... 22 }; 23 24 4.2.1. RTCConfiguration Dictionary 25 dictionary RTCConfiguration { 26 sequence<RTCIceServer> iceServers = []; 27 ... 28 }; 29 30 4.2.4. RTCIceServer Dictionary 31 dictionary RTCIceServer { 32 required (DOMString or sequence<DOMString>) urls; 33 DOMString username; 34 DOMString credential; 35 }; 36 */ 37 // RFC 8489 limits the length of the TURN username to 509 bytes: 38 // https://datatracker.ietf.org/doc/html/rfc8489#section-14.3 39 const kUsernameOfMaxPermittedLength = 'a'.repeat(509); 40 41 test(() => { 42 const pc = new RTCPeerConnection(); 43 assert_array_equals(pc.getConfiguration().iceServers, []); 44 }, 'new RTCPeerConnection() should have default configuration.iceServers of []'); 45 46 config_test(makePc => { 47 makePc({}); 48 }, '{} should succeed'); 49 50 config_test(makePc => { 51 assert_throws_js(TypeError, () => 52 makePc({ iceServers: null })); 53 }, '{ iceServers: null } should throw TypeError'); 54 55 config_test(makePc => { 56 const pc = makePc({ iceServers: undefined }); 57 assert_array_equals(pc.getConfiguration().iceServers, []); 58 }, '{ iceServers: undefined } should succeed'); 59 60 config_test(makePc => { 61 const pc = makePc({ iceServers: [] }); 62 assert_array_equals(pc.getConfiguration().iceServers, []); 63 }, '{ iceServers: [] } should succeed'); 64 65 config_test(makePc => { 66 assert_throws_js(TypeError, () => 67 makePc({ iceServers: [null] })); 68 }, '{ iceServers: [null] } should throw TypeError'); 69 70 config_test(makePc => { 71 assert_throws_js(TypeError, () => 72 makePc({ iceServers: [undefined] })); 73 }, '{ iceServers: [undefined] } should throw TypeError'); 74 75 config_test(makePc => { 76 assert_throws_js(TypeError, () => 77 makePc({ iceServers: [{}] })); 78 }, '{ iceServers: [{}] } should throw TypeError'); 79 80 config_test(makePc => { 81 const pc = makePc({ iceServers: [{ 82 urls: 'stun:stun1.example.net' 83 }] }); 84 85 const { iceServers } = pc.getConfiguration(); 86 assert_equals(iceServers.length, 1); 87 88 const server = iceServers[0]; 89 assert_array_equals(server.urls, ['stun:stun1.example.net']); 90 91 }, `with stun server should succeed`); 92 93 config_test(makePc => { 94 const pc = makePc({ iceServers: [{ 95 urls: ['stun:stun1.example.net'] 96 }] }); 97 98 const { iceServers } = pc.getConfiguration(); 99 assert_equals(iceServers.length, 1); 100 101 const server = iceServers[0]; 102 assert_array_equals(server.urls, ['stun:stun1.example.net']); 103 104 }, `with stun server array should succeed`); 105 106 config_test(makePc => { 107 const pc = makePc({ iceServers: [{ 108 urls: ['stun:stun1.example.net', 'stun:stun2.example.net'] 109 }] }); 110 111 const { iceServers } = pc.getConfiguration(); 112 assert_equals(iceServers.length, 1); 113 114 const server = iceServers[0]; 115 assert_array_equals(server.urls, ['stun:stun1.example.net', 'stun:stun2.example.net']); 116 117 }, `with 2 stun servers should succeed`); 118 119 config_test(makePc => { 120 const pc = makePc({ iceServers: [{ 121 urls: 'turn:turn.example.org', 122 username: 'user', 123 credential: 'cred' 124 }] }); 125 126 const { iceServers } = pc.getConfiguration(); 127 assert_equals(iceServers.length, 1); 128 129 const server = iceServers[0]; 130 assert_array_equals(server.urls, ['turn:turn.example.org']); 131 assert_equals(server.username, 'user'); 132 assert_equals(server.credential, 'cred'); 133 134 }, `with turn server, username, credential should succeed`); 135 136 config_test(makePc => { 137 const pc = makePc({ iceServers: [{ 138 urls: 'turns:turn.example.org', 139 username: '', 140 credential: '' 141 }] }); 142 143 const { iceServers } = pc.getConfiguration(); 144 assert_equals(iceServers.length, 1); 145 146 const server = iceServers[0]; 147 assert_array_equals(server.urls, ['turns:turn.example.org']); 148 assert_equals(server.username, ''); 149 assert_equals(server.credential, ''); 150 151 }, `with turns server and empty string username, credential should succeed`); 152 153 config_test(makePc => { 154 const pc = makePc({ iceServers: [{ 155 urls: 'turn:turn.example.org', 156 username: '', 157 credential: '' 158 }] }); 159 160 const { iceServers } = pc.getConfiguration(); 161 assert_equals(iceServers.length, 1); 162 163 const server = iceServers[0]; 164 assert_array_equals(server.urls, ['turn:turn.example.org']); 165 assert_equals(server.username, ''); 166 assert_equals(server.credential, ''); 167 168 }, `with turn server and empty string username, credential should succeed`); 169 170 config_test(makePc => { 171 const pc = makePc({ iceServers: [{ 172 urls: ['turns:turn.example.org', 'turn:turn.example.net'], 173 username: 'user', 174 credential: 'cred' 175 }] }); 176 177 const { iceServers } = pc.getConfiguration(); 178 assert_equals(iceServers.length, 1); 179 180 const server = iceServers[0]; 181 assert_array_equals(server.urls, ['turns:turn.example.org', 'turn:turn.example.net']); 182 assert_equals(server.username, 'user'); 183 assert_equals(server.credential, 'cred'); 184 185 }, `with one turns server, one turn server, username, credential should succeed`); 186 187 config_test(makePc => { 188 assert_equals(kUsernameOfMaxPermittedLength.length, 509); 189 const pc = makePc({ iceServers: [{ 190 urls: 'turn:turn.example.net', 191 username: kUsernameOfMaxPermittedLength, 192 credential: 'cred' 193 }] }); 194 }, `with a turn server and a username of 509 characters should succeed`); 195 196 /* 197 4.3.2. To set a configuration 198 11.4. If scheme name is turn or turns, and either of server.username or 199 server.credential are omitted, then throw an InvalidAccessError. 200 */ 201 config_test(makePc => { 202 assert_throws_dom('InvalidAccessError', () => 203 makePc({ iceServers: [{ 204 urls: 'turn:turn.example.net' 205 }] })); 206 }, 'with turn server and no credentials should throw InvalidAccessError'); 207 208 config_test(makePc => { 209 assert_throws_dom('InvalidAccessError', () => 210 makePc({ iceServers: [{ 211 urls: 'turn:turn.example.net', 212 username: 'user' 213 }] })); 214 }, 'with turn server and only username should throw InvalidAccessError'); 215 216 config_test(makePc => { 217 assert_throws_dom('InvalidAccessError', () => 218 makePc({ iceServers: [{ 219 urls: 'turn:turn.example.net', 220 credential: 'cred' 221 }] })); 222 }, 'with turn server and only credential should throw InvalidAccessError'); 223 224 config_test(makePc => { 225 assert_throws_dom('InvalidAccessError', () => 226 makePc({ iceServers: [{ 227 urls: 'turns:turn.example.net' 228 }] })); 229 }, 'with turns server and no credentials should throw InvalidAccessError'); 230 231 config_test(makePc => { 232 assert_throws_dom('InvalidAccessError', () => 233 makePc({ iceServers: [{ 234 urls: 'turns:turn.example.net', 235 username: 'user' 236 }] })); 237 }, 'with turns server and only username should throw InvalidAccessError'); 238 239 config_test(makePc => { 240 assert_throws_dom('InvalidAccessError', () => 241 makePc({ iceServers: [{ 242 urls: 'turns:turn.example.net', 243 credential: 'cred' 244 }] })); 245 }, 'with turns server and only credential should throw InvalidAccessError'); 246 247 config_test(makePc => { 248 assert_equals(kUsernameOfMaxPermittedLength.length, 509); 249 assert_throws_dom('InvalidAccessError', () => 250 makePc({ iceServers: [{ 251 urls: 'turns:turn.example.net', 252 username: kUsernameOfMaxPermittedLength + 'a', 253 credential: 'cred' 254 }] })); 255 }, `with a turn server and a username of 510 characters throw InvalidAccessError`); 256 257 /* 258 4.3.2. To set a configuration 259 11.3. For each url in server.urls parse url and obtain scheme name. 260 - If the scheme name is not implemented by the browser, throw a SyntaxError. 261 - or if parsing based on the syntax defined in [ RFC7064] and [RFC7065] fails, 262 throw a SyntaxError. 263 264 [RFC7064] URI Scheme for the Session Traversal Utilities for NAT (STUN) Protocol 265 3.1. URI Scheme Syntax 266 stunURI = scheme ":" host [ ":" port ] 267 scheme = "stun" / "stuns" 268 269 [RFC7065] Traversal Using Relays around NAT (TURN) Uniform Resource Identifiers 270 3.1. URI Scheme Syntax 271 turnURI = scheme ":" host [ ":" port ] 272 [ "?transport=" transport ] 273 scheme = "turn" / "turns" 274 transport = "udp" / "tcp" / transport-ext 275 transport-ext = 1*unreserved 276 */ 277 config_test(makePc => { 278 assert_throws_dom("SyntaxError", () => 279 makePc({ iceServers: [{ 280 urls: '' 281 }] })); 282 }, 'with "" url should throw SyntaxError'); 283 284 config_test(makePc => { 285 assert_throws_dom("SyntaxError", () => 286 makePc({ iceServers: [{ 287 urls: ['stun:stun1.example.net', ''] 288 }] })); 289 }, 'with ["stun:stun1.example.net", ""] url should throw SyntaxError'); 290 291 config_test(makePc => { 292 assert_throws_dom("SyntaxError", () => 293 makePc({ iceServers: [{ 294 urls: 'relative-url' 295 }] })); 296 }, 'with relative url should throw SyntaxError'); 297 298 config_test(makePc => { 299 assert_throws_dom("SyntaxError", () => 300 makePc({ iceServers: [{ 301 urls: 'http://example.com' 302 }] })); 303 }, 'with http url should throw SyntaxError'); 304 305 config_test(makePc => { 306 assert_throws_dom("SyntaxError", () => 307 makePc({ iceServers: [{ 308 urls: 'turn://example.org/foo?x=y' 309 // `username` and `credential` are not passed because the invalid url 310 // should be rejected before the check for those arguments. 311 }] })); 312 }, 'with invalid turn url should throw SyntaxError'); 313 314 config_test(makePc => { 315 assert_throws_dom("SyntaxError", () => 316 makePc({ iceServers: [{ 317 urls: 'stun://example.org/foo?x=y' 318 }] })); 319 }, 'with invalid stun url should throw SyntaxError'); 320 321 config_test(makePc => { 322 assert_throws_dom("SyntaxError", () => 323 makePc({ iceServers: [{ 324 urls: [] 325 }] })); 326 }, `with empty urls should throw SyntaxError`); 327 328 test(() => { 329 const pc = new RTCPeerConnection({ iceServers: [{ 330 urls: 'stun:stun1.example.net' 331 }] }); 332 let config = pc.getConfiguration(); 333 assert_equals(config.iceServers.length, 1); 334 pc.setConfiguration({}); 335 config = pc.getConfiguration(); 336 assert_equals(config.iceServers.length, 0); 337 }, `setConfiguration(config) - without iceServers removes ice servers`); 338 339 config_test(makePc => { 340 const pc = makePc({ iceServers: [...Array(32)].map((_, i) => ({ 341 urls: `stun:stun${i+1}.example.net` 342 })) }); 343 344 const { iceServers } = pc.getConfiguration(); 345 assert_equals(iceServers.length, 32); 346 347 for (let i = 0; i < 32; i++) { 348 const server = iceServers[i]; 349 assert_array_equals(server.urls, [`stun:stun${i+1}.example.net`]); 350 } 351 }, `with 32 ice servers must succeed`); 352 </script>