Commit 37d4e56a authored by Adam Rice's avatar Adam Rice Committed by Commit Bot

Transferable Streams: Remove exception special handling

Serialising and deserialising exceptions is now supported directly, so
transferable streams do not have to work around the lack of support.
Remove the workarounds.

Change the semantics so that failures to serialise are not hidden by
implicit conversion to undefined. Instead the cancel() or abort() method
will return a rejection, and the stream will be errored.

Update the http/streams/transferable/reason.html web test to reflect the
new semantics.

BUG=894838

Change-Id: I44c5bd968b4544df2706269900ca8461eabfa00c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2257655Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#782976}
parent 121c131b
...@@ -6,23 +6,26 @@ ...@@ -6,23 +6,26 @@
<script> <script>
'use strict'; 'use strict';
// These tests verify the algorithm for passing through error reasons from one // Chrome used to special-case the reason for cancel() and abort() in order to
// realm to another. We only test these for cancel on a ReadableStream, and // handle exceptions correctly. This is no longer necessary. These tests are
// assume that all the other places that should be using the same algorithm are // retained to avoid regressions.
// doing so.
function getTransferredReason(originalReason) { async function getTransferredReason(originalReason) {
return new Promise((resolve, reject) => { let resolvePromise;
createTransferredReadableStream({ const rv = new Promise(resolve => {
cancel(reason) { resolvePromise = resolve;
resolve(reason);
}
}).then(rs => rs.cancel(originalReason))
.catch(reject);
}); });
const rs = await createTransferredReadableStream({
cancel(reason) {
resolvePromise(reason);
}
});
await rs.cancel(originalReason);
return rv;
} }
for (const value of ['hi', '\t\r\n', 7, 3.0, undefined, null, true, false]) { for (const value of ['hi', '\t\r\n', 7, 3.0, undefined, null, true, false,
NaN, Infinity]) {
promise_test(async () => { promise_test(async () => {
const reason = await getTransferredReason(value); const reason = await getTransferredReason(value);
assert_equals(reason, value, 'reason should match'); assert_equals(reason, value, 'reason should match');
...@@ -30,17 +33,12 @@ for (const value of ['hi', '\t\r\n', 7, 3.0, undefined, null, true, false]) { ...@@ -30,17 +33,12 @@ for (const value of ['hi', '\t\r\n', 7, 3.0, undefined, null, true, false]) {
} }
for (const badType of [Symbol('hi'), _ => 'hi']) { for (const badType of [Symbol('hi'), _ => 'hi']) {
promise_test(async () => { promise_test(async t => {
const reason = await getTransferredReason(badType); return promise_rejects_dom(t, 'DataCloneError',
assert_equals(reason, undefined, 'reason should be undefined'); getTransferredReason(badType),
}, `reason with a type of '${typeof badType}' should be squished to undefined`); 'cancel() should reject');
} }, `reason with a type of '${typeof badType}' should be rejected and ` +
`error the stream`);
for (const badNumber of [NaN, Infinity]) {
promise_test(async () => {
const reason = await getTransferredReason(badNumber);
assert_equals(reason, null, 'reason should be null');
}, `number with a value of '${badNumber}' should be squished to null`);
} }
promise_test(async () => { promise_test(async () => {
...@@ -55,8 +53,10 @@ promise_test(async () => { ...@@ -55,8 +53,10 @@ promise_test(async () => {
const circularObject = {}; const circularObject = {};
circularObject.self = circularObject; circularObject.self = circularObject;
const reason = await getTransferredReason(circularObject); const reason = await getTransferredReason(circularObject);
assert_true(reason instanceof TypeError, 'a TypeError should be output'); assert_true(reason instanceof Object, 'an Object should be output');
}, 'objects that cannot be expressed in JSON should result in a TypeError'); assert_equals(reason.self, reason,
'the object should have a circular reference');
}, 'objects that cannot be expressed in JSON should also be preserved');
promise_test(async () => { promise_test(async () => {
const originalReason = new TypeError('hi'); const originalReason = new TypeError('hi');
...@@ -77,10 +77,10 @@ promise_test(async () => { ...@@ -77,10 +77,10 @@ promise_test(async () => {
promise_test(async () => { promise_test(async () => {
const originalReason = new TypeError(); const originalReason = new TypeError();
originalReason.message = {}; originalReason.message = [1, 2, 3];
const reason = await getTransferredReason(originalReason); const reason = await getTransferredReason(originalReason);
assert_equals(reason.message, '', 'message should not be preserved'); assert_equals(reason.message, '1,2,3', 'message should be stringified');
}, 'a TypeError message should not be preserved if it is not a string'); }, 'a TypeError message should be converted to a string');
promise_test(async () => { promise_test(async () => {
const originalReason = new TypeError(); const originalReason = new TypeError();
...@@ -111,17 +111,22 @@ promise_test(async () => { ...@@ -111,17 +111,22 @@ promise_test(async () => {
'the names should match'); 'the names should match');
}, 'DOMException errors should be preserved'); }, 'DOMException errors should be preserved');
promise_test(async () => { for (const errorConstructor of [EvalError, RangeError,
const originalReason = new RangeError('nope'); ReferenceError, SyntaxError, TypeError,
const reason = await getTransferredReason(originalReason); URIError]) {
assert_equals(typeof reason, 'object', 'reason should have type object'); promise_test(async () => {
assert_false(reason instanceof RangeError, const originalReason = new errorConstructor('nope');
'reason should not be a RangeError'); const reason = await getTransferredReason(originalReason);
assert_false(reason instanceof Error, assert_equals(typeof reason, 'object', 'reason should have type object');
'reason should not be an Error'); assert_true(reason instanceof errorConstructor,
assert_equals(reason.constructor, Object, 'reason should be an Object'); `reason should inherit ${errorConstructor.name}`);
assert_array_equals(Object.getOwnPropertyNames(reason), [], assert_true(reason instanceof Error, 'reason should inherit Error');
'reason should have no properties'); assert_equals(reason.constructor, errorConstructor,
}, 'RangeErrors should not be preserved'); 'reason should have the right constructor');
assert_equals(reason.name, errorConstructor.name,
`name should match constructor name`);
assert_equals(reason.message, 'nope', 'message should match');
}, `${errorConstructor.name} should be preserved`);
}
</script> </script>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment