fix: cross-origin navigation disposing WebFrameMain instances (#30076)
This commit is contained in:
parent
90b5ba3bed
commit
dd16d68e96
5 changed files with 150 additions and 96 deletions
|
@ -9,8 +9,8 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/lazy_instance.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "content/browser/renderer_host/frame_tree_node.h" // nogncheck
|
||||
#include "content/public/browser/render_frame_host.h"
|
||||
#include "electron/shell/common/api/api.mojom.h"
|
||||
|
@ -56,36 +56,54 @@ namespace electron {
|
|||
|
||||
namespace api {
|
||||
|
||||
typedef std::unordered_map<content::RenderFrameHost*, WebFrameMain*>
|
||||
RenderFrameMap;
|
||||
base::LazyInstance<RenderFrameMap>::DestructorAtExit g_render_frame_map =
|
||||
LAZY_INSTANCE_INITIALIZER;
|
||||
typedef std::unordered_map<int, WebFrameMain*> WebFrameMainIdMap;
|
||||
|
||||
WebFrameMain* FromRenderFrameHost(content::RenderFrameHost* rfh) {
|
||||
auto frame_map = g_render_frame_map.Get();
|
||||
auto iter = frame_map.find(rfh);
|
||||
WebFrameMainIdMap& GetWebFrameMainMap() {
|
||||
static base::NoDestructor<WebFrameMainIdMap> instance;
|
||||
return *instance;
|
||||
}
|
||||
|
||||
// static
|
||||
WebFrameMain* WebFrameMain::FromFrameTreeNodeId(int frame_tree_node_id) {
|
||||
WebFrameMainIdMap& frame_map = GetWebFrameMainMap();
|
||||
auto iter = frame_map.find(frame_tree_node_id);
|
||||
auto* web_frame = iter == frame_map.end() ? nullptr : iter->second;
|
||||
return web_frame;
|
||||
}
|
||||
|
||||
// static
|
||||
WebFrameMain* WebFrameMain::FromRenderFrameHost(content::RenderFrameHost* rfh) {
|
||||
return rfh ? FromFrameTreeNodeId(rfh->GetFrameTreeNodeId()) : nullptr;
|
||||
}
|
||||
|
||||
gin::WrapperInfo WebFrameMain::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
|
||||
WebFrameMain::WebFrameMain(content::RenderFrameHost* rfh) : render_frame_(rfh) {
|
||||
g_render_frame_map.Get().emplace(rfh, this);
|
||||
WebFrameMain::WebFrameMain(content::RenderFrameHost* rfh)
|
||||
: frame_tree_node_id_(rfh->GetFrameTreeNodeId()), render_frame_(rfh) {
|
||||
GetWebFrameMainMap().emplace(frame_tree_node_id_, this);
|
||||
}
|
||||
|
||||
WebFrameMain::~WebFrameMain() {
|
||||
Destroyed();
|
||||
}
|
||||
|
||||
void WebFrameMain::Destroyed() {
|
||||
MarkRenderFrameDisposed();
|
||||
GetWebFrameMainMap().erase(frame_tree_node_id_);
|
||||
Unpin();
|
||||
}
|
||||
|
||||
void WebFrameMain::MarkRenderFrameDisposed() {
|
||||
if (render_frame_disposed_)
|
||||
return;
|
||||
Unpin();
|
||||
g_render_frame_map.Get().erase(render_frame_);
|
||||
render_frame_ = nullptr;
|
||||
render_frame_disposed_ = true;
|
||||
}
|
||||
|
||||
void WebFrameMain::UpdateRenderFrameHost(content::RenderFrameHost* rfh) {
|
||||
// Should only be called when swapping frames.
|
||||
DCHECK(render_frame_);
|
||||
render_frame_ = rfh;
|
||||
}
|
||||
|
||||
bool WebFrameMain::CheckRenderFrame() const {
|
||||
if (render_frame_disposed_) {
|
||||
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
|
||||
|
@ -213,9 +231,7 @@ void WebFrameMain::PostMessage(v8::Isolate* isolate,
|
|||
}
|
||||
|
||||
int WebFrameMain::FrameTreeNodeID() const {
|
||||
if (!CheckRenderFrame())
|
||||
return -1;
|
||||
return render_frame_->GetFrameTreeNodeId();
|
||||
return frame_tree_node_id_;
|
||||
}
|
||||
|
||||
std::string WebFrameMain::Name() const {
|
||||
|
@ -293,6 +309,13 @@ std::vector<content::RenderFrameHost*> WebFrameMain::FramesInSubtree() const {
|
|||
return frame_hosts;
|
||||
}
|
||||
|
||||
void WebFrameMain::Connect() {
|
||||
if (pending_receiver_) {
|
||||
render_frame_->GetRemoteInterfaces()->GetInterface(
|
||||
std::move(pending_receiver_));
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<WebFrameMain> WebFrameMain::New(v8::Isolate* isolate) {
|
||||
return gin::Handle<WebFrameMain>();
|
||||
|
@ -315,35 +338,6 @@ gin::Handle<WebFrameMain> WebFrameMain::From(v8::Isolate* isolate,
|
|||
return handle;
|
||||
}
|
||||
|
||||
// static
|
||||
gin::Handle<WebFrameMain> WebFrameMain::FromID(v8::Isolate* isolate,
|
||||
int render_process_id,
|
||||
int render_frame_id) {
|
||||
auto* rfh =
|
||||
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
||||
return From(isolate, rfh);
|
||||
}
|
||||
|
||||
// static
|
||||
void WebFrameMain::RenderFrameDeleted(content::RenderFrameHost* rfh) {
|
||||
auto* web_frame = FromRenderFrameHost(rfh);
|
||||
if (web_frame)
|
||||
web_frame->MarkRenderFrameDisposed();
|
||||
}
|
||||
|
||||
void WebFrameMain::RenderFrameCreated(content::RenderFrameHost* rfh) {
|
||||
auto* web_frame = FromRenderFrameHost(rfh);
|
||||
if (web_frame)
|
||||
web_frame->Connect();
|
||||
}
|
||||
|
||||
void WebFrameMain::Connect() {
|
||||
if (pending_receiver_) {
|
||||
render_frame_->GetRemoteInterfaces()->GetInterface(
|
||||
std::move(pending_receiver_));
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
v8::Local<v8::ObjectTemplate> WebFrameMain::FillObjectTemplate(
|
||||
v8::Isolate* isolate,
|
||||
|
@ -387,9 +381,10 @@ v8::Local<v8::Value> FromID(gin_helper::ErrorThrower thrower,
|
|||
return v8::Null(thrower.isolate());
|
||||
}
|
||||
|
||||
return WebFrameMain::FromID(thrower.isolate(), render_process_id,
|
||||
render_frame_id)
|
||||
.ToV8();
|
||||
auto* rfh =
|
||||
content::RenderFrameHost::FromID(render_process_id, render_frame_id);
|
||||
|
||||
return WebFrameMain::From(thrower.isolate(), rfh).ToV8();
|
||||
}
|
||||
|
||||
void Initialize(v8::Local<v8::Object> exports,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue