StorableRequest.mjs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. Copyright 2018 Google LLC
  3. Use of this source code is governed by an MIT-style
  4. license that can be found in the LICENSE file or at
  5. https://opensource.org/licenses/MIT.
  6. */
  7. import {assert} from 'workbox-core/_private/assert.mjs';
  8. import '../_version.mjs';
  9. const serializableProperties = [
  10. 'method',
  11. 'referrer',
  12. 'referrerPolicy',
  13. 'mode',
  14. 'credentials',
  15. 'cache',
  16. 'redirect',
  17. 'integrity',
  18. 'keepalive',
  19. ];
  20. /**
  21. * A class to make it easier to serialize and de-serialize requests so they
  22. * can be stored in IndexedDB.
  23. *
  24. * @private
  25. */
  26. class StorableRequest {
  27. /**
  28. * Converts a Request object to a plain object that can be structured
  29. * cloned or JSON-stringified.
  30. *
  31. * @param {Request} request
  32. * @return {Promise<StorableRequest>}
  33. *
  34. * @private
  35. */
  36. static async fromRequest(request) {
  37. const requestData = {
  38. url: request.url,
  39. headers: {},
  40. };
  41. // Set the body if present.
  42. if (request.method !== 'GET') {
  43. // Use ArrayBuffer to support non-text request bodies.
  44. // NOTE: we can't use Blobs becuse Safari doesn't support storing
  45. // Blobs in IndexedDB in some cases:
  46. // https://github.com/dfahlander/Dexie.js/issues/618#issuecomment-398348457
  47. requestData.body = await request.clone().arrayBuffer();
  48. }
  49. // Convert the headers from an iterable to an object.
  50. for (const [key, value] of request.headers.entries()) {
  51. requestData.headers[key] = value;
  52. }
  53. // Add all other serializable request properties
  54. for (const prop of serializableProperties) {
  55. if (request[prop] !== undefined) {
  56. requestData[prop] = request[prop];
  57. }
  58. }
  59. return new StorableRequest(requestData);
  60. }
  61. /**
  62. * Accepts an object of request data that can be used to construct a
  63. * `Request` but can also be stored in IndexedDB.
  64. *
  65. * @param {Object} requestData An object of request data that includes the
  66. * `url` plus any relevant properties of
  67. * [requestInit]{@link https://fetch.spec.whatwg.org/#requestinit}.
  68. * @private
  69. */
  70. constructor(requestData) {
  71. if (process.env.NODE_ENV !== 'production') {
  72. assert.isType(requestData, 'object', {
  73. moduleName: 'workbox-background-sync',
  74. className: 'StorableRequest',
  75. funcName: 'constructor',
  76. paramName: 'requestData',
  77. });
  78. assert.isType(requestData.url, 'string', {
  79. moduleName: 'workbox-background-sync',
  80. className: 'StorableRequest',
  81. funcName: 'constructor',
  82. paramName: 'requestData.url',
  83. });
  84. }
  85. // If the request's mode is `navigate`, convert it to `same-origin` since
  86. // navigation requests can't be constructed via script.
  87. if (requestData.mode === 'navigate') {
  88. requestData.mode = 'same-origin';
  89. }
  90. this._requestData = requestData;
  91. }
  92. /**
  93. * Returns a deep clone of the instances `_requestData` object.
  94. *
  95. * @return {Object}
  96. *
  97. * @private
  98. */
  99. toObject() {
  100. const requestData = Object.assign({}, this._requestData);
  101. requestData.headers = Object.assign({}, this._requestData.headers);
  102. if (requestData.body) {
  103. requestData.body = requestData.body.slice(0);
  104. }
  105. return requestData;
  106. }
  107. /**
  108. * Converts this instance to a Request.
  109. *
  110. * @return {Request}
  111. *
  112. * @private
  113. */
  114. toRequest() {
  115. return new Request(this._requestData.url, this._requestData);
  116. }
  117. /**
  118. * Creates and returns a deep clone of the instance.
  119. *
  120. * @return {StorableRequest}
  121. *
  122. * @private
  123. */
  124. clone() {
  125. return new StorableRequest(this.toObject());
  126. }
  127. }
  128. export {StorableRequest};