Commit 18def511 authored by Adam Rice's avatar Adam Rice Committed by Commit Bot

Return ScriptPromise from TransformStreamTransformer

Previously the Transform() and Flush() methods of
TransformStreamTransformer returned void. This meant that there was no
way for them to wait for asynchronous work to finish.

Change the function signatures to return ScriptPromise. Transform() or
Flush() won't be called again until the returned promise is settled.

Returning v8::Local<v8::Promise> would have been slightly more
efficient, but ScriptPromise was used for consistency with
UnderlyingSinkBase and UnderlyingSourceBase.

Add tests that Transform() and Flush() promises are actually waited for.

BUG=962837

Change-Id: I2e79c6a79a457fd021eee17eca4f1502c3aa521f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1865735Reviewed-by: default avatarYutaka Hirano <yhirano@chromium.org>
Commit-Queue: Adam Rice <ricea@chromium.org>
Cr-Commit-Position: refs/heads/master@{#709861}
parent 9d5550ff
......@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/streams/transform_stream_native.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/core/execution_context/execution_context.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/streams/miscellaneous_operations.h"
......@@ -66,11 +67,12 @@ class TransformStreamNative::FlushAlgorithm final : public StreamAlgorithm {
ExceptionState exception_state(script_state->GetIsolate(),
ExceptionState::kUnknownContext, "", "");
ControllerInterface controller_interface(script_state, controller_);
ScriptPromise promise;
{
// This is needed because the realm of the transformer can be different
// from the realm of the transform stream.
ScriptState::Scope scope(transformer_->GetScriptState());
transformer_->Flush(&controller_interface, exception_state);
promise = transformer_->Flush(&controller_interface, exception_state);
}
if (exception_state.HadException()) {
auto exception = exception_state.GetException();
......@@ -78,7 +80,7 @@ class TransformStreamNative::FlushAlgorithm final : public StreamAlgorithm {
return PromiseReject(script_state, exception);
}
return PromiseResolveWithUndefined(script_state);
return promise.V8Value().As<v8::Promise>();
}
// SetController() must be called before Run() is.
......@@ -112,11 +114,13 @@ class TransformStreamNative::TransformAlgorithm final : public StreamAlgorithm {
ExceptionState exception_state(script_state->GetIsolate(),
ExceptionState::kUnknownContext, "", "");
ControllerInterface controller_interface(script_state, controller_);
ScriptPromise promise;
{
// This is needed because the realm of the transformer can be different
// from the realm of the transform stream.
ScriptState::Scope scope(transformer_->GetScriptState());
transformer_->Transform(argv[0], &controller_interface, exception_state);
promise = transformer_->Transform(argv[0], &controller_interface,
exception_state);
}
if (exception_state.HadException()) {
auto exception = exception_state.GetException();
......@@ -124,7 +128,7 @@ class TransformStreamNative::TransformAlgorithm final : public StreamAlgorithm {
return PromiseReject(script_state, exception);
}
return PromiseResolveWithUndefined(script_state);
return promise.V8Value().As<v8::Promise>();
}
// SetController() must be called before Run() is.
......
......@@ -14,6 +14,7 @@
namespace blink {
class ExceptionState;
class ScriptPromise;
class ScriptState;
class TransformStreamDefaultControllerInterface;
class Visitor;
......@@ -33,11 +34,11 @@ class CORE_EXPORT TransformStreamTransformer
TransformStreamTransformer() = default;
virtual ~TransformStreamTransformer() = default;
virtual void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
virtual void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
virtual ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
virtual ScriptPromise Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) = 0;
// Returns the ScriptState associated with this Transformer.
virtual ScriptState* GetScriptState() = 0;
......
......@@ -9,6 +9,7 @@
#include <limits>
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_uint8_array.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
......@@ -50,7 +51,7 @@ DeflateTransformer::~DeflateTransformer() {
}
}
void DeflateTransformer::Transform(
ScriptPromise DeflateTransformer::Transform(
v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
......@@ -59,29 +60,33 @@ void DeflateTransformer::Transform(
script_state_->GetIsolate(), chunk, buffer_source,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException()) {
return;
return ScriptPromise();
}
if (buffer_source.IsArrayBufferView()) {
const auto* view = buffer_source.GetAsArrayBufferView().View();
const uint8_t* start = static_cast<const uint8_t*>(view->BaseAddress());
wtf_size_t length = view->byteLength();
Deflate(start, length, IsFinished(false), controller, exception_state);
return;
return ScriptPromise::CastUndefined(script_state_);
}
DCHECK(buffer_source.IsArrayBuffer());
const auto* array_buffer = buffer_source.GetAsArrayBuffer();
const uint8_t* start = static_cast<const uint8_t*>(array_buffer->Data());
wtf_size_t length = array_buffer->ByteLength();
Deflate(start, length, IsFinished(false), controller, exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
void DeflateTransformer::Flush(
ScriptPromise DeflateTransformer::Flush(
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
Deflate(nullptr, 0u, IsFinished(true), controller, exception_state);
was_flush_called_ = true;
deflateEnd(&stream_);
out_buffer_.clear();
return ScriptPromise::CastUndefined(script_state_);
}
void DeflateTransformer::Deflate(
......
......@@ -21,12 +21,12 @@ class DeflateTransformer final : public TransformStreamTransformer {
DeflateTransformer(ScriptState*, Format, int level);
~DeflateTransformer() override;
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptState* GetScriptState() override { return script_state_; }
......
......@@ -5,6 +5,7 @@
#include <limits>
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_uint8_array.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
......@@ -41,7 +42,7 @@ InflateTransformer::~InflateTransformer() {
}
}
void InflateTransformer::Transform(
ScriptPromise InflateTransformer::Transform(
v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
......@@ -51,23 +52,25 @@ void InflateTransformer::Transform(
script_state_->GetIsolate(), chunk, buffer_source,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException()) {
return;
return ScriptPromise();
}
if (buffer_source.IsArrayBufferView()) {
const auto* view = buffer_source.GetAsArrayBufferView().View();
const uint8_t* start = static_cast<const uint8_t*>(view->BaseAddress());
wtf_size_t length = view->byteLength();
Inflate(start, length, IsFinished(false), controller, exception_state);
return;
return ScriptPromise::CastUndefined(script_state_);
}
DCHECK(buffer_source.IsArrayBuffer());
const auto* array_buffer = buffer_source.GetAsArrayBuffer();
const uint8_t* start = static_cast<const uint8_t*>(array_buffer->Data());
wtf_size_t length = array_buffer->ByteLength();
Inflate(start, length, IsFinished(false), controller, exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
void InflateTransformer::Flush(
ScriptPromise InflateTransformer::Flush(
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) {
DCHECK(!was_flush_called_);
......@@ -75,6 +78,8 @@ void InflateTransformer::Flush(
inflateEnd(&stream_);
was_flush_called_ = true;
out_buffer_.clear();
return ScriptPromise::CastUndefined(script_state_);
}
void InflateTransformer::Inflate(
......
......@@ -17,12 +17,12 @@ class InflateTransformer final : public TransformStreamTransformer {
InflateTransformer(ScriptState*, Format format);
~InflateTransformer() override;
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
void Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptPromise Flush(TransformStreamDefaultControllerInterface*,
ExceptionState&) override;
ScriptState* GetScriptState() override { return script_state_; }
......
......@@ -8,6 +8,7 @@
#include <utility>
#include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
......@@ -38,15 +39,15 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
// Implements the type conversion part of the "decode and enqueue a chunk"
// algorithm.
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ArrayBufferOrArrayBufferView bufferSource;
V8ArrayBufferOrArrayBufferView::ToImpl(
script_state_->GetIsolate(), chunk, bufferSource,
UnionTypeConversionMode::kNotNullable, exception_state);
if (exception_state.HadException())
return;
return ScriptPromise();
// This implements the "get a copy of the bytes held by the buffer source"
// algorithm (https://heycam.github.io/webidl/#dfn-get-buffer-source-copy).
......@@ -56,7 +57,7 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
uint32_t length = view->byteLength();
DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush,
controller, exception_state);
return;
return ScriptPromise::CastUndefined(script_state_);
}
DCHECK(bufferSource.IsArrayBuffer());
const auto* array_buffer = bufferSource.GetAsArrayBuffer();
......@@ -64,13 +65,17 @@ class TextDecoderStream::Transformer final : public TransformStreamTransformer {
uint32_t length = array_buffer->ByteLength();
DecodeAndEnqueue(start, length, WTF::FlushBehavior::kDoNotFlush, controller,
exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
// Implements the "encode and flush" algorithm.
void Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
DecodeAndEnqueue(nullptr, 0u, WTF::FlushBehavior::kDataEOF, controller,
exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
ScriptState* GetScriptState() override { return script_state_; }
......
......@@ -12,6 +12,7 @@
#include "base/optional.h"
#include "base/stl_util.h"
#include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_string_resource.h"
#include "third_party/blink/renderer/core/streams/transform_stream_default_controller_interface.h"
#include "third_party/blink/renderer/core/streams/transform_stream_transformer.h"
......@@ -34,15 +35,15 @@ class TextEncoderStream::Transformer final : public TransformStreamTransformer {
// Implements the "encode and enqueue a chunk" algorithm. For efficiency, only
// the characters at the end of chunks are special-cased.
void Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Transform(v8::Local<v8::Value> chunk,
TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
V8StringResource<> input_resource = chunk;
if (!input_resource.Prepare(script_state_->GetIsolate(), exception_state))
return;
return ScriptPromise();
const String input = input_resource;
if (input.IsEmpty())
return;
return ScriptPromise::CastUndefined(script_state_);
const base::Optional<UChar> high_surrogate = pending_high_surrogate_;
pending_high_surrogate_ = base::nullopt;
......@@ -60,19 +61,21 @@ class TextEncoderStream::Transformer final : public TransformStreamTransformer {
bool have_output =
Encode16BitString(input, high_surrogate, &prefix, &result);
if (!have_output)
return;
return ScriptPromise::CastUndefined(script_state_);
}
DOMUint8Array* array =
CreateDOMUint8ArrayFromTwoStdStringsConcatenated(prefix, result);
controller->Enqueue(ToV8(array, script_state_), exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
// Implements the "encode and flush" algorithm.
void Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
ScriptPromise Flush(TransformStreamDefaultControllerInterface* controller,
ExceptionState& exception_state) override {
if (!pending_high_surrogate_.has_value())
return;
return ScriptPromise::CastUndefined(script_state_);
const std::string replacement_character = ReplacementCharacterInUtf8();
const uint8_t* u8buffer =
......@@ -82,6 +85,8 @@ class TextEncoderStream::Transformer final : public TransformStreamTransformer {
replacement_character.length())),
script_state_),
exception_state);
return ScriptPromise::CastUndefined(script_state_);
}
ScriptState* GetScriptState() override { return script_state_; }
......
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