/* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { MatchURLFilters } = ChromeUtils.importESModule( "resource://gre/modules/MatchURLFilters.sys.mjs" ); const { Preferences } = ChromeUtils.importESModule( "resource://gre/modules/Preferences.sys.mjs" ); function createTestFilter({ url, filters }) { let m = new MatchURLFilters(filters); return m.matches(url); } function expectPass({ url, filters }) { ok( createTestFilter({ url, filters }), `Expected match: ${JSON.stringify(filters)}, ${url}` ); } function expectFail({ url, filters }) { ok( !createTestFilter({ url, filters }), `Expected no match: ${JSON.stringify(filters)}, ${url}` ); } function expectThrow({ url, filters, exceptionMessageContains }) { let logData = { filters, url }; Assert.throws( () => { createTestFilter({ url, filters }); }, exceptionMessageContains, `Check received exception for expected message: ${JSON.stringify(logData)}` ); } add_task(async function test_match_url_filters() { const shouldPass = true; const shouldFail = true; const shouldThrow = true; var testCases = [ // Empty, undefined and null filters. { shouldThrow, exceptionMessageContains: /filters array should not be empty/, filters: [], url: "http://mozilla.org", }, { shouldThrow, exceptionMessageContains: /filters should be an array/, filters: undefined, url: "http://mozilla.org", }, { shouldThrow, exceptionMessageContains: /filters should be an array/, filters: null, url: "http://mozilla.org", }, // Wrong formats (in a real webextension this will be blocked by the schema validation). { shouldThrow, exceptionMessageContains: /filters should be an array/, filters: {}, url: "http://mozilla.org", }, { shouldThrow, exceptionMessageContains: /filters should be an array/, filters: { nonExistentCriteria: true }, url: "http://mozilla.org", }, { shouldPass, filters: [{ nonExistentCriteria: true }], url: "http://mozilla.org", }, // Schemes filter over various url schemes. { shouldPass, filters: [{ schemes: ["http"] }], url: "http://mozilla.org" }, { shouldPass, filters: [{ schemes: ["https"] }], url: "https://mozilla.org", }, { shouldPass, filters: [{ schemes: ["ftp"] }], url: "ftp://fake/ftp/url" }, { shouldPass, filters: [{ schemes: ["about"] }], url: "about:blank" }, { shouldPass, filters: [{ schemes: ["data"] }], url: "data:,testDataURL" }, { shouldFail, filters: [{ schemes: ["http"] }], url: "ftp://fake/ftp/url" }, // Multiple schemes: pass when at least one scheme matches. { shouldPass, filters: [{ schemes: ["https", "about"] }], url: "https://mozilla.org", }, { shouldPass, filters: [{ schemes: ["about", "https"] }], url: "https://mozilla.org", }, { shouldFail, filters: [{ schemes: ["about", "http"] }], url: "https://mozilla.org", }, // Port filter: standard (implicit) ports. { shouldPass, filters: [{ ports: [443] }], url: "https://mozilla.org" }, { shouldPass, filters: [{ ports: [80] }], url: "http://mozilla.org" }, // Port matching unknown protocols will fail. { shouldFail, filters: [{ ports: [21] }], url: "ftp://ftp.mozilla.org", }, // Port filter: schemes without a default port. { shouldFail, filters: [{ ports: [-1] }], url: "about:blank" }, { shouldFail, filters: [{ ports: [-1] }], url: "data:,testDataURL" }, { shouldFail, filters: [{ ports: [[1, 65535]] }], url: "about:blank" }, { shouldFail, filters: [{ ports: [[1, 65535]] }], url: "data:,testDataURL", }, // Host filters (hostEquals, hostContains, hostPrefix, hostSuffix): schemes with an host. { shouldFail, filters: [{ hostEquals: "" }], url: "https://mozilla.org" }, { shouldPass, filters: [{ hostEquals: null }], url: "https://mozilla.org" }, { shouldPass, filters: [{ hostEquals: "mozilla.org" }], url: "https://mozilla.org", }, { shouldFail, filters: [{ hostEquals: "mozilla.com" }], url: "https://mozilla.org", }, // NOTE: trying at least once another valid protocol. { shouldPass, filters: [{ hostEquals: "mozilla.org" }], url: "ftp://mozilla.org", }, { shouldFail, filters: [{ hostEquals: "mozilla.com" }], url: "ftp://mozilla.org", }, { shouldPass, filters: [{ hostEquals: "mozilla.org" }], url: "https://mozilla.org:8888", }, { shouldPass, filters: [{ hostContains: "moz" }], url: "https://mozilla.org", }, // NOTE: an implicit '.' char is inserted into the host. { shouldPass, filters: [{ hostContains: ".moz" }], url: "https://mozilla.org", }, { shouldFail, filters: [{ hostContains: "com" }], url: "https://mozilla.org", }, { shouldPass, filters: [{ hostContains: "" }], url: "https://mozilla.org" }, { shouldPass, filters: [{ hostContains: null }], url: "https://mozilla.org", }, { shouldPass, filters: [{ hostPrefix: "moz" }], url: "https://mozilla.org", }, { shouldFail, filters: [{ hostPrefix: "org" }], url: "https://mozilla.org", }, { shouldPass, filters: [{ hostPrefix: "" }], url: "https://mozilla.org" }, { shouldPass, filters: [{ hostPrefix: null }], url: "https://mozilla.org" }, { shouldPass, filters: [{ hostSuffix: ".org" }], url: "https://mozilla.org", }, { shouldFail, filters: [{ hostSuffix: "moz" }], url: "https://mozilla.org", }, { shouldPass, filters: [{ hostSuffix: "" }], url: "https://mozilla.org" }, { shouldPass, filters: [{ hostSuffix: null }], url: "https://mozilla.org" }, { shouldPass, filters: [{ hostSuffix: "lla.org" }], url: "https://mozilla.org:8888", }, // hostEquals: urls without an host. // TODO: should we explicitly cover hostContains, hostPrefix, hostSuffix for // these sub-cases? { shouldFail, filters: [{ hostEquals: "blank" }], url: "about:blank" }, { shouldFail, filters: [{ hostEquals: "blank" }], url: "about://blank" }, { shouldFail, filters: [{ hostEquals: "testDataURL" }], url: "data:,testDataURL", }, { shouldPass, filters: [{ hostEquals: "" }], url: "about:blank" }, { shouldPass, filters: [{ hostEquals: "" }], url: "about://blank" }, { shouldPass, filters: [{ hostEquals: "" }], url: "data:,testDataURL" }, // Path filters (pathEquals, pathContains, pathPrefix, pathSuffix). { shouldFail, filters: [{ pathEquals: "" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathEquals: null }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathEquals: "/test/path" }], url: "https://mozilla.org/test/path", }, { shouldFail, filters: [{ pathEquals: "/wrong/path" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathEquals: "/test/path" }], url: "https://mozilla.org:8888/test/path", }, // NOTE: trying at least once another valid protocol { shouldPass, filters: [{ pathEquals: "/test/path" }], url: "ftp://mozilla.org/test/path", }, { shouldFail, filters: [{ pathEquals: "/wrong/path" }], url: "ftp://mozilla.org/test/path", }, { shouldPass, filters: [{ pathContains: "st/" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathContains: "/test" }], url: "https://mozilla.org/test/path", }, { shouldFail, filters: [{ pathContains: "org" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathContains: "" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathContains: null }], url: "https://mozilla.org/test/path", }, { shouldFail, filters: [{ pathContains: "param" }], url: "https://mozilla.org:8888/test/path?param=1", }, { shouldFail, filters: [{ pathContains: "ref" }], url: "https://mozilla.org:8888/test/path#ref", }, { shouldPass, filters: [{ pathContains: "st/pa" }], url: "https://mozilla.org:8888/test/path", }, { shouldPass, filters: [{ pathPrefix: "/te" }], url: "https://mozilla.org/test/path", }, { shouldFail, filters: [{ pathPrefix: "org/" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathPrefix: "" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathPrefix: null }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathSuffix: "/path" }], url: "https://mozilla.org/test/path", }, { shouldFail, filters: [{ pathSuffix: "th/" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathSuffix: "" }], url: "https://mozilla.org/test/path", }, { shouldPass, filters: [{ pathSuffix: null }], url: "https://mozilla.org/test/path", }, { shouldFail, filters: [{ pathSuffix: "p=1" }], url: "https://mozilla.org:8888/test/path?p=1", }, { shouldFail, filters: [{ pathSuffix: "ref" }], url: "https://mozilla.org:8888/test/path#ref", }, // Query filters (queryEquals, queryContains, queryPrefix, querySuffix). { shouldFail, filters: [{ queryEquals: "" }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ queryEquals: null }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ queryEquals: "param=val" }], url: "https://mozilla.org/?param=val", }, { shouldFail, filters: [{ queryEquals: "?param=val" }], url: "https://mozilla.org/?param=val", }, { shouldFail, filters: [{ queryEquals: "/path?param=val" }], url: "https://mozilla.org/path?param=val", }, // NOTE: about scheme urls cannot be matched by query. { shouldFail, filters: [{ queryEquals: "param=val" }], url: "about:blank?param=val", }, { shouldFail, filters: [{ queryEquals: "param" }], url: "ftp://mozilla.org?param=val", }, { shouldPass, filters: [{ queryContains: "ram" }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ queryContains: "=val" }], url: "https://mozilla.org/?param=val", }, { shouldFail, filters: [{ queryContains: "?param" }], url: "https://mozilla.org/?param=val", }, { shouldFail, filters: [{ queryContains: "path" }], url: "https://mozilla.org/path/?p=v#ref", }, { shouldPass, filters: [{ queryContains: "" }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ queryContains: null }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ queryPrefix: "param" }], url: "https://mozilla.org/?param=val", }, { shouldFail, filters: [{ queryPrefix: "p=" }], url: "https://mozilla.org/?param=val", }, { shouldFail, filters: [{ queryPrefix: "path" }], url: "https://mozilla.org/path?param=val", }, { shouldPass, filters: [{ queryPrefix: "" }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ queryPrefix: null }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ querySuffix: "=val" }], url: "https://mozilla.org/?param=val", }, { shouldFail, filters: [{ querySuffix: "=wrong" }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ querySuffix: "" }], url: "https://mozilla.org/?param=val", }, { shouldPass, filters: [{ querySuffix: null }], url: "https://mozilla.org/?param=val", }, // URL filters (urlEquals, urlContains, urlPrefix, urlSuffix). { shouldFail, filters: [{ urlEquals: "" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlEquals: null }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlEquals: "https://mozilla.org/?p=v#ref" }], url: "https://mozilla.org/?p=v#ref", }, { shouldFail, filters: [{ urlEquals: "https://mozilla.org/?p=v#ref2" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlEquals: "about:blank?p=v#ref" }], url: "about:blank?p=v#ref", }, { shouldPass, filters: [{ urlEquals: "ftp://mozilla.org?p=v#ref" }], url: "ftp://mozilla.org?p=v#ref", }, { shouldPass, filters: [{ urlContains: "org/?p" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlContains: "=v#ref" }], url: "https://mozilla.org/?p=v#ref", }, { shouldFail, filters: [{ urlContains: "ftp" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlContains: "" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlContains: null }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlPrefix: "http" }], url: "https://mozilla.org/?p=v#ref", }, { shouldFail, filters: [{ urlPrefix: "moz" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlPrefix: "" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlPrefix: null }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlSuffix: "#ref" }], url: "https://mozilla.org/?p=v#ref", }, { shouldFail, filters: [{ urlSuffix: "=wrong" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlSuffix: "" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlSuffix: null }], url: "https://mozilla.org/?p=v#ref", }, // More url filters: urlMatches. { shouldPass, filters: [{ urlMatches: ".*://mozilla" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlMatches: ".*://mozilla" }], url: "ftp://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlMatches: ".*://.*/?p" }], url: "ftp://mozilla.org/?p=v#ref", }, // NOTE: urlMatches should not match the url without the ref. { shouldFail, filters: [{ urlMatches: "v#ref$" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ urlMatches: "^ftp" }], url: "ftp://mozilla.org/?p=v#ref", }, // More url filters: originAndPathMatches. { shouldPass, filters: [{ originAndPathMatches: ".*://mozilla" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ originAndPathMatches: ".*://mozilla" }], url: "ftp://mozilla.org/?p=v#ref", }, // NOTE: urlMatches should not match the url without the query and the ref. { shouldFail, filters: [{ originAndPathMatches: ".*://.*/?p" }], url: "ftp://mozilla.org/?p=v#ref", }, { shouldFail, filters: [{ originAndPathMatches: "v#ref$" }], url: "https://mozilla.org/?p=v#ref", }, { shouldPass, filters: [{ originAndPathMatches: "^ftp" }], url: "ftp://mozilla.org/?p=v#ref", }, // Filter with all criteria: all matches, none matches, some matches. // All matches. { shouldPass, filters: [ { schemes: ["https", "http"], ports: [443, 80], hostEquals: "www.mozilla.org", hostContains: ".moz", hostPrefix: "www", hostSuffix: "org", pathEquals: "/sub/path", pathContains: "b/p", pathPrefix: "/sub", pathSuffix: "/path", queryEquals: "p1=v", queryContains: "1=", queryPrefix: "p1", querySuffix: "=v", urlEquals: "https://www.mozilla.org/sub/path?p1=v#ref", urlContains: "org/sub", urlPrefix: "https://www.moz", urlSuffix: "#ref", urlMatches: "p1=v$", originAndPathMatches: ".*://www.moz.*/", }, ], url: "https://www.mozilla.org/sub/path?p1=v#ref", }, // None matches. { shouldFail, filters: [ { schemes: ["http"], ports: [80], hostEquals: "mozilla.com", hostContains: "www.moz", hostPrefix: "www", hostSuffix: "com", pathEquals: "/wrong/path", pathContains: "g/p", pathPrefix: "/wrong", pathSuffix: "/wrong", queryEquals: "p2=v", queryContains: "2=", queryPrefix: "p2", querySuffix: "=value", urlEquals: "http://mozilla.com/sub/path?p1=v#ref", urlContains: "com/sub", urlPrefix: "http://moz", urlSuffix: "#ref2", urlMatches: "value#ref2$", originAndPathMatches: ".*://moz.*com/", }, ], url: "https://mozilla.org/sub/path?p1=v#ref", }, // Some matches { shouldFail, filters: [ { schemes: ["https"], ports: [80], hostEquals: "mozilla.com", hostContains: "www.moz", hostPrefix: "www", hostSuffix: "com", pathEquals: "/wrong/path", pathContains: "g/p", pathPrefix: "/wrong", pathSuffix: "/wrong", queryEquals: "p2=v", queryContains: "2=", queryPrefix: "p2", querySuffix: "=value", urlEquals: "http://mozilla.com/sub/path?p1=v#ref", urlContains: "com/sub", urlPrefix: "http://moz", urlSuffix: "#ref2", urlMatches: "value#ref2$", originAndPathMatches: ".*://moz.*com/", }, ], url: "https://mozilla.org/sub/path?p1=v#ref", }, // Filter with multiple filters: all matches, some matches, none matches. // All matches. { shouldPass, filters: [ { schemes: ["https", "http"] }, { ports: [443, 80] }, { hostEquals: "www.mozilla.org" }, { hostContains: ".moz" }, { hostPrefix: "www" }, { hostSuffix: "org" }, { pathEquals: "/sub/path" }, { pathContains: "b/p" }, { pathPrefix: "/sub" }, { pathSuffix: "/path" }, { queryEquals: "p=v" }, { queryContains: "1=" }, { queryPrefix: "p1" }, { querySuffix: "=v" }, { urlEquals: "https://www.mozilla.org/sub/path?p1=v#ref" }, { urlContains: "org/sub" }, { urlPrefix: "https://moz" }, { urlSuffix: "#ref" }, { urlMatches: "v#ref$" }, { originAndPathMatches: ".*://moz.*/" }, ], url: "https://www.mozilla.org/sub/path?p1=v#ref", }, // None matches. { shouldFail, filters: [ { schemes: ["http"] }, { ports: [80] }, { hostEquals: "mozilla.com" }, { hostContains: "www.moz" }, { hostPrefix: "www" }, { hostSuffix: "com" }, { pathEquals: "/wrong/path" }, { pathContains: "g/p" }, { pathPrefix: "/wrong" }, { pathSuffix: "/wrong" }, { queryEquals: "p2=v" }, { queryContains: "2=" }, { queryPrefix: "p2" }, { querySuffix: "=value" }, { urlEquals: "http://mozilla.com/sub/path?p1=v#ref" }, { urlContains: "com/sub" }, { urlPrefix: "http://moz" }, { urlSuffix: "#ref2" }, { urlMatches: "value#ref2$" }, { originAndPathMatches: ".*://moz.*com/" }, ], url: "https://mozilla.org/sub/path?p1=v#ref", }, // Some matches. { shouldPass, filters: [ { schemes: ["https"] }, { ports: [80] }, { hostEquals: "mozilla.com" }, { hostContains: "www.moz" }, { hostPrefix: "www" }, { hostSuffix: "com" }, { pathEquals: "/wrong/path" }, { pathContains: "g/p" }, { pathPrefix: "/wrong" }, { pathSuffix: "/wrong" }, { queryEquals: "p2=v" }, { queryContains: "2=" }, { queryPrefix: "p2" }, { querySuffix: "=value" }, { urlEquals: "http://mozilla.com/sub/path?p1=v#ref" }, { urlContains: "com/sub" }, { urlPrefix: "http://moz" }, { urlSuffix: "#ref2" }, { urlMatches: "value#ref2$" }, { originAndPathMatches: ".*://moz.*com/" }, ], url: "https://mozilla.org/sub/path?p1=v#ref", }, ]; // Run all the the testCases defined above. for (let currentTest of testCases) { let { exceptionMessageContains, url, filters, prefs } = currentTest; if (prefs !== undefined) { for (let [name, val] of prefs) { Preferences.set(name, val); } } if (currentTest.shouldThrow) { expectThrow({ url, filters, exceptionMessageContains }); } else if (currentTest.shouldFail) { expectFail({ url, filters }); } else { expectPass({ url, filters }); } if (prefs !== undefined) { for (let [name] of prefs) { Preferences.reset(name); } } } });