Skip to content

Reference implementation pipeTo() calls WritableStreamAbort() asynchronously when ReadableStream is already errored #727

@ricea

Description

@ricea

This is an abridged version of the 'Piping from an errored readable stream to a closed writable stream' test:

promise_test(t => {
  const rs = new ReadableStream({
    start(c) {
      c.error(error1);
    }
  });
  const ws = new WritableStream();
  const writer = ws.getWriter();
  const closePromise = writer.close();
  writer.releaseLock();

  return Promise.all([
    promise_rejects(t, error1, rs.pipeTo(ws), 'pipeTo should reject'),
    promise_rejects(t, new TypeError(), closePromise, 'close() should reject')
  ]);

}, 'Piping from an errored readable stream to a closing writable stream');

The expectations have been changed to match what Blink's implementation does. In the reference implementation closePromise is fulfilled. This is because Blink is calling WritableStreamAbort() synchronously and the reference implementation is calling it asynchronously.

I originally thought this was a bug in Blink's implementation and filed https://bugs.chromium.org/p/chromium/issues/detail?id=684543, but now I think the reference implementation doesn't match the standard.

The standard says about pipeTo():

  • Errors must be propagated forward: if this.[[state]] is or becomes "errored", then
    • If preventAbort is false, shutdown with an action of ! WritableStreamAbort(dest, this.[[storedError]]) and with this.[[storedError]].

In this case, [[state]] is "errored", so we should shutdown with an action.

Shutdown with an action says:

  1. If dest.[[state]] is "writable" and ! WritableStreamCloseQueuedOrInFlight(dest) is false,
    a. If any chunks have been read but not yet written, write them to dest.
    b. Wait until every chunk that has been read has been written (i.e. the corresponding promises have settled).
  2. If shuttingDown is true, abort these substeps.
  3. Set shuttingDown to true.
  4. Let p be the result of performing action.

In this case WritableStreamCloseQueuedOrInFlight(dest) is true, so we should perform action without waiting.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions