Skip to content

Commit

Permalink
stream: fix pipeline pump
Browse files Browse the repository at this point in the history
Refs: #39005
  • Loading branch information
ronag committed Jun 11, 2021
1 parent dc43066 commit 963f536
Showing 1 changed file with 39 additions and 9 deletions.
48 changes: 39 additions & 9 deletions lib/internal/streams/pipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,21 @@ const {
ERR_INVALID_ARG_TYPE,
ERR_INVALID_RETURN_VALUE,
ERR_MISSING_ARGS,
ERR_STREAM_DESTROYED
ERR_STREAM_DESTROYED,
ERR_STREAM_PREMATURE_CLOSE
} = require('internal/errors').codes;

const { validateCallback } = require('internal/validators');

function noop() {}

const {
isIterable,
isReadable,
isStream,
} = require('internal/streams/utils');
const assert = require('internal/assert');

let EE;
let PassThrough;
let Readable;

Expand Down Expand Up @@ -102,25 +105,52 @@ async function* fromReadable(val) {
}

async function pump(iterable, writable, finish) {
if (!EE) {
EE = require('events');
}
let error;
let callback = noop;
const resume = (err) => {
if (!error && err) {
error = err;
}
const _callback = callback;
callback = noop;
_callback();
};
const onClose = () => {
resume(new ERR_STREAM_PREMATURE_CLOSE());
};

const waitForDrain = () => new Promise((resolve) => {
assert.strictEqual(callback, noop);
if (error || writable.destroyed) {
resolve();
} else {
callback = resolve;
}
});

writable
.on('drain', resume)
.on('error', resume)
.on('close', onClose);

try {
if (writable.writableNeedDrain === true) {
await EE.once(writable, 'drain');
if (writable.writableNeedDrain) {
await waitForDrain();
}

for await (const chunk of iterable) {
if (!writable.write(chunk)) {
if (writable.destroyed) return;
await EE.once(writable, 'drain');
await waitForDrain();
}
}
writable.end();
} catch (err) {
error = err;
} finally {
writable
.off('drain', resume)
.off('error', resume)
.off('close', onClose);
finish(error);
}
}
Expand Down

0 comments on commit 963f536

Please sign in to comment.