/* Copyright 2018 Google LLC Use of this source code is governed by an MIT-style license that can be found in the LICENSE file or at https://opensource.org/licenses/MIT. */ import { assert } from 'workbox-core/_private/assert.js'; import '../_version.js'; const serializableProperties = [ 'method', 'referrer', 'referrerPolicy', 'mode', 'credentials', 'cache', 'redirect', 'integrity', 'keepalive', ]; /** * A class to make it easier to serialize and de-serialize requests so they * can be stored in IndexedDB. * * @private */ class StorableRequest { /** * Accepts an object of request data that can be used to construct a * `Request` but can also be stored in IndexedDB. * * @param {Object} requestData An object of request data that includes the * `url` plus any relevant properties of * [requestInit]{@link https://fetch.spec.whatwg.org/#requestinit}. * @private */ constructor(requestData) { if (process.env.NODE_ENV !== 'production') { assert.isType(requestData, 'object', { moduleName: 'workbox-background-sync', className: 'StorableRequest', funcName: 'constructor', paramName: 'requestData', }); assert.isType(requestData.url, 'string', { moduleName: 'workbox-background-sync', className: 'StorableRequest', funcName: 'constructor', paramName: 'requestData.url', }); } // If the request's mode is `navigate`, convert it to `same-origin` since // navigation requests can't be constructed via script. if (requestData['mode'] === 'navigate') { requestData['mode'] = 'same-origin'; } this._requestData = requestData; } /** * Converts a Request object to a plain object that can be structured * cloned or JSON-stringified. * * @param {Request} request * @return {Promise} * * @private */ static async fromRequest(request) { const requestData = { url: request.url, headers: {}, }; // Set the body if present. if (request.method !== 'GET') { // Use ArrayBuffer to support non-text request bodies. // NOTE: we can't use Blobs becuse Safari doesn't support storing // Blobs in IndexedDB in some cases: // https://github.com/dfahlander/Dexie.js/issues/618#issuecomment-398348457 requestData.body = await request.clone().arrayBuffer(); } // Convert the headers from an iterable to an object. for (const [key, value] of request.headers.entries()) { requestData.headers[key] = value; } // Add all other serializable request properties for (const prop of serializableProperties) { if (request[prop] !== undefined) { requestData[prop] = request[prop]; } } return new StorableRequest(requestData); } /** * Returns a deep clone of the instances `_requestData` object. * * @return {Object} * * @private */ toObject() { const requestData = Object.assign({}, this._requestData); requestData.headers = Object.assign({}, this._requestData.headers); if (requestData.body) { requestData.body = requestData.body.slice(0); } return requestData; } /** * Converts this instance to a Request. * * @return {Request} * * @private */ toRequest() { return new Request(this._requestData.url, this._requestData); } /** * Creates and returns a deep clone of the instance. * * @return {StorableRequest} * * @private */ clone() { return new StorableRequest(this.toObject()); } } export { StorableRequest };