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/. */
13 isLocalURL } = require('sdk/url');
15 const { pathFor } = require('sdk/system');
16 const file = require('sdk/io/file');
17 const tabs = require('sdk/tabs');
18 const { decode } = require('sdk/base64');
20 const httpd = require('sdk/test/httpd');
23 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, '"');
25 exports.testResolve = function(assert) {
26 assert.equal(URL('bar', 'http://www.foo.com/').toString(),
27 'http://www.foo.com/bar');
29 assert.equal(URL('bar', 'http://www.foo.com'),
30 'http://www.foo.com/bar');
32 assert.equal(URL('http://bar.com/', 'http://foo.com/'),
34 'relative should override base');
36 assert.throws(function() { URL('blah'); },
37 /malformed URI: blah/i,
38 'url.resolve() should throw malformed URI on base');
40 assert.throws(function() { URL('chrome://global'); },
41 /invalid URI: chrome:\/\/global/i,
42 'url.resolve() should throw invalid URI on base');
44 assert.throws(function() { URL('chrome://foo/bar'); },
45 /invalid URI: chrome:\/\/foo\/bar/i,
46 'url.resolve() should throw on bad chrome URI');
48 assert.equal(URL('', 'http://www.foo.com'),
49 'http://www.foo.com/',
50 'url.resolve() should add slash to end of domain');
53 exports.testParseHttp = function(assert) {
54 var aUrl = 'http://sub.foo.com/bar?locale=en-US&otherArg=%20x%20#myhash';
57 assert.equal(info.scheme, 'http');
58 assert.equal(info.protocol, 'http:');
59 assert.equal(info.host, 'sub.foo.com');
60 assert.equal(info.hostname, 'sub.foo.com');
61 assert.equal(info.port, null);
62 assert.equal(info.userPass, null);
63 assert.equal(info.path, '/bar?locale=en-US&otherArg=%20x%20#myhash');
64 assert.equal(info.pathname, '/bar');
65 assert.equal(info.href, aUrl);
66 assert.equal(info.hash, '#myhash');
67 assert.equal(info.search, '?locale=en-US&otherArg=%20x%20');
70 exports.testParseHttpSearchAndHash = function (assert) {
71 var info = URL('https://www.moz.com/some/page.html');
72 assert.equal(info.hash, '');
73 assert.equal(info.search, '');
75 var hashOnly = URL('https://www.sub.moz.com/page.html#justhash');
76 assert.equal(hashOnly.search, '');
77 assert.equal(hashOnly.hash, '#justhash');
79 var queryOnly = URL('https://www.sub.moz.com/page.html?my=query');
80 assert.equal(queryOnly.search, '?my=query');
81 assert.equal(queryOnly.hash, '');
83 var qMark = URL('http://www.moz.org?');
84 assert.equal(qMark.search, '');
85 assert.equal(qMark.hash, '');
87 var hash = URL('http://www.moz.org#');
88 assert.equal(hash.search, '');
89 assert.equal(hash.hash, '');
91 var empty = URL('http://www.moz.org?#');
92 assert.equal(hash.search, '');
93 assert.equal(hash.hash, '');
95 var strange = URL('http://moz.org?test1#test2?test3');
96 assert.equal(strange.search, '?test1');
97 assert.equal(strange.hash, '#test2?test3');
100 exports.testParseHttpWithPort = function(assert) {
101 var info = URL('http://foo.com:5/bar');
102 assert.equal(info.port, 5);
105 exports.testParseChrome = function(assert) {
106 var info = URL('chrome://global/content/blah');
107 assert.equal(info.scheme, 'chrome');
108 assert.equal(info.host, 'global');
109 assert.equal(info.port, null);
110 assert.equal(info.userPass, null);
111 assert.equal(info.path, '/content/blah');
114 exports.testParseAbout = function(assert) {
115 var info = URL('about:boop');
116 assert.equal(info.scheme, 'about');
117 assert.equal(info.host, null);
118 assert.equal(info.port, null);
119 assert.equal(info.userPass, null);
120 assert.equal(info.path, 'boop');
123 exports.testParseFTP = function(assert) {
124 var info = URL('ftp://1.2.3.4/foo');
125 assert.equal(info.scheme, 'ftp');
126 assert.equal(info.host, '1.2.3.4');
127 assert.equal(info.port, null);
128 assert.equal(info.userPass, null);
129 assert.equal(info.path, '/foo');
132 exports.testParseFTPWithUserPass = function(assert) {
133 var info = URL('ftp://user:pass@1.2.3.4/foo');
134 assert.equal(info.userPass, 'user:pass');
137 exports.testToFilename = function(assert) {
139 function() { toFilename('resource://nonexistent'); },
140 /resource does not exist: resource:\/\/nonexistent\//i,
141 'toFilename() on nonexistent resources should throw'
145 function() { toFilename('http://foo.com/'); },
146 /cannot map to filename: http:\/\/foo.com\//i,
147 'toFilename() on http: URIs should raise error'
152 /.*console\.xul$/.test(toFilename('chrome://global/content/console.xul')),
153 'toFilename() w/ console.xul works when it maps to filesystem'
157 if (/chrome url isn\'t on filesystem/.test(e.message))
158 assert.pass('accessing console.xul in jar raises exception');
160 assert.fail('accessing console.xul raises ' + e);
163 // TODO: Are there any chrome URLs that we're certain exist on the
165 // assert.ok(/.*main\.js$/.test(toFilename('chrome://myapp/content/main.js')));
168 exports.testFromFilename = function(assert) {
169 var profileDirName = require('sdk/system').pathFor('ProfD');
170 var fileUrl = fromFilename(profileDirName);
171 assert.equal(URL(fileUrl).scheme, 'file',
172 'toFilename() should return a file: url');
173 assert.equal(fromFilename(toFilename(fileUrl)), fileUrl);
176 exports.testURL = function(assert) {
177 assert.ok(URL('h:foo') instanceof URL, 'instance is of correct type');
178 assert.throws(function() URL(),
179 /malformed URI: undefined/i,
180 'url.URL should throw on undefined');
181 assert.throws(function() URL(''),
183 'url.URL should throw on empty string');
184 assert.throws(function() URL('foo'),
185 /malformed URI: foo/i,
186 'url.URL should throw on invalid URI');
187 assert.ok(URL('h:foo').scheme, 'has scheme');
188 assert.equal(URL('h:foo').toString(),
190 'toString should roundtrip');
191 // test relative + base
192 assert.equal(URL('mypath', 'http://foo').toString(),
194 'relative URL resolved to base');
195 // test relative + no base
196 assert.throws(function() URL('path').toString(),
197 /malformed URI: path/i,
198 'no base for relative URI should throw');
200 let a = URL('h:foo');
202 assert.equal(b.toString(),
204 'a URL can be initialized from another URL');
205 assert.notStrictEqual(a, b,
206 'a URL initialized from another URL is not the same object');
207 assert.ok(a == 'h:foo',
208 'toString is implicit when a URL is compared to a string via ==');
209 assert.strictEqual(a + '', 'h:foo',
210 'toString is implicit when a URL is concatenated to a string');
213 exports.testStringInterface = function(assert) {
214 var EM = 'about:addons';
217 // make sure the standard URL properties are enumerable and not the String interface bits
218 assert.equal(Object.keys(a),
219 'scheme,userPass,host,hostname,port,path,pathname,hash,href,origin,protocol,search',
220 'enumerable key list check for URL.');
224 'JSON.stringify should return a object with correct props and vals.');
226 // make sure that the String interface exists and works as expected
227 assert.equal(a.indexOf(':'), EM.indexOf(':'), 'indexOf on URL works');
228 assert.equal(a.valueOf(), EM.valueOf(), 'valueOf on URL works.');
229 assert.equal(a.toSource(), EM.toSource(), 'toSource on URL works.');
230 assert.equal(a.lastIndexOf('a'), EM.lastIndexOf('a'), 'lastIndexOf on URL works.');
231 assert.equal(a.match('t:').toString(), EM.match('t:').toString(), 'match on URL works.');
232 assert.equal(a.toUpperCase(), EM.toUpperCase(), 'toUpperCase on URL works.');
233 assert.equal(a.toLowerCase(), EM.toLowerCase(), 'toLowerCase on URL works.');
234 assert.equal(a.split(':').toString(), EM.split(':').toString(), 'split on URL works.');
235 assert.equal(a.charAt(2), EM.charAt(2), 'charAt on URL works.');
236 assert.equal(a.charCodeAt(2), EM.charCodeAt(2), 'charCodeAt on URL works.');
237 assert.equal(a.concat(EM), EM.concat(a), 'concat on URL works.');
238 assert.equal(a.substr(2,3), EM.substr(2,3), 'substr on URL works.');
239 assert.equal(a.substring(2,3), EM.substring(2,3), 'substring on URL works.');
240 assert.equal(a.trim(), EM.trim(), 'trim on URL works.');
241 assert.equal(a.trimRight(), EM.trimRight(), 'trimRight on URL works.');
242 assert.equal(a.trimLeft(), EM.trimLeft(), 'trimLeft on URL works.');
245 exports.testDataURLwithouthURI = function (assert) {
246 let dataURL = new DataURL();
248 assert.equal(dataURL.base64, false, 'base64 is false for empty uri')
249 assert.equal(dataURL.data, '', 'data is an empty string for empty uri')
250 assert.equal(dataURL.mimeType, '', 'mimeType is an empty string for empty uri')
251 assert.equal(Object.keys(dataURL.parameters).length, 0, 'parameters is an empty object for empty uri');
253 assert.equal(dataURL.toString(), 'data:,');
256 exports.testDataURLwithMalformedURI = function (assert) {
257 assert.throws(function() {
258 let dataURL = new DataURL('http://www.mozilla.com/');
260 /Malformed Data URL: http:\/\/www.mozilla.com\//i,
261 'DataURL raises an exception for malformed data uri'
265 exports.testDataURLparse = function (assert) {
266 let dataURL = new DataURL('data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E');
268 assert.equal(dataURL.base64, false, 'base64 is false for non base64 data uri')
269 assert.equal(dataURL.data, '<h1>Hello!</h1>', 'data is properly decoded')
270 assert.equal(dataURL.mimeType, 'text/html', 'mimeType is set properly')
271 assert.equal(Object.keys(dataURL.parameters).length, 1, 'one parameters specified');
272 assert.equal(dataURL.parameters['charset'], 'US-ASCII', 'charset parsed');
274 assert.equal(dataURL.toString(), 'data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E');
277 exports.testDataURLparseBase64 = function (assert) {
278 let text = 'Awesome!';
279 let b64text = 'QXdlc29tZSE=';
280 let dataURL = new DataURL('data:text/plain;base64,' + b64text);
282 assert.equal(dataURL.base64, true, 'base64 is true for base64 encoded data uri')
283 assert.equal(dataURL.data, text, 'data is properly decoded')
284 assert.equal(dataURL.mimeType, 'text/plain', 'mimeType is set properly')
285 assert.equal(Object.keys(dataURL.parameters).length, 1, 'one parameters specified');
286 assert.equal(dataURL.parameters['base64'], '', 'parameter set without value');
287 assert.equal(dataURL.toString(), 'data:text/plain;base64,' + encodeURIComponent(b64text));
290 exports.testIsValidURI = function (assert) {
291 validURIs().forEach(function (aUri) {
292 assert.equal(isValidURI(aUri), true, aUri + ' is a valid URL');
296 exports.testIsInvalidURI = function (assert) {
297 invalidURIs().forEach(function (aUri) {
298 assert.equal(isValidURI(aUri), false, aUri + ' is an invalid URL');
302 exports.testURLFromURL = function(assert) {
303 let aURL = URL('http://mozilla.org');
304 let bURL = URL(aURL);
305 assert.equal(aURL.toString(), bURL.toString(), 'Making a URL from a URL works');
308 exports.testTLD = function(assert) {
310 { url: 'http://my.sub.domains.mozilla.co.uk', tld: 'co.uk' },
311 { url: 'http://my.mozilla.com', tld: 'com' },
312 { url: 'http://my.domains.mozilla.org.hk', tld: 'org.hk' },
313 { url: 'chrome://global/content/blah', tld: 'global' },
314 { url: 'data:text/plain;base64,QXdlc29tZSE=', tld: null },
315 { url: 'https://1.2.3.4', tld: null }
318 urls.forEach(function (uri) {
319 assert.equal(getTLD(uri.url), uri.tld);
320 assert.equal(getTLD(URL(uri.url)), uri.tld);
324 exports.testWindowLocationMatch = function (assert, done) {
325 let server = httpd.startServerAsync(port);
326 server.registerPathHandler('/index.html', function (request, response) {
327 response.write('<html><head></head><body><h1>url tests</h1></body></html>');
330 let aUrl = 'http://localhost:' + port + '/index.html?q=aQuery#somehash';
331 let urlObject = URL(aUrl);
335 onReady: function (tab) {
337 onMessage: function (loc) {
338 for (let prop in loc) {
339 assert.equal(urlObject[prop], loc[prop], prop + ' matches');
342 tab.close(function() server.stop(done));
344 contentScript: '(' + function () {
346 // `origin` is `null` in this context???
347 let props = 'hostname,port,pathname,hash,href,protocol,search'.split(',');
348 props.forEach(function (prop) {
349 res[prop] = window.location[prop];
351 self.postMessage(res);
358 exports.testURLInRegExpTest = function(assert) {
359 let url = 'https://mozilla.org';
360 assert.equal((new RegExp(url).test(URL(url))), true, 'URL instances work in a RegExp test');
363 exports.testLocalURL = function(assert) {
365 'data:text/html;charset=utf-8,foo and bar',
366 'data:text/plain,foo and bar',
367 'resource://gre/modules/commonjs/',
368 'chrome://browser/content/browser.xul'
370 assert.ok(isLocalURL(aUri), aUri + ' is a Local URL');
375 exports.testLocalURLwithRemoteURL = function(assert) {
376 validURIs().filter(url => !url.startsWith('data:')).forEach(aUri => {
377 assert.ok(!isLocalURL(aUri), aUri + ' is an invalid Local URL');
381 exports.testLocalURLwithInvalidURL = function(assert) {
382 invalidURIs().concat([
384 'resource:// must fail',
387 assert.ok(!isLocalURL(aUri), aUri + ' is an invalid Local URL');
391 function validURIs() {
393 'http://foo.com/blah_blah',
394 'http://foo.com/blah_blah/',
395 'http://foo.com/blah_blah_(wikipedia)',
396 'http://foo.com/blah_blah_(wikipedia)_(again)',
397 'http://www.example.com/wpstyle/?p=364',
398 'https://www.example.com/foo/?bar=baz&inga=42&quux',
400 'http://userid:password@example.com:8080',
401 'http://userid:password@example.com:8080/',
402 'http://userid@example.com',
403 'http://userid@example.com/',
404 'http://userid@example.com:8080',
405 'http://userid@example.com:8080/',
406 'http://userid:password@example.com',
407 'http://userid:password@example.com/',
408 'http://142.42.1.1/',
409 'http://142.42.1.1:8080/',
413 'http://foo.com/blah_(wikipedia)#cite-1',
414 'http://foo.com/blah_(wikipedia)_blah#cite-1',
415 'http://foo.com/unicode_(✪)_in_parens',
416 'http://foo.com/(something)?after=parens',
417 'http://☺.damowmow.com/',
418 'http://code.google.com/events/#&product=browser',
421 'http://foo.bar/?q=Test%20URL-encoded%20stuff',
422 'http://مثال.إختبار',
424 'http://उदाहरण.परीक्षा',
425 'http://-.~_!$&\'()*+,;=:%40:80%2f::::::@example.com',
428 'http://223.255.255.254',
429 // Also want to validate data-uris, localhost
430 'http://localhost:8432/some-file.js',
431 'data:text/plain;base64,',
432 'data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E',
433 'data:text/html;charset=utf-8,'
437 // Some invalidURIs are valid according to the regex used,
438 // can be improved in the future, but better to pass some
439 // invalid URLs than prevent valid URLs
441 function invalidURIs () {
453 // 'http://foo.bar?q=Spaces should be encoded',
461 'http:// shouldfail.com',
463 // 'http://foo.bar/foo(bar)baz quux',
464 // 'http://-error-.invalid/',
465 // 'http://a.b--c.de/',
469 // 'http://10.1.1.0',
470 // 'http://10.1.1.255',
471 // 'http://224.1.1.1',
472 // 'http://1.1.1.1.1',
473 // 'http://123.123.123',
474 // 'http://3628126748',
475 // 'http://.www.foo.bar/',
476 // 'http://www.foo.bar./',
477 // 'http://.www.foo.bar./',
478 // 'http://10.1.1.1',
479 // 'http://10.1.1.254'
483 require('sdk/test').run(exports);