1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/guest_view/guest_view_manager.h"
7 #include "chrome/browser/extensions/extension_service.h"
8 #include "chrome/browser/guest_view/guest_view_base.h"
9 #include "chrome/browser/guest_view/guest_view_constants.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "content/public/browser/browser_context.h"
12 #include "content/public/browser/render_process_host.h"
13 #include "content/public/browser/user_metrics.h"
14 #include "content/public/browser/web_contents_observer.h"
15 #include "content/public/common/result_codes.h"
16 #include "extensions/browser/extension_system.h"
19 using content::BrowserContext
;
20 using content::SiteInstance
;
21 using content::WebContents
;
23 // A WebContents does not immediately have a RenderProcessHost. It acquires one
24 // on initial navigation. This observer exists until that initial navigation in
25 // order to grab the ID if tis RenderProcessHost so that it can register it as
27 class GuestWebContentsObserver
28 : public content::WebContentsObserver
{
30 explicit GuestWebContentsObserver(WebContents
* guest_web_contents
)
31 : WebContentsObserver(guest_web_contents
) {
34 virtual ~GuestWebContentsObserver() {
37 // WebContentsObserver:
38 virtual void DidStartProvisionalLoadForFrame(
40 int64 parent_frame_id
,
42 const GURL
& validated_url
,
44 bool is_iframe_srcdoc
,
45 content::RenderViewHost
* render_view_host
) OVERRIDE
{
46 GuestViewManager::FromBrowserContext(web_contents()->GetBrowserContext())->
47 AddRenderProcessHostID(web_contents()->GetRenderProcessHost()->GetID());
51 virtual void WebContentsDestroyed(WebContents
* web_contents
) OVERRIDE
{
56 DISALLOW_COPY_AND_ASSIGN(GuestWebContentsObserver
);
59 GuestViewManager::GuestViewManager(content::BrowserContext
* context
)
60 : current_instance_id_(0),
63 GuestViewManager::~GuestViewManager() {}
66 GuestViewManager
* GuestViewManager::FromBrowserContext(
67 BrowserContext
* context
) {
68 GuestViewManager
* guest_manager
=
69 static_cast<GuestViewManager
*>(context
->GetUserData(
70 guestview::kGuestViewManagerKeyName
));
72 guest_manager
= new GuestViewManager(context
);
73 context
->SetUserData(guestview::kGuestViewManagerKeyName
, guest_manager
);
78 int GuestViewManager::GetNextInstanceID() {
79 return ++current_instance_id_
;
82 void GuestViewManager::AddGuest(int guest_instance_id
,
83 WebContents
* guest_web_contents
) {
84 DCHECK(guest_web_contents_by_instance_id_
.find(guest_instance_id
) ==
85 guest_web_contents_by_instance_id_
.end());
86 guest_web_contents_by_instance_id_
[guest_instance_id
] = guest_web_contents
;
87 // This will add the RenderProcessHost ID when we get one.
88 new GuestWebContentsObserver(guest_web_contents
);
91 void GuestViewManager::RemoveGuest(int guest_instance_id
) {
92 GuestInstanceMap::iterator it
=
93 guest_web_contents_by_instance_id_
.find(guest_instance_id
);
94 DCHECK(it
!= guest_web_contents_by_instance_id_
.end());
95 render_process_host_id_multiset_
.erase(
96 it
->second
->GetRenderProcessHost()->GetID());
97 guest_web_contents_by_instance_id_
.erase(it
);
100 content::WebContents
* GuestViewManager::GetGuestByInstanceID(
101 int guest_instance_id
,
102 int embedder_render_process_id
) {
103 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id
,
104 guest_instance_id
)) {
107 GuestInstanceMap::const_iterator it
=
108 guest_web_contents_by_instance_id_
.find(guest_instance_id
);
109 if (it
== guest_web_contents_by_instance_id_
.end())
114 bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
115 int embedder_render_process_id
,
116 int guest_instance_id
) {
117 if (!CanEmbedderAccessInstanceID(embedder_render_process_id
,
118 guest_instance_id
)) {
119 // The embedder process is trying to access a guest it does not own.
120 content::RecordAction(
121 base::UserMetricsAction("BadMessageTerminate_BPGM"));
123 content::RenderProcessHost::FromID(embedder_render_process_id
)->
125 content::RESULT_CODE_KILLED_BAD_MESSAGE
, false);
131 bool GuestViewManager::CanEmbedderAccessInstanceID(
132 int embedder_render_process_id
,
133 int guest_instance_id
) {
134 // The embedder is trying to access a guest with a negative or zero
136 if (guest_instance_id
<= guestview::kInstanceIDNone
)
139 // The embedder is trying to access an instance ID that has not yet been
140 // allocated by GuestViewManager. This could cause instance ID
141 // collisions in the future, and potentially give one embedder access to a
142 // guest it does not own.
143 if (guest_instance_id
> current_instance_id_
)
146 GuestInstanceMap::const_iterator it
=
147 guest_web_contents_by_instance_id_
.find(guest_instance_id
);
148 if (it
== guest_web_contents_by_instance_id_
.end())
151 GuestViewBase
* guest_view
= GuestViewBase::FromWebContents(it
->second
);
155 return CanEmbedderAccessGuest(embedder_render_process_id
, guest_view
);
158 SiteInstance
* GuestViewManager::GetGuestSiteInstance(
159 const GURL
& guest_site
) {
160 for (GuestInstanceMap::const_iterator it
=
161 guest_web_contents_by_instance_id_
.begin();
162 it
!= guest_web_contents_by_instance_id_
.end(); ++it
) {
163 if (it
->second
->GetSiteInstance()->GetSiteURL() == guest_site
)
164 return it
->second
->GetSiteInstance();
169 bool GuestViewManager::ForEachGuest(WebContents
* embedder_web_contents
,
170 const GuestCallback
& callback
) {
171 for (GuestInstanceMap::iterator it
=
172 guest_web_contents_by_instance_id_
.begin();
173 it
!= guest_web_contents_by_instance_id_
.end(); ++it
) {
174 WebContents
* guest
= it
->second
;
175 if (embedder_web_contents
!= guest
->GetEmbedderWebContents())
178 if (callback
.Run(guest
))
184 void GuestViewManager::AddRenderProcessHostID(int render_process_host_id
) {
185 render_process_host_id_multiset_
.insert(render_process_host_id
);
188 bool GuestViewManager::CanEmbedderAccessGuest(int embedder_render_process_id
,
189 GuestViewBase
* guest
) {
190 // The embedder can access the guest if it has not been attached and its
191 // opener's embedder lives in the same process as the given embedder.
192 if (!guest
->attached()) {
193 if (!guest
->GetOpener())
196 return embedder_render_process_id
==
197 guest
->GetOpener()->GetEmbedderWebContents()->GetRenderProcessHost()->
201 return embedder_render_process_id
==
202 guest
->embedder_web_contents()->GetRenderProcessHost()->GetID();