refactor: port window.open and window.opener to use ctx bridge instead of hole punching (#23235)
* refactor: port window.open and window.opener to use ctx bridge instead of hole punching * refactor: only run the isolated init bundle when webview is enabled
This commit is contained in:
parent
c68589f212
commit
abe5cf398c
11 changed files with 178 additions and 85 deletions
|
@ -146,6 +146,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|||
v8::Local<v8::Value> value,
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
context_bridge::ObjectCache* object_cache,
|
||||
bool support_dynamic_properties,
|
||||
int recursion_depth) {
|
||||
if (recursion_depth >= kMaxRecursion) {
|
||||
v8::Context::Scope source_scope(source_context);
|
||||
|
@ -179,7 +180,8 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|||
{
|
||||
v8::Local<v8::Value> proxy_func = gin_helper::CallbackToV8Leaked(
|
||||
destination_context->GetIsolate(),
|
||||
base::BindRepeating(&ProxyFunctionWrapper, store, func_id));
|
||||
base::BindRepeating(&ProxyFunctionWrapper, store, func_id,
|
||||
support_dynamic_properties));
|
||||
FunctionLifeMonitor::BindTo(destination_context->GetIsolate(),
|
||||
v8::Local<v8::Object>::Cast(proxy_func),
|
||||
store->GetWeakPtr(), func_id);
|
||||
|
@ -209,7 +211,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|||
auto val =
|
||||
PassValueToOtherContext(global_source_context.Get(isolate),
|
||||
global_destination_context.Get(isolate),
|
||||
result, store, &object_cache, 0);
|
||||
result, store, &object_cache, false, 0);
|
||||
if (!val.IsEmpty())
|
||||
proxied_promise->Resolve(val.ToLocalChecked());
|
||||
delete proxied_promise;
|
||||
|
@ -230,7 +232,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|||
auto val =
|
||||
PassValueToOtherContext(global_source_context.Get(isolate),
|
||||
global_destination_context.Get(isolate),
|
||||
result, store, &object_cache, 0);
|
||||
result, store, &object_cache, false, 0);
|
||||
if (!val.IsEmpty())
|
||||
proxied_promise->Reject(val.ToLocalChecked());
|
||||
delete proxied_promise;
|
||||
|
@ -276,7 +278,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|||
auto value_for_array = PassValueToOtherContext(
|
||||
source_context, destination_context,
|
||||
arr->Get(source_context, i).ToLocalChecked(), store, object_cache,
|
||||
recursion_depth + 1);
|
||||
support_dynamic_properties, recursion_depth + 1);
|
||||
if (value_for_array.IsEmpty())
|
||||
return v8::MaybeLocal<v8::Value>();
|
||||
|
||||
|
@ -293,9 +295,9 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|||
// Proxy all objects
|
||||
if (IsPlainObject(value)) {
|
||||
auto object_value = v8::Local<v8::Object>::Cast(value);
|
||||
auto passed_value =
|
||||
CreateProxyForAPI(object_value, source_context, destination_context,
|
||||
store, object_cache, recursion_depth + 1);
|
||||
auto passed_value = CreateProxyForAPI(
|
||||
object_value, source_context, destination_context, store, object_cache,
|
||||
support_dynamic_properties, recursion_depth + 1);
|
||||
if (passed_value.IsEmpty())
|
||||
return v8::MaybeLocal<v8::Value>();
|
||||
return v8::MaybeLocal<v8::Value>(passed_value.ToLocalChecked());
|
||||
|
@ -324,6 +326,7 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
|||
v8::Local<v8::Value> ProxyFunctionWrapper(
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
size_t func_id,
|
||||
bool support_dynamic_properties,
|
||||
gin_helper::Arguments* args) {
|
||||
// Context the proxy function was called from
|
||||
v8::Local<v8::Context> calling_context = args->isolate()->GetCurrentContext();
|
||||
|
@ -343,7 +346,8 @@ v8::Local<v8::Value> ProxyFunctionWrapper(
|
|||
|
||||
for (auto value : original_args) {
|
||||
auto arg = PassValueToOtherContext(calling_context, func_owning_context,
|
||||
value, store, &object_cache, 0);
|
||||
value, store, &object_cache,
|
||||
support_dynamic_properties, 0);
|
||||
if (arg.IsEmpty())
|
||||
return v8::Undefined(args->isolate());
|
||||
proxied_args.push_back(arg.ToLocalChecked());
|
||||
|
@ -381,9 +385,10 @@ v8::Local<v8::Value> ProxyFunctionWrapper(
|
|||
if (maybe_return_value.IsEmpty())
|
||||
return v8::Undefined(args->isolate());
|
||||
|
||||
auto ret = PassValueToOtherContext(func_owning_context, calling_context,
|
||||
maybe_return_value.ToLocalChecked(),
|
||||
store, &object_cache, 0);
|
||||
auto ret =
|
||||
PassValueToOtherContext(func_owning_context, calling_context,
|
||||
maybe_return_value.ToLocalChecked(), store,
|
||||
&object_cache, support_dynamic_properties, 0);
|
||||
if (ret.IsEmpty())
|
||||
return v8::Undefined(args->isolate());
|
||||
return ret.ToLocalChecked();
|
||||
|
@ -396,6 +401,7 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
|||
const v8::Local<v8::Context>& destination_context,
|
||||
context_bridge::RenderFrameFunctionStore* store,
|
||||
context_bridge::ObjectCache* object_cache,
|
||||
bool support_dynamic_properties,
|
||||
int recursion_depth) {
|
||||
gin_helper::Dictionary api(source_context->GetIsolate(), api_object);
|
||||
v8::Context::Scope destination_context_scope(destination_context);
|
||||
|
@ -420,13 +426,54 @@ v8::MaybeLocal<v8::Object> CreateProxyForAPI(
|
|||
if (!gin::ConvertFromV8(api.isolate(), key, &key_str)) {
|
||||
continue;
|
||||
}
|
||||
if (support_dynamic_properties) {
|
||||
v8::Context::Scope source_context_scope(source_context);
|
||||
auto maybe_desc = api.GetHandle()->GetOwnPropertyDescriptor(
|
||||
source_context, v8::Local<v8::Name>::Cast(key));
|
||||
v8::Local<v8::Value> desc_value;
|
||||
if (!maybe_desc.ToLocal(&desc_value) || !desc_value->IsObject())
|
||||
continue;
|
||||
gin_helper::Dictionary desc(api.isolate(), desc_value.As<v8::Object>());
|
||||
if (desc.Has("get") || desc.Has("set")) {
|
||||
v8::Local<v8::Value> getter;
|
||||
v8::Local<v8::Value> setter;
|
||||
desc.Get("get", &getter);
|
||||
desc.Get("set", &setter);
|
||||
|
||||
{
|
||||
v8::Context::Scope destination_context_scope(destination_context);
|
||||
v8::Local<v8::Value> getter_proxy;
|
||||
v8::Local<v8::Value> setter_proxy;
|
||||
if (!getter.IsEmpty()) {
|
||||
if (!PassValueToOtherContext(source_context, destination_context,
|
||||
getter, store, object_cache, false,
|
||||
1)
|
||||
.ToLocal(&getter_proxy))
|
||||
continue;
|
||||
}
|
||||
if (!setter.IsEmpty()) {
|
||||
if (!PassValueToOtherContext(source_context, destination_context,
|
||||
setter, store, object_cache, false,
|
||||
1)
|
||||
.ToLocal(&setter_proxy))
|
||||
continue;
|
||||
}
|
||||
|
||||
v8::PropertyDescriptor desc(getter_proxy, setter_proxy);
|
||||
ignore_result(proxy.GetHandle()->DefineProperty(
|
||||
destination_context, gin::StringToV8(api.isolate(), key_str),
|
||||
desc));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
v8::Local<v8::Value> value;
|
||||
if (!api.Get(key_str, &value))
|
||||
continue;
|
||||
|
||||
auto passed_value =
|
||||
PassValueToOtherContext(source_context, destination_context, value,
|
||||
store, object_cache, recursion_depth + 1);
|
||||
auto passed_value = PassValueToOtherContext(
|
||||
source_context, destination_context, value, store, object_cache,
|
||||
support_dynamic_properties, recursion_depth + 1);
|
||||
if (passed_value.IsEmpty())
|
||||
return v8::MaybeLocal<v8::Object>();
|
||||
proxy.Set(key_str, passed_value.ToLocalChecked());
|
||||
|
@ -472,8 +519,9 @@ void ExposeAPIInMainWorld(const std::string& key,
|
|||
context_bridge::ObjectCache object_cache;
|
||||
v8::Context::Scope main_context_scope(main_context);
|
||||
{
|
||||
v8::MaybeLocal<v8::Object> maybe_proxy = CreateProxyForAPI(
|
||||
api_object, isolated_context, main_context, store, &object_cache, 0);
|
||||
v8::MaybeLocal<v8::Object> maybe_proxy =
|
||||
CreateProxyForAPI(api_object, isolated_context, main_context, store,
|
||||
&object_cache, false, 0);
|
||||
if (maybe_proxy.IsEmpty())
|
||||
return;
|
||||
auto proxy = maybe_proxy.ToLocalChecked();
|
||||
|
@ -493,13 +541,14 @@ gin_helper::Dictionary TraceKeyPath(const gin_helper::Dictionary& start,
|
|||
return current;
|
||||
}
|
||||
|
||||
void OverrideGlobalMethodFromIsolatedWorld(
|
||||
void OverrideGlobalValueFromIsolatedWorld(
|
||||
const std::vector<std::string>& key_path,
|
||||
v8::Local<v8::Function> method) {
|
||||
v8::Local<v8::Object> value,
|
||||
bool support_dynamic_properties) {
|
||||
if (key_path.size() == 0)
|
||||
return;
|
||||
|
||||
auto* render_frame = GetRenderFrame(method);
|
||||
auto* render_frame = GetRenderFrame(value);
|
||||
CHECK(render_frame);
|
||||
context_bridge::RenderFrameFunctionStore* store =
|
||||
GetOrCreateStore(render_frame);
|
||||
|
@ -515,9 +564,9 @@ void OverrideGlobalMethodFromIsolatedWorld(
|
|||
{
|
||||
v8::Context::Scope main_context_scope(main_context);
|
||||
context_bridge::ObjectCache object_cache;
|
||||
v8::MaybeLocal<v8::Value> maybe_proxy =
|
||||
PassValueToOtherContext(method->CreationContext(), main_context, method,
|
||||
store, &object_cache, 1);
|
||||
v8::MaybeLocal<v8::Value> maybe_proxy = PassValueToOtherContext(
|
||||
value->CreationContext(), main_context, value, store, &object_cache,
|
||||
support_dynamic_properties, 1);
|
||||
DCHECK(!maybe_proxy.IsEmpty());
|
||||
auto proxy = maybe_proxy.ToLocalChecked();
|
||||
|
||||
|
@ -555,14 +604,14 @@ bool OverrideGlobalPropertyFromIsolatedWorld(
|
|||
if (!getter->IsNullOrUndefined()) {
|
||||
v8::MaybeLocal<v8::Value> maybe_getter_proxy =
|
||||
PassValueToOtherContext(getter->CreationContext(), main_context,
|
||||
getter, store, &object_cache, 1);
|
||||
getter, store, &object_cache, false, 1);
|
||||
DCHECK(!maybe_getter_proxy.IsEmpty());
|
||||
getter_proxy = maybe_getter_proxy.ToLocalChecked();
|
||||
}
|
||||
if (!setter->IsNullOrUndefined() && setter->IsObject()) {
|
||||
v8::MaybeLocal<v8::Value> maybe_setter_proxy =
|
||||
PassValueToOtherContext(getter->CreationContext(), main_context,
|
||||
setter, store, &object_cache, 1);
|
||||
setter, store, &object_cache, false, 1);
|
||||
DCHECK(!maybe_setter_proxy.IsEmpty());
|
||||
setter_proxy = maybe_setter_proxy.ToLocalChecked();
|
||||
}
|
||||
|
@ -597,8 +646,8 @@ void Initialize(v8::Local<v8::Object> exports,
|
|||
v8::Isolate* isolate = context->GetIsolate();
|
||||
gin_helper::Dictionary dict(isolate, exports);
|
||||
dict.SetMethod("exposeAPIInMainWorld", &electron::api::ExposeAPIInMainWorld);
|
||||
dict.SetMethod("_overrideGlobalMethodFromIsolatedWorld",
|
||||
&electron::api::OverrideGlobalMethodFromIsolatedWorld);
|
||||
dict.SetMethod("_overrideGlobalValueFromIsolatedWorld",
|
||||
&electron::api::OverrideGlobalValueFromIsolatedWorld);
|
||||
dict.SetMethod("_overrideGlobalPropertyFromIsolatedWorld",
|
||||
&electron::api::OverrideGlobalPropertyFromIsolatedWorld);
|
||||
dict.SetMethod("_isCalledFromMainWorld",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue