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_base.h"
7 #include "base/lazy_instance.h"
8 #include "chrome/browser/guest_view/ad_view/ad_view_guest.h"
9 #include "chrome/browser/guest_view/guest_view_constants.h"
10 #include "chrome/browser/guest_view/guest_view_manager.h"
11 #include "chrome/browser/guest_view/web_view/web_view_guest.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/common/content_settings.h"
14 #include "content/public/browser/render_process_host.h"
15 #include "content/public/browser/web_contents.h"
16 #include "content/public/common/url_constants.h"
17 #include "extensions/browser/event_router.h"
18 #include "net/base/escape.h"
20 using content::WebContents
;
24 typedef std::map
<WebContents
*, GuestViewBase
*> WebContentsGuestViewMap
;
25 static base::LazyInstance
<WebContentsGuestViewMap
> webcontents_guestview_map
=
26 LAZY_INSTANCE_INITIALIZER
;
30 GuestViewBase::Event::Event(const std::string
& name
,
31 scoped_ptr
<base::DictionaryValue
> args
)
32 : name_(name
), args_(args
.Pass()) {
35 GuestViewBase::Event::~Event() {
38 scoped_ptr
<base::DictionaryValue
> GuestViewBase::Event::GetArguments() {
42 GuestViewBase::GuestViewBase(WebContents
* guest_web_contents
,
43 const std::string
& embedder_extension_id
,
44 const base::WeakPtr
<GuestViewBase
>& opener
)
45 : guest_web_contents_(guest_web_contents
),
46 embedder_web_contents_(NULL
),
47 embedder_extension_id_(embedder_extension_id
),
48 embedder_render_process_id_(0),
49 browser_context_(guest_web_contents
->GetBrowserContext()),
50 guest_instance_id_(guest_web_contents
->GetEmbeddedInstanceID()),
51 view_instance_id_(guestview::kInstanceIDNone
),
53 weak_ptr_factory_(this) {
54 webcontents_guestview_map
.Get().insert(
55 std::make_pair(guest_web_contents
, this));
59 GuestViewBase
* GuestViewBase::Create(
60 WebContents
* guest_web_contents
,
61 const std::string
& embedder_extension_id
,
62 const std::string
& view_type
,
63 const base::WeakPtr
<GuestViewBase
>& opener
) {
64 if (view_type
== "webview") {
65 return new WebViewGuest(guest_web_contents
, embedder_extension_id
, opener
);
66 } else if (view_type
== "adview") {
67 return new AdViewGuest(guest_web_contents
, embedder_extension_id
);
74 GuestViewBase
* GuestViewBase::FromWebContents(WebContents
* web_contents
) {
75 WebContentsGuestViewMap
* guest_map
= webcontents_guestview_map
.Pointer();
76 WebContentsGuestViewMap::iterator it
= guest_map
->find(web_contents
);
77 return it
== guest_map
->end() ? NULL
: it
->second
;
81 GuestViewBase
* GuestViewBase::From(int embedder_process_id
,
82 int guest_instance_id
) {
83 content::RenderProcessHost
* host
=
84 content::RenderProcessHost::FromID(embedder_process_id
);
88 content::WebContents
* guest_web_contents
=
89 GuestViewManager::FromBrowserContext(host
->GetBrowserContext())->
90 GetGuestByInstanceID(guest_instance_id
, embedder_process_id
);
91 if (!guest_web_contents
)
94 return GuestViewBase::FromWebContents(guest_web_contents
);
98 bool GuestViewBase::GetGuestPartitionConfigForSite(
100 std::string
* partition_domain
,
101 std::string
* partition_name
,
103 if (!site
.SchemeIs(content::kGuestScheme
))
106 // Since guest URLs are only used for packaged apps, there must be an app
108 CHECK(site
.has_host());
109 *partition_domain
= site
.host();
110 // Since persistence is optional, the path must either be empty or the
112 *in_memory
= (site
.path() != "/persist");
113 // The partition name is user supplied value, which we have encoded when the
114 // URL was created, so it needs to be decoded.
116 net::UnescapeURLComponent(site
.query(), net::UnescapeRule::NORMAL
);
121 void GuestViewBase::GetDefaultContentSettingRules(
122 RendererContentSettingRules
* rules
,
124 rules
->image_rules
.push_back(
125 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
126 ContentSettingsPattern::Wildcard(),
127 CONTENT_SETTING_ALLOW
,
131 rules
->script_rules
.push_back(
132 ContentSettingPatternSource(ContentSettingsPattern::Wildcard(),
133 ContentSettingsPattern::Wildcard(),
134 CONTENT_SETTING_ALLOW
,
139 base::WeakPtr
<GuestViewBase
> GuestViewBase::AsWeakPtr() {
140 return weak_ptr_factory_
.GetWeakPtr();
143 void GuestViewBase::Attach(content::WebContents
* embedder_web_contents
,
144 const base::DictionaryValue
& args
) {
145 embedder_web_contents_
= embedder_web_contents
;
146 embedder_render_process_id_
=
147 embedder_web_contents
->GetRenderProcessHost()->GetID();
148 args
.GetInteger(guestview::kParameterInstanceId
, &view_instance_id_
);
150 std::pair
<int, int> key(embedder_render_process_id_
, guest_instance_id_
);
152 // GuestViewBase::Attach is called prior to initialization (and initial
153 // navigation) of the guest in the content layer in order to permit mapping
154 // the necessary associations between the <*view> element and its guest. This
155 // is needed by the <webview> WebRequest API to allow intercepting resource
156 // requests during navigation. However, queued events should be fired after
157 // content layer initialization in order to ensure that load events (such as
158 // 'loadstop') fire in embedder after the contentWindow is available.
162 base::MessageLoop::current()->PostTask(
164 base::Bind(&GuestViewBase::SendQueuedEvents
,
165 weak_ptr_factory_
.GetWeakPtr()));
168 WebContents
* GuestViewBase::GetOpener() const {
171 return opener_
->guest_web_contents();
174 void GuestViewBase::SetOpener(WebContents
* web_contents
) {
175 GuestViewBase
* guest
= FromWebContents(web_contents
);
176 if (guest
&& guest
->IsViewType(GetViewType())) {
177 opener_
= guest
->AsWeakPtr();
180 opener_
= base::WeakPtr
<GuestViewBase
>();
183 GuestViewBase::~GuestViewBase() {
184 std::pair
<int, int> key(embedder_render_process_id_
, guest_instance_id_
);
186 webcontents_guestview_map
.Get().erase(guest_web_contents());
188 pending_events_
.clear();
191 void GuestViewBase::DispatchEvent(Event
* event
) {
192 scoped_ptr
<Event
> event_ptr(event
);
193 if (!in_extension()) {
199 pending_events_
.push_back(linked_ptr
<Event
>(event_ptr
.release()));
203 Profile
* profile
= Profile::FromBrowserContext(browser_context_
);
205 extensions::EventFilteringInfo info
;
207 info
.SetInstanceID(guest_instance_id_
);
208 scoped_ptr
<base::ListValue
> args(new base::ListValue());
209 args
->Append(event
->GetArguments().release());
211 extensions::EventRouter::DispatchEvent(
212 embedder_web_contents_
,
214 embedder_extension_id_
,
217 extensions::EventRouter::USER_GESTURE_UNKNOWN
,
221 void GuestViewBase::SendQueuedEvents() {
225 while (!pending_events_
.empty()) {
226 linked_ptr
<Event
> event_ptr
= pending_events_
.front();
227 pending_events_
.pop_front();
228 DispatchEvent(event_ptr
.release());