Intent to Implement and Ship: Body.bodyUsed

82 views
Skip to first unread message

Yutaka Hirano

unread,
Sep 14, 2015, 12:30:48 PM9/14/15
to blink-dev, Anne van Kesteren, Benjamin Kelly, Domenic Denicola, Takeshi Yoshino

Contact emails

yhi...@chromium.org


Spec

https://streams.spec.whatwg.org/

https://fetch.spec.whatwg.org/

https://github.com/yutakahirano/fetch-with-streams/ (will be merged to https://fetch.spec.whatwg.org/ shortly)


Summary

Body.bodyUsed is used to check if the object (Request or Response)'s body is read. Some customers (e.g. Cache.put) checks before reading the body.


The property was shipped at M40 in part of Fetch API (Notice Fetch API was shipped with ServiceWorker, and exposed to Window after that) and modified when body stream was introduced (M43). Recently we decided to change it again for the better consistency with other APIs (FetchEvent.respondWith, Cache.put, ...).


The change consists of two parts:


1. ReadableStreamReader will not be released when closed or errored.

Currently a reader of Readable[Byte]Stream will be released when the stream is closed or errored. We remove this auto-release mechanism.


var promise = fetch('https://www.example.com/').then(res => res.text().then(() => res.body.getReader()));


The promise will be resolved with the current implementation (because after text() is done the body stream will be closed and the reader will be released), but will be rejected with the new behavior.


2. Body.bodyUsed will be based on 'disturbed' internal property of ReadableStream.

Currently Body.bodyUsed returns true if the body stream is locked. With the new interpretation Body.bodyUsed returns true when someone has read any data from the body stream.


var stream = response.body;

var reader = stream.getReader();

reader.read(() => {

  reader.releaseLock();

  // Here the stream is no longer locked, but bodyUsed returns true.

  assert_true(response.bodyUsed);

});


I'm sorry we change the behavior after shipping, but we believe this change doesn't break user-code largely and the new behavior is stable enough (Fetch / Streams guys held a face-to-face meeting and reached consensus).


Discussion threads:

https://github.com/yutakahirano/fetch-with-streams/issues/37

https://github.com/whatwg/streams/issues/378

https://github.com/whatwg/streams/pull/385


Compatibility Risk


1. Removing auto-release mechanism affects users who try to read data from a stream that is already consumed. We did not find any useful use-cases, and we don't expect this change breaks user-code largely.

2. For the bodyUsed change, reading data partially from ReadableStream and calling other APIs (text(), cache.put, ...) will be disallowed. But currently we don't provide a means to read bytes with specifying byte length, so we think there are little code that will be affected.


We are not planning to investigate use-counters because the body stream itself is not yet so popular.


Ongoing technical constraints

None.


Will this feature be supported on all six Blink platforms (Windows, Mac, Linux, Chrome OS, Android, and Android WebView)?

Yes.


OWP launch tracking bug

None.


Link to entry on the feature dashboard

https://www.chromestatus.com/features/6730533392351232


Requesting approval to ship?

Yes.

Domenic Denicola

unread,
Sep 14, 2015, 12:35:36 PM9/14/15
to Yutaka Hirano, blink-dev, Anne van Kesteren, Benjamin Kelly, Takeshi Yoshino
Non-owner LGTM.

> Compatibility Risk

These changes were the end result of a long, long discussion with Mozilla on how they wished bodyUsed and streams to behave together. It was an important point for them and we finally hashed it out at the F2F Yutaka mentioned. So although this is a small change from past Chrome behavior, in terms of the future, it is a definite gain for achieving cross-browser compatibility.

PhistucK

unread,
Sep 14, 2015, 4:22:59 PM9/14/15
to Yutaka Hirano, blink-dev, Anne van Kesteren, Benjamin Kelly, Domenic Denicola, Takeshi Yoshino

On Mon, Sep 14, 2015 at 7:30 PM, Yutaka Hirano <yhi...@chromium.org> wrote:

1. ReadableStreamReader will not be released when closed or errored.

Currently a reader of Readable[Byte]Stream will be released when the stream is closed or errored. We remove this auto-release mechanism.


var promise = fetch('https://www.example.com/').then(res => res.text().then(() => res.body.getReader()));


The promise will be resolved with the current implementation (because after text() is done the body stream will be closed and the reader will be released), but will be rejected with the new behavior.


I mean, for the uneducated (or not native speaker) me, this sounds backwards... What is a released stream reader​?
Released means unlocked, which means, that others can read it? Not released means that it is locked?
So currently, the stream is locked during res.text() and once that is done, it gets unlocked and others can read from it, right?
The new behavior keeps it locked so others cannot read it, right?



PhistucK

Rick Byers

unread,
Sep 14, 2015, 4:55:38 PM9/14/15
to Domenic Denicola, Yutaka Hirano, blink-dev, Anne van Kesteren, Benjamin Kelly, Takeshi Yoshino
LGTM 1

