1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/test/test-url.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,483 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +'use strict'; 1.8 + 1.9 +const { 1.10 + URL, 1.11 + toFilename, 1.12 + fromFilename, 1.13 + isValidURI, 1.14 + getTLD, 1.15 + DataURL, 1.16 + isLocalURL } = require('sdk/url'); 1.17 + 1.18 +const { pathFor } = require('sdk/system'); 1.19 +const file = require('sdk/io/file'); 1.20 +const tabs = require('sdk/tabs'); 1.21 +const { decode } = require('sdk/base64'); 1.22 + 1.23 +const httpd = require('sdk/test/httpd'); 1.24 +const port = 8099; 1.25 + 1.26 +const defaultLocation = '{\'scheme\':\'about\',\'userPass\':null,\'host\':null,\'hostname\':null,\'port\':null,\'path\':\'addons\',\'pathname\':\'addons\',\'hash\':\'\',\'href\':\'about:addons\',\'origin\':\'about:\',\'protocol\':\'about:\',\'search\':\'\'}'.replace(/'/g, '"'); 1.27 + 1.28 +exports.testResolve = function(assert) { 1.29 + assert.equal(URL('bar', 'http://www.foo.com/').toString(), 1.30 + 'http://www.foo.com/bar'); 1.31 + 1.32 + assert.equal(URL('bar', 'http://www.foo.com'), 1.33 + 'http://www.foo.com/bar'); 1.34 + 1.35 + assert.equal(URL('http://bar.com/', 'http://foo.com/'), 1.36 + 'http://bar.com/', 1.37 + 'relative should override base'); 1.38 + 1.39 + assert.throws(function() { URL('blah'); }, 1.40 + /malformed URI: blah/i, 1.41 + 'url.resolve() should throw malformed URI on base'); 1.42 + 1.43 + assert.throws(function() { URL('chrome://global'); }, 1.44 + /invalid URI: chrome:\/\/global/i, 1.45 + 'url.resolve() should throw invalid URI on base'); 1.46 + 1.47 + assert.throws(function() { URL('chrome://foo/bar'); }, 1.48 + /invalid URI: chrome:\/\/foo\/bar/i, 1.49 + 'url.resolve() should throw on bad chrome URI'); 1.50 + 1.51 + assert.equal(URL('', 'http://www.foo.com'), 1.52 + 'http://www.foo.com/', 1.53 + 'url.resolve() should add slash to end of domain'); 1.54 +}; 1.55 + 1.56 +exports.testParseHttp = function(assert) { 1.57 + var aUrl = 'http://sub.foo.com/bar?locale=en-US&otherArg=%20x%20#myhash'; 1.58 + var info = URL(aUrl); 1.59 + 1.60 + assert.equal(info.scheme, 'http'); 1.61 + assert.equal(info.protocol, 'http:'); 1.62 + assert.equal(info.host, 'sub.foo.com'); 1.63 + assert.equal(info.hostname, 'sub.foo.com'); 1.64 + assert.equal(info.port, null); 1.65 + assert.equal(info.userPass, null); 1.66 + assert.equal(info.path, '/bar?locale=en-US&otherArg=%20x%20#myhash'); 1.67 + assert.equal(info.pathname, '/bar'); 1.68 + assert.equal(info.href, aUrl); 1.69 + assert.equal(info.hash, '#myhash'); 1.70 + assert.equal(info.search, '?locale=en-US&otherArg=%20x%20'); 1.71 +}; 1.72 + 1.73 +exports.testParseHttpSearchAndHash = function (assert) { 1.74 + var info = URL('https://www.moz.com/some/page.html'); 1.75 + assert.equal(info.hash, ''); 1.76 + assert.equal(info.search, ''); 1.77 + 1.78 + var hashOnly = URL('https://www.sub.moz.com/page.html#justhash'); 1.79 + assert.equal(hashOnly.search, ''); 1.80 + assert.equal(hashOnly.hash, '#justhash'); 1.81 + 1.82 + var queryOnly = URL('https://www.sub.moz.com/page.html?my=query'); 1.83 + assert.equal(queryOnly.search, '?my=query'); 1.84 + assert.equal(queryOnly.hash, ''); 1.85 + 1.86 + var qMark = URL('http://www.moz.org?'); 1.87 + assert.equal(qMark.search, ''); 1.88 + assert.equal(qMark.hash, ''); 1.89 + 1.90 + var hash = URL('http://www.moz.org#'); 1.91 + assert.equal(hash.search, ''); 1.92 + assert.equal(hash.hash, ''); 1.93 + 1.94 + var empty = URL('http://www.moz.org?#'); 1.95 + assert.equal(hash.search, ''); 1.96 + assert.equal(hash.hash, ''); 1.97 + 1.98 + var strange = URL('http://moz.org?test1#test2?test3'); 1.99 + assert.equal(strange.search, '?test1'); 1.100 + assert.equal(strange.hash, '#test2?test3'); 1.101 +}; 1.102 + 1.103 +exports.testParseHttpWithPort = function(assert) { 1.104 + var info = URL('http://foo.com:5/bar'); 1.105 + assert.equal(info.port, 5); 1.106 +}; 1.107 + 1.108 +exports.testParseChrome = function(assert) { 1.109 + var info = URL('chrome://global/content/blah'); 1.110 + assert.equal(info.scheme, 'chrome'); 1.111 + assert.equal(info.host, 'global'); 1.112 + assert.equal(info.port, null); 1.113 + assert.equal(info.userPass, null); 1.114 + assert.equal(info.path, '/content/blah'); 1.115 +}; 1.116 + 1.117 +exports.testParseAbout = function(assert) { 1.118 + var info = URL('about:boop'); 1.119 + assert.equal(info.scheme, 'about'); 1.120 + assert.equal(info.host, null); 1.121 + assert.equal(info.port, null); 1.122 + assert.equal(info.userPass, null); 1.123 + assert.equal(info.path, 'boop'); 1.124 +}; 1.125 + 1.126 +exports.testParseFTP = function(assert) { 1.127 + var info = URL('ftp://1.2.3.4/foo'); 1.128 + assert.equal(info.scheme, 'ftp'); 1.129 + assert.equal(info.host, '1.2.3.4'); 1.130 + assert.equal(info.port, null); 1.131 + assert.equal(info.userPass, null); 1.132 + assert.equal(info.path, '/foo'); 1.133 +}; 1.134 + 1.135 +exports.testParseFTPWithUserPass = function(assert) { 1.136 + var info = URL('ftp://user:pass@1.2.3.4/foo'); 1.137 + assert.equal(info.userPass, 'user:pass'); 1.138 +}; 1.139 + 1.140 +exports.testToFilename = function(assert) { 1.141 + assert.throws( 1.142 + function() { toFilename('resource://nonexistent'); }, 1.143 + /resource does not exist: resource:\/\/nonexistent\//i, 1.144 + 'toFilename() on nonexistent resources should throw' 1.145 + ); 1.146 + 1.147 + assert.throws( 1.148 + function() { toFilename('http://foo.com/'); }, 1.149 + /cannot map to filename: http:\/\/foo.com\//i, 1.150 + 'toFilename() on http: URIs should raise error' 1.151 + ); 1.152 + 1.153 + try { 1.154 + assert.ok( 1.155 + /.*console\.xul$/.test(toFilename('chrome://global/content/console.xul')), 1.156 + 'toFilename() w/ console.xul works when it maps to filesystem' 1.157 + ); 1.158 + } 1.159 + catch (e) { 1.160 + if (/chrome url isn\'t on filesystem/.test(e.message)) 1.161 + assert.pass('accessing console.xul in jar raises exception'); 1.162 + else 1.163 + assert.fail('accessing console.xul raises ' + e); 1.164 + } 1.165 + 1.166 + // TODO: Are there any chrome URLs that we're certain exist on the 1.167 + // filesystem? 1.168 + // assert.ok(/.*main\.js$/.test(toFilename('chrome://myapp/content/main.js'))); 1.169 +}; 1.170 + 1.171 +exports.testFromFilename = function(assert) { 1.172 + var profileDirName = require('sdk/system').pathFor('ProfD'); 1.173 + var fileUrl = fromFilename(profileDirName); 1.174 + assert.equal(URL(fileUrl).scheme, 'file', 1.175 + 'toFilename() should return a file: url'); 1.176 + assert.equal(fromFilename(toFilename(fileUrl)), fileUrl); 1.177 +}; 1.178 + 1.179 +exports.testURL = function(assert) { 1.180 + assert.ok(URL('h:foo') instanceof URL, 'instance is of correct type'); 1.181 + assert.throws(function() URL(), 1.182 + /malformed URI: undefined/i, 1.183 + 'url.URL should throw on undefined'); 1.184 + assert.throws(function() URL(''), 1.185 + /malformed URI: /i, 1.186 + 'url.URL should throw on empty string'); 1.187 + assert.throws(function() URL('foo'), 1.188 + /malformed URI: foo/i, 1.189 + 'url.URL should throw on invalid URI'); 1.190 + assert.ok(URL('h:foo').scheme, 'has scheme'); 1.191 + assert.equal(URL('h:foo').toString(), 1.192 + 'h:foo', 1.193 + 'toString should roundtrip'); 1.194 + // test relative + base 1.195 + assert.equal(URL('mypath', 'http://foo').toString(), 1.196 + 'http://foo/mypath', 1.197 + 'relative URL resolved to base'); 1.198 + // test relative + no base 1.199 + assert.throws(function() URL('path').toString(), 1.200 + /malformed URI: path/i, 1.201 + 'no base for relative URI should throw'); 1.202 + 1.203 + let a = URL('h:foo'); 1.204 + let b = URL(a); 1.205 + assert.equal(b.toString(), 1.206 + 'h:foo', 1.207 + 'a URL can be initialized from another URL'); 1.208 + assert.notStrictEqual(a, b, 1.209 + 'a URL initialized from another URL is not the same object'); 1.210 + assert.ok(a == 'h:foo', 1.211 + 'toString is implicit when a URL is compared to a string via =='); 1.212 + assert.strictEqual(a + '', 'h:foo', 1.213 + 'toString is implicit when a URL is concatenated to a string'); 1.214 +}; 1.215 + 1.216 +exports.testStringInterface = function(assert) { 1.217 + var EM = 'about:addons'; 1.218 + var a = URL(EM); 1.219 + 1.220 + // make sure the standard URL properties are enumerable and not the String interface bits 1.221 + assert.equal(Object.keys(a), 1.222 + 'scheme,userPass,host,hostname,port,path,pathname,hash,href,origin,protocol,search', 1.223 + 'enumerable key list check for URL.'); 1.224 + assert.equal( 1.225 + JSON.stringify(a), 1.226 + defaultLocation, 1.227 + 'JSON.stringify should return a object with correct props and vals.'); 1.228 + 1.229 + // make sure that the String interface exists and works as expected 1.230 + assert.equal(a.indexOf(':'), EM.indexOf(':'), 'indexOf on URL works'); 1.231 + assert.equal(a.valueOf(), EM.valueOf(), 'valueOf on URL works.'); 1.232 + assert.equal(a.toSource(), EM.toSource(), 'toSource on URL works.'); 1.233 + assert.equal(a.lastIndexOf('a'), EM.lastIndexOf('a'), 'lastIndexOf on URL works.'); 1.234 + assert.equal(a.match('t:').toString(), EM.match('t:').toString(), 'match on URL works.'); 1.235 + assert.equal(a.toUpperCase(), EM.toUpperCase(), 'toUpperCase on URL works.'); 1.236 + assert.equal(a.toLowerCase(), EM.toLowerCase(), 'toLowerCase on URL works.'); 1.237 + assert.equal(a.split(':').toString(), EM.split(':').toString(), 'split on URL works.'); 1.238 + assert.equal(a.charAt(2), EM.charAt(2), 'charAt on URL works.'); 1.239 + assert.equal(a.charCodeAt(2), EM.charCodeAt(2), 'charCodeAt on URL works.'); 1.240 + assert.equal(a.concat(EM), EM.concat(a), 'concat on URL works.'); 1.241 + assert.equal(a.substr(2,3), EM.substr(2,3), 'substr on URL works.'); 1.242 + assert.equal(a.substring(2,3), EM.substring(2,3), 'substring on URL works.'); 1.243 + assert.equal(a.trim(), EM.trim(), 'trim on URL works.'); 1.244 + assert.equal(a.trimRight(), EM.trimRight(), 'trimRight on URL works.'); 1.245 + assert.equal(a.trimLeft(), EM.trimLeft(), 'trimLeft on URL works.'); 1.246 +} 1.247 + 1.248 +exports.testDataURLwithouthURI = function (assert) { 1.249 + let dataURL = new DataURL(); 1.250 + 1.251 + assert.equal(dataURL.base64, false, 'base64 is false for empty uri') 1.252 + assert.equal(dataURL.data, '', 'data is an empty string for empty uri') 1.253 + assert.equal(dataURL.mimeType, '', 'mimeType is an empty string for empty uri') 1.254 + assert.equal(Object.keys(dataURL.parameters).length, 0, 'parameters is an empty object for empty uri'); 1.255 + 1.256 + assert.equal(dataURL.toString(), 'data:,'); 1.257 +} 1.258 + 1.259 +exports.testDataURLwithMalformedURI = function (assert) { 1.260 + assert.throws(function() { 1.261 + let dataURL = new DataURL('http://www.mozilla.com/'); 1.262 + }, 1.263 + /Malformed Data URL: http:\/\/www.mozilla.com\//i, 1.264 + 'DataURL raises an exception for malformed data uri' 1.265 + ); 1.266 +} 1.267 + 1.268 +exports.testDataURLparse = function (assert) { 1.269 + let dataURL = new DataURL('data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E'); 1.270 + 1.271 + assert.equal(dataURL.base64, false, 'base64 is false for non base64 data uri') 1.272 + assert.equal(dataURL.data, '<h1>Hello!</h1>', 'data is properly decoded') 1.273 + assert.equal(dataURL.mimeType, 'text/html', 'mimeType is set properly') 1.274 + assert.equal(Object.keys(dataURL.parameters).length, 1, 'one parameters specified'); 1.275 + assert.equal(dataURL.parameters['charset'], 'US-ASCII', 'charset parsed'); 1.276 + 1.277 + assert.equal(dataURL.toString(), 'data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E'); 1.278 +} 1.279 + 1.280 +exports.testDataURLparseBase64 = function (assert) { 1.281 + let text = 'Awesome!'; 1.282 + let b64text = 'QXdlc29tZSE='; 1.283 + let dataURL = new DataURL('data:text/plain;base64,' + b64text); 1.284 + 1.285 + assert.equal(dataURL.base64, true, 'base64 is true for base64 encoded data uri') 1.286 + assert.equal(dataURL.data, text, 'data is properly decoded') 1.287 + assert.equal(dataURL.mimeType, 'text/plain', 'mimeType is set properly') 1.288 + assert.equal(Object.keys(dataURL.parameters).length, 1, 'one parameters specified'); 1.289 + assert.equal(dataURL.parameters['base64'], '', 'parameter set without value'); 1.290 + assert.equal(dataURL.toString(), 'data:text/plain;base64,' + encodeURIComponent(b64text)); 1.291 +} 1.292 + 1.293 +exports.testIsValidURI = function (assert) { 1.294 + validURIs().forEach(function (aUri) { 1.295 + assert.equal(isValidURI(aUri), true, aUri + ' is a valid URL'); 1.296 + }); 1.297 +}; 1.298 + 1.299 +exports.testIsInvalidURI = function (assert) { 1.300 + invalidURIs().forEach(function (aUri) { 1.301 + assert.equal(isValidURI(aUri), false, aUri + ' is an invalid URL'); 1.302 + }); 1.303 +}; 1.304 + 1.305 +exports.testURLFromURL = function(assert) { 1.306 + let aURL = URL('http://mozilla.org'); 1.307 + let bURL = URL(aURL); 1.308 + assert.equal(aURL.toString(), bURL.toString(), 'Making a URL from a URL works'); 1.309 +}; 1.310 + 1.311 +exports.testTLD = function(assert) { 1.312 + let urls = [ 1.313 + { url: 'http://my.sub.domains.mozilla.co.uk', tld: 'co.uk' }, 1.314 + { url: 'http://my.mozilla.com', tld: 'com' }, 1.315 + { url: 'http://my.domains.mozilla.org.hk', tld: 'org.hk' }, 1.316 + { url: 'chrome://global/content/blah', tld: 'global' }, 1.317 + { url: 'data:text/plain;base64,QXdlc29tZSE=', tld: null }, 1.318 + { url: 'https://1.2.3.4', tld: null } 1.319 + ]; 1.320 + 1.321 + urls.forEach(function (uri) { 1.322 + assert.equal(getTLD(uri.url), uri.tld); 1.323 + assert.equal(getTLD(URL(uri.url)), uri.tld); 1.324 + }); 1.325 +} 1.326 + 1.327 +exports.testWindowLocationMatch = function (assert, done) { 1.328 + let server = httpd.startServerAsync(port); 1.329 + server.registerPathHandler('/index.html', function (request, response) { 1.330 + response.write('<html><head></head><body><h1>url tests</h1></body></html>'); 1.331 + }); 1.332 + 1.333 + let aUrl = 'http://localhost:' + port + '/index.html?q=aQuery#somehash'; 1.334 + let urlObject = URL(aUrl); 1.335 + 1.336 + tabs.open({ 1.337 + url: aUrl, 1.338 + onReady: function (tab) { 1.339 + tab.attach({ 1.340 + onMessage: function (loc) { 1.341 + for (let prop in loc) { 1.342 + assert.equal(urlObject[prop], loc[prop], prop + ' matches'); 1.343 + } 1.344 + 1.345 + tab.close(function() server.stop(done)); 1.346 + }, 1.347 + contentScript: '(' + function () { 1.348 + let res = {}; 1.349 + // `origin` is `null` in this context??? 1.350 + let props = 'hostname,port,pathname,hash,href,protocol,search'.split(','); 1.351 + props.forEach(function (prop) { 1.352 + res[prop] = window.location[prop]; 1.353 + }); 1.354 + self.postMessage(res); 1.355 + } + ')()' 1.356 + }); 1.357 + } 1.358 + }) 1.359 +}; 1.360 + 1.361 +exports.testURLInRegExpTest = function(assert) { 1.362 + let url = 'https://mozilla.org'; 1.363 + assert.equal((new RegExp(url).test(URL(url))), true, 'URL instances work in a RegExp test'); 1.364 +} 1.365 + 1.366 +exports.testLocalURL = function(assert) { 1.367 + [ 1.368 + 'data:text/html;charset=utf-8,foo and bar', 1.369 + 'data:text/plain,foo and bar', 1.370 + 'resource://gre/modules/commonjs/', 1.371 + 'chrome://browser/content/browser.xul' 1.372 + ].forEach(aUri => { 1.373 + assert.ok(isLocalURL(aUri), aUri + ' is a Local URL'); 1.374 + }) 1.375 + 1.376 +} 1.377 + 1.378 +exports.testLocalURLwithRemoteURL = function(assert) { 1.379 + validURIs().filter(url => !url.startsWith('data:')).forEach(aUri => { 1.380 + assert.ok(!isLocalURL(aUri), aUri + ' is an invalid Local URL'); 1.381 + }); 1.382 +} 1.383 + 1.384 +exports.testLocalURLwithInvalidURL = function(assert) { 1.385 + invalidURIs().concat([ 1.386 + 'data:foo and bar', 1.387 + 'resource:// must fail', 1.388 + 'chrome:// here too' 1.389 + ]).forEach(aUri => { 1.390 + assert.ok(!isLocalURL(aUri), aUri + ' is an invalid Local URL'); 1.391 + }); 1.392 +} 1.393 + 1.394 +function validURIs() { 1.395 + return [ 1.396 + 'http://foo.com/blah_blah', 1.397 + 'http://foo.com/blah_blah/', 1.398 + 'http://foo.com/blah_blah_(wikipedia)', 1.399 + 'http://foo.com/blah_blah_(wikipedia)_(again)', 1.400 + 'http://www.example.com/wpstyle/?p=364', 1.401 + 'https://www.example.com/foo/?bar=baz&inga=42&quux', 1.402 + 'http://✪df.ws/123', 1.403 + 'http://userid:password@example.com:8080', 1.404 + 'http://userid:password@example.com:8080/', 1.405 + 'http://userid@example.com', 1.406 + 'http://userid@example.com/', 1.407 + 'http://userid@example.com:8080', 1.408 + 'http://userid@example.com:8080/', 1.409 + 'http://userid:password@example.com', 1.410 + 'http://userid:password@example.com/', 1.411 + 'http://142.42.1.1/', 1.412 + 'http://142.42.1.1:8080/', 1.413 + 'http://➡.ws/䨹', 1.414 + 'http://⌘.ws', 1.415 + 'http://⌘.ws/', 1.416 + 'http://foo.com/blah_(wikipedia)#cite-1', 1.417 + 'http://foo.com/blah_(wikipedia)_blah#cite-1', 1.418 + 'http://foo.com/unicode_(✪)_in_parens', 1.419 + 'http://foo.com/(something)?after=parens', 1.420 + 'http://☺.damowmow.com/', 1.421 + 'http://code.google.com/events/#&product=browser', 1.422 + 'http://j.mp', 1.423 + 'ftp://foo.bar/baz', 1.424 + 'http://foo.bar/?q=Test%20URL-encoded%20stuff', 1.425 + 'http://مثال.إختبار', 1.426 + 'http://例子.测试', 1.427 + 'http://उदाहरण.परीक्षा', 1.428 + 'http://-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com', 1.429 + 'http://1337.net', 1.430 + 'http://a.b-c.de', 1.431 + 'http://223.255.255.254', 1.432 + // Also want to validate data-uris, localhost 1.433 + 'http://localhost:8432/some-file.js', 1.434 + 'data:text/plain;base64,', 1.435 + 'data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E', 1.436 + 'data:text/html;charset=utf-8,' 1.437 + ]; 1.438 +} 1.439 + 1.440 +// Some invalidURIs are valid according to the regex used, 1.441 +// can be improved in the future, but better to pass some 1.442 +// invalid URLs than prevent valid URLs 1.443 + 1.444 +function invalidURIs () { 1.445 + return [ 1.446 +// 'http://', 1.447 +// 'http://.', 1.448 +// 'http://..', 1.449 +// 'http://../', 1.450 +// 'http://?', 1.451 +// 'http://??', 1.452 +// 'http://??/', 1.453 +// 'http://#', 1.454 +// 'http://##', 1.455 +// 'http://##/', 1.456 +// 'http://foo.bar?q=Spaces should be encoded', 1.457 + 'not a url', 1.458 + '//', 1.459 + '//a', 1.460 + '///a', 1.461 + '///', 1.462 +// 'http:///a', 1.463 + 'foo.com', 1.464 + 'http:// shouldfail.com', 1.465 + ':// should fail', 1.466 +// 'http://foo.bar/foo(bar)baz quux', 1.467 +// 'http://-error-.invalid/', 1.468 +// 'http://a.b--c.de/', 1.469 +// 'http://-a.b.co', 1.470 +// 'http://a.b-.co', 1.471 +// 'http://0.0.0.0', 1.472 +// 'http://10.1.1.0', 1.473 +// 'http://10.1.1.255', 1.474 +// 'http://224.1.1.1', 1.475 +// 'http://1.1.1.1.1', 1.476 +// 'http://123.123.123', 1.477 +// 'http://3628126748', 1.478 +// 'http://.www.foo.bar/', 1.479 +// 'http://www.foo.bar./', 1.480 +// 'http://.www.foo.bar./', 1.481 +// 'http://10.1.1.1', 1.482 +// 'http://10.1.1.254' 1.483 + ]; 1.484 +} 1.485 + 1.486 +require('sdk/test').run(exports);