fix: use appropriate site instance for cross-site nav's (#15821)
* fix: use Chromium's determined new site instance as candidate when navigating. When navigating to a new address, consider using Chromium's determined site instance for the new page as it should belong to an existing browsing instance when the navigation was triggered by window.open(). fixes 8100. * Revert "fix: use Chromium's determined new site instance as candidate when navigating." This reverts commit eb95f935654a2c4d4457821297670836c10fdfd5. * fix: delegate site instance creation back to content when sandboxed. * fix: ensure site isolation is on * test: adapt ut for cross-site navigation * fix: register pending processes during a navigation. * refactor: dont call loadURL for a window constructed from an existing webContents. * test: add sandboxed affinity UT's. * fix: check affinity before deciding if to force a new site instance. * chore: adapt subsequent patch. * refactor: constify logically const methods. * fix: do not reuse site instances when navigation redirects cross-site. * test: ensure localStorage accessible after x-site redirect. * test: adapt localStorage acess denied UT for site isolation. * fix: do not send render-view-deleted for speculative frames. * chore: amend tests after rebase. * test: add ut for webContents' render-view-deleted emission * fix: introduce current-render-view-deleted for current RVH's deletions. Revert render-view-deleted to being emitted with any RVH's deletion. current-render-view-deleted is emitted only when the RVH being deleted is the current one. * refactor: style and comments fixed.
This commit is contained in:
parent
46e7214974
commit
d5d1fa8290
14 changed files with 581 additions and 240 deletions
|
@ -781,8 +781,29 @@ void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
|
||||||
impl->disable_hidden_ = !background_throttling_;
|
impl->disable_hidden_ = !background_throttling_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebContents::RenderViewHostChanged(content::RenderViewHost* old_host,
|
||||||
|
content::RenderViewHost* new_host) {
|
||||||
|
currently_committed_process_id_ = new_host->GetProcess()->GetID();
|
||||||
|
}
|
||||||
|
|
||||||
void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
|
void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
|
||||||
|
// This event is necessary for tracking any states with respect to
|
||||||
|
// intermediate render view hosts aka speculative render view hosts. Currently
|
||||||
|
// used by object-registry.js to ref count remote objects.
|
||||||
Emit("render-view-deleted", render_view_host->GetProcess()->GetID());
|
Emit("render-view-deleted", render_view_host->GetProcess()->GetID());
|
||||||
|
|
||||||
|
if (-1 == currently_committed_process_id_ ||
|
||||||
|
render_view_host->GetProcess()->GetID() ==
|
||||||
|
currently_committed_process_id_) {
|
||||||
|
currently_committed_process_id_ = -1;
|
||||||
|
|
||||||
|
// When the RVH that has been deleted is the current RVH it means that the
|
||||||
|
// the web contents are being closed. This is communicated by this event.
|
||||||
|
// Currently tracked by guest-window-manager.js to destroy the
|
||||||
|
// BrowserWindow.
|
||||||
|
Emit("current-render-view-deleted",
|
||||||
|
render_view_host->GetProcess()->GetID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::RenderProcessGone(base::TerminationStatus status) {
|
void WebContents::RenderProcessGone(base::TerminationStatus status) {
|
||||||
|
|
|
@ -402,6 +402,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
// content::WebContentsObserver:
|
// content::WebContentsObserver:
|
||||||
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
|
void BeforeUnloadFired(const base::TimeTicks& proceed_time) override;
|
||||||
void RenderViewCreated(content::RenderViewHost*) override;
|
void RenderViewCreated(content::RenderViewHost*) override;
|
||||||
|
void RenderViewHostChanged(content::RenderViewHost* old_host,
|
||||||
|
content::RenderViewHost* new_host) override;
|
||||||
void RenderViewDeleted(content::RenderViewHost*) override;
|
void RenderViewDeleted(content::RenderViewHost*) override;
|
||||||
void RenderProcessGone(base::TerminationStatus status) override;
|
void RenderProcessGone(base::TerminationStatus status) override;
|
||||||
void DocumentLoadedInFrame(
|
void DocumentLoadedInFrame(
|
||||||
|
@ -530,6 +532,10 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
// Observers of this WebContents.
|
// Observers of this WebContents.
|
||||||
base::ObserverList<ExtendedWebContentsObserver> observers_;
|
base::ObserverList<ExtendedWebContentsObserver> observers_;
|
||||||
|
|
||||||
|
// The ID of the process of the currently committed RenderViewHost.
|
||||||
|
// -1 means no speculative RVH has been committed yet.
|
||||||
|
int currently_committed_process_id_ = -1;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(WebContents);
|
DISALLOW_COPY_AND_ASSIGN(WebContents);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -179,7 +179,7 @@ AtomBrowserClient::~AtomBrowserClient() {
|
||||||
content::WebContents* AtomBrowserClient::GetWebContentsFromProcessID(
|
content::WebContents* AtomBrowserClient::GetWebContentsFromProcessID(
|
||||||
int process_id) {
|
int process_id) {
|
||||||
// If the process is a pending process, we should use the web contents
|
// If the process is a pending process, we should use the web contents
|
||||||
// for the frame host passed into OverrideSiteInstanceForNavigation.
|
// for the frame host passed into RegisterPendingProcess.
|
||||||
if (base::ContainsKey(pending_processes_, process_id))
|
if (base::ContainsKey(pending_processes_, process_id))
|
||||||
return pending_processes_[process_id];
|
return pending_processes_[process_id];
|
||||||
|
|
||||||
|
@ -188,24 +188,36 @@ content::WebContents* AtomBrowserClient::GetWebContentsFromProcessID(
|
||||||
return WebContentsPreferences::GetWebContentsFromProcessID(process_id);
|
return WebContentsPreferences::GetWebContentsFromProcessID(process_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomBrowserClient::ShouldCreateNewSiteInstance(
|
bool AtomBrowserClient::ShouldForceNewSiteInstance(
|
||||||
content::RenderFrameHost* render_frame_host,
|
content::RenderFrameHost* current_rfh,
|
||||||
|
content::RenderFrameHost* speculative_rfh,
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
content::SiteInstance* current_instance,
|
const GURL& url,
|
||||||
const GURL& url) {
|
bool has_response_started) const {
|
||||||
if (url.SchemeIs(url::kJavaScriptScheme))
|
if (url.SchemeIs(url::kJavaScriptScheme))
|
||||||
// "javacript:" scheme should always use same SiteInstance
|
// "javacript:" scheme should always use same SiteInstance
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
content::SiteInstance* current_instance = current_rfh->GetSiteInstance();
|
||||||
|
content::SiteInstance* speculative_instance =
|
||||||
|
speculative_rfh ? speculative_rfh->GetSiteInstance() : nullptr;
|
||||||
int process_id = current_instance->GetProcess()->GetID();
|
int process_id = current_instance->GetProcess()->GetID();
|
||||||
if (!IsRendererSandboxed(process_id)) {
|
if (NavigationWasRedirectedCrossSite(browser_context, current_instance,
|
||||||
if (!RendererUsesNativeWindowOpen(process_id)) {
|
speculative_instance, url,
|
||||||
|
has_response_started)) {
|
||||||
|
// Navigation was redirected. We can't force the current, speculative or a
|
||||||
|
// new unrelated site instance to be used. Delegate to the content layer.
|
||||||
|
return false;
|
||||||
|
} else if (IsRendererSandboxed(process_id)) {
|
||||||
|
// Renderer is sandboxed, delegate the decision to the content layer for all
|
||||||
|
// origins.
|
||||||
|
return false;
|
||||||
|
} else if (!RendererUsesNativeWindowOpen(process_id)) {
|
||||||
// non-sandboxed renderers without native window.open should always create
|
// non-sandboxed renderers without native window.open should always create
|
||||||
// a new SiteInstance
|
// a new SiteInstance
|
||||||
return true;
|
return true;
|
||||||
}
|
} else {
|
||||||
auto* web_contents =
|
auto* web_contents = content::WebContents::FromRenderFrameHost(current_rfh);
|
||||||
content::WebContents::FromRenderFrameHost(render_frame_host);
|
|
||||||
if (!ChildWebContentsTracker::FromWebContents(web_contents)) {
|
if (!ChildWebContentsTracker::FromWebContents(web_contents)) {
|
||||||
// Root WebContents should always create new process to make sure
|
// Root WebContents should always create new process to make sure
|
||||||
// native addons are loaded correctly after reload / navigation.
|
// native addons are loaded correctly after reload / navigation.
|
||||||
|
@ -220,6 +232,26 @@ bool AtomBrowserClient::ShouldCreateNewSiteInstance(
|
||||||
return !IsSameWebSite(browser_context, src_url, url);
|
return !IsSameWebSite(browser_context, src_url, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AtomBrowserClient::NavigationWasRedirectedCrossSite(
|
||||||
|
content::BrowserContext* browser_context,
|
||||||
|
content::SiteInstance* current_instance,
|
||||||
|
content::SiteInstance* speculative_instance,
|
||||||
|
const GURL& dest_url,
|
||||||
|
bool has_response_started) const {
|
||||||
|
bool navigation_was_redirected = false;
|
||||||
|
if (has_response_started) {
|
||||||
|
navigation_was_redirected = !IsSameWebSite(
|
||||||
|
browser_context, current_instance->GetSiteURL(), dest_url);
|
||||||
|
} else {
|
||||||
|
navigation_was_redirected =
|
||||||
|
speculative_instance &&
|
||||||
|
!IsSameWebSite(browser_context, speculative_instance->GetSiteURL(),
|
||||||
|
dest_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
return navigation_was_redirected;
|
||||||
|
}
|
||||||
|
|
||||||
void AtomBrowserClient::AddProcessPreferences(
|
void AtomBrowserClient::AddProcessPreferences(
|
||||||
int process_id,
|
int process_id,
|
||||||
AtomBrowserClient::ProcessPreferences prefs) {
|
AtomBrowserClient::ProcessPreferences prefs) {
|
||||||
|
@ -232,29 +264,69 @@ void AtomBrowserClient::RemoveProcessPreferences(int process_id) {
|
||||||
process_preferences_.erase(process_id);
|
process_preferences_.erase(process_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomBrowserClient::IsProcessObserved(int process_id) {
|
bool AtomBrowserClient::IsProcessObserved(int process_id) const {
|
||||||
base::AutoLock auto_lock(process_preferences_lock_);
|
base::AutoLock auto_lock(process_preferences_lock_);
|
||||||
return process_preferences_.find(process_id) != process_preferences_.end();
|
return process_preferences_.find(process_id) != process_preferences_.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomBrowserClient::IsRendererSandboxed(int process_id) {
|
bool AtomBrowserClient::IsRendererSandboxed(int process_id) const {
|
||||||
base::AutoLock auto_lock(process_preferences_lock_);
|
base::AutoLock auto_lock(process_preferences_lock_);
|
||||||
auto it = process_preferences_.find(process_id);
|
auto it = process_preferences_.find(process_id);
|
||||||
return it != process_preferences_.end() && it->second.sandbox;
|
return it != process_preferences_.end() && it->second.sandbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomBrowserClient::RendererUsesNativeWindowOpen(int process_id) {
|
bool AtomBrowserClient::RendererUsesNativeWindowOpen(int process_id) const {
|
||||||
base::AutoLock auto_lock(process_preferences_lock_);
|
base::AutoLock auto_lock(process_preferences_lock_);
|
||||||
auto it = process_preferences_.find(process_id);
|
auto it = process_preferences_.find(process_id);
|
||||||
return it != process_preferences_.end() && it->second.native_window_open;
|
return it != process_preferences_.end() && it->second.native_window_open;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomBrowserClient::RendererDisablesPopups(int process_id) {
|
bool AtomBrowserClient::RendererDisablesPopups(int process_id) const {
|
||||||
base::AutoLock auto_lock(process_preferences_lock_);
|
base::AutoLock auto_lock(process_preferences_lock_);
|
||||||
auto it = process_preferences_.find(process_id);
|
auto it = process_preferences_.find(process_id);
|
||||||
return it != process_preferences_.end() && it->second.disable_popups;
|
return it != process_preferences_.end() && it->second.disable_popups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string AtomBrowserClient::GetAffinityPreference(
|
||||||
|
content::RenderFrameHost* rfh) const {
|
||||||
|
auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
|
||||||
|
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
||||||
|
std::string affinity;
|
||||||
|
if (web_preferences &&
|
||||||
|
web_preferences->GetPreference("affinity", &affinity) &&
|
||||||
|
!affinity.empty()) {
|
||||||
|
affinity = base::ToLowerASCII(affinity);
|
||||||
|
}
|
||||||
|
|
||||||
|
return affinity;
|
||||||
|
}
|
||||||
|
|
||||||
|
content::SiteInstance* AtomBrowserClient::GetSiteInstanceFromAffinity(
|
||||||
|
content::BrowserContext* browser_context,
|
||||||
|
const GURL& url,
|
||||||
|
content::RenderFrameHost* rfh) const {
|
||||||
|
std::string affinity = GetAffinityPreference(rfh);
|
||||||
|
if (!affinity.empty()) {
|
||||||
|
auto iter = site_per_affinities_.find(affinity);
|
||||||
|
GURL dest_site = content::SiteInstance::GetSiteForURL(browser_context, url);
|
||||||
|
if (iter != site_per_affinities_.end() &&
|
||||||
|
IsSameWebSite(browser_context, iter->second->GetSiteURL(), dest_site)) {
|
||||||
|
return iter->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomBrowserClient::ConsiderSiteInstanceForAffinity(
|
||||||
|
content::RenderFrameHost* rfh,
|
||||||
|
content::SiteInstance* site_instance) {
|
||||||
|
std::string affinity = GetAffinityPreference(rfh);
|
||||||
|
if (!affinity.empty()) {
|
||||||
|
site_per_affinities_[affinity] = site_instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AtomBrowserClient::RenderProcessWillLaunch(
|
void AtomBrowserClient::RenderProcessWillLaunch(
|
||||||
content::RenderProcessHost* host,
|
content::RenderProcessHost* host,
|
||||||
service_manager::mojom::ServiceRequest* service_request) {
|
service_manager::mojom::ServiceRequest* service_request) {
|
||||||
|
@ -322,62 +394,59 @@ void AtomBrowserClient::OverrideWebkitPrefs(content::RenderViewHost* host,
|
||||||
web_preferences->OverrideWebkitPrefs(prefs);
|
web_preferences->OverrideWebkitPrefs(prefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomBrowserClient::OverrideSiteInstanceForNavigation(
|
content::ContentBrowserClient::SiteInstanceForNavigationType
|
||||||
content::RenderFrameHost* rfh,
|
AtomBrowserClient::ShouldOverrideSiteInstanceForNavigation(
|
||||||
|
content::RenderFrameHost* current_rfh,
|
||||||
|
content::RenderFrameHost* speculative_rfh,
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const GURL& url,
|
const GURL& url,
|
||||||
bool has_request_started,
|
bool has_response_started,
|
||||||
content::SiteInstance* candidate_instance,
|
content::SiteInstance** affinity_site_instance) const {
|
||||||
content::SiteInstance** new_instance) {
|
|
||||||
if (g_suppress_renderer_process_restart) {
|
if (g_suppress_renderer_process_restart) {
|
||||||
g_suppress_renderer_process_restart = false;
|
g_suppress_renderer_process_restart = false;
|
||||||
return;
|
return SiteInstanceForNavigationType::ASK_CHROMIUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
content::SiteInstance* current_instance = rfh->GetSiteInstance();
|
|
||||||
if (!ShouldCreateNewSiteInstance(rfh, browser_context, current_instance, url))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Do we have an affinity site to manage ?
|
// Do we have an affinity site to manage ?
|
||||||
auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
|
content::SiteInstance* site_instance_from_affinity =
|
||||||
auto* web_preferences = WebContentsPreferences::From(web_contents);
|
GetSiteInstanceFromAffinity(browser_context, url, current_rfh);
|
||||||
std::string affinity;
|
if (site_instance_from_affinity) {
|
||||||
if (web_preferences &&
|
*affinity_site_instance = site_instance_from_affinity;
|
||||||
web_preferences->GetPreference("affinity", &affinity) &&
|
return SiteInstanceForNavigationType::FORCE_AFFINITY;
|
||||||
!affinity.empty()) {
|
|
||||||
affinity = base::ToLowerASCII(affinity);
|
|
||||||
auto iter = site_per_affinities.find(affinity);
|
|
||||||
GURL dest_site = content::SiteInstance::GetSiteForURL(browser_context, url);
|
|
||||||
if (iter != site_per_affinities.end() &&
|
|
||||||
IsSameWebSite(browser_context, iter->second->GetSiteURL(), dest_site)) {
|
|
||||||
*new_instance = iter->second;
|
|
||||||
} else {
|
|
||||||
site_per_affinities[affinity] = candidate_instance;
|
|
||||||
*new_instance = candidate_instance;
|
|
||||||
// Remember the original web contents for the pending renderer process.
|
|
||||||
auto* pending_process = candidate_instance->GetProcess();
|
|
||||||
pending_processes_[pending_process->GetID()] = web_contents;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// OverrideSiteInstanceForNavigation will be called more than once during a
|
if (!ShouldForceNewSiteInstance(current_rfh, speculative_rfh, browser_context,
|
||||||
// navigation (currently twice, on request and when it's about to commit in
|
url, has_response_started)) {
|
||||||
// the renderer), look at RenderFrameHostManager::GetFrameHostForNavigation.
|
return SiteInstanceForNavigationType::ASK_CHROMIUM;
|
||||||
// In the default mode we should resuse the same site instance until the
|
}
|
||||||
|
|
||||||
|
// ShouldOverrideSiteInstanceForNavigation will be called more than once
|
||||||
|
// during a navigation (currently twice, on request and when it's about
|
||||||
|
// to commit in the renderer), look at
|
||||||
|
// RenderFrameHostManager::GetFrameHostForNavigation.
|
||||||
|
// In the default mode we should reuse the same site instance until the
|
||||||
// request commits otherwise it will get destroyed. Currently there is no
|
// request commits otherwise it will get destroyed. Currently there is no
|
||||||
// unique lifetime tracker for a navigation request during site instance
|
// unique lifetime tracker for a navigation request during site instance
|
||||||
// creation. We check for the state of the request, which should be one of
|
// creation. We check for the state of the request, which should be one of
|
||||||
// (WAITING_FOR_RENDERER_RESPONSE, STARTED, RESPONSE_STARTED, FAILED) along
|
// (WAITING_FOR_RENDERER_RESPONSE, STARTED, RESPONSE_STARTED, FAILED) along
|
||||||
// with the availability of a speculative render frame host.
|
// with the availability of a speculative render frame host.
|
||||||
if (has_request_started) {
|
if (has_response_started) {
|
||||||
*new_instance = current_instance;
|
return SiteInstanceForNavigationType::FORCE_CURRENT;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*new_instance = candidate_instance;
|
return SiteInstanceForNavigationType::FORCE_CANDIDATE_OR_NEW;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AtomBrowserClient::RegisterPendingSiteInstance(
|
||||||
|
content::RenderFrameHost* rfh,
|
||||||
|
content::SiteInstance* pending_site_instance) {
|
||||||
|
// Do we have an affinity site to manage?
|
||||||
|
ConsiderSiteInstanceForAffinity(rfh, pending_site_instance);
|
||||||
|
|
||||||
// Remember the original web contents for the pending renderer process.
|
// Remember the original web contents for the pending renderer process.
|
||||||
auto* pending_process = candidate_instance->GetProcess();
|
auto* web_contents = content::WebContents::FromRenderFrameHost(rfh);
|
||||||
|
auto* pending_process = pending_site_instance->GetProcess();
|
||||||
pending_processes_[pending_process->GetID()] = web_contents;
|
pending_processes_[pending_process->GetID()] = web_contents;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
void AtomBrowserClient::AppendExtraCommandLineSwitches(
|
||||||
|
@ -555,10 +624,10 @@ void AtomBrowserClient::SiteInstanceDeleting(
|
||||||
content::SiteInstance* site_instance) {
|
content::SiteInstance* site_instance) {
|
||||||
// We are storing weak_ptr, is it fundamental to maintain the map up-to-date
|
// We are storing weak_ptr, is it fundamental to maintain the map up-to-date
|
||||||
// when an instance is destroyed.
|
// when an instance is destroyed.
|
||||||
for (auto iter = site_per_affinities.begin();
|
for (auto iter = site_per_affinities_.begin();
|
||||||
iter != site_per_affinities.end(); ++iter) {
|
iter != site_per_affinities_.end(); ++iter) {
|
||||||
if (iter->second == site_instance) {
|
if (iter->second == site_instance) {
|
||||||
site_per_affinities.erase(iter);
|
site_per_affinities_.erase(iter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -786,7 +855,7 @@ void AtomBrowserClient::OnNetworkServiceCreated(
|
||||||
network_service);
|
network_service);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AtomBrowserClient::ShouldBypassCORB(int render_process_id) {
|
bool AtomBrowserClient::ShouldBypassCORB(int render_process_id) const {
|
||||||
// This is called on the network thread.
|
// This is called on the network thread.
|
||||||
base::AutoLock auto_lock(process_preferences_lock_);
|
base::AutoLock auto_lock(process_preferences_lock_);
|
||||||
auto it = process_preferences_.find(render_process_id);
|
auto it = process_preferences_.find(render_process_id);
|
||||||
|
@ -799,4 +868,9 @@ std::string AtomBrowserClient::GetApplicationLocale() {
|
||||||
return *g_application_locale;
|
return *g_application_locale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AtomBrowserClient::ShouldEnableStrictSiteIsolation() {
|
||||||
|
// Enable site isolation. It is off by default in Chromium <= 69.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
|
@ -65,6 +65,9 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
||||||
// content::ContentBrowserClient:
|
// content::ContentBrowserClient:
|
||||||
std::string GetApplicationLocale() override;
|
std::string GetApplicationLocale() override;
|
||||||
|
|
||||||
|
// content::ContentBrowserClient:
|
||||||
|
bool ShouldEnableStrictSiteIsolation() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void RenderProcessWillLaunch(
|
void RenderProcessWillLaunch(
|
||||||
content::RenderProcessHost* host,
|
content::RenderProcessHost* host,
|
||||||
|
@ -73,13 +76,16 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
||||||
CreateSpeechRecognitionManagerDelegate() override;
|
CreateSpeechRecognitionManagerDelegate() override;
|
||||||
void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
void OverrideWebkitPrefs(content::RenderViewHost* render_view_host,
|
||||||
content::WebPreferences* prefs) override;
|
content::WebPreferences* prefs) override;
|
||||||
void OverrideSiteInstanceForNavigation(
|
SiteInstanceForNavigationType ShouldOverrideSiteInstanceForNavigation(
|
||||||
content::RenderFrameHost* render_frame_host,
|
content::RenderFrameHost* current_rfh,
|
||||||
|
content::RenderFrameHost* speculative_rfh,
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
const GURL& dest_url,
|
const GURL& url,
|
||||||
bool has_request_started,
|
bool has_request_started,
|
||||||
content::SiteInstance* candidate_instance,
|
content::SiteInstance** affinity_site_instance) const override;
|
||||||
content::SiteInstance** new_instance) override;
|
void RegisterPendingSiteInstance(
|
||||||
|
content::RenderFrameHost* render_frame_host,
|
||||||
|
content::SiteInstance* pending_site_instance) override;
|
||||||
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
|
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
|
||||||
int child_process_id) override;
|
int child_process_id) override;
|
||||||
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
|
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
|
||||||
|
@ -144,7 +150,7 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
||||||
GetSystemSharedURLLoaderFactory() override;
|
GetSystemSharedURLLoaderFactory() override;
|
||||||
void OnNetworkServiceCreated(
|
void OnNetworkServiceCreated(
|
||||||
network::mojom::NetworkService* network_service) override;
|
network::mojom::NetworkService* network_service) override;
|
||||||
bool ShouldBypassCORB(int render_process_id) override;
|
bool ShouldBypassCORB(int render_process_id) const override;
|
||||||
|
|
||||||
// content::RenderProcessHostObserver:
|
// content::RenderProcessHostObserver:
|
||||||
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
|
void RenderProcessHostDestroyed(content::RenderProcessHost* host) override;
|
||||||
|
@ -169,16 +175,30 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
||||||
bool web_security = true;
|
bool web_security = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool ShouldCreateNewSiteInstance(content::RenderFrameHost* render_frame_host,
|
bool ShouldForceNewSiteInstance(content::RenderFrameHost* current_rfh,
|
||||||
|
content::RenderFrameHost* speculative_rfh,
|
||||||
|
content::BrowserContext* browser_context,
|
||||||
|
const GURL& dest_url,
|
||||||
|
bool has_request_started) const;
|
||||||
|
bool NavigationWasRedirectedCrossSite(
|
||||||
content::BrowserContext* browser_context,
|
content::BrowserContext* browser_context,
|
||||||
content::SiteInstance* current_instance,
|
content::SiteInstance* current_instance,
|
||||||
const GURL& dest_url);
|
content::SiteInstance* speculative_instance,
|
||||||
|
const GURL& dest_url,
|
||||||
|
bool has_request_started) const;
|
||||||
void AddProcessPreferences(int process_id, ProcessPreferences prefs);
|
void AddProcessPreferences(int process_id, ProcessPreferences prefs);
|
||||||
void RemoveProcessPreferences(int process_id);
|
void RemoveProcessPreferences(int process_id);
|
||||||
bool IsProcessObserved(int process_id);
|
bool IsProcessObserved(int process_id) const;
|
||||||
bool IsRendererSandboxed(int process_id);
|
bool IsRendererSandboxed(int process_id) const;
|
||||||
bool RendererUsesNativeWindowOpen(int process_id);
|
bool RendererUsesNativeWindowOpen(int process_id) const;
|
||||||
bool RendererDisablesPopups(int process_id);
|
bool RendererDisablesPopups(int process_id) const;
|
||||||
|
std::string GetAffinityPreference(content::RenderFrameHost* rfh) const;
|
||||||
|
content::SiteInstance* GetSiteInstanceFromAffinity(
|
||||||
|
content::BrowserContext* browser_context,
|
||||||
|
const GURL& url,
|
||||||
|
content::RenderFrameHost* rfh) const;
|
||||||
|
void ConsiderSiteInstanceForAffinity(content::RenderFrameHost* rfh,
|
||||||
|
content::SiteInstance* site_instance);
|
||||||
|
|
||||||
// pending_render_process => web contents.
|
// pending_render_process => web contents.
|
||||||
std::map<int, content::WebContents*> pending_processes_;
|
std::map<int, content::WebContents*> pending_processes_;
|
||||||
|
@ -186,7 +206,7 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
||||||
std::map<int, base::ProcessId> render_process_host_pids_;
|
std::map<int, base::ProcessId> render_process_host_pids_;
|
||||||
|
|
||||||
// list of site per affinity. weak_ptr to prevent instance locking
|
// list of site per affinity. weak_ptr to prevent instance locking
|
||||||
std::map<std::string, content::SiteInstance*> site_per_affinities;
|
std::map<std::string, content::SiteInstance*> site_per_affinities_;
|
||||||
|
|
||||||
std::unique_ptr<AtomResourceDispatcherHostDelegate>
|
std::unique_ptr<AtomResourceDispatcherHostDelegate>
|
||||||
resource_dispatcher_host_delegate_;
|
resource_dispatcher_host_delegate_;
|
||||||
|
@ -196,7 +216,7 @@ class AtomBrowserClient : public content::ContentBrowserClient,
|
||||||
|
|
||||||
Delegate* delegate_ = nullptr;
|
Delegate* delegate_ = nullptr;
|
||||||
|
|
||||||
base::Lock process_preferences_lock_;
|
mutable base::Lock process_preferences_lock_;
|
||||||
std::map<int, ProcessPreferences> process_preferences_;
|
std::map<int, ProcessPreferences> process_preferences_;
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
DISALLOW_COPY_AND_ASSIGN(AtomBrowserClient);
|
||||||
|
|
|
@ -90,9 +90,9 @@ const setupGuest = function (embedder, frameName, guest, options) {
|
||||||
}
|
}
|
||||||
const closedByUser = function () {
|
const closedByUser = function () {
|
||||||
embedder._sendInternal('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId)
|
embedder._sendInternal('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_' + guestId)
|
||||||
embedder.removeListener('render-view-deleted', closedByEmbedder)
|
embedder.removeListener('current-render-view-deleted', closedByEmbedder)
|
||||||
}
|
}
|
||||||
embedder.once('render-view-deleted', closedByEmbedder)
|
embedder.once('current-render-view-deleted', closedByEmbedder)
|
||||||
guest.once('closed', closedByUser)
|
guest.once('closed', closedByUser)
|
||||||
if (frameName) {
|
if (frameName) {
|
||||||
frameToGuest.set(frameName, guest)
|
frameToGuest.set(frameName, guest)
|
||||||
|
@ -118,28 +118,12 @@ const createGuest = function (embedder, url, referrer, frameName, options, postD
|
||||||
}
|
}
|
||||||
|
|
||||||
guest = new BrowserWindow(options)
|
guest = new BrowserWindow(options)
|
||||||
if (!options.webContents || url !== 'about:blank') {
|
if (!options.webContents) {
|
||||||
// We should not call `loadURL` if the window was constructed from an
|
// We should not call `loadURL` if the window was constructed from an
|
||||||
// existing webContents(window.open in a sandboxed renderer) and if the url
|
// existing webContents (window.open in a sandboxed renderer).
|
||||||
// is not 'about:blank'.
|
|
||||||
//
|
//
|
||||||
// Navigating to the url when creating the window from an existing
|
// Navigating to the url when creating the window from an existing
|
||||||
// webContents would not be necessary(it will navigate there anyway), but
|
// webContents is not necessary (it will navigate there anyway).
|
||||||
// apparently there's a bug that allows the child window to be scripted by
|
|
||||||
// the opener, even when the child window is from another origin.
|
|
||||||
//
|
|
||||||
// That's why the second condition(url !== "about:blank") is required: to
|
|
||||||
// force `OverrideSiteInstanceForNavigation` to be called and consequently
|
|
||||||
// spawn a new renderer if the new window is targeting a different origin.
|
|
||||||
//
|
|
||||||
// If the URL is "about:blank", then it is very likely that the opener just
|
|
||||||
// wants to synchronously script the popup, for example:
|
|
||||||
//
|
|
||||||
// let popup = window.open()
|
|
||||||
// popup.document.body.write('<h1>hello</h1>')
|
|
||||||
//
|
|
||||||
// The above code would not work if a navigation to "about:blank" is done
|
|
||||||
// here, since the window would be cleared of all changes in the next tick.
|
|
||||||
const loadOptions = {
|
const loadOptions = {
|
||||||
httpReferrer: referrer
|
httpReferrer: referrer
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,14 @@ index 907922701280b589bf11691342de0ec95cdec6a1..eaf8bac18f8e3a2735ce7ded60619909
|
||||||
}
|
}
|
||||||
|
|
||||||
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
|
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
|
||||||
index bb54b89bef5c6f32e7b4a056336c85494e2a04de..f069dfc4d2823b22eb0d90d28bc20236aeeddd04 100644
|
index f713d0cfbf90665d921f56f4d828887ad1f7842c..4fe21468aee93a7cb3783220ebfe8dd100a3d1d5 100644
|
||||||
--- a/content/public/browser/content_browser_client.cc
|
--- a/content/public/browser/content_browser_client.cc
|
||||||
+++ b/content/public/browser/content_browser_client.cc
|
+++ b/content/public/browser/content_browser_client.cc
|
||||||
@@ -47,6 +47,10 @@ void OverrideOnBindInterface(const service_manager::BindSourceInfo& remote_info,
|
@@ -57,6 +57,10 @@ ContentBrowserClient::SiteInstanceForNavigationType ContentBrowserClient::Should
|
||||||
handle);
|
return SiteInstanceForNavigationType::ASK_CHROMIUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
+bool ContentBrowserClient::ShouldBypassCORB(int render_process_id) {
|
+bool ContentBrowserClient::ShouldBypassCORB(int render_process_id) const {
|
||||||
+ return false;
|
+ return false;
|
||||||
+}
|
+}
|
||||||
+
|
+
|
||||||
|
@ -37,15 +37,15 @@ index bb54b89bef5c6f32e7b4a056336c85494e2a04de..f069dfc4d2823b22eb0d90d28bc20236
|
||||||
const MainFunctionParams& parameters) {
|
const MainFunctionParams& parameters) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
|
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
|
||||||
index 2c22cb1cfe0dddc97c00e5f4ff89de6b18bc232f..a7b59095a887d566af9e74a646443fb49ea23bfc 100644
|
index 4bf6b2b5f8110f539adc61858cfdc8f77f7ed08b..94454812e27d4d357eeee27cfc1e185386ea2003 100644
|
||||||
--- a/content/public/browser/content_browser_client.h
|
--- a/content/public/browser/content_browser_client.h
|
||||||
+++ b/content/public/browser/content_browser_client.h
|
+++ b/content/public/browser/content_browser_client.h
|
||||||
@@ -205,6 +205,9 @@ class CONTENT_EXPORT ContentBrowserClient {
|
@@ -225,6 +225,9 @@ class CONTENT_EXPORT ContentBrowserClient {
|
||||||
SiteInstance* candidate_site_instance,
|
content::RenderFrameHost* rfh,
|
||||||
SiteInstance** new_instance) {}
|
content::SiteInstance* pending_site_instance){};
|
||||||
|
|
||||||
+ // Electron: Allows bypassing CORB checks for a renderer process.
|
+ // Electron: Allows bypassing CORB checks for a renderer process.
|
||||||
+ virtual bool ShouldBypassCORB(int render_process_id);
|
+ virtual bool ShouldBypassCORB(int render_process_id) const;
|
||||||
+
|
+
|
||||||
// Allows the embedder to set any number of custom BrowserMainParts
|
// Allows the embedder to set any number of custom BrowserMainParts
|
||||||
// implementations for the browser startup code. See comments in
|
// implementations for the browser startup code. See comments in
|
||||||
|
|
|
@ -7,10 +7,10 @@ Allows embedder to intercept site instances chosen by chromium
|
||||||
and respond with custom instance.
|
and respond with custom instance.
|
||||||
|
|
||||||
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
|
diff --git a/content/browser/frame_host/render_frame_host_manager.cc b/content/browser/frame_host/render_frame_host_manager.cc
|
||||||
index 872e4609c94f1e052d623ae57c1279c72eb2c3f4..a59676004f2411631418bf12e2978623b9b27b53 100644
|
index 872e4609c94f1e052d623ae57c1279c72eb2c3f4..39d26adb60c50f88d19e824846519338083dc166 100644
|
||||||
--- a/content/browser/frame_host/render_frame_host_manager.cc
|
--- a/content/browser/frame_host/render_frame_host_manager.cc
|
||||||
+++ b/content/browser/frame_host/render_frame_host_manager.cc
|
+++ b/content/browser/frame_host/render_frame_host_manager.cc
|
||||||
@@ -1960,6 +1960,18 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
@@ -1960,6 +1960,17 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||||
bool was_server_redirect = request.navigation_handle() &&
|
bool was_server_redirect = request.navigation_handle() &&
|
||||||
request.navigation_handle()->WasServerRedirect();
|
request.navigation_handle()->WasServerRedirect();
|
||||||
|
|
||||||
|
@ -23,13 +23,12 @@ index 872e4609c94f1e052d623ae57c1279c72eb2c3f4..a59676004f2411631418bf12e2978623
|
||||||
+ scoped_refptr<SiteInstance> candidate_site_instance =
|
+ scoped_refptr<SiteInstance> candidate_site_instance =
|
||||||
+ speculative_render_frame_host_
|
+ speculative_render_frame_host_
|
||||||
+ ? speculative_render_frame_host_->GetSiteInstance()
|
+ ? speculative_render_frame_host_->GetSiteInstance()
|
||||||
+ : content::SiteInstance::CreateForURL(browser_context,
|
+ : nullptr;
|
||||||
+ request.common_params().url);
|
|
||||||
+
|
+
|
||||||
if (frame_tree_node_->IsMainFrame()) {
|
if (frame_tree_node_->IsMainFrame()) {
|
||||||
// Renderer-initiated main frame navigations that may require a
|
// Renderer-initiated main frame navigations that may require a
|
||||||
// SiteInstance swap are sent to the browser via the OpenURL IPC and are
|
// SiteInstance swap are sent to the browser via the OpenURL IPC and are
|
||||||
@@ -1979,6 +1991,19 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
@@ -1979,6 +1990,51 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||||
request.common_params().url));
|
request.common_params().url));
|
||||||
no_renderer_swap_allowed |=
|
no_renderer_swap_allowed |=
|
||||||
request.from_begin_navigation() && !can_renderer_initiate_transfer;
|
request.from_begin_navigation() && !can_renderer_initiate_transfer;
|
||||||
|
@ -39,17 +38,49 @@ index 872e4609c94f1e052d623ae57c1279c72eb2c3f4..a59676004f2411631418bf12e2978623
|
||||||
+ request.state() == NavigationRequest::FAILED) &&
|
+ request.state() == NavigationRequest::FAILED) &&
|
||||||
+ !speculative_render_frame_host_;
|
+ !speculative_render_frame_host_;
|
||||||
+ // Gives user a chance to choose a custom site instance.
|
+ // Gives user a chance to choose a custom site instance.
|
||||||
+ SiteInstance* client_custom_instance = nullptr;
|
+ SiteInstance* affinity_site_instance = nullptr;
|
||||||
+ GetContentClient()->browser()->OverrideSiteInstanceForNavigation(
|
+ scoped_refptr<SiteInstance> overriden_site_instance;
|
||||||
+ render_frame_host_.get(), browser_context, request.common_params().url,
|
+ ContentBrowserClient::SiteInstanceForNavigationType siteInstanceType =
|
||||||
+ has_response_started, candidate_site_instance.get(),
|
+ GetContentClient()->browser()->ShouldOverrideSiteInstanceForNavigation(
|
||||||
+ &client_custom_instance);
|
+ current_frame_host(), speculative_frame_host(), browser_context,
|
||||||
+ if (client_custom_instance)
|
+ request.common_params().url, has_response_started,
|
||||||
+ return scoped_refptr<SiteInstance>(client_custom_instance);
|
+ &affinity_site_instance);
|
||||||
|
+ switch (siteInstanceType) {
|
||||||
|
+ case ContentBrowserClient::SiteInstanceForNavigationType::
|
||||||
|
+ FORCE_CANDIDATE_OR_NEW:
|
||||||
|
+ overriden_site_instance =
|
||||||
|
+ candidate_site_instance
|
||||||
|
+ ? candidate_site_instance
|
||||||
|
+ : SiteInstance::CreateForURL(browser_context,
|
||||||
|
+ request.common_params().url);
|
||||||
|
+ break;
|
||||||
|
+ case ContentBrowserClient::SiteInstanceForNavigationType::FORCE_CURRENT:
|
||||||
|
+ overriden_site_instance = render_frame_host_->GetSiteInstance();
|
||||||
|
+ break;
|
||||||
|
+ case ContentBrowserClient::SiteInstanceForNavigationType::FORCE_AFFINITY:
|
||||||
|
+ DCHECK(affinity_site_instance);
|
||||||
|
+ overriden_site_instance =
|
||||||
|
+ scoped_refptr<SiteInstance>(affinity_site_instance);
|
||||||
|
+ break;
|
||||||
|
+ case ContentBrowserClient::SiteInstanceForNavigationType::ASK_CHROMIUM:
|
||||||
|
+ DCHECK(!affinity_site_instance);
|
||||||
|
+ break;
|
||||||
|
+ default:
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ if (overriden_site_instance) {
|
||||||
|
+ if (siteInstanceType ==
|
||||||
|
+ ContentBrowserClient::SiteInstanceForNavigationType::
|
||||||
|
+ FORCE_CANDIDATE_OR_NEW) {
|
||||||
|
+ GetContentClient()->browser()->RegisterPendingSiteInstance(
|
||||||
|
+ render_frame_host_.get(), overriden_site_instance.get());
|
||||||
|
+ }
|
||||||
|
+ return overriden_site_instance;
|
||||||
|
+ }
|
||||||
} else {
|
} else {
|
||||||
// Subframe navigations will use the current renderer, unless specifically
|
// Subframe navigations will use the current renderer, unless specifically
|
||||||
// allowed to swap processes.
|
// allowed to swap processes.
|
||||||
@@ -1990,18 +2015,9 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
@@ -1990,23 +2046,17 @@ RenderFrameHostManager::GetSiteInstanceForNavigationRequest(
|
||||||
if (no_renderer_swap_allowed)
|
if (no_renderer_swap_allowed)
|
||||||
return scoped_refptr<SiteInstance>(current_site_instance);
|
return scoped_refptr<SiteInstance>(current_site_instance);
|
||||||
|
|
||||||
|
@ -69,22 +100,73 @@ index 872e4609c94f1e052d623ae57c1279c72eb2c3f4..a59676004f2411631418bf12e2978623
|
||||||
request.common_params().transition,
|
request.common_params().transition,
|
||||||
request.state() == NavigationRequest::FAILED,
|
request.state() == NavigationRequest::FAILED,
|
||||||
request.restore_type() != RestoreType::NONE, request.is_view_source(),
|
request.restore_type() != RestoreType::NONE, request.is_view_source(),
|
||||||
|
was_server_redirect);
|
||||||
|
|
||||||
|
+ GetContentClient()->browser()->RegisterPendingSiteInstance(
|
||||||
|
+ render_frame_host_.get(), dest_site_instance.get());
|
||||||
|
+
|
||||||
|
return dest_site_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/content/public/browser/content_browser_client.cc b/content/public/browser/content_browser_client.cc
|
||||||
|
index bb54b89bef5c6f32e7b4a056336c85494e2a04de..f713d0cfbf90665d921f56f4d828887ad1f7842c 100644
|
||||||
|
--- a/content/public/browser/content_browser_client.cc
|
||||||
|
+++ b/content/public/browser/content_browser_client.cc
|
||||||
|
@@ -47,6 +47,16 @@ void OverrideOnBindInterface(const service_manager::BindSourceInfo& remote_info,
|
||||||
|
handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ContentBrowserClient::SiteInstanceForNavigationType ContentBrowserClient::ShouldOverrideSiteInstanceForNavigation(
|
||||||
|
+ content::RenderFrameHost* current_rfh,
|
||||||
|
+ content::RenderFrameHost* speculative_rfh,
|
||||||
|
+ content::BrowserContext* browser_context,
|
||||||
|
+ const GURL& url,
|
||||||
|
+ bool has_request_started,
|
||||||
|
+ content::SiteInstance** affinity_site_instance) const {
|
||||||
|
+ return SiteInstanceForNavigationType::ASK_CHROMIUM;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
BrowserMainParts* ContentBrowserClient::CreateBrowserMainParts(
|
||||||
|
const MainFunctionParams& parameters) {
|
||||||
|
return nullptr;
|
||||||
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
|
diff --git a/content/public/browser/content_browser_client.h b/content/public/browser/content_browser_client.h
|
||||||
index 3be31602689cb93b965729cc4e35cf6d23a8ec2f..2c22cb1cfe0dddc97c00e5f4ff89de6b18bc232f 100644
|
index 3be31602689cb93b965729cc4e35cf6d23a8ec2f..4bf6b2b5f8110f539adc61858cfdc8f77f7ed08b 100644
|
||||||
--- a/content/public/browser/content_browser_client.h
|
--- a/content/public/browser/content_browser_client.h
|
||||||
+++ b/content/public/browser/content_browser_client.h
|
+++ b/content/public/browser/content_browser_client.h
|
||||||
@@ -196,6 +196,15 @@ class CONTENT_EXPORT ContentBrowserClient {
|
@@ -194,8 +194,37 @@ CONTENT_EXPORT void OverrideOnBindInterface(
|
||||||
|
// the observer interfaces.)
|
||||||
|
class CONTENT_EXPORT ContentBrowserClient {
|
||||||
public:
|
public:
|
||||||
|
+ // Identifies the type of site instance to use for a navigation.
|
||||||
|
+ enum SiteInstanceForNavigationType {
|
||||||
|
+ // Use either the candidate site instance or, if it doesn't exist
|
||||||
|
+ // a new, unrelated site instance for the navigation.
|
||||||
|
+ FORCE_CANDIDATE_OR_NEW = 0,
|
||||||
|
+
|
||||||
|
+ // Use the current site instance for the navigation.
|
||||||
|
+ FORCE_CURRENT,
|
||||||
|
+
|
||||||
|
+ // Use the provided affinity site instance for the navigation.
|
||||||
|
+ FORCE_AFFINITY,
|
||||||
|
+
|
||||||
|
+ // Delegate the site instance creation to Chromium.
|
||||||
|
+ ASK_CHROMIUM
|
||||||
|
+ };
|
||||||
virtual ~ContentBrowserClient() {}
|
virtual ~ContentBrowserClient() {}
|
||||||
|
|
||||||
+ // Electron: Allows overriding the SiteInstance when navigating.
|
+ // Electron: Allows overriding the SiteInstance when navigating.
|
||||||
+ virtual void OverrideSiteInstanceForNavigation(
|
+ virtual SiteInstanceForNavigationType ShouldOverrideSiteInstanceForNavigation(
|
||||||
+ RenderFrameHost* render_frame_host,
|
+ content::RenderFrameHost* current_rfh,
|
||||||
+ BrowserContext* browser_context,
|
+ content::RenderFrameHost* speculative_rfh,
|
||||||
+ const GURL& dest_url,
|
+ content::BrowserContext* browser_context,
|
||||||
+ bool has_response_started,
|
+ const GURL& url,
|
||||||
+ SiteInstance* candidate_site_instance,
|
+ bool has_request_started,
|
||||||
+ SiteInstance** new_instance) {}
|
+ content::SiteInstance** affinity_site_instance) const;
|
||||||
|
+
|
||||||
|
+ // Electron: Registers a pending site instance during a navigation.
|
||||||
|
+ virtual void RegisterPendingSiteInstance(
|
||||||
|
+ content::RenderFrameHost* rfh,
|
||||||
|
+ content::SiteInstance* pending_site_instance){};
|
||||||
+
|
+
|
||||||
// Allows the embedder to set any number of custom BrowserMainParts
|
// Allows the embedder to set any number of custom BrowserMainParts
|
||||||
// implementations for the browser startup code. See comments in
|
// implementations for the browser startup code. See comments in
|
||||||
|
|
|
@ -26,10 +26,11 @@ describe('BrowserWindow with affinity module', () => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
describe(`BrowserWindow with an affinity '${myAffinityName}'`, () => {
|
function testAffinityProcessIds (name, webPreferences = {}) {
|
||||||
|
describe(name, () => {
|
||||||
let mAffinityWindow
|
let mAffinityWindow
|
||||||
before(done => {
|
before(done => {
|
||||||
createWindowWithWebPrefs({ affinity: myAffinityName })
|
createWindowWithWebPrefs({ affinity: myAffinityName, ...webPreferences })
|
||||||
.then((w) => {
|
.then((w) => {
|
||||||
mAffinityWindow = w
|
mAffinityWindow = w
|
||||||
done()
|
done()
|
||||||
|
@ -44,7 +45,7 @@ describe('BrowserWindow with affinity module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should have a different process id than a default window', done => {
|
it('should have a different process id than a default window', done => {
|
||||||
createWindowWithWebPrefs({})
|
createWindowWithWebPrefs({ ...webPreferences })
|
||||||
.then(w => {
|
.then(w => {
|
||||||
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
||||||
const wcID = w.webContents.getOSProcessId()
|
const wcID = w.webContents.getOSProcessId()
|
||||||
|
@ -55,7 +56,7 @@ describe('BrowserWindow with affinity module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it(`should have a different process id than a window with a different affinity '${anotherAffinityName}'`, done => {
|
it(`should have a different process id than a window with a different affinity '${anotherAffinityName}'`, done => {
|
||||||
createWindowWithWebPrefs({ affinity: anotherAffinityName })
|
createWindowWithWebPrefs({ affinity: anotherAffinityName, ...webPreferences })
|
||||||
.then(w => {
|
.then(w => {
|
||||||
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
||||||
const wcID = w.webContents.getOSProcessId()
|
const wcID = w.webContents.getOSProcessId()
|
||||||
|
@ -66,7 +67,7 @@ describe('BrowserWindow with affinity module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it(`should have the same OS process id than a window with the same affinity '${myAffinityName}'`, done => {
|
it(`should have the same OS process id than a window with the same affinity '${myAffinityName}'`, done => {
|
||||||
createWindowWithWebPrefs({ affinity: myAffinityName })
|
createWindowWithWebPrefs({ affinity: myAffinityName, ...webPreferences })
|
||||||
.then(w => {
|
.then(w => {
|
||||||
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
||||||
const wcID = w.webContents.getOSProcessId()
|
const wcID = w.webContents.getOSProcessId()
|
||||||
|
@ -77,7 +78,7 @@ describe('BrowserWindow with affinity module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it(`should have the same OS process id than a window with an equivalent affinity '${myAffinityNameUpper}' (case insensitive)`, done => {
|
it(`should have the same OS process id than a window with an equivalent affinity '${myAffinityNameUpper}' (case insensitive)`, done => {
|
||||||
createWindowWithWebPrefs({ affinity: myAffinityNameUpper })
|
createWindowWithWebPrefs({ affinity: myAffinityNameUpper, ...webPreferences })
|
||||||
.then(w => {
|
.then(w => {
|
||||||
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
const affinityID = mAffinityWindow.webContents.getOSProcessId()
|
||||||
const wcID = w.webContents.getOSProcessId()
|
const wcID = w.webContents.getOSProcessId()
|
||||||
|
@ -87,6 +88,11 @@ describe('BrowserWindow with affinity module', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
testAffinityProcessIds(`BrowserWindow with an affinity '${myAffinityName}'`)
|
||||||
|
testAffinityProcessIds(`BrowserWindow with an affinity '${myAffinityName}' and sandbox enabled`, { sandbox: true })
|
||||||
|
testAffinityProcessIds(`BrowserWindow with an affinity '${myAffinityName}' and nativeWindowOpen enabled`, { nativeWindowOpen: true })
|
||||||
|
|
||||||
describe(`BrowserWindow with an affinity : nodeIntegration=false`, () => {
|
describe(`BrowserWindow with an affinity : nodeIntegration=false`, () => {
|
||||||
const preload = path.join(fixtures, 'module', 'send-later.js')
|
const preload = path.join(fixtures, 'module', 'send-later.js')
|
||||||
|
|
|
@ -90,6 +90,8 @@ describe('BrowserWindow module', () => {
|
||||||
res.end()
|
res.end()
|
||||||
} else if (req.url === '/navigate-302') {
|
} else if (req.url === '/navigate-302') {
|
||||||
res.end(`<html><body><script>window.location='${server.url}/302'</script></body></html>`)
|
res.end(`<html><body><script>window.location='${server.url}/302'</script></body></html>`)
|
||||||
|
} else if (req.url === '/cross-site') {
|
||||||
|
res.end(`<html><body><h1>${req.url}</h1></body></html>`)
|
||||||
} else {
|
} else {
|
||||||
res.end()
|
res.end()
|
||||||
}
|
}
|
||||||
|
@ -1470,29 +1472,6 @@ describe('BrowserWindow module', () => {
|
||||||
|
|
||||||
const preload = path.join(fixtures, 'module', 'preload-sandbox.js')
|
const preload = path.join(fixtures, 'module', 'preload-sandbox.js')
|
||||||
|
|
||||||
// http protocol to simulate accessing another domain. This is required
|
|
||||||
// because the code paths for cross domain popups is different.
|
|
||||||
function crossDomainHandler (request, callback) {
|
|
||||||
// Disabled due to false positive in StandardJS
|
|
||||||
// eslint-disable-next-line standard/no-callback-literal
|
|
||||||
callback({
|
|
||||||
mimeType: 'text/html',
|
|
||||||
data: `<html><body><h1>${request.url}</h1></body></html>`
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
before((done) => {
|
|
||||||
protocol.interceptStringProtocol('http', crossDomainHandler, () => {
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
after((done) => {
|
|
||||||
protocol.uninterceptProtocol('http', () => {
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
it('exposes ipcRenderer to preload script', (done) => {
|
it('exposes ipcRenderer to preload script', (done) => {
|
||||||
ipcMain.once('answer', function (event, test) {
|
ipcMain.once('answer', function (event, test) {
|
||||||
assert.strictEqual(test, 'preload')
|
assert.strictEqual(test, 'preload')
|
||||||
|
@ -1587,35 +1566,53 @@ describe('BrowserWindow module', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
ipcRenderer.send('set-web-preferences-on-next-new-window', w.webContents.id, 'preload', preload)
|
ipcRenderer.send('set-web-preferences-on-next-new-window', w.webContents.id, 'preload', preload)
|
||||||
|
const openerWindowOpen = emittedOnce(ipcMain, 'opener-loaded')
|
||||||
|
w.loadFile(
|
||||||
|
path.join(fixtures, 'api', 'sandbox.html'),
|
||||||
|
{ search: 'window-open-external' }
|
||||||
|
)
|
||||||
|
|
||||||
|
// Wait for a message from the main window saying that it's ready.
|
||||||
|
await openerWindowOpen
|
||||||
|
|
||||||
|
// Ask the opener to open a popup with window.opener.
|
||||||
|
const expectedPopupUrl = `${server.url}/cross-site` // Set in "sandbox.html".
|
||||||
|
|
||||||
const browserWindowCreated = emittedOnce(app, 'browser-window-created')
|
const browserWindowCreated = emittedOnce(app, 'browser-window-created')
|
||||||
const childLoaded = emittedOnce(ipcMain, 'child-loaded')
|
w.webContents.send('open-the-popup', expectedPopupUrl)
|
||||||
w.loadFile(path.join(fixtures, 'api', 'sandbox.html'), { search: 'window-open-external' })
|
|
||||||
const expectedPopupUrl = 'http://www.google.com/#q=electron' // Set in the "sandbox.html".
|
|
||||||
|
|
||||||
// The page is going to open a popup that it won't be able to close.
|
// The page is going to open a popup that it won't be able to close.
|
||||||
// We have to close it from here later.
|
// We have to close it from here later.
|
||||||
// XXX(alexeykuzmin): It will leak if the test fails too soon.
|
// XXX(alexeykuzmin): It will leak if the test fails too soon.
|
||||||
const [, popupWindow] = await browserWindowCreated
|
const [, popupWindow] = await browserWindowCreated
|
||||||
|
|
||||||
// Wait for a message from the popup's preload script.
|
// Ask the popup window for details.
|
||||||
const [, openerIsNull, html, locationHref] = await childLoaded
|
const detailsAnswer = emittedOnce(ipcMain, 'child-loaded')
|
||||||
expect(openerIsNull).to.be.true('window.opener is not null')
|
popupWindow.webContents.send('provide-details')
|
||||||
expect(html).to.equal(`<h1>${expectedPopupUrl}</h1>`,
|
const [, openerIsNull, , locationHref] = await detailsAnswer
|
||||||
'looks like a http: request has not been intercepted locally')
|
expect(openerIsNull).to.be.false('window.opener is null')
|
||||||
expect(locationHref).to.equal(expectedPopupUrl)
|
expect(locationHref).to.equal(expectedPopupUrl)
|
||||||
|
|
||||||
// Ask the page to access the popup.
|
// Ask the page to access the popup.
|
||||||
const answer = emittedOnce(ipcMain, 'answer')
|
const touchPopupResult = emittedOnce(ipcMain, 'answer')
|
||||||
w.webContents.send('touch-the-popup')
|
w.webContents.send('touch-the-popup')
|
||||||
const [, exceptionMessage] = await answer
|
const [, popupAccessMessage] = await touchPopupResult
|
||||||
|
|
||||||
|
// Ask the popup to access the opener.
|
||||||
|
const touchOpenerResult = emittedOnce(ipcMain, 'answer')
|
||||||
|
popupWindow.webContents.send('touch-the-opener')
|
||||||
|
const [, openerAccessMessage] = await touchOpenerResult
|
||||||
|
|
||||||
// We don't need the popup anymore, and its parent page can't close it,
|
// We don't need the popup anymore, and its parent page can't close it,
|
||||||
// so let's close it from here before we run any checks.
|
// so let's close it from here before we run any checks.
|
||||||
await closeWindow(popupWindow, { assertSingleWindow: false })
|
await closeWindow(popupWindow, { assertSingleWindow: false })
|
||||||
|
|
||||||
expect(exceptionMessage).to.be.a('string',
|
expect(popupAccessMessage).to.be.a('string',
|
||||||
`child's .document is accessible from its parent window`)
|
`child's .document is accessible from its parent window`)
|
||||||
expect(exceptionMessage).to.match(/^Blocked a frame with origin/)
|
expect(popupAccessMessage).to.match(/^Blocked a frame with origin/)
|
||||||
|
expect(openerAccessMessage).to.be.a('string',
|
||||||
|
`opener .document is accessible from a popup window`)
|
||||||
|
expect(openerAccessMessage).to.match(/^Blocked a frame with origin/)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should inherit the sandbox setting in opened windows', (done) => {
|
it('should inherit the sandbox setting in opened windows', (done) => {
|
||||||
|
|
|
@ -712,6 +712,85 @@ describe('webContents module', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('render view deleted events', () => {
|
||||||
|
let server = null
|
||||||
|
|
||||||
|
before((done) => {
|
||||||
|
server = http.createServer((req, res) => {
|
||||||
|
const respond = () => {
|
||||||
|
if (req.url === '/redirect-cross-site') {
|
||||||
|
res.setHeader('Location', `${server.cross_site_url}/redirected`)
|
||||||
|
res.statusCode = 302
|
||||||
|
res.end()
|
||||||
|
} else if (req.url === '/redirected') {
|
||||||
|
res.end('<html><script>window.localStorage</script></html>')
|
||||||
|
} else {
|
||||||
|
res.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(respond, 0)
|
||||||
|
})
|
||||||
|
server.listen(0, '127.0.0.1', () => {
|
||||||
|
server.url = `http://127.0.0.1:${server.address().port}`
|
||||||
|
server.cross_site_url = `http://localhost:${server.address().port}`
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
server.close()
|
||||||
|
server = null
|
||||||
|
})
|
||||||
|
|
||||||
|
it('does not emit current-render-view-deleted when speculative RVHs are deleted', (done) => {
|
||||||
|
let currentRenderViewDeletedEmitted = false
|
||||||
|
w.webContents.once('destroyed', () => {
|
||||||
|
assert.strictEqual(currentRenderViewDeletedEmitted, false, 'current-render-view-deleted was emitted')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
const renderViewDeletedHandler = () => {
|
||||||
|
currentRenderViewDeletedEmitted = true
|
||||||
|
}
|
||||||
|
w.webContents.on('current-render-view-deleted', renderViewDeletedHandler)
|
||||||
|
w.webContents.on('did-finish-load', (e) => {
|
||||||
|
w.webContents.removeListener('current-render-view-deleted', renderViewDeletedHandler)
|
||||||
|
w.close()
|
||||||
|
})
|
||||||
|
w.loadURL(`${server.url}/redirect-cross-site`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits current-render-view-deleted if the current RVHs are deleted', (done) => {
|
||||||
|
let currentRenderViewDeletedEmitted = false
|
||||||
|
w.webContents.once('destroyed', () => {
|
||||||
|
assert.strictEqual(currentRenderViewDeletedEmitted, true, 'current-render-view-deleted wasn\'t emitted')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.webContents.on('current-render-view-deleted', () => {
|
||||||
|
currentRenderViewDeletedEmitted = true
|
||||||
|
})
|
||||||
|
w.webContents.on('did-finish-load', (e) => {
|
||||||
|
w.close()
|
||||||
|
})
|
||||||
|
w.loadURL(`${server.url}/redirect-cross-site`)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('emits render-view-deleted if any RVHs are deleted', (done) => {
|
||||||
|
let rvhDeletedCount = 0
|
||||||
|
w.webContents.once('destroyed', () => {
|
||||||
|
const expectedRenderViewDeletedEventCount = 3 // 1 speculative upon redirection + 2 upon window close.
|
||||||
|
assert.strictEqual(rvhDeletedCount, expectedRenderViewDeletedEventCount, 'render-view-deleted wasn\'t emitted the expected nr. of times')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.webContents.on('render-view-deleted', () => {
|
||||||
|
rvhDeletedCount++
|
||||||
|
})
|
||||||
|
w.webContents.on('did-finish-load', (e) => {
|
||||||
|
w.close()
|
||||||
|
})
|
||||||
|
w.loadURL(`${server.url}/redirect-cross-site`)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('setIgnoreMenuShortcuts(ignore)', () => {
|
describe('setIgnoreMenuShortcuts(ignore)', () => {
|
||||||
it('does not throw', () => {
|
it('does not throw', () => {
|
||||||
assert.strictEqual(w.webContents.setIgnoreMenuShortcuts(true), undefined)
|
assert.strictEqual(w.webContents.setIgnoreMenuShortcuts(true), undefined)
|
||||||
|
|
|
@ -1016,17 +1016,21 @@ describe('chromium feature', () => {
|
||||||
contents = null
|
contents = null
|
||||||
})
|
})
|
||||||
|
|
||||||
// FIXME(deepak1556): Disabled with site isolation ON
|
it('cannot access localStorage', (done) => {
|
||||||
// Localstorage area is accessed on the browser process
|
contents.on('crashed', (event, killed) => {
|
||||||
// before checking accessibility on the renderer side,
|
// Site isolation ON: process is killed for trying to access resources without permission.
|
||||||
// causing illegal origin access renderer termination.
|
if (process.platform !== 'win32') {
|
||||||
xit('cannot access localStorage', (done) => {
|
// Chromium on Windows does not set this flag correctly.
|
||||||
ipcMain.once('local-storage-response', (event, error) => {
|
assert.strictEqual(killed, true, 'Process should\'ve been killed')
|
||||||
assert.strictEqual(
|
}
|
||||||
error,
|
|
||||||
'Failed to read the \'localStorage\' property from \'Window\': Access is denied for this document.')
|
|
||||||
done()
|
done()
|
||||||
})
|
})
|
||||||
|
ipcMain.once('local-storage-response', (event, message) => {
|
||||||
|
// Site isolation OFF: access is refused.
|
||||||
|
assert.strictEqual(
|
||||||
|
message,
|
||||||
|
'Failed to read the \'localStorage\' property from \'Window\': Access is denied for this document.')
|
||||||
|
})
|
||||||
contents.loadURL(protocolName + '://host/localStorage')
|
contents.loadURL(protocolName + '://host/localStorage')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1066,6 +1070,59 @@ describe('chromium feature', () => {
|
||||||
contents.loadURL(`${protocolName}://host/cookie`)
|
contents.loadURL(`${protocolName}://host/cookie`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('can be accessed', () => {
|
||||||
|
let server = null
|
||||||
|
before((done) => {
|
||||||
|
server = http.createServer((req, res) => {
|
||||||
|
const respond = () => {
|
||||||
|
if (req.url === '/redirect-cross-site') {
|
||||||
|
res.setHeader('Location', `${server.cross_site_url}/redirected`)
|
||||||
|
res.statusCode = 302
|
||||||
|
res.end()
|
||||||
|
} else if (req.url === '/redirected') {
|
||||||
|
res.end('<html><script>window.localStorage</script></html>')
|
||||||
|
} else {
|
||||||
|
res.end()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(respond, 0)
|
||||||
|
})
|
||||||
|
server.listen(0, '127.0.0.1', () => {
|
||||||
|
server.url = `http://127.0.0.1:${server.address().port}`
|
||||||
|
server.cross_site_url = `http://localhost:${server.address().port}`
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after(() => {
|
||||||
|
server.close()
|
||||||
|
server = null
|
||||||
|
})
|
||||||
|
|
||||||
|
const testLocalStorageAfterXSiteRedirect = (testTitle, extraPreferences = {}) => {
|
||||||
|
it(testTitle, (done) => {
|
||||||
|
const webPreferences = { show: false, ...extraPreferences }
|
||||||
|
w = new BrowserWindow(webPreferences)
|
||||||
|
let redirected = false
|
||||||
|
w.webContents.on('crashed', () => {
|
||||||
|
assert.fail('renderer crashed / was killed')
|
||||||
|
})
|
||||||
|
w.webContents.on('did-redirect-navigation', (event, url) => {
|
||||||
|
assert.strictEqual(url, `${server.cross_site_url}/redirected`)
|
||||||
|
redirected = true
|
||||||
|
})
|
||||||
|
w.webContents.on('did-finish-load', () => {
|
||||||
|
assert.strictEqual(redirected, true, 'didnt redirect')
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
w.loadURL(`${server.url}/redirect-cross-site`)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
testLocalStorageAfterXSiteRedirect('after a cross-site redirect')
|
||||||
|
testLocalStorageAfterXSiteRedirect('after a cross-site redirect in sandbox mode', { sandbox: true })
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('websockets', () => {
|
describe('websockets', () => {
|
||||||
|
|
5
spec/fixtures/api/sandbox.html
vendored
5
spec/fixtures/api/sandbox.html
vendored
|
@ -81,6 +81,9 @@
|
||||||
},
|
},
|
||||||
'window-open-external': () => {
|
'window-open-external': () => {
|
||||||
addEventListener('load', () => {
|
addEventListener('load', () => {
|
||||||
|
ipcRenderer.once('open-the-popup', (event, url) => {
|
||||||
|
popup = open(url, '', 'top=65,left=55,width=505,height=605')
|
||||||
|
})
|
||||||
ipcRenderer.once('touch-the-popup', () => {
|
ipcRenderer.once('touch-the-popup', () => {
|
||||||
let errorMessage = null
|
let errorMessage = null
|
||||||
try {
|
try {
|
||||||
|
@ -90,7 +93,7 @@
|
||||||
}
|
}
|
||||||
ipcRenderer.send('answer', errorMessage)
|
ipcRenderer.send('answer', errorMessage)
|
||||||
})
|
})
|
||||||
popup = open('http://www.google.com/#q=electron', '', 'top=65,left=55,width=505,height=605')
|
ipcRenderer.send('opener-loaded')
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
'verify-ipc-sender': () => {
|
'verify-ipc-sender': () => {
|
||||||
|
|
11
spec/fixtures/module/preload-sandbox.js
vendored
11
spec/fixtures/module/preload-sandbox.js
vendored
|
@ -22,7 +22,16 @@
|
||||||
}
|
}
|
||||||
} else if (location.href !== 'about:blank') {
|
} else if (location.href !== 'about:blank') {
|
||||||
addEventListener('DOMContentLoaded', () => {
|
addEventListener('DOMContentLoaded', () => {
|
||||||
|
ipcRenderer.on('touch-the-opener', () => {
|
||||||
|
let errorMessage = null
|
||||||
|
try {
|
||||||
|
const openerDoc = opener.document // eslint-disable-line no-unused-vars
|
||||||
|
} catch (error) {
|
||||||
|
errorMessage = error.message
|
||||||
|
}
|
||||||
|
ipcRenderer.send('answer', errorMessage)
|
||||||
|
})
|
||||||
ipcRenderer.send('child-loaded', window.opener == null, document.body.innerHTML, location.href)
|
ipcRenderer.send('child-loaded', window.opener == null, document.body.innerHTML, location.href)
|
||||||
}, false)
|
})
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
<script>
|
<script>
|
||||||
|
const {ipcRenderer} = require('electron')
|
||||||
|
|
||||||
|
let message = 'Ok'
|
||||||
try {
|
try {
|
||||||
window.localStorage
|
window.localStorage
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const {ipcRenderer} = require('electron')
|
message = e.message
|
||||||
ipcRenderer.send('local-storage-response', e.message)
|
|
||||||
}
|
}
|
||||||
|
ipcRenderer.send('local-storage-response', message)
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue