Skip to content

Commit

Permalink
LibWeb: Implement and wire up TransformerStream's cancel callback
Browse files Browse the repository at this point in the history
  • Loading branch information
kennethmyhra committed Jun 7, 2024
1 parent 97b3595 commit be4fff3
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
TransformStream cancelled due to: Test cancellation
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<script src="../include.js"></script>
<script>
function testTransformStreamReadableStreamCancellation() {
const readableStream = new ReadableStream();
const transformStream = new TransformStream({
cancel(reason) {
println(`TransformStream cancelled due to: ${reason}`);
return Promise.resolve();
}
});
const transformedStream = readableStream.pipeThrough(transformStream);

transformedStream.cancel('Test cancellation');
}

test(() => {
testTransformStreamReadableStreamCancellation();
});
</script>
50 changes: 42 additions & 8 deletions Userland/Libraries/LibWeb/Streams/AbstractOperations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4619,7 +4619,7 @@ void initialize_transform_stream(TransformStream& stream, JS::NonnullGCPtr<JS::P
}

// https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller
void set_up_transform_stream_default_controller(TransformStream& stream, TransformStreamDefaultController& controller, JS::NonnullGCPtr<TransformAlgorithm> transform_algorithm, JS::NonnullGCPtr<FlushAlgorithm> flush_algorithm)
void set_up_transform_stream_default_controller(TransformStream& stream, TransformStreamDefaultController& controller, JS::NonnullGCPtr<TransformAlgorithm> transform_algorithm, JS::NonnullGCPtr<FlushAlgorithm> flush_algorithm, JS::NonnullGCPtr<CancelAlgorithm> cancel_algorithm)
{
// 1. Assert: stream implements TransformStream.
// 2. Assert: stream.[[controller]] is undefined.
Expand All @@ -4636,6 +4636,9 @@ void set_up_transform_stream_default_controller(TransformStream& stream, Transfo

// 6. Set controller.[[flushAlgorithm]] to flushAlgorithm.
controller.set_flush_algorithm(flush_algorithm);

// 7. Set controller.[[cancelAlgorithm]] to cancelAlgorithm.
controller.set_cancel_algorithm(cancel_algorithm);
}

// https://streams.spec.whatwg.org/#set-up-transform-stream-default-controller-from-transformer
Expand Down Expand Up @@ -4667,7 +4670,12 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
});

// 4. If transformerDict["transform"] exists, set transformAlgorithm to an algorithm which takes an argument chunk
// 4. Let cancelAlgorithm be an algorithm which returns a promise resolved with undefined.
auto cancel_algorithm = JS::create_heap_function(realm.heap(), [&realm](JS::Value) {
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
});

// 5. If transformerDict["transform"] exists, set transformAlgorithm to an algorithm which takes an argument chunk
// and returns the result of invoking transformerDict["transform"] with argument list « chunk, controller » and
// callback this value transformer.
if (transformer_dict.transform) {
Expand All @@ -4678,7 +4686,7 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream
});
}

// 5. If transformerDict["flush"] exists, set flushAlgorithm to an algorithm which returns the result of invoking
// 6. If transformerDict["flush"] exists, set flushAlgorithm to an algorithm which returns the result of invoking
// transformerDict["flush"] with argument list « controller » and callback this value transformer.
if (transformer_dict.flush) {
flush_algorithm = JS::create_heap_function(realm.heap(), [&realm, transformer, callback = transformer_dict.flush, controller]() {
Expand All @@ -4688,8 +4696,18 @@ void set_up_transform_stream_default_controller_from_transformer(TransformStream
});
}

// 6. Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm).
set_up_transform_stream_default_controller(stream, *controller, transform_algorithm, flush_algorithm);
// 7. If transformerDict["cancel"] exists, set cancelAlgorithm to an algorithm which takes an argument reason and returns
// the result of invoking transformerDict["cancel"] with argument list « reason » and callback this value transformer.
if (transformer_dict.cancel) {
cancel_algorithm = JS::create_heap_function(realm.heap(), [&realm, transformer, callback = transformer_dict.cancel](JS::Value reason) {
// Note: callback returns a promise, so invoke_callback will never return an abrupt completion
auto result = MUST(WebIDL::invoke_callback(*callback, transformer, reason)).release_value();
return WebIDL::create_resolved_promise(realm, result);
});
}

// 8. Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithm, flushAlgorithm).
set_up_transform_stream_default_controller(stream, *controller, transform_algorithm, flush_algorithm, cancel_algorithm);
}

// https://streams.spec.whatwg.org/#transform-stream-default-controller-clear-algorithms
Expand All @@ -4701,6 +4719,9 @@ void transform_stream_default_controller_clear_algorithms(TransformStreamDefault

// 2. Set controller.[[flushAlgorithm]] to undefined.
controller.set_flush_algorithm({});

// 3. Set controller.[[cancelAlgorithm]] to undefined.
controller.set_cancel_algorithm({});
}

// https://streams.spec.whatwg.org/#transform-stream-default-controller-enqueue
Expand Down Expand Up @@ -5025,7 +5046,7 @@ void transform_stream_set_backpressure(TransformStream& stream, bool backpressur
}

