Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

<!DOCTYPE html>
<meta charset='utf-8'>
<title>protocol handlers</title>
<script src='/resources/testharness.js'></script>
<script src='/resources/testharnessreport.js'></script>
<noscript><p>Enable JavaScript and reload.</p></noscript>
<p><strong>Note:</strong> If your browser limits the number of handler
registration requests on a page, you might need to disable or significantly
increase that limit for the tests below to run.</p>
<script>
test(() => {
assert_idl_attribute(navigator, 'registerProtocolHandler');
}, 'the registerProtocolHandler method should exist on the navigator object');
test(() => {
assert_idl_attribute(navigator, 'unregisterProtocolHandler');
}, 'the unregisterProtocolHandler method should exist on the navigator object');
/* URL argument */
[
'%s',
'foo/%s',
`%s${location.href}`,
location.href.replace(location.protocol,
`${location.protocol[0]}%s${location.protocol.substring(1)}`),
location.href.replace(location.protocol, `${location.protocol}%s`),
location.href + '/%s',
location.href + '#%s',
location.href + '?foo=%s',
location.href + '?foo=%s&bar',
location.href + '/%s/bar/baz/',
location.href + '/%s/bar/baz/?foo=1337&bar#baz',
location.href + '/%s/foo/%s/',
].forEach(url => {
test(() => {
navigator.registerProtocolHandler('tel', url, 'foo');
}, 'registerProtocolHandler: Valid URL "' + url + '" should work.');
test(() => {
navigator.unregisterProtocolHandler('tel', url);
}, 'unregisterProtocolHandler: Valid URL "' + url + '" should work.');
});
/* Invalid URLs */
[
'',
'%S',
location.href.replace(location.hostname, `%s${location.hostname}`),
location.href.replace(location.port, `%s${location.port}`),
location.href + '',
location.href + '/%',
location.href + '/%a',
].forEach(url => {
test(() => {
assert_throws_dom('SYNTAX_ERR', () => { navigator.registerProtocolHandler('mailto', url, 'foo'); });
assert_throws_dom('SECURITY_ERR', () => { navigator.registerProtocolHandler('x', url, 'foo'); });
}, `registerProtocolHandler: Invalid URL "${url}" should throw (but after scheme)`);
test(() => {
assert_throws_dom('SYNTAX_ERR', () => { navigator.unregisterProtocolHandler('mailto', url); });
assert_throws_dom('SECURITY_ERR', () => { navigator.unregisterProtocolHandler('x', url, 'foo'); });
}, `unregisterProtocolHandler: Invalid URL "${url}" should throw (but after scheme)`);
});
[
'mailto:%s@example.com',
'mailto:%s',
`chrome://${location.host}/%s`,
`foo://${location.host}/%s`,
URL.createObjectURL(new Blob()) + "#%s",
].forEach(url => {
const title = url.startsWith("blob:") ? "blob: URL" : url;
test(() => {
assert_throws_dom('SECURITY_ERR', () => { navigator.registerProtocolHandler('mailto', url, 'foo'); });
}, `registerProtocolHandler: Invalid URL "${title}" should throw SECURITY_ERR.`);
test(() => {
assert_throws_dom('SECURITY_ERR', () => { navigator.unregisterProtocolHandler('mailto', url); });
}, `unregisterProtocolHandler: Invalid URL "${title}" should throw SECURITY_ERR.`);
});
/* Protocol argument */
/* Overriding any of the following protocols must never be allowed. That would
* break the browser. */
[
'about',
'attachment',
'blob',
'chrome',
'cid',
'data',
'file',
'http',
'https',
'javascript',
'livescript',
'mid',
'mocha',
'moz-icon',
'opera',
'operamail',
'res',
'resource',
'shttp',
'tcl',
'vbscript',
'view-source',
'ws',
'wss',
'wyciwyg',
/* other invalid schemes */
'unrecognized',
'mаilto', /* a cyrillic "а" */
'mailto:',
'mailto://',
'mailto' + String.fromCharCode(0),
'mailtoo' + String.fromCharCode(8),
'mailto' + String.fromCharCode(10),
'http://',
'ssh:/',
'magnet:+',
'tel:sip',
'foo',
'fweb+oo',
/* web+ prefixed schemes must be followed by 1+ ascii alphas */
'web+',
'web+1',
'web+namewithid123',
'web+namewithtrailingspace ',
'web+préfixewithaccent', // é is not ascii alpha
'web+Kelvinsign', // ASCII-lower KELVIN SIGN is not k
'web+latinsmallletterlongſ', // ASCII-lower LATIN SMALL LETTER LONG S is not s
'web+dots.are.forbidden',
'web+dashes-are-forbidden',
'web+underscores_are_forbidden',
'web+spaces are forbidden',
'web+non*alpha*are*forbidden',
'web+digits123areforbidden',
].forEach(scheme => {
test(() => {
// https://test:test/ does not parse and does not contain %s, but the scheme check happens first
assert_throws_dom('SECURITY_ERR', () => { navigator.registerProtocolHandler(scheme, 'https://test:test/', 'foo'); });
}, 'registerProtocolHandler: Attempting to override the "' + scheme + '" protocol should throw SECURITY_ERR.');
test(() => {
assert_throws_dom('SECURITY_ERR', () => { navigator.unregisterProtocolHandler(scheme, 'https://test:test/'); });
}, 'unregisterProtocolHandler: Attempting to override the "' + scheme + '" protocol should throw SECURITY_ERR.');
});
/* The following protocols must be possible to override.
* We're just testing that the call goes through here. Whether or not they
* actually work as handlers is covered by the interactive tests. */
[
/* safelisted schemes listed in
'bitcoin',
'ftp',
'ftps',
'geo',
'im',
'irc',
'ircs',
'magnet',
'mailto',
'matrix',
'mms',
'news',
'nntp',
'openpgp4fpr',
'sftp',
'sip',
'sms',
'smsto',
'ssh',
'tel',
'urn',
'webcal',
'wtai',
'xmpp',
/* other valid schemes */
'BitcoIn',
'Irc',
'MagneT',
'Matrix',
'SmsTo',
'TEL',
'teL',
'WebCAL',
'WTAI',
'web+myprotocol',
'web+abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', // all alphas
'web+UpperCasedIsLowercased',
'WEB+seeabove',
'WeB+SeEaBoVe'
].forEach(scheme => {
test(() => {
navigator.registerProtocolHandler(scheme, location.href + '/%s', "foo");
}, 'registerProtocolHandler: overriding the "' + scheme + '" protocol should work');
test(() => {
navigator.unregisterProtocolHandler(scheme, location.href + '/%s');
}, 'unregisterProtocolHandler: overriding the "' + scheme + '" protocol should work');
});
</script>