| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as Platform from '../../core/platform/platform.js'; |
| import * as Extensions from '../extensions/extensions.js'; |
| |
| const {urlString} = Platform.DevToolsPath; |
| |
| // The test expectations are from //extensions/common/url_pattern_unittest.cc but leave out tests for the unsupported |
| // schemes and paths. Also left out are tests for whitespace and unicode urls since that doesn't go through the url |
| // constructor anyways. |
| |
| describe('HostUrlPattern', () => { |
| it('ParseInvalid', () => { |
| const invalidPatterns = [ |
| 'http', // Missing Scheme Separator |
| 'http:', // Wrong Scheme Separator |
| 'http:/', // Wrong Scheme Separator |
| 'about://', // Wrong Scheme Separator |
| 'http://', // Empty Host |
| 'http:///', // Empty Host |
| 'http://:1234/', // Empty Host |
| 'http://*./', // Empty Host |
| 'http://\0www/', // Invalid host |
| 'http://*foo/', // Invalid Host Wildcard |
| 'http://foo.*.bar/', // Invalid Host Wildcard |
| 'http://fo.*.ba:123/', // Invalid Host Wildcard |
| 'http:/bar', // Wrong Scheme Separator |
| 'http://foo.*/', // Invalid Host Wildcard |
| ]; |
| |
| for (const pattern of invalidPatterns) { |
| const parsedPattern = Extensions.HostUrlPattern.HostUrlPattern.parse(pattern); |
| assert.isUndefined(parsedPattern); |
| } |
| }); |
| |
| it('Ports', () => { |
| const testPatterns = [ |
| {pattern: 'http://foo:1234', success: true, port: '1234'}, |
| {pattern: 'http://foo:1234/', success: true, port: '1234'}, |
| {pattern: 'http://foo:1234/*', success: true, port: '1234'}, |
| {pattern: 'http://*.foo:1234/', success: true, port: '1234'}, |
| {pattern: 'http://foo:/', success: false /* Invalid Port*/, port: '*'}, |
| {pattern: 'http://*:1234/', success: true, port: '1234'}, |
| {pattern: 'http://*:*/', success: true, port: '*'}, |
| {pattern: 'http://foo:*/', success: true, port: '*'}, |
| {pattern: 'http://*.foo:/', success: false /* Invalid Port*/, port: '*'}, |
| {pattern: 'http://foo:com/', success: false /* Invalid Port*/, port: '*'}, |
| {pattern: 'http://foo:123456/', success: false /* Invalid Port*/, port: '*'}, |
| {pattern: 'http://foo:80:80/', success: false /* Invalid Port*/, port: '*'}, |
| {pattern: 'chrome://foo:1234/', success: false /* Invalid Port*/, port: '*'}, |
| ]; |
| |
| for (const {pattern, success, port} of testPatterns) { |
| const parsedPattern = Extensions.HostUrlPattern.HostUrlPattern.parse(pattern); |
| if (success) { |
| assert.exists(parsedPattern); |
| assert.strictEqual(parsedPattern.port, port); |
| } else { |
| assert.isUndefined(parsedPattern); |
| } |
| } |
| }); |
| |
| it('IPv6Patterns', () => { |
| const successTestPatterns = [ |
| {pattern: 'http://[2607:f8b0:4005:805::200e]/', host: '[2607:f8b0:4005:805::200e]', port: '*'}, |
| {pattern: 'http://[2607:f8b0:4005:805::200e]/*', host: '[2607:f8b0:4005:805::200e]', port: '*'}, |
| {pattern: 'http://[2607:f8b0:4005:805::200e]:8888/*', host: '[2607:f8b0:4005:805::200e]', port: '8888'}, |
| ]; |
| |
| for (const {pattern, host, port} of successTestPatterns) { |
| const parsedPattern = Extensions.HostUrlPattern.HostUrlPattern.parse(pattern); |
| assert.exists(parsedPattern); |
| assert.strictEqual(parsedPattern.host, host); |
| assert.strictEqual(parsedPattern.port, port); |
| } |
| |
| const failureTestPatterns = [ |
| 'http://[2607:f8b0:4005:805::200e]:/*', // Invalid Port |
| 'http://[]:8888/*', // Empty Host |
| 'http://[2607:f8b0:4005:805::200e/*', // Invalid Host |
| 'http://[2607:f8b0:4005:805::200e]]/*', // Invalid Host |
| 'http://[[2607:f8b0:4005:805::200e]/*', // Invalid Host |
| 'http://[2607:f8b0:4005:805:200e]/*', // Invalid Host |
| 'http://[2607:f8b0:4005:805:200e:12:bogus]/*', // Invalid Host |
| 'http://[[2607:f8b0:4005:805::200e]:abc/*', // Invalid Port |
| ]; |
| |
| for (const pattern of failureTestPatterns) { |
| const parsedPattern = Extensions.HostUrlPattern.HostUrlPattern.parse(pattern); |
| assert.isUndefined(parsedPattern); |
| } |
| }); |
| |
| it('Matches all pages for a given scheme', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('http://*/*'); |
| assert.exists(pattern); |
| assert.strictEqual('http', pattern.scheme); |
| assert.strictEqual('*', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`http://google.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://yahoo.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://google.com/foo`)); |
| assert.isFalse(pattern.matchesUrl(urlString`https://google.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://74.125.127.100/search`)); |
| }); |
| |
| it('Matches all domains', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('https://*/*'); |
| assert.exists(pattern); |
| assert.strictEqual('https', pattern.scheme); |
| assert.strictEqual('*', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`https://www.google.com/foo`)); |
| assert.isTrue(pattern.matchesUrl(urlString`https://www.google.com/foobar`)); |
| assert.isFalse(pattern.matchesUrl(urlString`http://www.google.com/foo`)); |
| assert.isTrue(pattern.matchesUrl(urlString`https://www.google.com/`)); |
| }); |
| |
| it('Matches subdomains', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('http://*.google.com/'); |
| assert.exists(pattern); |
| assert.strictEqual('http', pattern.scheme); |
| assert.strictEqual('*.google.com', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`http://google.com/foobar`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://www.google.com/foobar`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://www.google.com/foo?bar`)); |
| assert.isFalse(pattern.matchesUrl(urlString`http://wwwgoogle.com/foobar`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://monkey.images.google.com/foooobar`)); |
| assert.isFalse(pattern.matchesUrl(urlString`http://yahoo.com/foobar`)); |
| }); |
| |
| it('Matches ip addresses', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('http://127.0.0.1/'); |
| assert.exists(pattern); |
| assert.strictEqual('http', pattern.scheme); |
| assert.strictEqual('127.0.0.1', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`http://127.0.0.1`)); |
| }); |
| |
| it('Matches subdomain matching with ip addresses', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('http://*.0.0.1/'); |
| assert.exists(pattern); |
| assert.strictEqual('http', pattern.scheme); |
| assert.strictEqual('*.0.0.0.1', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isFalse(pattern.matchesUrl(urlString`http://127.0.0.1`)); |
| }); |
| |
| it('Matches chrome://', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('chrome://favicon/*'); |
| assert.exists(pattern); |
| assert.strictEqual('chrome', pattern.scheme); |
| assert.strictEqual('favicon', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome://favicon/http://google.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome://favicon/https://google.com`)); |
| assert.isFalse(pattern.matchesUrl(urlString`chrome://history`)); |
| }); |
| |
| it('Matches *://', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('*://*/*'); |
| assert.exists(pattern); |
| assert.isTrue(pattern.matchesScheme('http')); |
| assert.isTrue(pattern.matchesScheme('https')); |
| assert.isFalse(pattern.matchesScheme('chrome')); |
| assert.isFalse(pattern.matchesScheme('file')); |
| assert.isFalse(pattern.matchesScheme('ftp')); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`http://127.0.0.1`)); |
| assert.isFalse(pattern.matchesUrl(urlString`chrome://favicon/http://google.com`)); |
| assert.isFalse(pattern.matchesUrl(urlString`file:///foo/bar`)); |
| assert.isFalse(pattern.matchesUrl(urlString`file://localhost/foo/bar`)); |
| }); |
| |
| it('Matches <all_urls>', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('<all_urls>'); |
| assert.exists(pattern); |
| assert.isTrue(pattern.matchesScheme('chrome')); |
| assert.isTrue(pattern.matchesScheme('http')); |
| assert.isTrue(pattern.matchesScheme('https')); |
| assert.isTrue(pattern.matchesScheme('file')); |
| assert.isTrue(pattern.matchesScheme('chrome-extension')); |
| assert.isTrue(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome://favicon/http://google.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://127.0.0.1`)); |
| assert.isTrue(pattern.matchesUrl(urlString`file:///foo/bar`)); |
| assert.isTrue(pattern.matchesUrl(urlString`file://localhost/foo/bar`)); |
| }); |
| |
| it('Matches SCHEME_ALL matches all schemes.', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('<all_urls>'); |
| assert.exists(pattern); |
| assert.isTrue(pattern.matchesScheme('chrome')); |
| assert.isTrue(pattern.matchesScheme('http')); |
| assert.isTrue(pattern.matchesScheme('https')); |
| assert.isTrue(pattern.matchesScheme('file')); |
| assert.isTrue(pattern.matchesScheme('javascript')); |
| assert.isTrue(pattern.matchesScheme('data')); |
| assert.isTrue(pattern.matchesScheme('about')); |
| assert.isTrue(pattern.matchesScheme('chrome-extension')); |
| assert.isTrue(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome://favicon/http://google.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://127.0.0.1`)); |
| assert.isTrue(pattern.matchesUrl(urlString`file:///foo/bar`)); |
| assert.isTrue(pattern.matchesUrl(urlString`file://localhost/foo/bar`)); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome://newtab`)); |
| assert.isTrue(pattern.matchesUrl(urlString`about:blank`)); |
| assert.isTrue(pattern.matchesUrl(urlString`about:version`)); |
| assert.isTrue(pattern.matchesUrl(urlString`data:text/html;charset=utf-8,<html>asdf</html>`)); |
| }); |
| |
| it('Doesn\'t Match Invalid', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('<all_urls>'); |
| assert.exists(pattern); |
| assert.isFalse(pattern.matchesUrl(urlString`http:`)); |
| }); |
| |
| it('Matches SCHEME_ALL and specific schemes.', () => { |
| const urlPatternTestCases = [ |
| {pattern: 'chrome-extension://*/*', matches: 'chrome-extension://FTW'}, |
| ]; |
| |
| for (const {pattern, matches} of urlPatternTestCases) { |
| const parsedPattern = Extensions.HostUrlPattern.HostUrlPattern.parse(pattern); |
| assert.exists(parsedPattern); |
| assert.isTrue(parsedPattern.matchesUrl(urlString`${matches}`)); |
| } |
| }); |
| |
| it('Matches Specific port', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('http://www.example.com:80/'); |
| assert.exists(pattern); |
| assert.strictEqual('http', pattern.scheme); |
| assert.strictEqual('www.example.com', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.strictEqual('80', pattern.port); |
| assert.isTrue(pattern.matchesUrl(urlString`http://www.example.com:80/foo`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://www.example.com/foo`)); |
| assert.isFalse(pattern.matchesUrl(urlString`http://www.example.com:8080/foo`)); |
| }); |
| |
| it('Matches Explicit port wildcard', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('http://www.example.com:*/*'); |
| assert.exists(pattern); |
| assert.strictEqual('http', pattern.scheme); |
| assert.strictEqual('www.example.com', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.strictEqual('*', pattern.port); |
| assert.isTrue(pattern.matchesUrl(urlString`http://www.example.com:80/foo`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://www.example.com/foo`)); |
| assert.isTrue(pattern.matchesUrl(urlString`http://www.example.com:8080/foo`)); |
| }); |
| |
| it('Matches chrome-extension://', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('chrome-extension://ftw/*'); |
| assert.exists(pattern); |
| assert.strictEqual('chrome-extension', pattern.scheme); |
| assert.strictEqual('ftw', pattern.host); |
| assert.isFalse(pattern.matchesAllUrls()); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome-extension://ftw`)); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome-extension://ftw/http://google.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`chrome-extension://ftw/https://google.com`)); |
| assert.isFalse(pattern.matchesUrl(urlString`chrome-extension://foobar`)); |
| }); |
| |
| it('Ignore Ports', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('http://www.example.com:8080/'); |
| assert.exists(pattern); |
| |
| assert.isFalse(pattern.matchesUrl(urlString`http://www.example.com:1234/foo`)); |
| }); |
| |
| it('Trailing Dot Domain', () => { |
| const normalDomain = urlString`http://example.com/`; |
| const trailingDotDomain = urlString`http://example.com./`; |
| |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('*://example.com/*'); |
| assert.exists(pattern); |
| assert.isTrue(pattern.matchesUrl(normalDomain)); |
| assert.isTrue(pattern.matchesUrl(trailingDotDomain)); |
| |
| const trailingPattern = Extensions.HostUrlPattern.HostUrlPattern.parse('*://example.com./*'); |
| assert.exists(trailingPattern); |
| assert.isTrue(trailingPattern.matchesUrl(normalDomain)); |
| assert.isTrue(trailingPattern.matchesUrl(trailingDotDomain)); |
| }); |
| |
| it('URLPattern properly canonicalizes uncanonicalized hosts', () => { |
| const pattern = Extensions.HostUrlPattern.HostUrlPattern.parse('*://*.gOoGle.com/*'); |
| assert.exists(pattern); |
| assert.isTrue(pattern.matchesUrl(urlString`https://google.com`)); |
| assert.isTrue(pattern.matchesUrl(urlString`https://maps.google.com`)); |
| assert.isFalse(pattern.matchesUrl(urlString`https://example.com`)); |
| |
| const pattern2 = Extensions.HostUrlPattern.HostUrlPattern.parse('https://*.ɡoogle.com/*'); |
| assert.exists(pattern2); |
| const canonicalizedHost = 'xn--oogle-qmc.com'; |
| assert.strictEqual(`*.${canonicalizedHost}`, pattern2.host); |
| assert.isFalse(pattern2.matchesUrl(urlString`https://google.com`)); |
| assert.isTrue(pattern2.matchesUrl(urlString`${`https://${canonicalizedHost}/`}`)); |
| assert.isTrue(pattern2.matchesHost('ɡoogle.com')); |
| |
| const pattern3 = Extensions.HostUrlPattern.HostUrlPattern.parse('https://\xef\xb7\x90zyx.com/*'); |
| assert.isUndefined(pattern3); // Invalid Host |
| }); |
| }); |