Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / browser_plugin / browser_plugin_guest_manager.cc
1 // Copyright (c) 2013 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.
4
5 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h"
6
7 #include "content/browser/browser_plugin/browser_plugin_guest.h"
8 #include "content/browser/browser_plugin/browser_plugin_host_factory.h"
9 #include "content/browser/renderer_host/render_view_host_impl.h"
10 #include "content/browser/web_contents/web_contents_impl.h"
11 #include "content/common/browser_plugin/browser_plugin_constants.h"
12 #include "content/common/browser_plugin/browser_plugin_messages.h"
13 #include "content/common/content_export.h"
14 #include "content/public/browser/browser_context.h"
15 #include "content/public/browser/browser_plugin_guest_manager_delegate.h"
16 #include "content/public/browser/content_browser_client.h"
17 #include "content/public/browser/render_process_host.h"
18 #include "content/public/browser/user_metrics.h"
19 #include "content/public/common/content_client.h"
20 #include "content/public/common/result_codes.h"
21 #include "content/public/common/url_constants.h"
22 #include "content/public/common/url_utils.h"
23 #include "net/base/escape.h"
24
25 namespace content {
26
27 // static
28 BrowserPluginHostFactory* BrowserPluginGuestManager::factory_ = NULL;
29
30 BrowserPluginGuestManager::BrowserPluginGuestManager(BrowserContext* context)
31     : context_(context) {}
32
33 BrowserPluginGuestManagerDelegate*
34 BrowserPluginGuestManager::GetDelegate() const {
35   return context_->GetGuestManagerDelegate();
36 }
37
38 BrowserPluginGuestManager::~BrowserPluginGuestManager() {
39 }
40
41 // static.
42 BrowserPluginGuestManager* BrowserPluginGuestManager::FromBrowserContext(
43     BrowserContext* context) {
44   BrowserPluginGuestManager* guest_manager =
45       static_cast<BrowserPluginGuestManager*>(
46         context->GetUserData(
47             browser_plugin::kBrowserPluginGuestManagerKeyName));
48   if (!guest_manager) {
49     guest_manager = BrowserPluginGuestManager::Create(context);
50     context->SetUserData(browser_plugin::kBrowserPluginGuestManagerKeyName,
51                          guest_manager);
52   }
53   return guest_manager;
54 }
55
56 // static
57 BrowserPluginGuestManager* BrowserPluginGuestManager::Create(
58     BrowserContext* context) {
59   if (factory_)
60     return factory_->CreateBrowserPluginGuestManager(context);
61   return new BrowserPluginGuestManager(context);
62 }
63
64 int BrowserPluginGuestManager::GetNextInstanceID() {
65   if (!GetDelegate())
66     return 0;
67   return GetDelegate()->GetNextInstanceID();
68 }
69
70 BrowserPluginGuest* BrowserPluginGuestManager::CreateGuest(
71     SiteInstance* embedder_site_instance,
72     int instance_id,
73     const BrowserPluginHostMsg_Attach_Params& params,
74     scoped_ptr<base::DictionaryValue> extra_params) {
75   RenderProcessHost* embedder_process_host =
76       embedder_site_instance->GetProcess();
77   // Validate that the partition id coming from the renderer is valid UTF-8,
78   // since we depend on this in other parts of the code, such as FilePath
79   // creation. If the validation fails, treat it as a bad message and kill the
80   // renderer process.
81   if (!base::IsStringUTF8(params.storage_partition_id)) {
82     content::RecordAction(
83         base::UserMetricsAction("BadMessageTerminate_BPGM"));
84     base::KillProcess(
85         embedder_process_host->GetHandle(),
86         content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
87     return NULL;
88   }
89
90   const GURL& embedder_site_url = embedder_site_instance->GetSiteURL();
91   const std::string& host = embedder_site_url.host();
92
93   std::string url_encoded_partition = net::EscapeQueryParamValue(
94       params.storage_partition_id, false);
95   // The SiteInstance of a given webview tag is based on the fact that it's
96   // a guest process in addition to which platform application the tag
97   // belongs to and what storage partition is in use, rather than the URL
98   // that the tag is being navigated to.
99   GURL guest_site(base::StringPrintf("%s://%s/%s?%s",
100                                      kGuestScheme,
101                                      host.c_str(),
102                                      params.persist_storage ? "persist" : "",
103                                      url_encoded_partition.c_str()));
104
105   // If we already have a webview tag in the same app using the same storage
106   // partition, we should use the same SiteInstance so the existing tag and
107   // the new tag can script each other.
108   SiteInstance* guest_site_instance = GetGuestSiteInstance(guest_site);
109   if (!guest_site_instance) {
110     // Create the SiteInstance in a new BrowsingInstance, which will ensure
111     // that webview tags are also not allowed to send messages across
112     // different partitions.
113     guest_site_instance = SiteInstance::CreateForURL(
114         embedder_site_instance->GetBrowserContext(), guest_site);
115   }
116
117   return WebContentsImpl::CreateGuest(
118       embedder_site_instance->GetBrowserContext(),
119       guest_site_instance,
120       instance_id,
121       extra_params.Pass());
122 }
123
124 static void BrowserPluginGuestByInstanceIDCallback(
125     const BrowserPluginGuestManager::GuestByInstanceIDCallback& callback,
126     WebContents* guest_web_contents) {
127   if (!guest_web_contents) {
128     callback.Run(NULL);
129     return;
130   }
131   callback.Run(static_cast<WebContentsImpl*>(guest_web_contents)->
132                    GetBrowserPluginGuest());
133 }
134
135 void BrowserPluginGuestManager::MaybeGetGuestByInstanceIDOrKill(
136     int instance_id,
137     int embedder_render_process_id,
138     const GuestByInstanceIDCallback& callback) const {
139   if (!GetDelegate()) {
140     callback.Run(NULL);
141     return;
142   }
143
144   GetDelegate()->MaybeGetGuestByInstanceIDOrKill(
145       instance_id,
146       embedder_render_process_id,
147       base::Bind(&BrowserPluginGuestByInstanceIDCallback,
148                  callback));
149 }
150
151 void BrowserPluginGuestManager::AddGuest(int instance_id,
152                                          WebContents* guest_web_contents) {
153   if (!GetDelegate())
154     return;
155   GetDelegate()->AddGuest(instance_id, guest_web_contents);
156 }
157
158 void BrowserPluginGuestManager::RemoveGuest(int instance_id) {
159   if (!GetDelegate())
160     return;
161   GetDelegate()->RemoveGuest(instance_id);
162 }
163
164 static void BrowserPluginGuestMessageCallback(const IPC::Message& message,
165                                               BrowserPluginGuest* guest) {
166   if (!guest)
167     return;
168   guest->OnMessageReceivedFromEmbedder(message);
169 }
170
171 void BrowserPluginGuestManager::OnMessageReceived(const IPC::Message& message,
172                                                   int render_process_id) {
173   DCHECK(BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(message));
174   int instance_id = 0;
175   // All allowed messages must have instance_id as their first parameter.
176   PickleIterator iter(message);
177   bool success = iter.ReadInt(&instance_id);
178   DCHECK(success);
179   MaybeGetGuestByInstanceIDOrKill(instance_id,
180                                   render_process_id,
181                                   base::Bind(&BrowserPluginGuestMessageCallback,
182                                              message));
183 }
184
185 SiteInstance* BrowserPluginGuestManager::GetGuestSiteInstance(
186     const GURL& guest_site) {
187   if (!GetDelegate())
188     return NULL;
189   return GetDelegate()->GetGuestSiteInstance(guest_site);
190 }
191
192 static bool BrowserPluginGuestCallback(
193     const BrowserPluginGuestManager::GuestCallback& callback,
194     WebContents* guest_web_contents) {
195   return callback.Run(static_cast<WebContentsImpl*>(guest_web_contents)
196                           ->GetBrowserPluginGuest());
197 }
198
199 bool BrowserPluginGuestManager::ForEachGuest(
200     WebContents* embedder_web_contents, const GuestCallback& callback) {
201   if (!GetDelegate())
202     return false;
203   return GetDelegate()->ForEachGuest(embedder_web_contents,
204                                      base::Bind(&BrowserPluginGuestCallback,
205                                                 callback));
206 }
207
208 }  // namespace content