match-pattern.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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. module.metadata = {
  6. "stability": "unstable"
  7. };
  8. const { URL } = require('../url');
  9. const cache = {};
  10. function MatchPattern(pattern) {
  11. if (cache[pattern]) return cache[pattern];
  12. if (typeof pattern.test == "function") {
  13. // For compatibility with -moz-document rules, we require the RegExp's
  14. // global, ignoreCase, and multiline flags to be set to false.
  15. if (pattern.global) {
  16. throw new Error("A RegExp match pattern cannot be set to `global` " +
  17. "(i.e. //g).");
  18. }
  19. if (pattern.ignoreCase) {
  20. throw new Error("A RegExp match pattern cannot be set to `ignoreCase` " +
  21. "(i.e. //i).");
  22. }
  23. if (pattern.multiline) {
  24. throw new Error("A RegExp match pattern cannot be set to `multiline` " +
  25. "(i.e. //m).");
  26. }
  27. this.regexp = pattern;
  28. }
  29. else {
  30. let firstWildcardPosition = pattern.indexOf("*");
  31. let lastWildcardPosition = pattern.lastIndexOf("*");
  32. if (firstWildcardPosition != lastWildcardPosition)
  33. throw new Error("There can be at most one '*' character in a wildcard.");
  34. if (firstWildcardPosition == 0) {
  35. if (pattern.length == 1)
  36. this.anyWebPage = true;
  37. else if (pattern[1] != ".")
  38. throw new Error("Expected a *.<domain name> string, got: " + pattern);
  39. else
  40. this.domain = pattern.substr(2);
  41. }
  42. else {
  43. if (pattern.indexOf(":") == -1) {
  44. throw new Error("When not using *.example.org wildcard, the string " +
  45. "supplied is expected to be either an exact URL to " +
  46. "match or a URL prefix. The provided string ('" +
  47. pattern + "') is unlikely to match any pages.");
  48. }
  49. if (firstWildcardPosition == -1)
  50. this.exactURL = pattern;
  51. else if (firstWildcardPosition == pattern.length - 1)
  52. this.urlPrefix = pattern.substr(0, pattern.length - 1);
  53. else {
  54. throw new Error("The provided wildcard ('" + pattern + "') has a '*' " +
  55. "in an unexpected position. It is expected to be the " +
  56. "first or the last character in the wildcard.");
  57. }
  58. }
  59. }
  60. cache[pattern] = this;
  61. }
  62. MatchPattern.prototype = {
  63. test: function MatchPattern_test(urlStr) {
  64. try {
  65. var url = URL(urlStr);
  66. }
  67. catch (err) {
  68. return false;
  69. }
  70. // Test the URL against a RegExp pattern. For compatibility with
  71. // -moz-document rules, we require the RegExp to match the entire URL,
  72. // so we not only test for a match, we also make sure the matched string
  73. // is the entire URL string.
  74. //
  75. // Assuming most URLs don't match most match patterns, we call `test` for
  76. // speed when determining whether or not the URL matches, then call `exec`
  77. // for the small subset that match to make sure the entire URL matches.
  78. //
  79. if (this.regexp && this.regexp.test(urlStr) &&
  80. this.regexp.exec(urlStr)[0] == urlStr)
  81. return true;
  82. if (this.anyWebPage && /^(https?|ftp)$/.test(url.scheme))
  83. return true;
  84. if (this.exactURL && this.exactURL == urlStr)
  85. return true;
  86. // Tests the urlStr against domain and check if
  87. // wildcard submitted (*.domain.com), it only allows
  88. // subdomains (sub.domain.com) or from the root (http://domain.com)
  89. // and reject non-matching domains (otherdomain.com)
  90. // bug 856913
  91. if (this.domain && url.host &&
  92. (url.host === this.domain ||
  93. url.host.slice(-this.domain.length - 1) === "." + this.domain))
  94. return true;
  95. if (this.urlPrefix && 0 == urlStr.indexOf(this.urlPrefix))
  96. return true;
  97. return false;
  98. },
  99. toString: function () '[object MatchPattern]'
  100. };
  101. exports.MatchPattern = MatchPattern;