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() 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 content::WebContents* GuestViewManager::GetGuestByInstanceIDSafely(
79 int guest_instance_id,
80 int embedder_render_process_id) {
81 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id,
85 return GetGuestByInstanceID(guest_instance_id, embedder_render_process_id);
88 int GuestViewManager::GetNextInstanceID() {
89 return ++current_instance_id_;
92 void GuestViewManager::AddGuest(int guest_instance_id,
93 WebContents* guest_web_contents) {
94 DCHECK(guest_web_contents_by_instance_id_.find(guest_instance_id) ==
95 guest_web_contents_by_instance_id_.end());
96 guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents;
97 // This will add the RenderProcessHost ID when we get one.
98 new GuestWebContentsObserver(guest_web_contents);
101 void GuestViewManager::RemoveGuest(int guest_instance_id) {
102 GuestInstanceMap::iterator it =
103 guest_web_contents_by_instance_id_.find(guest_instance_id);
104 DCHECK(it != guest_web_contents_by_instance_id_.end());
105 render_process_host_id_multiset_.erase(
106 it->second->GetRenderProcessHost()->GetID());
107 guest_web_contents_by_instance_id_.erase(it);
110 void GuestViewManager::MaybeGetGuestByInstanceIDOrKill(
111 int guest_instance_id,
112 int embedder_render_process_id,
113 const GuestByInstanceIDCallback& callback) {
114 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id,
115 guest_instance_id)) {
116 // If we kill the embedder, then don't bother calling back.
119 content::WebContents* guest_web_contents =
120 GetGuestByInstanceID(guest_instance_id, embedder_render_process_id);
121 callback.Run(guest_web_contents);
124 SiteInstance* GuestViewManager::GetGuestSiteInstance(
125 const GURL& guest_site) {
126 for (GuestInstanceMap::const_iterator it =
127 guest_web_contents_by_instance_id_.begin();
128 it != guest_web_contents_by_instance_id_.end(); ++it) {
129 if (it->second->GetSiteInstance()->GetSiteURL() == guest_site)
130 return it->second->GetSiteInstance();
135 bool GuestViewManager::ForEachGuest(WebContents* embedder_web_contents,
136 const GuestCallback& callback) {
137 for (GuestInstanceMap::iterator it =
138 guest_web_contents_by_instance_id_.begin();
139 it != guest_web_contents_by_instance_id_.end(); ++it) {
140 WebContents* guest = it->second;
141 if (embedder_web_contents != guest->GetEmbedderWebContents())
144 if (callback.Run(guest))
150 void GuestViewManager::AddRenderProcessHostID(int render_process_host_id) {
151 render_process_host_id_multiset_.insert(render_process_host_id);
154 content::WebContents* GuestViewManager::GetGuestByInstanceID(
155 int guest_instance_id,
156 int embedder_render_process_id) {
157 GuestInstanceMap::const_iterator it =
158 guest_web_contents_by_instance_id_.find(guest_instance_id);
159 if (it == guest_web_contents_by_instance_id_.end())
164 bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
165 int embedder_render_process_id,
166 int guest_instance_id) {
167 if (!CanEmbedderAccessInstanceID(embedder_render_process_id,
168 guest_instance_id)) {
169 // The embedder process is trying to access a guest it does not own.
170 content::RecordAction(
171 base::UserMetricsAction("BadMessageTerminate_BPGM"));
173 content::RenderProcessHost::FromID(embedder_render_process_id)->
175 content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
181 bool GuestViewManager::CanEmbedderAccessInstanceID(
182 int embedder_render_process_id,
183 int guest_instance_id) {
184 // The embedder is trying to access a guest with a negative or zero
186 if (guest_instance_id <= guestview::kInstanceIDNone)
189 // The embedder is trying to access an instance ID that has not yet been
190 // allocated by GuestViewManager. This could cause instance ID
191 // collisions in the future, and potentially give one embedder access to a
192 // guest it does not own.
193 if (guest_instance_id > current_instance_id_)
196 GuestInstanceMap::const_iterator it =
197 guest_web_contents_by_instance_id_.find(guest_instance_id);
198 if (it == guest_web_contents_by_instance_id_.end())
201 GuestViewBase* guest_view = GuestViewBase::FromWebContents(it->second);
205 return CanEmbedderAccessGuest(embedder_render_process_id, guest_view);
208 bool GuestViewManager::CanEmbedderAccessGuest(int embedder_render_process_id,
209 GuestViewBase* guest) {
210 // The embedder can access the guest if it has not been attached and its
211 // opener's embedder lives in the same process as the given embedder.
212 if (!guest->attached()) {
213 if (!guest->GetOpener())
216 return embedder_render_process_id ==
217 guest->GetOpener()->GetEmbedderWebContents()->GetRenderProcessHost()->
221 return embedder_render_process_id ==
222 guest->embedder_web_contents()->GetRenderProcessHost()->GetID();