From d1980854fee1765cd02fa0787adf5d6e34dd9dcf Mon Sep 17 00:00:00 2001 From: Dmitriy Mozgovoy Date: Sat, 31 Aug 2024 22:14:23 +0300 Subject: [PATCH] fix(fetch): fix stream handling in Safari by fallback to using a stream reader instead of an async iterator; (#6584) --- lib/adapters/fetch.js | 4 ++-- lib/helpers/trackStream.js | 30 +++++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/adapters/fetch.js b/lib/adapters/fetch.js index b7d3771..f871a05 100644 --- a/lib/adapters/fetch.js +++ b/lib/adapters/fetch.js @@ -146,7 +146,7 @@ export default isFetchSupported && (async (config) => { progressEventReducer(asyncDecorator(onUploadProgress)) ); - data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush, encodeText); + data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush); } } @@ -189,7 +189,7 @@ export default isFetchSupported && (async (config) => { trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => { flush && flush(); unsubscribe && unsubscribe(); - }, encodeText), + }), options ); } diff --git a/lib/helpers/trackStream.js b/lib/helpers/trackStream.js index 0ae39ab..95d6008 100644 --- a/lib/helpers/trackStream.js +++ b/lib/helpers/trackStream.js @@ -17,14 +17,34 @@ export const streamChunk = function* (chunk, chunkSize) { } } -export const readBytes = async function* (iterable, chunkSize, encode) { - for await (const chunk of iterable) { - yield* streamChunk(ArrayBuffer.isView(chunk) ? chunk : (await encode(String(chunk))), chunkSize); +export const readBytes = async function* (iterable, chunkSize) { + for await (const chunk of readStream(iterable)) { + yield* streamChunk(chunk, chunkSize); } } -export const trackStream = (stream, chunkSize, onProgress, onFinish, encode) => { - const iterator = readBytes(stream, chunkSize, encode); +const readStream = async function* (stream) { + if (stream[Symbol.asyncIterator]) { + yield* stream; + return; + } + + const reader = stream.getReader(); + try { + for (;;) { + const {done, value} = await reader.read(); + if (done) { + break; + } + yield value; + } + } finally { + await reader.cancel(); + } +} + +export const trackStream = (stream, chunkSize, onProgress, onFinish) => { + const iterator = readBytes(stream, chunkSize); let bytes = 0; let done;