Move stream timeout promise to util
Signed-off-by: Otto Sichert <git@ottosichert.de>
This commit is contained in:
@@ -24,6 +24,7 @@ import {
|
||||
ReadTreeResponseDirOptions,
|
||||
ReadTreeResponseFile,
|
||||
} from '../types';
|
||||
import { streamToTimeoutPromise } from './util';
|
||||
|
||||
/**
|
||||
* Wraps a zip archive stream into a tree response reader.
|
||||
@@ -86,27 +87,9 @@ export class ZipArchiveResponse implements ReadTreeResponse {
|
||||
|
||||
const files = Array<ReadTreeResponseFile>();
|
||||
|
||||
// Some corrupted ZIP files cause the zlib inflater to hang indefinitely.
|
||||
// This is a workaround to bail on stuck streams after 3 seconds.
|
||||
const piped = this.stream.pipe(unzipper.Parse());
|
||||
let lastEntryTimeout: NodeJS.Timeout | undefined;
|
||||
|
||||
await piped
|
||||
const parseStream = this.stream
|
||||
.pipe(unzipper.Parse())
|
||||
.on('entry', (entry: Entry) => {
|
||||
clearTimeout(lastEntryTimeout);
|
||||
|
||||
lastEntryTimeout = setTimeout(() => {
|
||||
piped.emit(
|
||||
'error',
|
||||
new Error(`Timed out unzipping file ${entry.path}`),
|
||||
);
|
||||
}, 3000);
|
||||
|
||||
if (entry.type === 'Directory') {
|
||||
entry.resume();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.shouldBeIncluded(entry)) {
|
||||
files.push({
|
||||
path: this.getInnerPath(entry.path),
|
||||
@@ -115,10 +98,14 @@ export class ZipArchiveResponse implements ReadTreeResponse {
|
||||
} else {
|
||||
entry.autodrain();
|
||||
}
|
||||
})
|
||||
.promise();
|
||||
});
|
||||
|
||||
clearTimeout(lastEntryTimeout);
|
||||
await streamToTimeoutPromise(parseStream, {
|
||||
eventName: 'entry',
|
||||
timeoutMs: 3000,
|
||||
getError: (entry: Entry) =>
|
||||
new Error(`Timed out while unzipping ${entry.type}: ${entry.path}`),
|
||||
});
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
@@ -23,3 +23,30 @@ const directoryNameRegex = /^[^\/]+\//;
|
||||
export function stripFirstDirectoryFromPath(path: string): string {
|
||||
return path.replace(directoryNameRegex, '');
|
||||
}
|
||||
|
||||
// Some corrupted ZIP files cause the zlib inflater to hang indefinitely.
|
||||
// This is a workaround to bail on stuck streams after 3 seconds.
|
||||
export async function streamToTimeoutPromise<T>(
|
||||
stream: NodeJS.ReadableStream,
|
||||
options: {
|
||||
timeoutMs: number;
|
||||
eventName: string;
|
||||
getError: (data: T) => Error;
|
||||
},
|
||||
) {
|
||||
let lastEntryTimeout: NodeJS.Timeout | undefined;
|
||||
stream.on(options.eventName, (data: T) => {
|
||||
clearTimeout(lastEntryTimeout);
|
||||
|
||||
lastEntryTimeout = setTimeout(() => {
|
||||
stream.emit('error', options.getError(data));
|
||||
}, options.timeoutMs);
|
||||
});
|
||||
|
||||
await new Promise(function (resolve, reject) {
|
||||
stream.on('finish', resolve);
|
||||
stream.on('error', reject);
|
||||
});
|
||||
|
||||
clearTimeout(lastEntryTimeout);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user