cookies.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  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 file,
  3. * You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. "use strict";
  5. const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
  6. Cu.import("resource://gre/modules/Log.jsm");
  7. Cu.import("chrome://marionette/content/error.js");
  8. const logger = Log.repository.getLogger("Marionette");
  9. this.EXPORTED_SYMBOLS = ["Cookies"];
  10. const IPV4_PORT_EXPR = /:\d+$/;
  11. /**
  12. * Interface for manipulating cookies from content space.
  13. */
  14. this.Cookies = class {
  15. /**
  16. * @param {function(): Document} documentFn
  17. * Closure that returns the current content document.
  18. * @param {Proxy(SyncChromeSender)} chromeProxy
  19. * A synchronous proxy interface to chrome space.
  20. */
  21. constructor(documentFn, chromeProxy) {
  22. this.documentFn_ = documentFn;
  23. this.chrome = chromeProxy;
  24. }
  25. get document() {
  26. return this.documentFn_();
  27. }
  28. [Symbol.iterator]() {
  29. let path = this.document.location.pathname || "/";
  30. let cs = this.chrome.getVisibleCookies(path, this.document.location.hostname)[0];
  31. return cs[Symbol.iterator]();
  32. }
  33. /**
  34. * Add a new cookie to a content document.
  35. *
  36. * @param {string} name
  37. * Cookie key.
  38. * @param {string} value
  39. * Cookie value.
  40. * @param {Object.<string, ?>} opts
  41. * An object with the optional fields {@code domain}, {@code path},
  42. * {@code secure}, {@code httpOnly}, and {@code expiry}.
  43. *
  44. * @return {Object.<string, ?>}
  45. * A serialisation of the cookie that was added.
  46. *
  47. * @throws UnableToSetCookieError
  48. * If the document's content type isn't HTML, the current document's
  49. * domain is a mismatch to the cookie's provided domain, or there
  50. * otherwise was issues with the input data.
  51. */
  52. add(name, value, opts={}) {
  53. if (typeof this.document == "undefined" || !this.document.contentType.match(/html/i)) {
  54. throw new UnableToSetCookieError(
  55. "You may only set cookies on HTML documents: " + this.document.contentType);
  56. }
  57. if (!opts.expiry) {
  58. // date twenty years into future, in seconds
  59. let date = new Date();
  60. let now = new Date(Date.now());
  61. date.setYear(now.getFullYear() + 20);
  62. opts.expiry = date.getTime() / 1000;
  63. }
  64. if (!opts.domain) {
  65. opts.domain = this.document.location.host;
  66. } else if (this.document.location.host.indexOf(opts.domain) < 0) {
  67. throw new InvalidCookieDomainError(
  68. "You may only set cookies for the current domain");
  69. }
  70. // remove port from domain, if present.
  71. // unfortunately this catches IPv6 addresses by mistake
  72. // TODO: Bug 814416
  73. opts.domain = opts.domain.replace(IPV4_PORT_EXPR, "");
  74. let cookie = {
  75. domain: opts.domain,
  76. path: opts.path,
  77. name: name,
  78. value: value,
  79. secure: opts.secure,
  80. httpOnly: opts.httpOnly,
  81. session: false,
  82. expiry: opts.expiry,
  83. };
  84. if (!this.chrome.addCookie(cookie)) {
  85. throw new UnableToSetCookieError();
  86. }
  87. return cookie;
  88. }
  89. /**
  90. * Delete cookie by reference or by name.
  91. *
  92. * @param {(string|Object.<string, ?>)} cookie
  93. * Name of cookie or cookie object.
  94. *
  95. * @throws {UnknownError}
  96. * If unable to delete the cookie.
  97. */
  98. delete(cookie) {
  99. let name;
  100. if (cookie.hasOwnProperty("name")) {
  101. name = cookie.name;
  102. } else {
  103. name = cookie;
  104. }
  105. for (let candidate of this) {
  106. if (candidate.name == name) {
  107. if (!this.chrome.deleteCookie(candidate)) {
  108. throw new UnknownError("Unable to delete cookie by name: " + name);
  109. }
  110. }
  111. }
  112. }
  113. };