| Index: third_party/WebKit/Source/modules/fetch/Response.cpp
|
| diff --git a/third_party/WebKit/Source/modules/fetch/Response.cpp b/third_party/WebKit/Source/modules/fetch/Response.cpp
|
| index d5319f453f05869de885768408521d50bf6970f7..d93ab9a7d5d4c40c74feae654a5694040752fbd1 100644
|
| --- a/third_party/WebKit/Source/modules/fetch/Response.cpp
|
| +++ b/third_party/WebKit/Source/modules/fetch/Response.cpp
|
| @@ -16,6 +16,7 @@
|
| #include "bindings/core/v8/V8HiddenValue.h"
|
| #include "bindings/core/v8/V8URLSearchParams.h"
|
| #include "bindings/modules/v8/ByteStringSequenceSequenceOrDictionaryOrHeaders.h"
|
| +#include "bindings/modules/v8/V8Response.h"
|
| #include "core/dom/DOMArrayBuffer.h"
|
| #include "core/dom/DOMArrayBufferView.h"
|
| #include "core/dom/URLSearchParams.h"
|
| @@ -122,6 +123,171 @@ bool isValidReasonPhrase(const String& statusText) {
|
|
|
| } // namespace
|
|
|
| +class FetchDataLoaderAsWasm final : public FetchDataLoader,
|
| + public BytesConsumer::Client {
|
| + USING_GARBAGE_COLLECTED_MIXIN(FetchDataLoaderAsWasm);
|
| +
|
| + public:
|
| + explicit FetchDataLoaderAsWasm(v8::Isolate* isolate,
|
| + ScriptPromiseResolver* resolver,
|
| + ScriptState* scriptState)
|
| + : m_resolver(resolver), m_builder(isolate), m_scriptState(scriptState) {}
|
| +
|
| + void start(BytesConsumer* consumer,
|
| + FetchDataLoader::Client* client) override {
|
| + DCHECK(!m_consumer);
|
| + DCHECK(!m_client);
|
| + m_consumer = consumer;
|
| + m_consumer->setClient(this);
|
| + m_client = client;
|
| + onStateChange();
|
| + }
|
| +
|
| + void onStateChange() override {
|
| + while (true) {
|
| + const char* buffer;
|
| + size_t available;
|
| + auto result = m_consumer->beginRead(&buffer, &available);
|
| + if (result == BytesConsumer::Result::ShouldWait) {
|
| + return;
|
| + }
|
| + if (result == BytesConsumer::Result::Ok) {
|
| + char* bufferCopy = new char[available];
|
| + memcpy(bufferCopy, buffer, available);
|
| + m_builder.OnBytesReceived(
|
| + std::unique_ptr<const uint8_t[]>(
|
| + reinterpret_cast<const uint8_t*>(bufferCopy)),
|
| + available);
|
| + result = m_consumer->endRead(available);
|
| + }
|
| + switch (result) {
|
| + case BytesConsumer::Result::Ok:
|
| + break;
|
| + case BytesConsumer::Result::ShouldWait:
|
| + NOTREACHED();
|
| + return;
|
| + case BytesConsumer::Result::Done: {
|
| + ScriptState::Scope scope(m_scriptState.get());
|
| + v8::MaybeLocal<v8::WasmCompiledModule> module = m_builder.Finish();
|
| + ScriptValue sv(m_scriptState.get(), module.ToLocalChecked());
|
| + m_resolver->resolve(sv);
|
| + m_client->didFetchDataLoadedStream();
|
| + return;
|
| + }
|
| + case BytesConsumer::Result::Error:
|
| + // TODO(mtrofin): do we need an abort?
|
| + // m_outStream->abort();
|
| + m_client->didFetchDataLoadFailed();
|
| + return;
|
| + }
|
| + }
|
| + }
|
| +
|
| + void cancel() override { m_consumer->cancel(); }
|
| +
|
| + DEFINE_INLINE_TRACE() {
|
| + visitor->trace(m_consumer);
|
| + visitor->trace(m_resolver);
|
| + visitor->trace(m_client);
|
| + FetchDataLoader::trace(visitor);
|
| + BytesConsumer::Client::trace(visitor);
|
| + }
|
| +
|
| + Member<BytesConsumer> m_consumer;
|
| + Member<ScriptPromiseResolver> m_resolver;
|
| + v8::WasmModuleObjectBuilder m_builder;
|
| + Member<FetchDataLoader::Client> m_client;
|
| + const RefPtr<ScriptState> m_scriptState;
|
| +};
|
| +
|
| +class WasmConsumer final : public GarbageCollectedFinalized<WasmConsumer>,
|
| + public FetchDataLoader::Client {
|
| + WTF_MAKE_NONCOPYABLE(WasmConsumer);
|
| + USING_GARBAGE_COLLECTED_MIXIN(WasmConsumer);
|
| +
|
| + public:
|
| + explicit WasmConsumer(ScriptPromiseResolver* resolver)
|
| + : m_resolver(resolver) {}
|
| + ScriptPromiseResolver* resolver() { return m_resolver; }
|
| + void didFetchDataLoadFailed() override {
|
| + ScriptState::Scope scope(resolver()->getScriptState());
|
| + m_resolver->reject(V8ThrowException::createTypeError(
|
| + resolver()->getScriptState()->isolate(), "Failed to fetch"));
|
| + }
|
| +
|
| + void didFetchDataLoadedStream() {}
|
| +
|
| + DEFINE_INLINE_TRACE() {
|
| + visitor->trace(m_resolver);
|
| + FetchDataLoader::Client::trace(visitor);
|
| + }
|
| +
|
| + private:
|
| + Member<ScriptPromiseResolver> m_resolver;
|
| +};
|
| +
|
| +void CompileCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| + ExceptionState exceptionState(args.GetIsolate(),
|
| + ExceptionState::ExecutionContext, "WebAssembly",
|
| + "compile");
|
| + ExceptionToRejectPromiseScope rejectPromiseScope(args, exceptionState);
|
| + // TODO(mtrofin): what if args[0] is again a promise? We can probably
|
| + // factor this better.
|
| +
|
| + ScriptState* scriptState = ScriptState::forReceiverObject(args);
|
| + if (args.Length() < 1 || !args[0]->IsObject() ||
|
| + !V8Response::hasInstance(args[0], args.GetIsolate())) {
|
| + args.GetReturnValue().Set(
|
| + ScriptPromise::reject(
|
| + scriptState, V8ThrowException::createTypeError(
|
| + scriptState->isolate(),
|
| + "Promise argument must produce a Response object"))
|
| + .v8Value());
|
| + return;
|
| + }
|
| +
|
| + Response* response = V8Response::toImpl(v8::Local<v8::Object>::Cast(args[0]));
|
| + ScriptPromise promise = response->rejectInvalidConsumption(scriptState);
|
| + if (!promise.isEmpty()) {
|
| + args.GetReturnValue().Set(promise.v8Value());
|
| + return;
|
| + }
|
| +
|
| + if (!scriptState->getExecutionContext()) {
|
| + args.GetReturnValue().Set(ScriptPromise().v8Value());
|
| + return;
|
| + }
|
| + ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState);
|
| + promise = resolver->promise();
|
| + if (response->bodyBuffer()) {
|
| + response->bodyBuffer()->startLoading(
|
| + new FetchDataLoaderAsWasm(args.GetIsolate(), resolver, scriptState),
|
| + new WasmConsumer(resolver));
|
| + } else {
|
| + resolver->reject();
|
| + }
|
| + args.GetReturnValue().Set(promise.v8Value());
|
| +}
|
| +
|
| +bool WasmResponseOverloads::CompileOverload(
|
| + const v8::FunctionCallbackInfo<v8::Value>& args) {
|
| + if (args.Length() < 1 || !args[0]->IsObject())
|
| + return false;
|
| + if (args[0]->IsPromise()) {
|
| + ScriptState* scriptState = ScriptState::forReceiverObject(args);
|
| + ScriptPromise sp = ScriptPromise(scriptState, args[0]);
|
| + ScriptPromise thenCompile =
|
| + sp.then(v8::Function::New(args.GetIsolate(), CompileCallback));
|
| + args.GetReturnValue().Set(thenCompile.v8Value());
|
| + return true;
|
| + }
|
| + if (!V8Response::hasInstance(args[0], args.GetIsolate()))
|
| + return false;
|
| +
|
| + CompileCallback(args);
|
| + return true;
|
| +}
|
| +
|
| Response* Response::create(ScriptState* scriptState,
|
| ExceptionState& exceptionState) {
|
| return create(scriptState, nullptr, String(), ResponseInit(), exceptionState);
|
|
|