protocol-handler-unregister.https.html (5357B)
1 <!DOCTYPE html> 2 <meta name="timeout" content="long"> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script src="/resources/testdriver.js"></script> 6 <script src="/resources/testdriver-vendor.js"></script> 7 <script src="/common/utils.js"></script> 8 <script src="/common/dispatcher/dispatcher.js"></script> 9 <script src="../resources/utils.js"></script> 10 <script src="resources/utils.js"></script> 11 <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> 12 13 <script> 14 15 function getNextWindowMessageFromFrame(frame) { 16 return new Promise(resolve => { 17 window.addEventListener('message', event => { 18 if (event.source === frame.contentWindow) { 19 resolve(event.data); 20 } 21 }); 22 }); 23 } 24 25 function getNextMessageFromServiceWorker(serviceWorker) { 26 return new Promise(resolve => { 27 serviceWorker.addEventListener('message', event => { 28 resolve(event.data); 29 }, {once: true}); 30 }); 31 } 32 33 promise_setup(async () => { 34 assertSpeculationRulesIsSupported() 35 await test_driver.set_rph_registration_mode('autoAccept'); 36 await test_driver.bless('handler registration'); 37 }); 38 39 // The overall idea for this test is: 40 // 1. Register a protocol handler for a custom URI scheme. 41 // 2. Create a prerendered page that unregisters the protocol handler. 42 // 3. Navigate an iframe to the custom URI scheme. It should navigate 43 // successfully. 44 // 4. Activate the prerendered page. This should run the deferred unregistration 45 // work. 46 // 5. Navigate the iframe to the custom URI scheme again. It should fail to 47 // navigate. 48 // To detect the navigation failure, we use a service worker to perform the 49 // navigation via client.navigate and report the result back to 50 // the test. This is because the service worker's client.navigate method 51 // actually reports if the navigation failed, unlike other mechanisms which 52 // tell us nothing in this case. 53 promise_test(async t => { 54 const customUrlScheme = 'web+wptrphtest'; 55 function getProtocolHandlerUrlTemplate(id) { 56 return new URL( 57 `resources/protocol-handler.html?id=${id}&s=%s`, location.href).href; 58 } 59 60 const urlTemplate = getProtocolHandlerUrlTemplate('unregister'); 61 62 t.add_cleanup(() => { 63 navigator.unregisterProtocolHandler( 64 customUrlScheme, urlTemplate); 65 }); 66 navigator.registerProtocolHandler(customUrlScheme, urlTemplate); 67 68 const {exec, activate} = await create_prerendered_page(t); 69 70 const result = await exec( 71 (customUrlScheme, urlTemplate) => { 72 try { 73 navigator.unregisterProtocolHandler( 74 customUrlScheme, urlTemplate); 75 } catch (registerProtocolHandlerException) { 76 return 'registerProtocolHandler failed with \'' + 77 registerProtocolHandlerException.name + '\''; 78 } 79 return 'success'; 80 }, [customUrlScheme, urlTemplate]); 81 assert_equals(result, 'success', 'unregisterProtocolHandler should succeed.'); 82 83 const frame1 = await with_iframe('about:blank'); 84 85 const frame1MessagePromise = getNextWindowMessageFromFrame(frame1); 86 frame1.src = `${customUrlScheme}:1`; 87 assert_equals((await frame1MessagePromise).id, 'unregister', 88 'Until activation, the initial handler should be registered.'); 89 90 frame1.remove(); 91 92 // Activate the prerendered page. 93 await activate(); 94 95 // At this point the deferred unregistration work has run during activation 96 // and the protocol handler is no longer registered. 97 // We use Service Worker client.navigate to detect the failed navigation since 98 // it is well supported and reliably reports error for unknown URL schemes. 99 const serviceWorkerScope = 100 'resources/protocol-handler.html?service_worker_client'; 101 const frame2Url = serviceWorkerScope + '&id=communication'; 102 const frame3Url = serviceWorkerScope + '&id=nav_target'; 103 const serviceWorkerUrl = 'resources/protocol-handler-service-worker.js'; 104 const serviceWorkerRegistration = 105 await service_worker_unregister_and_register( 106 t, serviceWorkerUrl, serviceWorkerScope); 107 108 t.add_cleanup(async () => { 109 await serviceWorkerRegistration.unregister(); 110 }); 111 112 await wait_for_state(t, serviceWorkerRegistration.installing, 'activated'); 113 114 // We use frame2 to communicate with the service worker. 115 const frame2 = await with_iframe(frame2Url); 116 117 // Frame3 is used by the service worker to attempt navigation. 118 const frame3 = await with_iframe(frame3Url); 119 120 const serviceWorkerMessagePromise = getNextMessageFromServiceWorker( 121 frame2.contentWindow.navigator.serviceWorker); 122 123 // Post message via frame2 to the service worker to tell it to navigate frame3 124 // to the custom URI. 125 frame2.contentWindow.navigator.serviceWorker.controller.postMessage( 126 {clientUrlMatch: new URL(frame3Url, location.href).href, 127 navigationUrl: `${customUrlScheme}:3`}); 128 129 // The service worker will post message back the result of the navigation. 130 const navigationResult = await serviceWorkerMessagePromise; 131 132 frame2.remove(); 133 frame3.remove(); 134 135 assert_false(navigationResult.success, 'Navigation to unregistered URI should fail'); 136 assert_equals(navigationResult.message, 'navigate failure: TypeError', 137 'unregisterProtocolHandler should have completed.'); 138 }, 'prerendering page unregisterProtocolHandler call defers registration until activation.'); 139 140 </script>