browser_webrtc_hooks.js (10059B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 const ORIGIN = "https://example.com"; 6 7 async function tryPeerConnection(browser, expectedError = null) { 8 let errtype = await SpecialPowers.spawn(browser, [], async function () { 9 let pc = new content.RTCPeerConnection(); 10 try { 11 await pc.createOffer({ offerToReceiveAudio: true }); 12 return null; 13 } catch (err) { 14 return err.name; 15 } 16 }); 17 18 let detail = expectedError 19 ? `createOffer() threw a ${expectedError}` 20 : "createOffer() succeeded"; 21 is(errtype, expectedError, detail); 22 } 23 24 // Helper for tests that use the peer-request-allowed and -blocked events. 25 // A test that expects some of those events does the following: 26 // - call Events.on() before the test to setup event handlers 27 // - call Events.expect(name) after a specific event is expected to have 28 // occured. This will fail if the event didn't occur, and will return 29 // the details passed to the handler for furhter checking. 30 // - call Events.off() at the end of the test to clean up. At this point, if 31 // any events were triggered that the test did not expect, the test fails. 32 const Events = { 33 events: ["peer-request-allowed", "peer-request-blocked"], 34 details: new Map(), 35 handlers: new Map(), 36 on() { 37 for (let event of this.events) { 38 let handler = data => { 39 if (this.details.has(event)) { 40 ok(false, `Got multiple ${event} events`); 41 } 42 this.details.set(event, data); 43 }; 44 webrtcUI.on(event, handler); 45 this.handlers.set(event, handler); 46 } 47 }, 48 expect(event) { 49 let result = this.details.get(event); 50 isnot(result, undefined, `${event} event was triggered`); 51 this.details.delete(event); 52 53 // All events should have a good origin 54 is(result.origin, ORIGIN, `${event} event has correct origin`); 55 56 return result; 57 }, 58 off() { 59 for (let event of this.events) { 60 webrtcUI.off(event, this.handlers.get(event)); 61 this.handlers.delete(event); 62 } 63 for (let [event] of this.details) { 64 ok(false, `Got unexpected event ${event}`); 65 } 66 }, 67 }; 68 69 var gTests = [ 70 { 71 desc: "Basic peer-request-allowed event", 72 run: async function testPeerRequestEvent(browser) { 73 Events.on(); 74 75 await tryPeerConnection(browser); 76 77 let details = Events.expect("peer-request-allowed"); 78 isnot( 79 details.callID, 80 undefined, 81 "peer-request-allowed event includes callID" 82 ); 83 isnot( 84 details.windowID, 85 undefined, 86 "peer-request-allowed event includes windowID" 87 ); 88 89 Events.off(); 90 }, 91 }, 92 93 { 94 desc: "Immediate peer connection blocker can allow", 95 run: async function testBlocker(browser) { 96 Events.on(); 97 98 let blockerCalled = false; 99 let blocker = params => { 100 is( 101 params.origin, 102 ORIGIN, 103 "Peer connection blocker origin parameter is correct" 104 ); 105 blockerCalled = true; 106 return "allow"; 107 }; 108 109 webrtcUI.addPeerConnectionBlocker(blocker); 110 111 await tryPeerConnection(browser); 112 is(blockerCalled, true, "Blocker was called"); 113 Events.expect("peer-request-allowed"); 114 115 webrtcUI.removePeerConnectionBlocker(blocker); 116 Events.off(); 117 }, 118 }, 119 120 { 121 desc: "Deferred peer connection blocker can allow", 122 run: async function testDeferredBlocker(browser) { 123 Events.on(); 124 125 let blocker = () => Promise.resolve("allow"); 126 webrtcUI.addPeerConnectionBlocker(blocker); 127 128 await tryPeerConnection(browser); 129 Events.expect("peer-request-allowed"); 130 131 webrtcUI.removePeerConnectionBlocker(blocker); 132 Events.off(); 133 }, 134 }, 135 136 { 137 desc: "Immediate peer connection blocker can deny", 138 run: async function testBlockerDeny(browser) { 139 Events.on(); 140 141 let blocker = () => "deny"; 142 webrtcUI.addPeerConnectionBlocker(blocker); 143 144 await tryPeerConnection(browser, "NotAllowedError"); 145 146 Events.expect("peer-request-blocked"); 147 148 webrtcUI.removePeerConnectionBlocker(blocker); 149 Events.off(); 150 }, 151 }, 152 153 { 154 desc: "Multiple blockers work (both allow)", 155 run: async function testMultipleAllowBlockers(browser) { 156 Events.on(); 157 158 let blocker1Called = false, 159 blocker1 = () => { 160 blocker1Called = true; 161 return "allow"; 162 }; 163 webrtcUI.addPeerConnectionBlocker(blocker1); 164 165 let blocker2Called = false, 166 blocker2 = () => { 167 blocker2Called = true; 168 return "allow"; 169 }; 170 webrtcUI.addPeerConnectionBlocker(blocker2); 171 172 await tryPeerConnection(browser); 173 174 Events.expect("peer-request-allowed"); 175 ok(blocker1Called, "First blocker was called"); 176 ok(blocker2Called, "Second blocker was called"); 177 178 webrtcUI.removePeerConnectionBlocker(blocker1); 179 webrtcUI.removePeerConnectionBlocker(blocker2); 180 Events.off(); 181 }, 182 }, 183 184 { 185 desc: "Multiple blockers work (allow then deny)", 186 run: async function testAllowDenyBlockers(browser) { 187 Events.on(); 188 189 let blocker1Called = false, 190 blocker1 = () => { 191 blocker1Called = true; 192 return "allow"; 193 }; 194 webrtcUI.addPeerConnectionBlocker(blocker1); 195 196 let blocker2Called = false, 197 blocker2 = () => { 198 blocker2Called = true; 199 return "deny"; 200 }; 201 webrtcUI.addPeerConnectionBlocker(blocker2); 202 203 await tryPeerConnection(browser, "NotAllowedError"); 204 205 Events.expect("peer-request-blocked"); 206 ok(blocker1Called, "First blocker was called"); 207 ok(blocker2Called, "Second blocker was called"); 208 209 webrtcUI.removePeerConnectionBlocker(blocker1); 210 webrtcUI.removePeerConnectionBlocker(blocker2); 211 Events.off(); 212 }, 213 }, 214 215 { 216 desc: "Multiple blockers work (deny first)", 217 run: async function testDenyAllowBlockers(browser) { 218 Events.on(); 219 220 let blocker1Called = false, 221 blocker1 = () => { 222 blocker1Called = true; 223 return "deny"; 224 }; 225 webrtcUI.addPeerConnectionBlocker(blocker1); 226 227 let blocker2Called = false, 228 blocker2 = () => { 229 blocker2Called = true; 230 return "allow"; 231 }; 232 webrtcUI.addPeerConnectionBlocker(blocker2); 233 234 await tryPeerConnection(browser, "NotAllowedError"); 235 236 Events.expect("peer-request-blocked"); 237 ok(blocker1Called, "First blocker was called"); 238 ok( 239 !blocker2Called, 240 "Peer connection blocker after a deny is not invoked" 241 ); 242 243 webrtcUI.removePeerConnectionBlocker(blocker1); 244 webrtcUI.removePeerConnectionBlocker(blocker2); 245 Events.off(); 246 }, 247 }, 248 249 { 250 desc: "Blockers may be removed", 251 run: async function testRemoveBlocker(browser) { 252 Events.on(); 253 254 let blocker1Called = false, 255 blocker1 = () => { 256 blocker1Called = true; 257 return "allow"; 258 }; 259 webrtcUI.addPeerConnectionBlocker(blocker1); 260 261 let blocker2Called = false, 262 blocker2 = () => { 263 blocker2Called = true; 264 return "allow"; 265 }; 266 webrtcUI.addPeerConnectionBlocker(blocker2); 267 webrtcUI.removePeerConnectionBlocker(blocker1); 268 269 await tryPeerConnection(browser); 270 271 Events.expect("peer-request-allowed"); 272 273 ok(!blocker1Called, "Removed peer connection blocker is not invoked"); 274 ok(blocker2Called, "Second peer connection blocker was invoked"); 275 276 webrtcUI.removePeerConnectionBlocker(blocker2); 277 Events.off(); 278 }, 279 }, 280 281 { 282 desc: "Blocker that throws is ignored", 283 run: async function testBlockerThrows(browser) { 284 Events.on(); 285 let blocker1Called = false, 286 blocker1 = () => { 287 blocker1Called = true; 288 throw new Error("kaboom"); 289 }; 290 webrtcUI.addPeerConnectionBlocker(blocker1); 291 292 let blocker2Called = false, 293 blocker2 = () => { 294 blocker2Called = true; 295 return "allow"; 296 }; 297 webrtcUI.addPeerConnectionBlocker(blocker2); 298 299 await tryPeerConnection(browser); 300 301 Events.expect("peer-request-allowed"); 302 ok(blocker1Called, "First blocker was invoked"); 303 ok(blocker2Called, "Second blocker was invoked"); 304 305 webrtcUI.removePeerConnectionBlocker(blocker1); 306 webrtcUI.removePeerConnectionBlocker(blocker2); 307 Events.off(); 308 }, 309 }, 310 311 { 312 desc: "Cancel peer request", 313 run: async function testBlockerCancel(browser) { 314 let blocker, 315 blockerPromise = new Promise(resolve => { 316 blocker = () => { 317 resolve(); 318 // defer indefinitely 319 return new Promise(() => {}); 320 }; 321 }); 322 webrtcUI.addPeerConnectionBlocker(blocker); 323 324 await SpecialPowers.spawn(browser, [], async function () { 325 new content.RTCPeerConnection().createOffer({ 326 offerToReceiveAudio: true, 327 }); 328 }); 329 330 await blockerPromise; 331 332 let eventPromise = new Promise(resolve => { 333 webrtcUI.on("peer-request-cancel", function listener(details) { 334 resolve(details); 335 webrtcUI.off("peer-request-cancel", listener); 336 }); 337 }); 338 339 await SpecialPowers.spawn(browser, [], async function () { 340 content.location.reload(); 341 }); 342 343 let details = await eventPromise; 344 isnot( 345 details.callID, 346 undefined, 347 "peer-request-cancel event includes callID" 348 ); 349 is( 350 details.origin, 351 ORIGIN, 352 "peer-request-cancel event has correct origin" 353 ); 354 355 webrtcUI.removePeerConnectionBlocker(blocker); 356 }, 357 }, 358 ]; 359 360 add_task(async function test() { 361 await runTests(gTests, { 362 skipObserverVerification: true, 363 cleanup() { 364 is( 365 webrtcUI.peerConnectionBlockers.size, 366 0, 367 "Peer connection blockers list is empty" 368 ); 369 }, 370 }); 371 });