diff --git a/index.js b/index.js index 8749a15..f779c99 100644 --- a/index.js +++ b/index.js @@ -10,6 +10,33 @@ function md5(str) { return crypto.createHash('md5').update(str).digest('hex'); } +function getFormDataCacheKey(formData) { + const cacheKey = { ...formData }; + + if (typeof formData.getBoundary === 'function') { + const boundary = formData.getBoundary(); + + // eslint-disable-next-line no-underscore-dangle + delete cacheKey._boundary; + + // eslint-disable-next-line no-underscore-dangle + if (Array.isArray(cacheKey._streams)) { + const boundaryReplaceRegex = new RegExp(boundary, 'g'); + + // eslint-disable-next-line no-underscore-dangle + cacheKey._streams = cacheKey._streams.map((s) => { + if (typeof s === 'string') { + return s.replace(boundaryReplaceRegex, ''); + } + + return s; + }); + } + } + + return cacheKey; +} + function getBodyCacheKeyJson(body) { if (!body) { return body; @@ -19,6 +46,8 @@ function getBodyCacheKeyJson(body) { return body.toString(); } if (body instanceof fs.ReadStream) { return body.path; + } if (body.toString && body.toString() === '[object FormData]') { + return getFormDataCacheKey(body); } throw new Error('Unsupported body type'); diff --git a/package-lock.json b/package-lock.json index a6e7c0b..e919496 100644 --- a/package-lock.json +++ b/package-lock.json @@ -156,6 +156,12 @@ "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", "dev": true }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, "balanced-match": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", @@ -310,6 +316,15 @@ "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "dev": true }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, "compare-versions": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", @@ -418,6 +433,12 @@ "object-keys": "^1.0.12" } }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, "diff": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", @@ -829,6 +850,17 @@ "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", "dev": true }, + "form-data": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -1433,6 +1465,21 @@ } } }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "dev": true + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dev": true, + "requires": { + "mime-db": "1.44.0" + } + }, "mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", diff --git a/package.json b/package.json index d8e5084..be64d84 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ "eslint": "^6.8.0", "eslint-config-airbnb-base": "^14.1.0", "eslint-plugin-import": "^2.20.2", + "form-data": "^3.0.0", "husky": "^4.3.0", "mocha": "^8.2.1", "rimraf": "^3.0.2" diff --git a/test/tests.js b/test/tests.js index acca098..dfd232b 100644 --- a/test/tests.js +++ b/test/tests.js @@ -1,4 +1,5 @@ const fs = require('fs'); +const FormData = require('form-data'); const assert = require('assert'); const rimraf = require('rimraf'); const path = require('path'); @@ -163,6 +164,34 @@ describe('Cache tests', function() { res = await fetch(TWO_HUNDRED_URL, post(s1)); assert.strictEqual(res.fromCache, true); }); + + it('Gives different form data different cache keys', async function() { + const data1 = new FormData(); + data1.append('a', 'a'); + + const data2 = new FormData(); + data2.append('b', 'b'); + + res = await fetch(TWO_HUNDRED_URL, post(data1)); + assert.strictEqual(res.fromCache, false); + + res = await fetch(TWO_HUNDRED_URL, post(data2)); + assert.strictEqual(res.fromCache, false); + }); + + it('Gives same form data same cache keys', async function() { + const data1 = new FormData(); + data1.append('a', 'a'); + + const data2 = new FormData(); + data2.append('a', 'a'); + + res = await fetch(TWO_HUNDRED_URL, post(data1)); + assert.strictEqual(res.fromCache, false); + + res = await fetch(TWO_HUNDRED_URL, post(data2)); + assert.strictEqual(res.fromCache, true); + }); }).timeout(10000); describe('Data tests', function() {