Index: extensions/browser/extension_web_contents_observer.cc |
diff --git a/extensions/browser/extension_web_contents_observer.cc b/extensions/browser/extension_web_contents_observer.cc |
index 665fc0809cca1b3ebcfa428ae79d762d9c8c5caa..321c3c30820b23a3c62808e21ae31f914b2d9ce8 100644 |
--- a/extensions/browser/extension_web_contents_observer.cc |
+++ b/extensions/browser/extension_web_contents_observer.cc |
@@ -4,7 +4,9 @@ |
#include "extensions/browser/extension_web_contents_observer.h" |
+#include "components/guest_view/browser/guest_view_base.h" |
#include "content/public/browser/child_process_security_policy.h" |
+#include "content/public/browser/navigation_details.h" |
#include "content/public/browser/render_frame_host.h" |
#include "content/public/browser/render_process_host.h" |
#include "content/public/browser/render_view_host.h" |
@@ -24,6 +26,14 @@ |
namespace extensions { |
+namespace { |
+ |
+bool IsExtensionURL(const GURL& url) { |
+ return url.SchemeIs(kExtensionScheme) || url.SchemeIs(content::kGuestScheme); |
+} |
+ |
+} // namespace |
+ |
// static |
ExtensionWebContentsObserver* ExtensionWebContentsObserver::GetForWebContents( |
content::WebContents* web_contents) { |
@@ -50,18 +60,34 @@ void ExtensionWebContentsObserver::InitializeRenderFrame( |
DCHECK(render_frame_host); |
DCHECK(render_frame_host->IsRenderFrameLive()); |
+ ViewType view_type = GetViewType(web_contents()); |
+ if (view_type == VIEW_TYPE_INVALID) { |
+ // This is expected to happen only for non-extension pages (e.g. devtools) |
+ // and GuestViews. |
+ DCHECK(guest_view::GuestViewBase::FromWebContents(web_contents()) || |
+ !IsExtensionURL(render_frame_host->GetLastCommittedURL())); |
ncarter (slow)
2015/11/24 05:22:13
Use render_frame_host->GetSiteInstance()->GetSiteU
robwu
2015/11/25 00:44:17
Done.
|
+ return; |
+ } |
+ |
+ // At the initialization of the render frame, the last committed URL is not |
+ // reliable, so do not take it into account in determining whether it is an |
+ // extension frame. |
+ const Extension* frame_extension = |
+ GetExtensionFromFrame(render_frame_host, false); |
+ // TODO(robwu): Add DCHECK that verifies that |frame_extension| always exists |
+ // if OOP frames is enabled. |
ncarter (slow)
2015/11/24 05:22:13
Is this TODO stale? I'm not sure what it means.
robwu
2015/11/25 00:44:17
When OOPIF is enabled, only extension frames shoul
ncarter (slow)
2015/11/30 22:56:45
--site-per-process is a content flag, so that shou
robwu
2015/12/01 00:45:26
I'll use --site-per-process for now, and hope that
|
+ if (!frame_extension) |
+ return; |
+ |
// Notify the render frame of the view type. |
render_frame_host->Send(new ExtensionMsg_NotifyRenderViewType( |
- render_frame_host->GetRoutingID(), GetViewType(web_contents()))); |
- |
- const Extension* frame_extension = GetExtensionFromFrame(render_frame_host); |
- if (frame_extension) { |
- ExtensionsBrowserClient::Get()->RegisterMojoServices(render_frame_host, |
- frame_extension); |
- ProcessManager::Get(browser_context_) |
- ->RegisterRenderFrameHost(web_contents(), render_frame_host, |
- frame_extension); |
- } |
+ render_frame_host->GetRoutingID(), view_type)); |
+ |
+ ExtensionsBrowserClient::Get()->RegisterMojoServices(render_frame_host, |
+ frame_extension); |
+ ProcessManager::Get(browser_context_) |
+ ->RegisterRenderFrameHost(web_contents(), render_frame_host, |
+ frame_extension); |
} |
content::WebContents* ExtensionWebContentsObserver::GetAssociatedWebContents() |
@@ -110,6 +136,49 @@ void ExtensionWebContentsObserver::RenderFrameDeleted( |
->UnregisterRenderFrameHost(render_frame_host); |
} |
+void ExtensionWebContentsObserver::DidCommitProvisionalLoadForFrame( |
+ content::RenderFrameHost* render_frame_host, |
+ const GURL& url, |
+ ui::PageTransition transition_type) { |
+ ProcessManager* pm = ProcessManager::Get(browser_context_); |
+ |
+ if (pm->IsRenderFrameHostRegistered(render_frame_host)) { |
+ const Extension* frame_extension = |
+ GetExtensionFromFrame(render_frame_host, true); |
+ |
+ if (!frame_extension) |
+ pm->UnregisterRenderFrameHost(render_frame_host); |
+ } |
+} |
+ |
+void ExtensionWebContentsObserver::DidNavigateAnyFrame( |
+ content::RenderFrameHost* render_frame_host, |
+ const content::LoadCommittedDetails& details, |
+ const content::FrameNavigateParams& params) { |
+ if (details.is_in_page) |
+ return; |
+ |
+ const Extension* frame_extension = |
+ GetExtensionFromFrame(render_frame_host, true); |
+ ProcessManager* pm = ProcessManager::Get(browser_context_); |
+ |
+ if (!frame_extension) { |
+ // Should have been unregistered by DidCommitProvisionalLoadForFrame. |
+ DCHECK(!pm->IsRenderFrameHostRegistered(render_frame_host)); |
+ return; |
+ } |
+ |
+ if (pm->IsRenderFrameHostRegistered(render_frame_host)) { |
+ // Notify ProcessManager, because some clients do not just want to know |
+ // whether the frame is in an extension process, but also whether the frame |
+ // was navigated. |
+ pm->DidNavigateRenderFrameHost(render_frame_host); |
+ } else { |
+ pm->RegisterRenderFrameHost(web_contents(), render_frame_host, |
+ frame_extension); |
+ } |
ncarter (slow)
2015/11/24 05:22:13
After consulting with creis@ and debugging the cod
robwu
2015/11/25 00:44:17
I need DidNavigateAnyFrame to detect whether the f
|
+} |
+ |
bool ExtensionWebContentsObserver::OnMessageReceived( |
const IPC::Message& message, |
content::RenderFrameHost* render_frame_host) { |
@@ -146,24 +215,44 @@ void ExtensionWebContentsObserver::PepperInstanceDeleted() { |
std::string ExtensionWebContentsObserver::GetExtensionIdFromFrame( |
content::RenderFrameHost* render_frame_host) const { |
- content::SiteInstance* site_instance = render_frame_host->GetSiteInstance(); |
- GURL url = render_frame_host->GetLastCommittedURL(); |
- if (!url.is_empty()) { |
- if (site_instance->GetSiteURL().GetOrigin() != url.GetOrigin()) |
- return std::string(); |
- } else { |
- url = site_instance->GetSiteURL(); |
- } |
- |
- return url.SchemeIs(kExtensionScheme) ? url.host() : std::string(); |
+ const Extension* extension = GetExtensionFromFrame(render_frame_host, true); |
+ return extension ? extension->id() : std::string(); |
} |
const Extension* ExtensionWebContentsObserver::GetExtensionFromFrame( |
- content::RenderFrameHost* render_frame_host) const { |
- return ExtensionRegistry::Get( |
- render_frame_host->GetProcess()->GetBrowserContext()) |
- ->enabled_extensions() |
- .GetByID(GetExtensionIdFromFrame(render_frame_host)); |
+ content::RenderFrameHost* render_frame_host, |
+ bool verify_url) const { |
+ const GURL site_url(render_frame_host->GetSiteInstance()->GetSiteURL()); |
+ if (!IsExtensionURL(site_url)) |
+ return nullptr; |
+ |
+ const std::string& extension_id = site_url.host(); |
+ |
+ // This verify_url logic can completely be removed once site isolation is |
+ // fully enabled. |
+ if (verify_url) { |
+ GURL url(render_frame_host->GetLastCommittedURL()); |
+ if (!IsExtensionURL(url)) { |
+ // Any about:* frame (in particular about:blank and about:srcdoc) runs in |
+ // the security context of the parent page that created it. Treat such |
+ // frames as extension pages iff the parent frame is registered. |
+ if (url.SchemeIs(url::kAboutScheme) && render_frame_host->GetParent()) |
ncarter (slow)
2015/11/24 05:22:13
This heuristic (which I know I suggested!) may not
robwu
2015/11/25 00:44:17
Nice! I'll rebase when your patch lands.
ncarter (slow)
2015/11/30 22:56:45
It's landed.
When you use GetLastCommittedOrigin(
robwu
2015/12/01 00:45:26
Yep, this makes most sense.
(is it really the cas
|
+ return GetExtensionFromFrame(render_frame_host->GetParent(), true); |
+ return nullptr; |
+ } |
+ if (url.host() != extension_id) { |
+ return nullptr; |
+ } |
+ } |
+ |
+ const Extension* extension = |
+ ExtensionRegistry::Get( |
+ render_frame_host->GetProcess()->GetBrowserContext()) |
+ ->enabled_extensions() |
+ .GetByID(extension_id); |
+ |
+ // A hosted app is not an extension. Its SiteInstance only contains web pages. |
+ return extension && !extension->is_hosted_app() ? extension : nullptr; |
} |
const Extension* ExtensionWebContentsObserver::GetExtension( |