diff --git a/shell/common/gin_helper/callback.cc b/shell/common/gin_helper/callback.cc index 403fe751b1..14c35a4242 100644 --- a/shell/common/gin_helper/callback.cc +++ b/shell/common/gin_helper/callback.cc @@ -5,7 +5,7 @@ #include "shell/common/gin_helper/callback.h" #include "content/public/browser/browser_thread.h" -#include "gin/dictionary.h" +#include "gin/arguments.h" #include "shell/common/process_util.h" namespace gin_helper { @@ -31,42 +31,28 @@ struct TranslatorHolder { delete data.GetParameter(); } - static gin::DeprecatedWrapperInfo kWrapperInfo; - v8::Global handle; Translator translator; + bool one_time = false; + bool called = false; }; -gin::DeprecatedWrapperInfo TranslatorHolder::kWrapperInfo = { - gin::kEmbedderNativeGin}; +void CallTranslator(const v8::FunctionCallbackInfo& info) { + gin::Arguments args(info); + auto* holder = + static_cast(info.Data().As()->Value( + v8::kExternalPointerTypeTagDefault)); -void CallTranslator(v8::Local external, - v8::Local state, - gin::Arguments* args) { - // Whether the callback should only be called once. - v8::Isolate* isolate = args->isolate(); - auto context = isolate->GetCurrentContext(); - bool one_time = - state->Has(context, gin::StringToSymbol(isolate, "oneTime")).ToChecked(); - - // Check if the callback has already been called. - if (one_time) { - auto called_symbol = gin::StringToSymbol(isolate, "called"); - if (state->Has(context, called_symbol).ToChecked()) { - args->ThrowTypeError("One-time callback was called more than once"); - return; - } else { - state->Set(context, called_symbol, v8::True(isolate)).ToChecked(); - } + if (holder->one_time && holder->called) { + args.ThrowTypeError("One-time callback was called more than once"); + return; } + holder->called = true; - auto* holder = static_cast( - external->Value(v8::kExternalPointerTypeTagDefault)); - holder->translator.Run(args); + holder->translator.Run(&args); - // Free immediately for one-time callback. - if (one_time) - delete holder; + if (holder->one_time) + holder->translator.Reset(); } } // namespace @@ -120,41 +106,11 @@ v8::Local SafeV8Function::NewHandle(v8::Isolate* isolate) const { v8::Local CreateFunctionFromTranslator(v8::Isolate* isolate, const Translator& translator, bool one_time) { - gin::PerIsolateData* data = gin::PerIsolateData::From(isolate); - auto* wrapper_info = &TranslatorHolder::kWrapperInfo; - v8::Local constructor = - data->DeprecatedGetFunctionTemplate(wrapper_info); - // The FunctionTemplate is cached. - if (constructor.IsEmpty()) { - constructor = - CreateFunctionTemplate(isolate, base::BindRepeating(&CallTranslator)); - data->DeprecatedSetFunctionTemplate(wrapper_info, constructor); - } - auto* holder = new TranslatorHolder(isolate); holder->translator = translator; - auto state = gin::Dictionary::CreateEmpty(isolate); - if (one_time) - state.Set("oneTime", true); + holder->one_time = one_time; auto context = isolate->GetCurrentContext(); - return BindFunctionWith( - isolate, context, constructor->GetFunction(context).ToLocalChecked(), - holder->handle.Get(isolate), gin::ConvertToV8(isolate, state)); -} - -// func.bind(func, arg1). -// NB(zcbenz): Using C++11 version crashes VS. -v8::Local BindFunctionWith(v8::Isolate* isolate, - v8::Local context, - v8::Local func, - v8::Local arg1, - v8::Local arg2) { - v8::MaybeLocal bind = - func->Get(context, gin::StringToV8(isolate, "bind")); - CHECK(!bind.IsEmpty()); - v8::Local bind_func = bind.ToLocalChecked().As(); - v8::Local converted[] = {func, arg1, arg2}; - return bind_func->Call(context, func, std::size(converted), converted) + return v8::Function::New(context, CallTranslator, holder->handle.Get(isolate)) .ToLocalChecked(); } diff --git a/shell/common/gin_helper/callback.h b/shell/common/gin_helper/callback.h index b16c431f34..addf278db0 100644 --- a/shell/common/gin_helper/callback.h +++ b/shell/common/gin_helper/callback.h @@ -118,11 +118,6 @@ using Translator = base::RepeatingCallback; v8::Local CreateFunctionFromTranslator(v8::Isolate* isolate, const Translator& translator, bool one_time); -v8::Local BindFunctionWith(v8::Isolate* isolate, - v8::Local context, - v8::Local func, - v8::Local arg1, - v8::Local arg2); // Calls callback with Arguments. template diff --git a/spec/api-context-bridge-spec.ts b/spec/api-context-bridge-spec.ts index e5700f1b99..c532bb2a35 100644 --- a/spec/api-context-bridge-spec.ts +++ b/spec/api-context-bridge-spec.ts @@ -372,6 +372,33 @@ describe('contextBridge', () => { expect(result).to.equal(123); }); + it('should proxy promises correctly when Function.prototype has been overridden in the main world', async () => { + await makeBindingWindow(() => { + contextBridge.exposeInMainWorld('example', { + getPromise: () => Promise.resolve('proxied-ok') + }); + }); + const result = await callWithBindings((root: any) => { + return new Promise(resolve => { + let observed = false; + const original = Function.prototype.bind; + // eslint-disable-next-line no-extend-native + Function.prototype.bind = new Proxy(original, { + apply (target, thisArg, args) { + observed = true; + return Reflect.apply(target, thisArg, args); + } + }); + root.example.getPromise().then((v: string) => { + // eslint-disable-next-line no-extend-native + Function.prototype.bind = original; + resolve({ observed, value: v }); + }); + }); + }); + expect(result).to.deep.equal({ observed: false, value: 'proxied-ok' }); + }); + it('should proxy methods', async () => { await makeBindingWindow(() => { contextBridge.exposeInMainWorld('example', {