Bumping manifests a=b2g-bump
[gecko.git] / addon-sdk / source / test / test-url.js
blobbfd55572a5468b6a4e0762311653079303725311
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 'use strict';
6 const {
7   URL,
8   toFilename,
9   fromFilename,
10   isValidURI,
11   getTLD,
12   DataURL,
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');
21 const port = 8099;
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/'),
33                    'http://bar.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';
55   var info = URL(aUrl);
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) {
138   assert.throws(
139     function() { toFilename('resource://nonexistent'); },
140     /resource does not exist: resource:\/\/nonexistent\//i,
141     'toFilename() on nonexistent resources should throw'
142   );
144   assert.throws(
145     function() { toFilename('http://foo.com/'); },
146     /cannot map to filename: http:\/\/foo.com\//i,
147     'toFilename() on http: URIs should raise error'
148   );
150   try {
151     assert.ok(
152       /.*console\.xul$/.test(toFilename('chrome://global/content/console.xul')),
153       'toFilename() w/ console.xul works when it maps to filesystem'
154     );
155   }
156   catch (e) {
157     if (/chrome url isn\'t on filesystem/.test(e.message))
158       assert.pass('accessing console.xul in jar raises exception');
159     else
160       assert.fail('accessing console.xul raises ' + e);
161   }
163   // TODO: Are there any chrome URLs that we're certain exist on the
164   // filesystem?
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(''),
182                     /malformed URI: /i,
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(),
189                    'h:foo',
190                    'toString should roundtrip');
191   // test relative + base
192   assert.equal(URL('mypath', 'http://foo').toString(),
193                    'http://foo/mypath',
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');
201   let b = URL(a);
202   assert.equal(b.toString(),
203                    'h:foo',
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';
215   var a = URL(EM);
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.');
221   assert.equal(
222       JSON.stringify(a),
223       defaultLocation,
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/');
259     },
260     /Malformed Data URL: http:\/\/www.mozilla.com\//i,
261     'DataURL raises an exception for malformed data uri'
262   );
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');
293   });
296 exports.testIsInvalidURI = function (assert) {
297   invalidURIs().forEach(function (aUri) {
298     assert.equal(isValidURI(aUri), false, aUri + ' is an invalid URL');
299   });
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) {
309   let urls = [
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 }
316   ];
318   urls.forEach(function (uri) {
319     assert.equal(getTLD(uri.url), uri.tld);
320     assert.equal(getTLD(URL(uri.url)), uri.tld);
321   });
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>');
328   });
330   let aUrl = 'http://localhost:' + port + '/index.html?q=aQuery#somehash';
331   let urlObject = URL(aUrl);
333   tabs.open({
334     url: aUrl,
335     onReady: function (tab) {
336       tab.attach({
337         onMessage: function (loc) {
338           for (let prop in loc) {
339             assert.equal(urlObject[prop], loc[prop], prop + ' matches');
340           }
342           tab.close(function() server.stop(done));
343         },
344         contentScript: '(' + function () {
345           let res = {};
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];
350           });
351           self.postMessage(res);
352         } + ')()'
353       });
354     }
355   })
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) {
364   [
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'
369   ].forEach(aUri => {
370     assert.ok(isLocalURL(aUri), aUri + ' is a Local URL');
371   })
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');
378   });
381 exports.testLocalURLwithInvalidURL = function(assert) {
382   invalidURIs().concat([
383     'data:foo and bar',
384     'resource:// must fail',
385     'chrome:// here too'
386   ]).forEach(aUri => {
387     assert.ok(!isLocalURL(aUri), aUri + ' is an invalid Local URL');
388   });
391 function validURIs() {
392   return [
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&amp;inga=42&amp;quux',
399   'http://✪df.ws/123',
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/',
410   'http://➡.ws/䨹',
411   'http://⌘.ws',
412   'http://⌘.ws/',
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/#&amp;product=browser',
419   'http://j.mp',
420   'ftp://foo.bar/baz',
421   'http://foo.bar/?q=Test%20URL-encoded%20stuff',
422   'http://مثال.إختبار',
423   'http://例子.测试',
424   'http://उदाहरण.परीक्षा',
425   'http://-.~_!$&amp;\'()*+,;=:%40:80%2f::::::@example.com',
426   'http://1337.net',
427   'http://a.b-c.de',
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,'
434   ];
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 () {
442   return [
443 //  'http://',
444 //  'http://.',
445 //  'http://..',
446 //  'http://../',
447 //  'http://?',
448 //  'http://??',
449 //  'http://??/',
450 //  'http://#',
451 //  'http://##',
452 //  'http://##/',
453 //  'http://foo.bar?q=Spaces should be encoded',
454   'not a url',
455   '//',
456   '//a',
457   '///a',
458   '///',
459 //  'http:///a',
460   'foo.com',
461   'http:// shouldfail.com',
462   ':// should fail',
463 //  'http://foo.bar/foo(bar)baz quux',
464 //  'http://-error-.invalid/',
465 //  'http://a.b--c.de/',
466 //  'http://-a.b.co',
467 //  'http://a.b-.co',
468 //  'http://0.0.0.0',
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'
480   ];
483 require('sdk/test').run(exports);