From 49f9bbbf3d40758e3c6fa0b7f63839d12e3ff3d0 Mon Sep 17 00:00:00 2001 From: Offir Golan Date: Tue, 1 Jun 2021 18:02:43 -0700 Subject: [PATCH] fix: Clone the arraybuffer if it fails instanceof check --- packages/@pollyjs/adapter-fetch/src/index.js | 21 +++++++++++++++++-- packages/@pollyjs/adapter-xhr/src/index.js | 21 +++++++++++++++++-- packages/@pollyjs/utils/src/index.js | 1 + .../utils/src/utils/clone-arraybuffer.js | 12 +++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 packages/@pollyjs/utils/src/utils/clone-arraybuffer.js diff --git a/packages/@pollyjs/adapter-fetch/src/index.js b/packages/@pollyjs/adapter-fetch/src/index.js index 75c8c9c7..d755bc01 100644 --- a/packages/@pollyjs/adapter-fetch/src/index.js +++ b/packages/@pollyjs/adapter-fetch/src/index.js @@ -1,5 +1,5 @@ import Adapter from '@pollyjs/adapter'; -import { isBufferUtf8Representable } from '@pollyjs/utils'; +import { cloneArrayBuffer, isBufferUtf8Representable } from '@pollyjs/utils'; import isNode from 'detect-node'; import { Buffer } from 'buffer/'; import bufferToArrayBuffer from 'to-arraybuffer'; @@ -167,7 +167,24 @@ export default class FetchAdapter extends Adapter { } ]); - const buffer = Buffer.from(await response.arrayBuffer()); + let arrayBuffer = await response.arrayBuffer(); + + /* + If the returned array buffer is not an instance of the global ArrayBuffer, + clone it in order to pass Buffer.from's instanceof check. This can happen + when using this adapter with a different context. + + https://github.com/feross/buffer/issues/289 + */ + if ( + arrayBuffer && + !(arrayBuffer instanceof ArrayBuffer) && + 'byteLength' in arrayBuffer + ) { + arrayBuffer = cloneArrayBuffer(arrayBuffer); + } + + const buffer = Buffer.from(arrayBuffer); const isBinaryBuffer = !isBufferUtf8Representable(buffer); return { diff --git a/packages/@pollyjs/adapter-xhr/src/index.js b/packages/@pollyjs/adapter-xhr/src/index.js index ca51964e..de33bf5b 100644 --- a/packages/@pollyjs/adapter-xhr/src/index.js +++ b/packages/@pollyjs/adapter-xhr/src/index.js @@ -1,6 +1,6 @@ import fakeXhr from '@offirgolan/nise/lib/fake-xhr'; import Adapter from '@pollyjs/adapter'; -import { isBufferUtf8Representable } from '@pollyjs/utils'; +import { cloneArrayBuffer, isBufferUtf8Representable } from '@pollyjs/utils'; import { Buffer } from 'buffer/'; import bufferToArrayBuffer from 'to-arraybuffer'; @@ -112,7 +112,24 @@ export default class XHRAdapter extends Adapter { // responseType will either be `arraybuffer` or `text` if (xhr.responseType === 'arraybuffer') { - const buffer = Buffer.from(xhr.response); + let arrayBuffer = xhr.response; + + /* + If the returned array buffer is not an instance of the global ArrayBuffer, + clone it in order to pass Buffer.from's instanceof check. This can happen + when using this adapter with a different context. + + https://github.com/feross/buffer/issues/289 + */ + if ( + arrayBuffer && + !(arrayBuffer instanceof ArrayBuffer) && + 'byteLength' in arrayBuffer + ) { + arrayBuffer = cloneArrayBuffer(arrayBuffer); + } + + const buffer = Buffer.from(arrayBuffer); isBinary = !isBufferUtf8Representable(buffer); body = buffer.toString(isBinary ? 'hex' : 'utf8'); diff --git a/packages/@pollyjs/utils/src/index.js b/packages/@pollyjs/utils/src/index.js index 8e803735..086cc67b 100644 --- a/packages/@pollyjs/utils/src/index.js +++ b/packages/@pollyjs/utils/src/index.js @@ -17,3 +17,4 @@ export { default as URL } from './utils/url'; export { default as isBufferUtf8Representable } from './utils/is-buffer-utf8-representable'; +export { default as cloneArrayBuffer } from './utils/clone-arraybuffer'; diff --git a/packages/@pollyjs/utils/src/utils/clone-arraybuffer.js b/packages/@pollyjs/utils/src/utils/clone-arraybuffer.js new file mode 100644 index 00000000..66908056 --- /dev/null +++ b/packages/@pollyjs/utils/src/utils/clone-arraybuffer.js @@ -0,0 +1,12 @@ +/** + * Clone an array buffer + * + * @param {ArrayBuffer} arrayBuffer + */ +export default function cloneArrayBuffer(arrayBuffer) { + const clonedArrayBuffer = new ArrayBuffer(arrayBuffer.byteLength); + + new Uint8Array(clonedArrayBuffer).set(new Uint8Array(arrayBuffer)); + + return clonedArrayBuffer; +}