diff --git a/cvat-core/src/download.worker.js b/cvat-core/src/download.worker.js index b3e48789357c..411a49abd9a8 100644 --- a/cvat-core/src/download.worker.js +++ b/cvat-core/src/download.worker.js @@ -13,6 +13,7 @@ onmessage = (e) => { .then((response) => { postMessage({ responseData: response.data, + headers: response.headers, id: e.data.id, isSuccess: true, }); diff --git a/cvat-core/src/server-proxy.ts b/cvat-core/src/server-proxy.ts index 978b2c4bf61c..7296764e092a 100644 --- a/cvat-core/src/server-proxy.ts +++ b/cvat-core/src/server-proxy.ts @@ -199,7 +199,7 @@ class WorkerWrappedAxios { if (e.data.id in requests) { try { if (e.data.isSuccess) { - requests[e.data.id].resolve(e.data.responseData); + requests[e.data.id].resolve({ data: e.data.responseData, headers: e.data.headers }); } else { requests[e.data.id].reject(new AxiosError(e.data.message, e.data.code)); } @@ -1495,7 +1495,7 @@ async function getImageContext(jid: number, frame: number): Promise } } -async function getData(jid: number, chunk: number, quality: ChunkQuality): Promise { +async function getData(jid: number, chunk: number, quality: ChunkQuality, retry = 0): Promise { const { backendAPI } = config; try { @@ -1509,7 +1509,29 @@ async function getData(jid: number, chunk: number, quality: ChunkQuality): Promi responseType: 'arraybuffer', }); - return response; + const contentLength = +(response.headers || {})['content-length']; + if (Number.isInteger(contentLength) && response.data.byteLength < +contentLength) { + if (retry < 10) { + // corrupted zip tmp workaround + // if content length more than received byteLength, request the chunk again + // and log this error + setTimeout(() => { + throw new Error( + `Truncated chunk, try: ${retry}. Job: ${jid}, chunk: ${chunk}, quality: ${quality}. ` + + `Body size: ${response.data.byteLength}`, + ); + }); + return await getData(jid, chunk, quality, retry + 1); + } + + // not to try anymore, throw explicit error + throw new Error( + `Truncated chunk. Job: ${jid}, chunk: ${chunk}, quality: ${quality}. ` + + `Body size: ${response.data.byteLength}`, + ); + } + + return response.data; } catch (errorData) { throw generateError(errorData); }