StorableRequest.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  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. * Most developers will not need to access this class directly;
  25. * it is exposed for advanced use cases.
  26. */
  27. class StorableRequest {
  28. /**
  29. * Converts a Request object to a plain object that can be structured
  30. * cloned or JSON-stringified.
  31. *
  32. * @param {Request} request
  33. * @return {Promise<StorableRequest>}
  34. */
  35. static async fromRequest(request) {
  36. const requestData = {
  37. url: request.url,
  38. headers: {},
  39. };
  40. // Set the body if present.
  41. if (request.method !== 'GET') {
  42. // Use ArrayBuffer to support non-text request bodies.
  43. // NOTE: we can't use Blobs becuse Safari doesn't support storing
  44. // Blobs in IndexedDB in some cases:
  45. // https://github.com/dfahlander/Dexie.js/issues/618#issuecomment-398348457
  46. requestData.body = await request.clone().arrayBuffer();
  47. }
  48. // Convert the headers from an iterable to an object.
  49. for (const [key, value] of request.headers.entries()) {
  50. requestData.headers[key] = value;
  51. }
  52. // Add all other serializable request properties
  53. for (const prop of serializableProperties) {
  54. if (request[prop] !== undefined) {
  55. requestData[prop] = request[prop];
  56. }
  57. }
  58. return new StorableRequest(requestData);
  59. }
  60. /**
  61. * Accepts an object of request data that can be used to construct a
  62. * `Request` but can also be stored in IndexedDB.
  63. *
  64. * @param {Object} requestData An object of request data that includes the
  65. * `url` plus any relevant properties of
  66. * [requestInit]{@link https://fetch.spec.whatwg.org/#requestinit}.
  67. */
  68. constructor(requestData) {
  69. if (process.env.NODE_ENV !== 'production') {
  70. assert.isType(requestData, 'object', {
  71. moduleName: 'workbox-background-sync',
  72. className: 'StorableRequest',
  73. funcName: 'constructor',
  74. paramName: 'requestData',
  75. });
  76. assert.isType(requestData.url, 'string', {
  77. moduleName: 'workbox-background-sync',
  78. className: 'StorableRequest',
  79. funcName: 'constructor',
  80. paramName: 'requestData.url',
  81. });
  82. }
  83. // If the request's mode is `navigate`, convert it to `same-origin` since
  84. // navigation requests can't be constructed via script.
  85. if (requestData['mode'] === 'navigate') {
  86. requestData['mode'] = 'same-origin';
  87. }
  88. this._requestData = requestData;
  89. }
  90. /**
  91. * Returns a deep clone of the instances `_requestData` object.
  92. *
  93. * @return {Object}
  94. */
  95. toObject() {
  96. const requestData = Object.assign({}, this._requestData);
  97. requestData.headers = Object.assign({}, this._requestData.headers);
  98. if (requestData.body) {
  99. requestData.body = requestData.body.slice(0);
  100. }
  101. return requestData;
  102. }
  103. /**
  104. * Converts this instance to a Request.
  105. *
  106. * @return {Request}
  107. */
  108. toRequest() {
  109. return new Request(this._requestData.url, this._requestData);
  110. }
  111. /**
  112. * Creates and returns a deep clone of the instance.
  113. *
  114. * @return {StorableRequest}
  115. */
  116. clone() {
  117. return new StorableRequest(this.toObject());
  118. }
  119. }
  120. export { StorableRequest };