It would be great to see the PR land before this change actually gets to stable (just to confirm that there is indeed consensus on the fine details).  But I've skimmed the threads / GitHub issues and I agree that it sounds like there's good agreement here in general (and so a step forwards wrt. eventual interoperability).  I don't think it's necessary to block on the PR landing.

However, if new non-trivial concerns arise before this gets merged, please ping this thread (eg. in some cases it may make sense to revert changes from beta, pushing back to the next release in order to minimize developer churn).

Thanks,
  Rick

Yutaka Hirano

unread,
Sep 15, 2015, 4:29:40 AM9/15/15
to PhistucK, blink-dev, Anne van Kesteren, Benjamin Kelly, Domenic Denicola, Takeshi Yoshino
Sorry for not being clear. I'm not a native speaker, too.

I mean, for the uneducated (or not native speaker) me, this sounds backwards... What is a released stream reader​? 
ReadableStream has "getReader" method. When called,
- The stream is already locked => Throw an error.
- Mark the stream as locked.
- Return a ReadableStreamReader.

ReadableStreamReader has "releaseLock" method. When called,
- The reader is already released => Return and do nothing
- Unmark "locked" label on the associated stream.
- Mark the reader as released.

Currently, when a stream is closed or errored and the stream is locked, the associated reader will be automatically released (i.e. releaseLock is called).
"1. ReadableStreamReader will not be released when closed or errored." removes this automatic release.
 
So currently, the stream is locked during res.text() and once that is done, it gets unlocked and others can read from it, right?
Yes. Please note that text() reads all data from the body stream and "others" can read only empty data after that.

The new behavior keeps it locked so others cannot read it, right?
Yes.

Takeshi Yoshino

unread,
Sep 15, 2015, 5:40:50 AM9/15/15
to Yutaka Hirano, PhistucK, blink-dev, Anne van Kesteren, Benjamin Kelly, Domenic Denicola
On Tue, Sep 15, 2015 at 5:29 PM, Yutaka Hirano <yhi...@chromium.org> wrote:
Sorry for not being clear. I'm not a native speaker, too.

I mean, for the uneducated (or not native speaker) me, this sounds backwards... What is a released stream reader​? 
ReadableStream has "getReader" method. When called,
- The stream is already locked => Throw an error.
- Mark the stream as locked.
- Return a ReadableStreamReader.

ReadableStreamReader has "releaseLock" method. When called,
- The reader is already released => Return and do nothing
- Unmark "locked" label on the associated stream.
- Mark the reader as released.

Currently, when a stream is closed or errored and the stream is locked, the associated reader will be automatically released (i.e. releaseLock is called).
"1. ReadableStreamReader will not be released when closed or errored." removes this automatic release.
 
So currently, the stream is locked during res.text() and once that is done, it gets unlocked and others can read from it, right?
Yes. Please note that text() reads all data from the body stream and "others" can read only empty data after that.

The new behavior keeps it locked so others cannot read it, right?
Yes.


The main motivation of the reader mechanism is to arbitrate operations among JS code, advanced library functions (e.g. pipeTo), and off-thread operations. It's still satisfied. A reader is basically representing an exclusive access to the stream.

IIRC, we were thinking of how to let one customer of a stream to notify another waiting for access. https://github.com/whatwg/streams/pull/251#issuecomment-66701976. Auto-release was introduced to meet this requirement. After a while, we've decided to move the functionality out of the Streams' scope (users should notify the other consumer just by themselves). So, it's no longer necessary but preserved for compatibility.

Before the discussion about needs for "disturbed" property arises, there was nothing to arbitrate after a stream gets "closed"/"errored" (read() and cancel() were no-op. .closed attribute has already been fulfilled/rejected). So, we just preserved the auto-release (also because it's a bit convenient).

A "released" ReadableStreamReader was representing the state of the stream at the time the reader was released. I.e. closing/erroring a stream automatically releases the associated reader -> the reader starts saying "I've been closed/errored". Releasing a reader was kinda freezing the state of the associated stream into the reader. For a "readable" stream, the reader represented "disconnection from the stream" by saying "I've been closed". Currently, these semantics are not providing the Streams with any big practical value.

TAMURA, Kent

unread,
Sep 15, 2015, 7:55:05 PM9/15/15
to Rick Byers, Domenic Denicola, Yutaka Hirano, blink-dev, Anne van Kesteren, Benjamin Kelly, Takeshi Yoshino
LGTM2.

--
TAMURA Kent
Software Engineer, Google


Philip Jägenstedt

unread,
Sep 16, 2015, 4:41:40 AM9/16/15
to TAMURA, Kent, Rick Byers, Domenic Denicola, Yutaka Hirano, blink-dev, Anne van Kesteren, Benjamin Kelly, Takeshi Yoshino
LGTM3

To unsubscribe from this group and stop receiving emails from it, send an email to blink-dev+...@chromium.org.

Reply all
Reply to author
Forward
0 new messages