WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
RESOLVED FIXED
227690
ReadableStream's pipeTo() and pipeThrough() don't handle options in spec-perfect way
https://bugs.webkit.org/show_bug.cgi?id=227690
Summary
ReadableStream's pipeTo() and pipeThrough() don't handle options in spec-perf...
Alexey Shvayka
Reported
2021-07-05 14:24:44 PDT
Streams spec for pipeThrough():
https://streams.spec.whatwg.org/#rs-pipe-through
WebIDL spec for dictionary types:
https://heycam.github.io/webidl/#es-dictionary
Implementation:
https://github.com/WebKit/WebKit/blob/3cd76abcda098f91d46fb0ad42e1eab68b6ddb12/Source/WebCore/Modules/streams/ReadableStream.js#L122
> if (@isReadableStreamLocked(this)) > throw @makeTypeError("ReadableStream is locked");
While this is the first step of pipeThrough() algorithm, it should happen after all arguments (including `options`) are checked / handled.
> if (options === @undefined) > options = { };
This causes properties to queried from Object.prototype; the WebIDL spec doesn't perform [[Get]] for non-objects at all. @Object.@create(null) may be used instead.
> let signal; > if ("signal" in options) { > signal = options["signal"];
This is observable is options is a Proxy; the WebIDL spec merely compares [[Get]] result with undefined.
> const preventClose = !!options["preventClose"]; > const preventAbort = !!options["preventAbort"]; > const preventCancel = !!options["preventCancel"];
For these 3, lookup order matches the member declaration order of Streams spec. However, the WebIDL spec requires "lexicographical order"; does it translate to 1) "preventAbort" 2) "preventCancel" 3) "preventClose"? Either way, `options.signal` should be queried after these 3, which is observable by a userland getter.
Attachments
Patch
(7.97 KB, patch)
2021-08-02 06:32 PDT
,
youenn fablet
no flags
Details
Formatted Diff
Diff
Patch
(17.61 KB, patch)
2021-08-02 11:27 PDT
,
youenn fablet
no flags
Details
Formatted Diff
Diff
Patch
(18.32 KB, patch)
2021-08-02 11:33 PDT
,
youenn fablet
no flags
Details
Formatted Diff
Diff
Patch for landing
(18.49 KB, patch)
2021-08-03 08:12 PDT
,
youenn fablet
no flags
Details
Formatted Diff
Diff
Show Obsolete
(3)
View All
Add attachment
proposed patch, testcase, etc.
Radar WebKit Bug Importer
Comment 1
2021-07-12 14:25:17 PDT
<
rdar://problem/80482144
>
youenn fablet
Comment 2
2021-08-02 06:32:13 PDT
Created
attachment 434748
[details]
Patch
EWS Watchlist
Comment 3
2021-08-02 06:33:01 PDT
This patch modifies the imported WPT tests. Please ensure that any changes on the tests (not coming from a WPT import) are exported to WPT. Please see
https://trac.webkit.org/wiki/WPTExportProcess
Alexey Shvayka
Comment 4
2021-08-02 09:15:43 PDT
Comment on
attachment 434748
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=434748&action=review
> Source/WebCore/Modules/streams/ReadableStream.js:133 > + if (options != @undefined) {
Aha, this fixes very important issue that I've missed. Seems like before this change, a TypeError was thrown (from `in` operator) for `options` that is `null` instead of using the defaults (step 1 of
https://heycam.github.io/webidl/#es-dictionary
). This does fix it, yet we should rather use @isUndefinedOrNull built-in because `== @undefined` is false-positive for `document.all`. It would be nice to have `options = null` test case if we haven't already.
> Source/WebCore/Modules/streams/ReadableStream.js:134 > + preventAbort = !!options["preventAbort"];
Also, we should throw here `if (!@isObject(options))` per step 1 to avoid lookups on primitives, which are observable. A test would be nice.
> Source/WebCore/Modules/streams/ReadableStream.js:136 > + preventClose = !!options["preventClose"];
Since we are changing these lines, could we please use (semantically equivalent) `options.preventAbort` syntax? Square bracket access is normally used with a variable rather than string literal.
> Source/WebCore/Modules/streams/ReadableStream.js:139 > + if (signal !== @undefined && !(signal instanceof @AbortSignal))
It would be nice to have `{ signal: undefined }` test case if we haven't already.
youenn fablet
Comment 5
2021-08-02 11:27:00 PDT
Created
attachment 434777
[details]
Patch
youenn fablet
Comment 6
2021-08-02 11:33:34 PDT
Created
attachment 434779
[details]
Patch
youenn fablet
Comment 7
2021-08-02 11:43:37 PDT
https://github.com/youennf/wpt/tree/wpt-export-for-webkit-227690
youenn fablet
Comment 8
2021-08-02 23:47:53 PDT
Thanks Alexey, I updated tests accordingly.
> > Source/WebCore/Modules/streams/ReadableStream.js:136 > > + preventClose = !!options["preventClose"]; > > Since we are changing these lines, could we please use (semantically > equivalent) `options.preventAbort` syntax? > Square bracket access is normally used with a variable rather than string > literal.
I kept the way the spec is written and the way it is done for now in other stream related implementation files. I guess it is a tad shorter so there is a small gain to change.
youenn fablet
Comment 9
2021-08-02 23:48:42 PDT
Comment on
attachment 434779
[details]
Patch bot error is unrelated
Alexey Shvayka
Comment 10
2021-08-03 05:41:44 PDT
Comment on
attachment 434779
[details]
Patch View in context:
https://bugs.webkit.org/attachment.cgi?id=434779&action=review
r=me with 2 nits. Thank you for fixing this, Youenn!
> Source/WebCore/ChangeLog:9 > + Make one getter for signal.
Technically, `in` doesn't invoke a getter, only a Proxy trap. Apart from not invoking getters on Object.prototype and tweaking their order, this patch also fixed `options = null` case, added exception for primitive `options`, and fixed exception handling in pipeTo(). It would be nice to mention that in ChangeLog.
> Source/WebCore/Modules/streams/ReadableStream.js:182 > + try {
It's nice to have this fixed. A suggestion: what if we limit try { ... } scope only to rethrow userland errors, while returning rejected Promises for non-object `options` and incorrect `signal`? Like if (!@isObject(options)) return @Promise.@reject(@makeTypeError("options must be an object")); try { preventAbort = !!options["preventAbort"]; preventCancel = !!options["preventCancel"]; preventClose = !!options["preventClose"]; signal = options["signal"]; } catch(e) { return @Promise.@reject(e); } if (signal !== @undefined && !(signal instanceof @AbortSignal)) return @Promise.@reject(@makeTypeError("options.signal must be AbortSignal")); This way it's more clear that we are handling getter errors, and it's consistent with the rest of the checks like if (!@isWritableStream(destination)) etc. `instanceof` can't throw for @AbortSignal (and it will be replaced with @isAbortSignal after this patch is landed).
youenn fablet
Comment 11
2021-08-03 08:12:17 PDT
Created
attachment 434833
[details]
Patch for landing
youenn fablet
Comment 12
2021-08-03 08:15:18 PDT
Submitted web-platform-tests pull request:
https://github.com/web-platform-tests/wpt/pull/29880
youenn fablet
Comment 13
2021-08-03 08:16:14 PDT
Thanks for the review, I updated the change log and reduced the try/catch as you suggested.
EWS
Comment 14
2021-08-03 08:59:34 PDT
Committed
r280593
(
240215@main
): <
https://commits.webkit.org/240215@main
> All reviewed patches have been landed. Closing bug and clearing flags on
attachment 434833
[details]
.
Note
You need to
log in
before you can comment on or make changes to this bug.
Top of Page
Format For Printing
XML
Clone This Bug