diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-13 16:23:34 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2019-02-14 10:37:21 +0000 |
commit | 38a9a29f4f9436cace7f0e7abf9c586057df8a4e (patch) | |
tree | c4e8c458dc595bc0ddb435708fa2229edfd00bd4 /chromium/third_party/blink/renderer/core/streams | |
parent | e684a3455bcc29a6e3e66a004e352dea4e1141e7 (diff) | |
download | qtwebengine-chromium-38a9a29f4f9436cace7f0e7abf9c586057df8a4e.tar.gz |
BASELINE: Update Chromium to 73.0.3683.37
Change-Id: I08c9af2948b645f671e5d933aca1f7a90ea372f2
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/streams')
12 files changed, 514 insertions, 347 deletions
diff --git a/chromium/third_party/blink/renderer/core/streams/BUILD.gn b/chromium/third_party/blink/renderer/core/streams/BUILD.gn index 4ddb512fda8..1e82808c34a 100644 --- a/chromium/third_party/blink/renderer/core/streams/BUILD.gn +++ b/chromium/third_party/blink/renderer/core/streams/BUILD.gn @@ -22,5 +22,7 @@ blink_core_sources("streams") { "underlying_source_base.h", "writable_stream.cc", "writable_stream.h", + "writable_stream_wrapper.cc", + "writable_stream_wrapper.h", ] } diff --git a/chromium/third_party/blink/renderer/core/streams/CommonOperations.js b/chromium/third_party/blink/renderer/core/streams/CommonOperations.js index 266850799a4..9423a115435 100644 --- a/chromium/third_party/blink/renderer/core/streams/CommonOperations.js +++ b/chromium/third_party/blink/renderer/core/streams/CommonOperations.js @@ -310,7 +310,7 @@ function isATypeError(object) { // There doesn't appear to be a 100% reliable way to identify a TypeError // from JS. - return getPrototypeOf(object) === TypeError_prototype; + return object !== null && getPrototypeOf(object) === TypeError_prototype; } function isADOMException(object) { @@ -329,6 +329,7 @@ switch (typeof reason) { case 'string': case 'number': + case 'boolean': return {encoder: 'json', string: JSON_stringify(reason)}; case 'object': @@ -477,20 +478,17 @@ const {type, value} = callFunction(binding.MessageEvent_data_get, evt); // assert(type === kChunk || type === kClose || type === kAbort || // type=kError); + if (finished) { + return; + } switch (type) { case kChunk: - if (finished) { - return; - } binding.ReadableStreamDefaultControllerEnqueue(controller, value); resolvePromise(backpressurePromise); backpressurePromise = v8.createPromise(); break; case kClose: - if (finished) { - return; - } finished = true; binding.ReadableStreamDefaultControllerClose(controller); callFunction(binding.MessagePort_close, port); @@ -498,9 +496,6 @@ case kAbort: case kError: - if (finished) { - return; - } finished = true; binding.ReadableStreamDefaultControllerError( controller, unpackReason(value)); diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream.cc index f71fefdabc0..1d4e81ad22e 100644 --- a/chromium/third_party/blink/renderer/core/streams/readable_stream.cc +++ b/chromium/third_party/blink/renderer/core/streams/readable_stream.cc @@ -9,6 +9,7 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h" #include "third_party/blink/renderer/core/streams/readable_stream_operations.h" #include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h" +#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/v8_binding.h" @@ -240,6 +241,7 @@ ScriptValue ReadableStream::pipeThrough(ScriptState* script_state, exception_state); } +// https://streams.spec.whatwg.org/#rs-pipe-through ScriptValue ReadableStream::pipeThrough(ScriptState* script_state, ScriptValue transform_stream, ScriptValue options, @@ -247,57 +249,100 @@ ScriptValue ReadableStream::pipeThrough(ScriptState* script_state, v8::Local<v8::Value> pair_value = transform_stream.V8Value(); v8::Local<v8::Context> context = script_state->GetContext(); - constexpr char kWritableIsUndefined[] = - "Failed to execute 'pipeThrough' on 'ReadableStream': " - "parameter 1's 'writable' property is undefined."; - constexpr char kReadableIsUndefined[] = - "Failed to execute 'pipeThrough' on 'ReadableStream': " - "parameter 1's 'readable' property is undefined."; + constexpr char kWritableIsNotWritableStream[] = + "parameter 1's 'writable' property is not a WritableStream."; + constexpr char kReadableIsNotReadableStream[] = + "parameter 1's 'readable' property is not a ReadableStream."; + constexpr char kWritableIsLocked[] = "parameter 1's 'writable' is locked."; v8::Local<v8::Object> pair; if (!pair_value->ToObject(context).ToLocal(&pair)) { - exception_state.ThrowTypeError(kWritableIsUndefined); + exception_state.ThrowTypeError(kWritableIsNotWritableStream); return ScriptValue(); } - v8::TryCatch block(script_state->GetIsolate()); + v8::Isolate* isolate = script_state->GetIsolate(); v8::Local<v8::Value> writable, readable; - if (!pair->Get(context, V8String(script_state->GetIsolate(), "writable")) - .ToLocal(&writable)) { - exception_state.RethrowV8Exception(block.Exception()); + { + v8::TryCatch block(isolate); + if (!pair->Get(context, V8String(isolate, "writable")).ToLocal(&writable)) { + exception_state.RethrowV8Exception(block.Exception()); + return ScriptValue(); + } + DCHECK(!block.HasCaught()); + + if (!pair->Get(context, V8String(isolate, "readable")).ToLocal(&readable)) { + exception_state.RethrowV8Exception(block.Exception()); + return ScriptValue(); + } + DCHECK(!block.HasCaught()); + } + + // 2. If ! IsWritableStream(_writable_) is *false*, throw a *TypeError* + // exception. + WritableStream* dom_writable = + V8WritableStream::ToImplWithTypeCheck(isolate, writable); + if (!dom_writable) { + exception_state.ThrowTypeError(kWritableIsNotWritableStream); return ScriptValue(); } - DCHECK(!block.HasCaught()); - if (writable->IsUndefined()) { - exception_state.ThrowTypeError(kWritableIsUndefined); + // 3. If ! IsReadableStream(_readable_) is *false*, throw a *TypeError* + // exception. + if (!V8ReadableStream::HasInstance(readable, isolate)) { + exception_state.ThrowTypeError(kReadableIsNotReadableStream); return ScriptValue(); } - if (!pair->Get(context, V8String(script_state->GetIsolate(), "readable")) - .ToLocal(&readable)) { - exception_state.RethrowV8Exception(block.Exception()); + // TODO(ricea): When aborting pipes is supported, implement step 5: + // 5. If _signal_ is not *undefined*, and _signal_ is not an instance of the + // `AbortSignal` interface, throw a *TypeError* exception. + + // 6. If ! IsReadableStreamLocked(*this*) is *true*, throw a *TypeError* + // exception. + if (IsLocked(script_state, exception_state).value_or(false)) { + exception_state.ThrowTypeError("Cannot pipe a locked stream"); + return ScriptValue(); + } + if (exception_state.HadException()) { return ScriptValue(); } - DCHECK(!block.HasCaught()); - if (readable->IsUndefined()) { - exception_state.ThrowTypeError(kReadableIsUndefined); + // 7. If ! IsWritableStreamLocked(_writable_) is *true*, throw a *TypeError* + // exception. + if (dom_writable->IsLocked(script_state, exception_state).value_or(false)) { + exception_state.ThrowTypeError(kWritableIsLocked); return ScriptValue(); } + if (exception_state.HadException()) { + return ScriptValue(); + } + + // This cast is safe because the following code will only be run when the + // native version of WritableStream is not in use. + // TODO(ricea): Add a CHECK() for the feature flag here. + WritableStreamWrapper* writable_wrapper = + static_cast<WritableStreamWrapper*>(dom_writable); + + // 8. Let _promise_ be ! ReadableStreamPipeTo(*this*, _writable_, + // _preventClose_, _preventAbort_, _preventCancel_, + // _signal_). - ScriptPromise promise = - pipeTo(script_state, ScriptValue(script_state, writable), options, - exception_state); - if (!exception_state.HadException()) { - // set promise.[[PromiseIsHandled]] to true. - // We don't have a primitive to do this, so let's attach a catch handler. - // - // ScriptPromise::Then(f, g) is a confusing interface, it is actually - // |promise.then(f).catch(g)|. - promise.Then(v8::Local<v8::Function>(), - NoopFunction::CreateFunction(script_state)); + // TODO(ricea): Maybe change the parameters to + // ReadableStreamOperations::PipeTo to match ReadableStreamPipeTo() in the + // standard? + ScriptPromise promise = ReadableStreamOperations::PipeTo( + script_state, GetInternalStream(script_state), + writable_wrapper->GetInternalStream(script_state), options, + exception_state); + if (exception_state.HadException()) { + return ScriptValue(); } + + // 9. Set _promise_.[[PromiseIsHandled]] to *true*. + promise.MarkAsHandled(); + + // 10. Return _readable_. return ScriptValue(script_state, readable); } @@ -336,9 +381,16 @@ ScriptPromise ReadableStream::pipeTo(ScriptState* script_state, if (exception_state.HadException()) return ScriptPromise(); + // This cast is safe because the following code will only be run when the + // native version of WritableStream is not in use. + // TODO(ricea): Add a CHECK() for the feature flag here. + WritableStreamWrapper* destination_wrapper = + static_cast<WritableStreamWrapper*>(destination); + return ReadableStreamOperations::PipeTo( script_state, GetInternalStream(script_state), - destination->GetInternalStream(script_state), options, exception_state); + destination_wrapper->GetInternalStream(script_state), options, + exception_state); } ScriptValue ReadableStream::tee(ScriptState* script_state, diff --git a/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc b/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc index 8ad8e81b3b4..840c87f185b 100644 --- a/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc +++ b/chromium/third_party/blink/renderer/core/streams/readable_stream_operations_test.cc @@ -34,14 +34,15 @@ class ReadableStreamOperationsTestNotReached : public ScriptFunction { public: static v8::Local<v8::Function> CreateFunction(ScriptState* script_state) { ReadableStreamOperationsTestNotReached* self = - new ReadableStreamOperationsTestNotReached(script_state); + MakeGarbageCollected<ReadableStreamOperationsTestNotReached>( + script_state); return self->BindToV8Function(); } - private: explicit ReadableStreamOperationsTestNotReached(ScriptState* script_state) : ScriptFunction(script_state) {} + private: ScriptValue Call(ScriptValue) override; }; @@ -67,7 +68,8 @@ class Iteration final : public GarbageCollectedFinalized<Iteration> { is_valid_ = false; return; } - value_ = ToCoreString(value->ToString(v.GetScriptState()->GetIsolate())); + value_ = ToCoreString( + value->ToString(v.GetScriptState()->GetContext()).ToLocalChecked()); } bool IsSet() const { return is_set_; } @@ -88,19 +90,20 @@ class ReaderFunction : public ScriptFunction { public: static v8::Local<v8::Function> CreateFunction(ScriptState* script_state, Iteration* iteration) { - ReaderFunction* self = new ReaderFunction(script_state, iteration); + ReaderFunction* self = + MakeGarbageCollected<ReaderFunction>(script_state, iteration); return self->BindToV8Function(); } + ReaderFunction(ScriptState* script_state, Iteration* iteration) + : ScriptFunction(script_state), iteration_(iteration) {} + void Trace(blink::Visitor* visitor) override { visitor->Trace(iteration_); ScriptFunction::Trace(visitor); } private: - ReaderFunction(ScriptState* script_state, Iteration* iteration) - : ScriptFunction(script_state), iteration_(iteration) {} - ScriptValue Call(ScriptValue value) override { iteration_->Set(value); return value; @@ -244,8 +247,8 @@ TEST(ReadableStreamOperationsTest, Read) { scope.GetScriptState(), reader, ASSERT_NO_EXCEPTION) .value_or(false)); - Iteration* it1 = new Iteration(); - Iteration* it2 = new Iteration(); + Iteration* it1 = MakeGarbageCollected<Iteration>(); + Iteration* it2 = MakeGarbageCollected<Iteration>(); ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader) .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1), ReadableStreamOperationsTestNotReached::CreateFunction( @@ -283,7 +286,8 @@ TEST(ReadableStreamOperationsTest, CreateReadableStreamWithCustomUnderlyingSourceAndStrategy) { V8TestingScope scope; TryCatchScope try_catch_scope(scope.GetIsolate()); - auto* underlying_source = new TestUnderlyingSource(scope.GetScriptState()); + auto* underlying_source = + MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState()); ScriptValue strategy = ReadableStreamOperations::CreateCountQueuingStrategy( scope.GetScriptState(), 10); @@ -306,9 +310,9 @@ TEST(ReadableStreamOperationsTest, ASSERT_NO_EXCEPTION); ASSERT_FALSE(reader.IsEmpty()); - Iteration* it1 = new Iteration(); - Iteration* it2 = new Iteration(); - Iteration* it3 = new Iteration(); + Iteration* it1 = MakeGarbageCollected<Iteration>(); + Iteration* it2 = MakeGarbageCollected<Iteration>(); + Iteration* it3 = MakeGarbageCollected<Iteration>(); ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader) .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1), ReadableStreamOperationsTestNotReached::CreateFunction( @@ -350,7 +354,8 @@ TEST(ReadableStreamOperationsTest, UnderlyingSourceShouldHavePendingActivityWhenLockedAndControllerIsActive) { V8TestingScope scope; TryCatchScope try_catch_scope(scope.GetIsolate()); - auto* underlying_source = new TestUnderlyingSource(scope.GetScriptState()); + auto* underlying_source = + MakeGarbageCollected<TestUnderlyingSource>(scope.GetScriptState()); ScriptValue strategy = ReadableStreamOperations::CreateCountQueuingStrategy( scope.GetScriptState(), 10); @@ -545,8 +550,8 @@ TEST(ReadableStreamOperationsTest, Tee) { ASSERT_FALSE(reader1.IsEmpty()); ASSERT_FALSE(reader2.IsEmpty()); - Iteration* it1 = new Iteration(); - Iteration* it2 = new Iteration(); + Iteration* it1 = MakeGarbageCollected<Iteration>(); + Iteration* it2 = MakeGarbageCollected<Iteration>(); ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader1) .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it1), ReadableStreamOperationsTestNotReached::CreateFunction( @@ -600,7 +605,7 @@ TEST(ReadableStreamOperationsTest, Serialize) { ScriptValue reader = ReadableStreamOperations::GetReader( scope.GetScriptState(), transferred, ASSERT_NO_EXCEPTION); ASSERT_FALSE(reader.IsEmpty()); - Iteration* it = new Iteration(); + Iteration* it = MakeGarbageCollected<Iteration>(); ReadableStreamOperations::DefaultReaderRead(scope.GetScriptState(), reader) .Then(ReaderFunction::CreateFunction(scope.GetScriptState(), it), ReadableStreamOperationsTestNotReached::CreateFunction( diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream.cc b/chromium/third_party/blink/renderer/core/streams/transform_stream.cc index 066821136b1..77f74ea721d 100644 --- a/chromium/third_party/blink/renderer/core/streams/transform_stream.cc +++ b/chromium/third_party/blink/renderer/core/streams/transform_stream.cc @@ -12,7 +12,7 @@ #include "third_party/blink/renderer/core/streams/readable_stream.h" #include "third_party/blink/renderer/core/streams/transform_stream_default_controller.h" #include "third_party/blink/renderer/core/streams/transform_stream_transformer.h" -#include "third_party/blink/renderer/core/streams/writable_stream.h" +#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/script_state.h" #include "third_party/blink/renderer/platform/bindings/v8_binding.h" @@ -30,16 +30,11 @@ class TransformStream::Algorithm : public ScriptFunction { static v8::Local<v8::Function> Create(TransformStreamTransformer* transformer, ScriptState* script_state, ExceptionState& exception_state) { - auto* algorithm = new T(transformer, script_state, exception_state); + auto* algorithm = + MakeGarbageCollected<T>(transformer, script_state, exception_state); return algorithm->BindToV8Function(); } - void Trace(Visitor* visitor) override { - visitor->Trace(transformer_); - ScriptFunction::Trace(visitor); - } - - protected: Algorithm(TransformStreamTransformer* transformer, ScriptState* script_state, ExceptionState& exception_state) @@ -48,6 +43,12 @@ class TransformStream::Algorithm : public ScriptFunction { interface_name_(exception_state.InterfaceName()), property_name_(exception_state.PropertyName()) {} + void Trace(Visitor* visitor) override { + visitor->Trace(transformer_); + ScriptFunction::Trace(visitor); + } + + protected: // AlgorithmScope holds the stack-allocated objects used by the CallRaw() // methods for FlushAlgorithm and TransformAlgorithm. class AlgorithmScope { @@ -122,6 +123,9 @@ class TransformStream::TransformAlgorithm : public TransformStream::Algorithm { }; TransformStream::TransformStream() = default; +TransformStream::TransformStream(ReadableStream* readable, + WritableStream* writable) + : readable_(readable), writable_(writable) {} TransformStream::~TransformStream() = default; @@ -174,8 +178,10 @@ TransformStream* TransformStream::Create(ScriptState* script_state, } } DCHECK(stream->IsObject()); - ts->InitInternal(script_state, stream.As<v8::Object>(), exception_state); - return ts->stream_.IsEmpty() ? nullptr : ts; + if (!ts->InitInternal(script_state, stream.As<v8::Object>(), exception_state)) + return nullptr; + + return ts; } void TransformStream::Init(TransformStreamTransformer* transformer, @@ -202,13 +208,12 @@ void TransformStream::Init(TransformStreamTransformer* transformer, } void TransformStream::Trace(Visitor* visitor) { - visitor->Trace(stream_); visitor->Trace(readable_); visitor->Trace(writable_); ScriptWrappable::Trace(visitor); } -void TransformStream::InitInternal(ScriptState* script_state, +bool TransformStream::InitInternal(ScriptState* script_state, v8::Local<v8::Object> stream, ExceptionState& exception_state) { v8::Local<v8::Value> readable, writable; @@ -218,13 +223,13 @@ void TransformStream::InitInternal(ScriptState* script_state, args) .ToLocal(&readable)) { exception_state.RethrowV8Exception(block.Exception()); - return; + return false; } if (!V8ScriptRunner::CallExtra(script_state, "getTransformStreamWritable", args) .ToLocal(&writable)) { exception_state.RethrowV8Exception(block.Exception()); - return; + return false; } DCHECK(readable->IsObject()); @@ -232,16 +237,16 @@ void TransformStream::InitInternal(ScriptState* script_state, script_state, readable.As<v8::Object>(), exception_state); if (!readable_) - return; + return false; DCHECK(writable->IsObject()); - writable_ = WritableStream::CreateFromInternalStream( + writable_ = WritableStreamWrapper::CreateFromInternalStream( script_state, writable.As<v8::Object>(), exception_state); if (!writable_) - return; + return false; - stream_.Set(script_state->GetIsolate(), stream); + return true; } } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream.h b/chromium/third_party/blink/renderer/core/streams/transform_stream.h index 45149039855..602a383c707 100644 --- a/chromium/third_party/blink/renderer/core/streams/transform_stream.h +++ b/chromium/third_party/blink/renderer/core/streams/transform_stream.h @@ -29,7 +29,8 @@ class WritableStream; // defined in C++. Provides access to the readable and writable streams. // // On-heap references to this class must always be via a TraceWrapperMember, and -// must always have an ancestor in the V8 heap, or |stream_| will be lost. +// must always have an ancestor in the V8 heap, or the internal JavaScript +// objects owned by |readable_| and |writable_| will be lost. // // To ensure that the JS TransformStream is always referenced, this class uses // two-stage construction. After calling the constructor, store the reference @@ -40,6 +41,11 @@ class CORE_EXPORT TransformStream final : public ScriptWrappable { public: TransformStream(); + + // This constructor produces a TransformStream from an existing {readable, + // writable} pair. It cannot fail and does not require calling Init(). + TransformStream(ReadableStream*, WritableStream*); + ~TransformStream() override; // |Create| functions internally call Init(). @@ -76,11 +82,10 @@ class CORE_EXPORT TransformStream final : public ScriptWrappable { class FlushAlgorithm; class TransformAlgorithm; - void InitInternal(ScriptState*, + bool InitInternal(ScriptState*, v8::Local<v8::Object> stream, ExceptionState&); - TraceWrapperV8Reference<v8::Value> stream_; TraceWrapperMember<ReadableStream> readable_; TraceWrapperMember<WritableStream> writable_; diff --git a/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc b/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc index 26d78b97e3b..abeaa2f815b 100644 --- a/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc +++ b/chromium/third_party/blink/renderer/core/streams/transform_stream_test.cc @@ -45,7 +45,7 @@ class TransformStreamTest : public ::testing::Test { void Init(TransformStreamTransformer* transformer, ScriptState* script_state, ExceptionState& exception_state) { - holder_ = new Holder(script_state); + holder_ = MakeGarbageCollected<Holder>(script_state); holder_->Stream()->Init(transformer, script_state, exception_state); } @@ -135,13 +135,15 @@ class MockTransformStreamTransformer : public TransformStreamTransformer { // If this doesn't work then nothing else will. TEST_F(TransformStreamTest, Construct) { V8TestingScope scope; - Init(new IdentityTransformer(), scope.GetScriptState(), ASSERT_NO_EXCEPTION); + Init(MakeGarbageCollected<IdentityTransformer>(), scope.GetScriptState(), + ASSERT_NO_EXCEPTION); EXPECT_TRUE(Stream()); } TEST_F(TransformStreamTest, Accessors) { V8TestingScope scope; - Init(new IdentityTransformer(), scope.GetScriptState(), ASSERT_NO_EXCEPTION); + Init(MakeGarbageCollected<IdentityTransformer>(), scope.GetScriptState(), + ASSERT_NO_EXCEPTION); ReadableStream* readable = Stream()->Readable(); WritableStream* writable = Stream()->Writable(); EXPECT_TRUE(readable); @@ -150,7 +152,7 @@ TEST_F(TransformStreamTest, Accessors) { TEST_F(TransformStreamTest, TransformIsCalled) { V8TestingScope scope; - auto* mock = new ::testing::StrictMock<MockTransformStreamTransformer>(); + auto* mock = MakeGarbageCollected<MockTransformStreamTransformer>(); Init(mock, scope.GetScriptState(), ASSERT_NO_EXCEPTION); // Need to run microtasks so the startAlgorithm promise resolves. v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate()); @@ -170,7 +172,7 @@ TEST_F(TransformStreamTest, TransformIsCalled) { TEST_F(TransformStreamTest, FlushIsCalled) { V8TestingScope scope; - auto* mock = new ::testing::StrictMock<MockTransformStreamTransformer>(); + auto* mock = MakeGarbageCollected<MockTransformStreamTransformer>(); Init(mock, scope.GetScriptState(), ASSERT_NO_EXCEPTION); // Need to run microtasks so the startAlgorithm promise resolves. v8::MicrotasksScope::PerformCheckpoint(scope.GetIsolate()); @@ -189,14 +191,14 @@ TEST_F(TransformStreamTest, FlushIsCalled) { class ExpectNotReached : public ScriptFunction { public: static v8::Local<v8::Function> Create(ScriptState* script_state) { - auto* self = new ExpectNotReached(script_state); + auto* self = MakeGarbageCollected<ExpectNotReached>(script_state); return self->BindToV8Function(); } - private: explicit ExpectNotReached(ScriptState* script_state) : ScriptFunction(script_state) {} + private: ScriptValue Call(ScriptValue) override { ADD_FAILURE() << "ExpectNotReached was reached"; return ScriptValue(); @@ -210,16 +212,17 @@ class ExpectChunkIsString : public ScriptFunction { static v8::Local<v8::Function> Create(ScriptState* script_state, const String& expected, bool* called) { - auto* self = new ExpectChunkIsString(script_state, expected, called); + auto* self = MakeGarbageCollected<ExpectChunkIsString>(script_state, + expected, called); return self->BindToV8Function(); } - private: ExpectChunkIsString(ScriptState* script_state, const String& expected, bool* called) : ScriptFunction(script_state), expected_(expected), called_(called) {} + private: ScriptValue Call(ScriptValue value) override { *called_ = true; if (!value.IsObject()) { @@ -248,16 +251,17 @@ class ExpectTypeError : public ScriptFunction { static v8::Local<v8::Function> Create(ScriptState* script_state, const String& message, bool* called) { - auto* self = new ExpectTypeError(script_state, message, called); + auto* self = + MakeGarbageCollected<ExpectTypeError>(script_state, message, called); return self->BindToV8Function(); } - private: ExpectTypeError(ScriptState* script_state, const String& message, bool* called) : ScriptFunction(script_state), message_(message), called_(called) {} + private: ScriptValue Call(ScriptValue value) override { *called_ = true; EXPECT_TRUE(IsTypeError(GetScriptState(), value, message_)); @@ -298,7 +302,8 @@ class ExpectTypeError : public ScriptFunction { TEST_F(TransformStreamTest, EnqueueFromTransform) { V8TestingScope scope; auto* script_state = scope.GetScriptState(); - Init(new IdentityTransformer(), script_state, ASSERT_NO_EXCEPTION); + Init(MakeGarbageCollected<IdentityTransformer>(), script_state, + ASSERT_NO_EXCEPTION); CopyReadableAndWritableToGlobal(scope); @@ -337,8 +342,8 @@ TEST_F(TransformStreamTest, EnqueueFromFlush) { }; V8TestingScope scope; auto* script_state = scope.GetScriptState(); - Init(new EnqueueFromFlushTransformer(scope.GetContext()->Global(), - scope.GetIsolate()), + Init(MakeGarbageCollected<EnqueueFromFlushTransformer>( + scope.GetContext()->Global(), scope.GetIsolate()), script_state, ASSERT_NO_EXCEPTION); CopyReadableAndWritableToGlobal(scope); @@ -370,7 +375,8 @@ TEST_F(TransformStreamTest, ThrowFromTransform) { }; V8TestingScope scope; auto* script_state = scope.GetScriptState(); - Init(new ThrowFromTransformTransformer(), script_state, ASSERT_NO_EXCEPTION); + Init(MakeGarbageCollected<ThrowFromTransformTransformer>(), script_state, + ASSERT_NO_EXCEPTION); CopyReadableAndWritableToGlobal(scope); @@ -410,7 +416,8 @@ TEST_F(TransformStreamTest, ThrowFromFlush) { }; V8TestingScope scope; auto* script_state = scope.GetScriptState(); - Init(new ThrowFromFlushTransformer(), script_state, ASSERT_NO_EXCEPTION); + Init(MakeGarbageCollected<ThrowFromFlushTransformer>(), script_state, + ASSERT_NO_EXCEPTION); CopyReadableAndWritableToGlobal(scope); @@ -436,5 +443,16 @@ TEST_F(TransformStreamTest, ThrowFromFlush) { EXPECT_TRUE(writableTypeErrorThrown); } +TEST_F(TransformStreamTest, CreateFromReadableWritablePair) { + V8TestingScope scope; + ReadableStream* readable = + ReadableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION); + WritableStream* writable = + WritableStream::Create(scope.GetScriptState(), ASSERT_NO_EXCEPTION); + TransformStream transform(readable, writable); + EXPECT_EQ(readable, transform.Readable()); + EXPECT_EQ(writable, transform.Writable()); +} + } // namespace } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl b/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl index 8e61f0aac31..d943658bcc2 100644 --- a/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl +++ b/chromium/third_party/blink/renderer/core/streams/underlying_source_base.idl @@ -14,7 +14,7 @@ interface UnderlyingSourceBase { [CallWith=ScriptState, ImplementedAs=startWrapper] Promise<void> start(any stream); [CallWith=ScriptState] Promise<void> pull(); - [CallWith=ScriptState, ImplementedAs=cancelWrapper] Promise<void> cancel([Default=Undefined] optional any reason); + [CallWith=ScriptState, ImplementedAs=cancelWrapper] Promise<void> cancel([DefaultValue=Undefined] optional any reason); // This only exists to prevent Object.prototype.type being accessed. [CallWith=ScriptState] readonly attribute any type; diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream.cc index 26ea2b2dd08..292fda8738c 100644 --- a/chromium/third_party/blink/renderer/core/streams/writable_stream.cc +++ b/chromium/third_party/blink/renderer/core/streams/writable_stream.cc @@ -8,32 +8,13 @@ #include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h" #include "third_party/blink/renderer/core/messaging/message_port.h" #include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h" +#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h" #include "third_party/blink/renderer/platform/bindings/exception_state.h" #include "third_party/blink/renderer/platform/bindings/v8_binding.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" namespace blink { -void WritableStream::Init(ScriptState* script_state, - ScriptValue underlying_sink, - ScriptValue strategy, - ExceptionState& exception_state) { - v8::Local<v8::Object> internal_stream; - v8::TryCatch block(script_state->GetIsolate()); - - if (!CreateInternalStream(script_state, underlying_sink.V8Value(), - strategy.V8Value()) - .ToLocal(&internal_stream)) { - exception_state.RethrowV8Exception(block.Exception()); - return; - } - - if (!InitInternal(script_state, internal_stream)) { - exception_state.RethrowV8Exception(block.Exception()); - return; - } -} - WritableStream* WritableStream::Create(ScriptState* script_state, ExceptionState& exception_state) { return Create( @@ -56,7 +37,8 @@ WritableStream* WritableStream::Create(ScriptState* script_state, ScriptValue underlying_sink, ScriptValue strategy, ExceptionState& exception_state) { - auto* stream = MakeGarbageCollected<WritableStream>(); + // TODO(ricea): Switch on Blink feature. + auto* stream = MakeGarbageCollected<WritableStreamWrapper>(); stream->Init(script_state, underlying_sink, strategy, exception_state); if (exception_state.HadException()) return nullptr; @@ -64,193 +46,13 @@ WritableStream* WritableStream::Create(ScriptState* script_state, return stream; } -WritableStream* WritableStream::CreateFromInternalStream( - ScriptState* script_state, - v8::Local<v8::Object> internal_stream, - ExceptionState& exception_state) { - v8::TryCatch block(script_state->GetIsolate()); - auto* stream = MakeGarbageCollected<WritableStream>(); - if (!stream->InitInternal(script_state, internal_stream)) { - exception_state.RethrowV8Exception(block.Exception()); - return nullptr; - } - return stream; -} - -bool WritableStream::InitInternal(ScriptState* script_state, - v8::Local<v8::Object> internal_stream) { - v8::Isolate* isolate = script_state->GetIsolate(); - -#if DCHECK_IS_ON() - v8::Local<v8::Value> args[] = {internal_stream}; - v8::Local<v8::Value> result_value; - - if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStream", args) - .ToLocal(&result_value)) { - DLOG(FATAL) << "Failing to call IsWritableStream for DCHECK."; - return false; - } - DCHECK(result_value->BooleanValue(isolate)); -#endif // DCHECK_IS_ON() - - internal_stream_.Set(isolate, internal_stream); - - v8::Local<v8::Value> wrapper = ToV8(this, script_state); - if (wrapper.IsEmpty()) - return false; - - v8::Local<v8::Context> context = script_state->GetContext(); - v8::Local<v8::Object> bindings = - context->GetExtrasBindingObject().As<v8::Object>(); - v8::Local<v8::Value> symbol_value; - if (!bindings->Get(context, V8String(isolate, "internalWritableStreamSymbol")) - .ToLocal(&symbol_value)) { - return false; - } - - if (wrapper.As<v8::Object>() - ->Set(context, symbol_value.As<v8::Symbol>(), - internal_stream_.NewLocal(isolate)) - .IsNothing()) { - return false; - } - - return RetainWrapperDuringConstruction(this, script_state); -} - -v8::MaybeLocal<v8::Object> WritableStream::CreateInternalStream( - ScriptState* script_state, - v8::Local<v8::Value> underlying_sink, - v8::Local<v8::Value> strategy) { - v8::Local<v8::Value> args[] = {underlying_sink, strategy}; - v8::Local<v8::Value> stream; - - if (!V8ScriptRunner::CallExtra(script_state, "createWritableStream", args) - .ToLocal(&stream)) { - return v8::MaybeLocal<v8::Object>(); - } - - DCHECK(stream->IsObject()); - return v8::MaybeLocal<v8::Object>(stream.As<v8::Object>()); -} - -void WritableStream::Trace(Visitor* visitor) { - visitor->Trace(internal_stream_); - ScriptWrappable::Trace(visitor); -} - -bool WritableStream::locked(ScriptState* script_state, - ExceptionState& exception_state) const { - auto result = IsLocked(script_state, exception_state); - - return !result || *result; -} - -ScriptPromise WritableStream::abort(ScriptState* script_state, - ExceptionState& exception_state) { - return abort( - script_state, - ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())), - exception_state); -} - -ScriptPromise WritableStream::abort(ScriptState* script_state, - ScriptValue reason, - ExceptionState& exception_state) { - if (locked(script_state, exception_state) && - !exception_state.HadException()) { - exception_state.ThrowTypeError("Cannot abort a locked stream"); - } - - v8::Local<v8::Value> args[] = { - internal_stream_.NewLocal(script_state->GetIsolate()), reason.V8Value()}; - v8::TryCatch block(script_state->GetIsolate()); - v8::Local<v8::Value> result; - - if (!V8ScriptRunner::CallExtra(script_state, "WritableStreamAbort", args) - .ToLocal(&result)) { - exception_state.RethrowV8Exception(block.Exception()); - return ScriptPromise(); - } - return ScriptPromise(script_state, result); -} - -ScriptValue WritableStream::getWriter(ScriptState* script_state, - ExceptionState& exception_state) { - v8::TryCatch block(script_state->GetIsolate()); - v8::Local<v8::Value> args[] = { - internal_stream_.NewLocal(script_state->GetIsolate())}; - v8::Local<v8::Value> result; - - if (!V8ScriptRunner::CallExtra(script_state, - "AcquireWritableStreamDefaultWriter", args) - .ToLocal(&result)) { - exception_state.RethrowV8Exception(block.Exception()); - return ScriptValue(); - } - return ScriptValue(script_state, result); -} - -base::Optional<bool> WritableStream::IsLocked( - ScriptState* script_state, - ExceptionState& exception_state) const { - v8::TryCatch block(script_state->GetIsolate()); - v8::Local<v8::Value> args[] = { - internal_stream_.NewLocal(script_state->GetIsolate())}; - v8::Local<v8::Value> result_value; - - if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStreamLocked", args) - .ToLocal(&result_value)) { - exception_state.RethrowV8Exception(block.Exception()); - return base::nullopt; - } - return result_value->BooleanValue(script_state->GetIsolate()); -} - -void WritableStream::Serialize(ScriptState* script_state, - MessagePort* port, - ExceptionState& exception_state) { - DCHECK(port); - DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled()); - v8::TryCatch block(script_state->GetIsolate()); - v8::Local<v8::Value> port_v8_value = ToV8(port, script_state); - DCHECK(!port_v8_value.IsEmpty()); - v8::Local<v8::Value> args[] = {ToV8(this, script_state), port_v8_value}; - V8ScriptRunner::CallExtra(script_state, "WritableStreamSerialize", args); - if (block.HasCaught()) { - exception_state.RethrowV8Exception(block.Exception()); - } -} - // static WritableStream* WritableStream::Deserialize(ScriptState* script_state, MessagePort* port, ExceptionState& exception_state) { - // We need to execute V8 Extras JavaScript to create the new WritableStream. - // We will not run author code. - auto* isolate = script_state->GetIsolate(); - v8::Isolate::AllowJavascriptExecutionScope allow_js(isolate); - DCHECK(port); - DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled()); - v8::TryCatch block(isolate); - v8::Local<v8::Value> port_v8 = ToV8(port, script_state); - DCHECK(!port_v8.IsEmpty()); - v8::Local<v8::Value> args[] = {port_v8}; - ScriptValue internal_stream( - script_state, V8ScriptRunner::CallExtra( - script_state, "WritableStreamDeserialize", args)); - if (block.HasCaught()) { - exception_state.RethrowV8Exception(block.Exception()); - return nullptr; - } - DCHECK(!internal_stream.IsEmpty()); - return CreateFromInternalStream(script_state, internal_stream, - exception_state); -} - -ScriptValue WritableStream::GetInternalStream(ScriptState* script_state) const { - return ScriptValue(script_state, - internal_stream_.NewLocal(script_state->GetIsolate())); + // TODO(ricea): Switch on Blink feature. + return WritableStreamWrapper::Deserialize(script_state, port, + exception_state); } } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream.h b/chromium/third_party/blink/renderer/core/streams/writable_stream.h index c2326c72673..0520505622b 100644 --- a/chromium/third_party/blink/renderer/core/streams/writable_stream.h +++ b/chromium/third_party/blink/renderer/core/streams/writable_stream.h @@ -22,19 +22,8 @@ class CORE_EXPORT WritableStream : public ScriptWrappable { DEFINE_WRAPPERTYPEINFO(); public: - // Call one of Init functions before using the instance. - WritableStream() = default; - ~WritableStream() override = default; - - // If an error happens, |exception_state.HadException()| will be true, and - // |this| will not be usable after that. - void Init(ScriptState*, - ScriptValue underlying_sink, - ScriptValue strategy, - ExceptionState& exception_state); - - // Create* functions call Init* internally and return null when an error - // happens. + // Create function selects an implementation of WritableStream to use at + // runtime. static WritableStream* Create(ScriptState*, ExceptionState&); static WritableStream* Create(ScriptState*, ScriptValue underlying_sink, @@ -43,33 +32,21 @@ class CORE_EXPORT WritableStream : public ScriptWrappable { ScriptValue underlying_sink, ScriptValue strategy, ExceptionState&); - static WritableStream* CreateFromInternalStream( - ScriptState* script_state, - ScriptValue internal_stream, - ExceptionState& exception_state) { - DCHECK(internal_stream.IsObject()); - return CreateFromInternalStream(script_state, - internal_stream.V8Value().As<v8::Object>(), - exception_state); - } - static WritableStream* CreateFromInternalStream( - ScriptState*, - v8::Local<v8::Object> internal_stream, - ExceptionState&); - - void Trace(Visitor* visitor) override; // IDL defined functions - bool locked(ScriptState*, ExceptionState&) const; - ScriptPromise abort(ScriptState*, ExceptionState&); - ScriptPromise abort(ScriptState*, ScriptValue reason, ExceptionState&); - ScriptValue getWriter(ScriptState*, ExceptionState&); + virtual bool locked(ScriptState*, ExceptionState&) const = 0; + virtual ScriptPromise abort(ScriptState*, ExceptionState&) = 0; + virtual ScriptPromise abort(ScriptState*, + ScriptValue reason, + ExceptionState&) = 0; + virtual ScriptValue getWriter(ScriptState*, ExceptionState&) = 0; - base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const; + virtual base::Optional<bool> IsLocked(ScriptState*, + ExceptionState&) const = 0; // Serialize this stream to |port|. The stream will be locked by this // operation. - void Serialize(ScriptState*, MessagePort* port, ExceptionState&); + virtual void Serialize(ScriptState*, MessagePort* port, ExceptionState&) = 0; // Given a |port| which is entangled with a MessagePort that was previously // passed to Serialize(), returns a new WritableStream which behaves like it @@ -77,18 +54,6 @@ class CORE_EXPORT WritableStream : public ScriptWrappable { static WritableStream* Deserialize(ScriptState*, MessagePort* port, ExceptionState&); - - ScriptValue GetInternalStream(ScriptState*) const; - - private: - bool InitInternal(ScriptState*, v8::Local<v8::Object> internal_stream); - - static v8::MaybeLocal<v8::Object> CreateInternalStream( - ScriptState* script_state, - v8::Local<v8::Value> underlying_sink, - v8::Local<v8::Value> strategy); - - TraceWrapperV8Reference<v8::Object> internal_stream_; }; } // namespace blink diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc new file mode 100644 index 00000000000..e8c7bd1d3d2 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.cc @@ -0,0 +1,230 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "third_party/blink/renderer/core/streams/writable_stream_wrapper.h" + +#include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h" +#include "third_party/blink/renderer/bindings/core/v8/v8_writable_stream.h" +#include "third_party/blink/renderer/core/messaging/message_port.h" +#include "third_party/blink/renderer/core/streams/retain_wrapper_during_construction.h" +#include "third_party/blink/renderer/platform/bindings/exception_state.h" +#include "third_party/blink/renderer/platform/bindings/v8_binding.h" +#include "third_party/blink/renderer/platform/runtime_enabled_features.h" + +namespace blink { + +void WritableStreamWrapper::Init(ScriptState* script_state, + ScriptValue underlying_sink, + ScriptValue strategy, + ExceptionState& exception_state) { + v8::Local<v8::Object> internal_stream; + v8::TryCatch block(script_state->GetIsolate()); + + if (!CreateInternalStream(script_state, underlying_sink.V8Value(), + strategy.V8Value()) + .ToLocal(&internal_stream)) { + exception_state.RethrowV8Exception(block.Exception()); + return; + } + + if (!InitInternal(script_state, internal_stream)) { + exception_state.RethrowV8Exception(block.Exception()); + return; + } +} + +WritableStreamWrapper* WritableStreamWrapper::CreateFromInternalStream( + ScriptState* script_state, + v8::Local<v8::Object> internal_stream, + ExceptionState& exception_state) { + v8::TryCatch block(script_state->GetIsolate()); + auto* stream = MakeGarbageCollected<WritableStreamWrapper>(); + if (!stream->InitInternal(script_state, internal_stream)) { + exception_state.RethrowV8Exception(block.Exception()); + return nullptr; + } + return stream; +} + +bool WritableStreamWrapper::InitInternal( + ScriptState* script_state, + v8::Local<v8::Object> internal_stream) { + v8::Isolate* isolate = script_state->GetIsolate(); + +#if DCHECK_IS_ON() + v8::Local<v8::Value> args[] = {internal_stream}; + v8::Local<v8::Value> result_value; + + if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStream", args) + .ToLocal(&result_value)) { + DLOG(FATAL) << "Failing to call IsWritableStream for DCHECK."; + return false; + } + DCHECK(result_value->BooleanValue(isolate)); +#endif // DCHECK_IS_ON() + + internal_stream_.Set(isolate, internal_stream); + + v8::Local<v8::Value> wrapper = ToV8(this, script_state); + if (wrapper.IsEmpty()) + return false; + + v8::Local<v8::Context> context = script_state->GetContext(); + v8::Local<v8::Object> bindings = + context->GetExtrasBindingObject().As<v8::Object>(); + v8::Local<v8::Value> symbol_value; + if (!bindings->Get(context, V8String(isolate, "internalWritableStreamSymbol")) + .ToLocal(&symbol_value)) { + return false; + } + + if (wrapper.As<v8::Object>() + ->Set(context, symbol_value.As<v8::Symbol>(), + internal_stream_.NewLocal(isolate)) + .IsNothing()) { + return false; + } + + return RetainWrapperDuringConstruction(this, script_state); +} + +v8::MaybeLocal<v8::Object> WritableStreamWrapper::CreateInternalStream( + ScriptState* script_state, + v8::Local<v8::Value> underlying_sink, + v8::Local<v8::Value> strategy) { + v8::Local<v8::Value> args[] = {underlying_sink, strategy}; + v8::Local<v8::Value> stream; + + if (!V8ScriptRunner::CallExtra(script_state, "createWritableStream", args) + .ToLocal(&stream)) { + return v8::MaybeLocal<v8::Object>(); + } + + DCHECK(stream->IsObject()); + return v8::MaybeLocal<v8::Object>(stream.As<v8::Object>()); +} + +void WritableStreamWrapper::Trace(Visitor* visitor) { + visitor->Trace(internal_stream_); + ScriptWrappable::Trace(visitor); +} + +bool WritableStreamWrapper::locked(ScriptState* script_state, + ExceptionState& exception_state) const { + auto result = IsLocked(script_state, exception_state); + + return !result || *result; +} + +ScriptPromise WritableStreamWrapper::abort(ScriptState* script_state, + ExceptionState& exception_state) { + return abort( + script_state, + ScriptValue(script_state, v8::Undefined(script_state->GetIsolate())), + exception_state); +} + +ScriptPromise WritableStreamWrapper::abort(ScriptState* script_state, + ScriptValue reason, + ExceptionState& exception_state) { + if (locked(script_state, exception_state) && + !exception_state.HadException()) { + exception_state.ThrowTypeError("Cannot abort a locked stream"); + } + + v8::Local<v8::Value> args[] = { + internal_stream_.NewLocal(script_state->GetIsolate()), reason.V8Value()}; + v8::TryCatch block(script_state->GetIsolate()); + v8::Local<v8::Value> result; + + if (!V8ScriptRunner::CallExtra(script_state, "WritableStreamAbort", args) + .ToLocal(&result)) { + exception_state.RethrowV8Exception(block.Exception()); + return ScriptPromise(); + } + return ScriptPromise(script_state, result); +} + +ScriptValue WritableStreamWrapper::getWriter(ScriptState* script_state, + ExceptionState& exception_state) { + v8::TryCatch block(script_state->GetIsolate()); + v8::Local<v8::Value> args[] = { + internal_stream_.NewLocal(script_state->GetIsolate())}; + v8::Local<v8::Value> result; + + if (!V8ScriptRunner::CallExtra(script_state, + "AcquireWritableStreamDefaultWriter", args) + .ToLocal(&result)) { + exception_state.RethrowV8Exception(block.Exception()); + return ScriptValue(); + } + return ScriptValue(script_state, result); +} + +base::Optional<bool> WritableStreamWrapper::IsLocked( + ScriptState* script_state, + ExceptionState& exception_state) const { + v8::TryCatch block(script_state->GetIsolate()); + v8::Local<v8::Value> args[] = { + internal_stream_.NewLocal(script_state->GetIsolate())}; + v8::Local<v8::Value> result_value; + + if (!V8ScriptRunner::CallExtra(script_state, "IsWritableStreamLocked", args) + .ToLocal(&result_value)) { + exception_state.RethrowV8Exception(block.Exception()); + return base::nullopt; + } + return result_value->BooleanValue(script_state->GetIsolate()); +} + +void WritableStreamWrapper::Serialize(ScriptState* script_state, + MessagePort* port, + ExceptionState& exception_state) { + DCHECK(port); + DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled()); + v8::TryCatch block(script_state->GetIsolate()); + v8::Local<v8::Value> port_v8_value = ToV8(port, script_state); + DCHECK(!port_v8_value.IsEmpty()); + v8::Local<v8::Value> args[] = {GetInternalStream(script_state).V8Value(), + port_v8_value}; + V8ScriptRunner::CallExtra(script_state, "WritableStreamSerialize", args); + if (block.HasCaught()) { + exception_state.RethrowV8Exception(block.Exception()); + } +} + +// static +WritableStreamWrapper* WritableStreamWrapper::Deserialize( + ScriptState* script_state, + MessagePort* port, + ExceptionState& exception_state) { + // We need to execute V8 Extras JavaScript to create the new WritableStream. + // We will not run author code. + auto* isolate = script_state->GetIsolate(); + v8::Isolate::AllowJavascriptExecutionScope allow_js(isolate); + DCHECK(port); + DCHECK(RuntimeEnabledFeatures::TransferableStreamsEnabled()); + v8::TryCatch block(isolate); + v8::Local<v8::Value> port_v8 = ToV8(port, script_state); + DCHECK(!port_v8.IsEmpty()); + v8::Local<v8::Value> args[] = {port_v8}; + ScriptValue internal_stream( + script_state, V8ScriptRunner::CallExtra( + script_state, "WritableStreamDeserialize", args)); + if (block.HasCaught()) { + exception_state.RethrowV8Exception(block.Exception()); + return nullptr; + } + DCHECK(!internal_stream.IsEmpty()); + return CreateFromInternalStream(script_state, internal_stream, + exception_state); +} + +ScriptValue WritableStreamWrapper::GetInternalStream( + ScriptState* script_state) const { + return ScriptValue(script_state, + internal_stream_.NewLocal(script_state->GetIsolate())); +} + +} // namespace blink diff --git a/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.h b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.h new file mode 100644 index 00000000000..81f2e96a380 --- /dev/null +++ b/chromium/third_party/blink/renderer/core/streams/writable_stream_wrapper.h @@ -0,0 +1,88 @@ +// Copyright 2018 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_ +#define THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_ + +#include "third_party/blink/renderer/bindings/core/v8/script_promise.h" +#include "third_party/blink/renderer/bindings/core/v8/script_value.h" +#include "third_party/blink/renderer/core/streams/writable_stream.h" +#include "third_party/blink/renderer/platform/bindings/script_wrappable.h" +#include "third_party/blink/renderer/platform/bindings/trace_wrapper_v8_reference.h" +#include "third_party/blink/renderer/platform/heap/handle.h" +#include "v8/include/v8.h" + +namespace blink { + +class MessagePort; + +// This is an implementation of the WritableStream interface that delegates to +// the V8 Extras implementation. Use TraceWrapperMember to hold a reference to +// an instance of this class. +class CORE_EXPORT WritableStreamWrapper final : public WritableStream { + public: + // Call one of Init functions before using the instance. + WritableStreamWrapper() = default; + ~WritableStreamWrapper() override = default; + + // If an error happens, |exception_state.HadException()| will be true, and + // |this| will not be usable after that. + void Init(ScriptState*, + ScriptValue underlying_sink, + ScriptValue strategy, + ExceptionState& exception_state); + + static WritableStreamWrapper* CreateFromInternalStream( + ScriptState* script_state, + ScriptValue internal_stream, + ExceptionState& exception_state) { + DCHECK(internal_stream.IsObject()); + return CreateFromInternalStream(script_state, + internal_stream.V8Value().As<v8::Object>(), + exception_state); + } + static WritableStreamWrapper* CreateFromInternalStream( + ScriptState*, + v8::Local<v8::Object> internal_stream, + ExceptionState&); + + void Trace(Visitor* visitor) override; + + // IDL defined functions + bool locked(ScriptState*, ExceptionState&) const override; + ScriptPromise abort(ScriptState*, ExceptionState&) override; + ScriptPromise abort(ScriptState*, + ScriptValue reason, + ExceptionState&) override; + ScriptValue getWriter(ScriptState*, ExceptionState&) override; + + base::Optional<bool> IsLocked(ScriptState*, ExceptionState&) const override; + + // Serialize this stream to |port|. The stream will be locked by this + // operation. + void Serialize(ScriptState*, MessagePort* port, ExceptionState&) override; + + // Given a |port| which is entangled with a MessagePort that was previously + // passed to Serialize(), returns a new WritableStreamWrapper which behaves + // like it was the original. + static WritableStreamWrapper* Deserialize(ScriptState*, + MessagePort* port, + ExceptionState&); + + ScriptValue GetInternalStream(ScriptState*) const; + + private: + bool InitInternal(ScriptState*, v8::Local<v8::Object> internal_stream); + + static v8::MaybeLocal<v8::Object> CreateInternalStream( + ScriptState* script_state, + v8::Local<v8::Value> underlying_sink, + v8::Local<v8::Value> strategy); + + TraceWrapperV8Reference<v8::Object> internal_stream_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_CORE_STREAMS_WRITABLE_STREAM_WRAPPER_H_ |