addon-sdk/source/test/test-url.js

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:5e47b6e0d6d3
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';
5
6 const {
7 URL,
8 toFilename,
9 fromFilename,
10 isValidURI,
11 getTLD,
12 DataURL,
13 isLocalURL } = require('sdk/url');
14
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');
19
20 const httpd = require('sdk/test/httpd');
21 const port = 8099;
22
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, '"');
24
25 exports.testResolve = function(assert) {
26 assert.equal(URL('bar', 'http://www.foo.com/').toString(),
27 'http://www.foo.com/bar');
28
29 assert.equal(URL('bar', 'http://www.foo.com'),
30 'http://www.foo.com/bar');
31
32 assert.equal(URL('http://bar.com/', 'http://foo.com/'),
33 'http://bar.com/',
34 'relative should override base');
35
36 assert.throws(function() { URL('blah'); },
37 /malformed URI: blah/i,
38 'url.resolve() should throw malformed URI on base');
39
40 assert.throws(function() { URL('chrome://global'); },
41 /invalid URI: chrome:\/\/global/i,
42 'url.resolve() should throw invalid URI on base');
43
44 assert.throws(function() { URL('chrome://foo/bar'); },
45 /invalid URI: chrome:\/\/foo\/bar/i,
46 'url.resolve() should throw on bad chrome URI');
47
48 assert.equal(URL('', 'http://www.foo.com'),
49 'http://www.foo.com/',
50 'url.resolve() should add slash to end of domain');
51 };
52
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);
56
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');
68 };
69
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, '');
74
75 var hashOnly = URL('https://www.sub.moz.com/page.html#justhash');
76 assert.equal(hashOnly.search, '');
77 assert.equal(hashOnly.hash, '#justhash');
78
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, '');
82
83 var qMark = URL('http://www.moz.org?');
84 assert.equal(qMark.search, '');
85 assert.equal(qMark.hash, '');
86
87 var hash = URL('http://www.moz.org#');
88 assert.equal(hash.search, '');
89 assert.equal(hash.hash, '');
90
91 var empty = URL('http://www.moz.org?#');
92 assert.equal(hash.search, '');
93 assert.equal(hash.hash, '');
94
95 var strange = URL('http://moz.org?test1#test2?test3');
96 assert.equal(strange.search, '?test1');
97 assert.equal(strange.hash, '#test2?test3');
98 };
99
100 exports.testParseHttpWithPort = function(assert) {
101 var info = URL('http://foo.com:5/bar');
102 assert.equal(info.port, 5);
103 };
104
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');
112 };
113
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');
121 };
122
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');
130 };
131
132 exports.testParseFTPWithUserPass = function(assert) {
133 var info = URL('ftp://user:pass@1.2.3.4/foo');
134 assert.equal(info.userPass, 'user:pass');
135 };
136
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 );
143
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 );
149
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 }
162
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')));
166 };
167
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);
174 };
175
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');
199
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');
211 };
212
213 exports.testStringInterface = function(assert) {
214 var EM = 'about:addons';
215 var a = URL(EM);
216
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.');
225
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.');
243 }
244
245 exports.testDataURLwithouthURI = function (assert) {
246 let dataURL = new DataURL();
247
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');
252
253 assert.equal(dataURL.toString(), 'data:,');
254 }
255
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 );
263 }
264
265 exports.testDataURLparse = function (assert) {
266 let dataURL = new DataURL('data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E');
267
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');
273
274 assert.equal(dataURL.toString(), 'data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E');
275 }
276
277 exports.testDataURLparseBase64 = function (assert) {
278 let text = 'Awesome!';
279 let b64text = 'QXdlc29tZSE=';
280 let dataURL = new DataURL('data:text/plain;base64,' + b64text);
281
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));
288 }
289
290 exports.testIsValidURI = function (assert) {
291 validURIs().forEach(function (aUri) {
292 assert.equal(isValidURI(aUri), true, aUri + ' is a valid URL');
293 });
294 };
295
296 exports.testIsInvalidURI = function (assert) {
297 invalidURIs().forEach(function (aUri) {
298 assert.equal(isValidURI(aUri), false, aUri + ' is an invalid URL');
299 });
300 };
301
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');
306 };
307
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 ];
317
318 urls.forEach(function (uri) {
319 assert.equal(getTLD(uri.url), uri.tld);
320 assert.equal(getTLD(URL(uri.url)), uri.tld);
321 });
322 }
323
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 });
329
330 let aUrl = 'http://localhost:' + port + '/index.html?q=aQuery#somehash';
331 let urlObject = URL(aUrl);
332
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 }
341
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 })
356 };
357
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');
361 }
362
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 })
372
373 }
374
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 });
379 }
380
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 });
389 }
390
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 ];
435 }
436
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
440
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 ];
481 }
482
483 require('sdk/test').run(exports);

mercurial