StorableRequest.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  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.js';
  8. import '../_version.js';
  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. * Accepts an object of request data that can be used to construct a
  29. * `Request` but can also be stored in IndexedDB.
  30. *
  31. * @param {Object} requestData An object of request data that includes the
  32. * `url` plus any relevant properties of
  33. * [requestInit]{@link https://fetch.spec.whatwg.org/#requestinit}.
  34. * @private
  35. */
  36. constructor(requestData) {
  37. if (process.env.NODE_ENV !== 'production') {
  38. assert.isType(requestData, 'object', {
  39. moduleName: 'workbox-background-sync',
  40. className: 'StorableRequest',
  41. funcName: 'constructor',
  42. paramName: 'requestData',
  43. });
  44. assert.isType(requestData.url, 'string', {
  45. moduleName: 'workbox-background-sync',
  46. className: 'StorableRequest',
  47. funcName: 'constructor',
  48. paramName: 'requestData.url',
  49. });
  50. }
  51. // If the request's mode is `navigate`, convert it to `same-origin` since
  52. // navigation requests can't be constructed via script.
  53. if (requestData['mode'] === 'navigate') {
  54. requestData['mode'] = 'same-origin';
  55. }
  56. this._requestData = requestData;
  57. }
  58. /**
  59. * Converts a Request object to a plain object that can be structured
  60. * cloned or JSON-stringified.
  61. *
  62. * @param {Request} request
  63. * @return {Promise<StorableRequest>}
  64. *
  65. * @private
  66. */
  67. static async fromRequest(request) {
  68. const requestData = {
  69. url: request.url,
  70. headers: {},
  71. };
  72. // Set the body if present.
  73. if (request.method !== 'GET') {
  74. // Use ArrayBuffer to support non-text request bodies.
  75. // NOTE: we can't use Blobs becuse Safari doesn't support storing
  76. // Blobs in IndexedDB in some cases:
  77. // https://github.com/dfahlander/Dexie.js/issues/618#issuecomment-398348457
  78. requestData.body = await request.clone().arrayBuffer();
  79. }
  80. // Convert the headers from an iterable to an object.
  81. for (const [key, value] of request.headers.entries()) {
  82. requestData.headers[key] = value;
  83. }
  84. // Add all other serializable request properties
  85. for (const prop of serializableProperties) {
  86. if (request[prop] !== undefined) {
  87. requestData[prop] = request[prop];
  88. }
  89. }
  90. return new StorableRequest(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 };