// https://streams.spec.whatwg.org/#transformstream-set-up
void transform_stream_set_up(TransformStream& stream, JS::NonnullGCPtr<TransformAlgorithm> transform_algorithm, JS::GCPtr<FlushAlgorithm> flush_algorithm, JS::GCPtr<CancelAlgorithm>)
void transform_stream_set_up(TransformStream& stream, JS::NonnullGCPtr<TransformAlgorithm> transform_algorithm, JS::GCPtr<FlushAlgorithm> flush_algorithm, JS::GCPtr<CancelAlgorithm> cancel_algorithm)
{
auto& realm = stream.realm();

Expand Down Expand Up @@ -5074,7 +5095,20 @@ void transform_stream_set_up(TransformStream& stream, JS::NonnullGCPtr<Transform
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
});

// FIXME 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
// 7. Let cancelAlgorithmWrapper be an algorithm that runs these steps given a value reason:
auto cancel_algorithm_wrapper = JS::create_heap_function(realm.heap(), [&realm, cancel_algorithm](JS::Value reason) -> JS::NonnullGCPtr<WebIDL::Promise> {
// 1. Let result be the result of running cancelAlgorithm given reason, if cancelAlgorithm was given, or null otherwise. If this throws an exception e, return a promise rejected with e.
JS::GCPtr<JS::PromiseCapability> result = nullptr;
if (cancel_algorithm)
result = cancel_algorithm->function()(reason);

// 2. If result is a Promise, then return result.
if (result)
return JS::NonnullGCPtr { *result };

// 3. Return a promise resolved with undefined.
return WebIDL::create_resolved_promise(realm, JS::js_undefined());
});

// 8. Let startPromise be a promise resolved with undefined.
auto start_promise = WebIDL::create_resolved_promise(realm, JS::js_undefined());
Expand All @@ -5086,7 +5120,7 @@ void transform_stream_set_up(TransformStream& stream, JS::NonnullGCPtr<Transform
auto controller = realm.heap().allocate<TransformStreamDefaultController>(realm, realm);

// 11. Perform ! SetUpTransformStreamDefaultController(stream, controller, transformAlgorithmWrapper, flushAlgorithmWrapper, cancelAlgorithmWrapper).
set_up_transform_stream_default_controller(stream, controller, transform_algorithm_wrapper, flush_algorithm_wrapper);
set_up_transform_stream_default_controller(stream, controller, transform_algorithm_wrapper, flush_algorithm_wrapper, cancel_algorithm_wrapper);
}

// https://streams.spec.whatwg.org/#transform-stream-unblock-write
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibWeb/Streams/AbstractOperations.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ void writable_stream_default_controller_process_write(WritableStreamDefaultContr
void writable_stream_default_controller_write(WritableStreamDefaultController&, JS::Value chunk, JS::Value chunk_size);

void initialize_transform_stream(TransformStream&, JS::NonnullGCPtr<JS::PromiseCapability> start_promise, double writable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> writable_size_algorithm, double readable_high_water_mark, JS::NonnullGCPtr<SizeAlgorithm> readable_size_algorithm);
void set_up_transform_stream_default_controller(TransformStream&, TransformStreamDefaultController&, JS::NonnullGCPtr<TransformAlgorithm>, JS::NonnullGCPtr<FlushAlgorithm>);
void set_up_transform_stream_default_controller(TransformStream&, TransformStreamDefaultController&, JS::NonnullGCPtr<TransformAlgorithm>, JS::NonnullGCPtr<FlushAlgorithm>, JS::NonnullGCPtr<CancelAlgorithm>);
void set_up_transform_stream_default_controller_from_transformer(TransformStream&, JS::Value transformer, Transformer&);
void transform_stream_default_controller_clear_algorithms(TransformStreamDefaultController&);
WebIDL::ExceptionOr<void> transform_stream_default_controller_enqueue(TransformStreamDefaultController&, JS::Value chunk);
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/Streams/Transformer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ JS::ThrowCompletionOr<Transformer> Transformer::from_value(JS::VM& vm, JS::Value
.start = TRY(property_to_callback(vm, value, "start", WebIDL::OperationReturnsPromise::No)),
.transform = TRY(property_to_callback(vm, value, "transform", WebIDL::OperationReturnsPromise::Yes)),
.flush = TRY(property_to_callback(vm, value, "flush", WebIDL::OperationReturnsPromise::Yes)),
.cancel = TRY(property_to_callback(vm, value, "cancel", WebIDL::OperationReturnsPromise::Yes)),
.readable_type = {},
.writable_type = {},
};
Expand Down
2 changes: 2 additions & 0 deletions Userland/Libraries/LibWeb/Streams/Transformer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ struct Transformer {
JS::Handle<WebIDL::CallbackType> transform;
// https://streams.spec.whatwg.org/#dom-transformer-flush
JS::Handle<WebIDL::CallbackType> flush;
// https://streams.spec.whatwg.org/#dom-transformer-cancel
JS::Handle<WebIDL::CallbackType> cancel;

// https://streams.spec.whatwg.org/#dom-transformer-readabletype
Optional<JS::Value> readable_type;
Expand Down

0 comments on commit be4fff3

Please sign in to comment.