OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h" | 5 #include "content/browser/browser_plugin/browser_plugin_guest_manager.h" |
6 | 6 |
7 #include "content/browser/browser_plugin/browser_plugin_guest.h" | 7 #include "content/browser/browser_plugin/browser_plugin_guest.h" |
8 #include "content/browser/browser_plugin/browser_plugin_host_factory.h" | 8 #include "content/browser/browser_plugin/browser_plugin_host_factory.h" |
9 #include "content/browser/renderer_host/render_view_host_impl.h" | 9 #include "content/browser/renderer_host/render_view_host_impl.h" |
10 #include "content/browser/web_contents/web_contents_impl.h" | 10 #include "content/browser/web_contents/web_contents_impl.h" |
11 #include "content/common/browser_plugin/browser_plugin_constants.h" | 11 #include "content/common/browser_plugin/browser_plugin_constants.h" |
12 #include "content/common/browser_plugin/browser_plugin_messages.h" | 12 #include "content/common/browser_plugin/browser_plugin_messages.h" |
13 #include "content/common/content_export.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" |
14 #include "content/public/browser/render_process_host.h" | 17 #include "content/public/browser/render_process_host.h" |
15 #include "content/public/browser/user_metrics.h" | 18 #include "content/public/browser/user_metrics.h" |
| 19 #include "content/public/common/content_client.h" |
16 #include "content/public/common/result_codes.h" | 20 #include "content/public/common/result_codes.h" |
17 #include "content/public/common/url_constants.h" | 21 #include "content/public/common/url_constants.h" |
18 #include "content/public/common/url_utils.h" | 22 #include "content/public/common/url_utils.h" |
19 #include "net/base/escape.h" | 23 #include "net/base/escape.h" |
20 | 24 |
21 namespace content { | 25 namespace content { |
22 | 26 |
23 // static | 27 // static |
24 BrowserPluginHostFactory* BrowserPluginGuestManager::factory_ = NULL; | 28 BrowserPluginHostFactory* BrowserPluginGuestManager::factory_ = NULL; |
25 | 29 |
26 BrowserPluginGuestManager::BrowserPluginGuestManager() | 30 BrowserPluginGuestManager::BrowserPluginGuestManager(BrowserContext* context) |
27 : next_instance_id_(browser_plugin::kInstanceIDNone) { | 31 : context_(context) {} |
| 32 |
| 33 BrowserPluginGuestManagerDelegate* |
| 34 BrowserPluginGuestManager::GetDelegate() const { |
| 35 return context_->GetGuestManagerDelegate(); |
28 } | 36 } |
29 | 37 |
30 BrowserPluginGuestManager::~BrowserPluginGuestManager() { | 38 BrowserPluginGuestManager::~BrowserPluginGuestManager() { |
31 } | 39 } |
32 | 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 |
33 // static | 56 // static |
34 BrowserPluginGuestManager* BrowserPluginGuestManager::Create() { | 57 BrowserPluginGuestManager* BrowserPluginGuestManager::Create( |
| 58 BrowserContext* context) { |
35 if (factory_) | 59 if (factory_) |
36 return factory_->CreateBrowserPluginGuestManager(); | 60 return factory_->CreateBrowserPluginGuestManager(context); |
37 return new BrowserPluginGuestManager(); | 61 return new BrowserPluginGuestManager(context); |
| 62 } |
| 63 |
| 64 int BrowserPluginGuestManager::GetNextInstanceID() { |
| 65 if (!GetDelegate()) |
| 66 return 0; |
| 67 return GetDelegate()->GetNextInstanceID(); |
38 } | 68 } |
39 | 69 |
40 BrowserPluginGuest* BrowserPluginGuestManager::CreateGuest( | 70 BrowserPluginGuest* BrowserPluginGuestManager::CreateGuest( |
41 SiteInstance* embedder_site_instance, | 71 SiteInstance* embedder_site_instance, |
42 int instance_id, | 72 int instance_id, |
43 const BrowserPluginHostMsg_Attach_Params& params, | 73 const BrowserPluginHostMsg_Attach_Params& params, |
44 scoped_ptr<base::DictionaryValue> extra_params) { | 74 scoped_ptr<base::DictionaryValue> extra_params) { |
45 RenderProcessHost* embedder_process_host = | 75 RenderProcessHost* embedder_process_host = |
46 embedder_site_instance->GetProcess(); | 76 embedder_site_instance->GetProcess(); |
47 // Validate that the partition id coming from the renderer is valid UTF-8, | 77 // Validate that the partition id coming from the renderer is valid UTF-8, |
48 // since we depend on this in other parts of the code, such as FilePath | 78 // since we depend on this in other parts of the code, such as FilePath |
49 // creation. If the validation fails, treat it as a bad message and kill the | 79 // creation. If the validation fails, treat it as a bad message and kill the |
50 // renderer process. | 80 // renderer process. |
51 if (!IsStringUTF8(params.storage_partition_id)) { | 81 if (!IsStringUTF8(params.storage_partition_id)) { |
52 content::RecordAction( | 82 content::RecordAction( |
53 base::UserMetricsAction("BadMessageTerminate_BPGM")); | 83 base::UserMetricsAction("BadMessageTerminate_BPGM")); |
54 base::KillProcess( | 84 base::KillProcess( |
55 embedder_process_host->GetHandle(), | 85 embedder_process_host->GetHandle(), |
56 content::RESULT_CODE_KILLED_BAD_MESSAGE, false); | 86 content::RESULT_CODE_KILLED_BAD_MESSAGE, false); |
57 return NULL; | 87 return NULL; |
58 } | 88 } |
59 | 89 |
60 // We usually require BrowserPlugins to be hosted by a storage isolated | |
61 // extension. We treat WebUI pages as a special case if they host the | |
62 // BrowserPlugin in a component extension iframe. In that case, we use the | |
63 // iframe's URL to determine the extension. | |
64 const GURL& embedder_site_url = embedder_site_instance->GetSiteURL(); | 90 const GURL& embedder_site_url = embedder_site_instance->GetSiteURL(); |
65 GURL validated_frame_url(params.embedder_frame_url); | 91 const std::string& host = embedder_site_url.host(); |
66 embedder_process_host->FilterURL(false, &validated_frame_url); | |
67 const std::string& host = content::HasWebUIScheme(embedder_site_url) ? | |
68 validated_frame_url.host() : embedder_site_url.host(); | |
69 | 92 |
70 std::string url_encoded_partition = net::EscapeQueryParamValue( | 93 std::string url_encoded_partition = net::EscapeQueryParamValue( |
71 params.storage_partition_id, false); | 94 params.storage_partition_id, false); |
72 // The SiteInstance of a given webview tag is based on the fact that it's | 95 // The SiteInstance of a given webview tag is based on the fact that it's |
73 // a guest process in addition to which platform application the tag | 96 // a guest process in addition to which platform application the tag |
74 // belongs to and what storage partition is in use, rather than the URL | 97 // belongs to and what storage partition is in use, rather than the URL |
75 // that the tag is being navigated to. | 98 // that the tag is being navigated to. |
76 GURL guest_site(base::StringPrintf("%s://%s/%s?%s", | 99 GURL guest_site(base::StringPrintf("%s://%s/%s?%s", |
77 kGuestScheme, | 100 kGuestScheme, |
78 host.c_str(), | 101 host.c_str(), |
(...skipping 15 matching lines...) Expand all Loading... |
94 return WebContentsImpl::CreateGuest( | 117 return WebContentsImpl::CreateGuest( |
95 embedder_site_instance->GetBrowserContext(), | 118 embedder_site_instance->GetBrowserContext(), |
96 guest_site_instance, | 119 guest_site_instance, |
97 instance_id, | 120 instance_id, |
98 extra_params.Pass()); | 121 extra_params.Pass()); |
99 } | 122 } |
100 | 123 |
101 BrowserPluginGuest* BrowserPluginGuestManager::GetGuestByInstanceID( | 124 BrowserPluginGuest* BrowserPluginGuestManager::GetGuestByInstanceID( |
102 int instance_id, | 125 int instance_id, |
103 int embedder_render_process_id) const { | 126 int embedder_render_process_id) const { |
104 if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id, | 127 if (!GetDelegate()) |
105 instance_id)) { | |
106 return NULL; | 128 return NULL; |
107 } | 129 |
108 GuestInstanceMap::const_iterator it = | 130 WebContentsImpl* guest_web_contents = static_cast<WebContentsImpl*>( |
109 guest_web_contents_by_instance_id_.find(instance_id); | 131 GetDelegate()->GetGuestByInstanceID(instance_id, |
110 if (it == guest_web_contents_by_instance_id_.end()) | 132 embedder_render_process_id)); |
111 return NULL; | 133 |
112 return static_cast<WebContentsImpl*>(it->second)->GetBrowserPluginGuest(); | 134 return guest_web_contents ? |
| 135 guest_web_contents->GetBrowserPluginGuest() : NULL; |
113 } | 136 } |
114 | 137 |
115 void BrowserPluginGuestManager::AddGuest(int instance_id, | 138 void BrowserPluginGuestManager::AddGuest(int instance_id, |
116 WebContentsImpl* guest_web_contents) { | 139 WebContents* guest_web_contents) { |
117 DCHECK(guest_web_contents_by_instance_id_.find(instance_id) == | 140 if (!GetDelegate()) |
118 guest_web_contents_by_instance_id_.end()); | 141 return; |
119 guest_web_contents_by_instance_id_[instance_id] = guest_web_contents; | 142 GetDelegate()->AddGuest(instance_id, guest_web_contents); |
120 } | 143 } |
121 | 144 |
122 void BrowserPluginGuestManager::RemoveGuest(int instance_id) { | 145 void BrowserPluginGuestManager::RemoveGuest(int instance_id) { |
123 DCHECK(guest_web_contents_by_instance_id_.find(instance_id) != | 146 if (!GetDelegate()) |
124 guest_web_contents_by_instance_id_.end()); | 147 return; |
125 guest_web_contents_by_instance_id_.erase(instance_id); | 148 GetDelegate()->RemoveGuest(instance_id); |
126 } | 149 } |
127 | 150 |
128 bool BrowserPluginGuestManager::CanEmbedderAccessInstanceIDMaybeKill( | 151 bool BrowserPluginGuestManager::CanEmbedderAccessInstanceIDMaybeKill( |
129 int embedder_render_process_id, | 152 int embedder_render_process_id, |
130 int instance_id) const { | 153 int instance_id) const { |
131 if (!CanEmbedderAccessInstanceID(embedder_render_process_id, instance_id)) { | 154 if (!GetDelegate()) |
132 // The embedder process is trying to access a guest it does not own. | |
133 content::RecordAction( | |
134 base::UserMetricsAction("BadMessageTerminate_BPGM")); | |
135 base::KillProcess( | |
136 RenderProcessHost::FromID(embedder_render_process_id)->GetHandle(), | |
137 content::RESULT_CODE_KILLED_BAD_MESSAGE, false); | |
138 return false; | 155 return false; |
139 } | 156 |
140 return true; | 157 return GetDelegate()->CanEmbedderAccessInstanceIDMaybeKill( |
| 158 embedder_render_process_id, instance_id); |
141 } | 159 } |
142 | 160 |
143 void BrowserPluginGuestManager::OnMessageReceived(const IPC::Message& message, | 161 void BrowserPluginGuestManager::OnMessageReceived(const IPC::Message& message, |
144 int render_process_id) { | 162 int render_process_id) { |
145 DCHECK(BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(message)); | 163 DCHECK(BrowserPluginGuest::ShouldForwardToBrowserPluginGuest(message)); |
146 int instance_id = 0; | 164 int instance_id = 0; |
147 // All allowed messages must have instance_id as their first parameter. | 165 // All allowed messages must have instance_id as their first parameter. |
148 PickleIterator iter(message); | 166 PickleIterator iter(message); |
149 bool success = iter.ReadInt(&instance_id); | 167 bool success = iter.ReadInt(&instance_id); |
150 DCHECK(success); | 168 DCHECK(success); |
151 BrowserPluginGuest* guest = | 169 BrowserPluginGuest* guest = |
152 GetGuestByInstanceID(instance_id, render_process_id); | 170 GetGuestByInstanceID(instance_id, render_process_id); |
153 if (!guest) | 171 if (!guest) |
154 return; | 172 return; |
155 guest->OnMessageReceivedFromEmbedder(message); | 173 guest->OnMessageReceivedFromEmbedder(message); |
156 } | 174 } |
157 | 175 |
158 // static | |
159 bool BrowserPluginGuestManager::CanEmbedderAccessGuest( | |
160 int embedder_render_process_id, | |
161 BrowserPluginGuest* guest) { | |
162 // The embedder can access the guest if it has not been attached and its | |
163 // opener's embedder lives in the same process as the given embedder. | |
164 if (!guest->attached()) { | |
165 if (!guest->opener()) | |
166 return false; | |
167 | |
168 return embedder_render_process_id == | |
169 guest->opener()->embedder_web_contents()->GetRenderProcessHost()-> | |
170 GetID(); | |
171 } | |
172 | |
173 return embedder_render_process_id == | |
174 guest->embedder_web_contents()->GetRenderProcessHost()->GetID(); | |
175 } | |
176 | |
177 bool BrowserPluginGuestManager::CanEmbedderAccessInstanceID( | |
178 int embedder_render_process_id, | |
179 int instance_id) const { | |
180 // The embedder is trying to access a guest with a negative or zero | |
181 // instance ID. | |
182 if (instance_id <= browser_plugin::kInstanceIDNone) | |
183 return false; | |
184 | |
185 // The embedder is trying to access an instance ID that has not yet been | |
186 // allocated by BrowserPluginGuestManager. This could cause instance ID | |
187 // collisions in the future, and potentially give one embedder access to a | |
188 // guest it does not own. | |
189 if (instance_id > next_instance_id_) | |
190 return false; | |
191 | |
192 GuestInstanceMap::const_iterator it = | |
193 guest_web_contents_by_instance_id_.find(instance_id); | |
194 if (it == guest_web_contents_by_instance_id_.end()) | |
195 return true; | |
196 BrowserPluginGuest* guest = | |
197 static_cast<WebContentsImpl*>(it->second)->GetBrowserPluginGuest(); | |
198 | |
199 return CanEmbedderAccessGuest(embedder_render_process_id, guest); | |
200 } | |
201 | |
202 SiteInstance* BrowserPluginGuestManager::GetGuestSiteInstance( | 176 SiteInstance* BrowserPluginGuestManager::GetGuestSiteInstance( |
203 const GURL& guest_site) { | 177 const GURL& guest_site) { |
204 for (GuestInstanceMap::const_iterator it = | 178 if (!GetDelegate()) |
205 guest_web_contents_by_instance_id_.begin(); | 179 return NULL; |
206 it != guest_web_contents_by_instance_id_.end(); ++it) { | 180 return GetDelegate()->GetGuestSiteInstance(guest_site); |
207 if (it->second->GetSiteInstance()->GetSiteURL() == guest_site) | 181 } |
208 return it->second->GetSiteInstance(); | 182 |
209 } | 183 static bool BrowserPluginGuestCallback( |
210 return NULL; | 184 const BrowserPluginGuestManager::GuestCallback& callback, |
| 185 WebContents* guest_web_contents) { |
| 186 return callback.Run(static_cast<WebContentsImpl*>(guest_web_contents) |
| 187 ->GetBrowserPluginGuest()); |
211 } | 188 } |
212 | 189 |
213 bool BrowserPluginGuestManager::ForEachGuest( | 190 bool BrowserPluginGuestManager::ForEachGuest( |
214 WebContentsImpl* embedder_web_contents, const GuestCallback& callback) { | 191 WebContents* embedder_web_contents, const GuestCallback& callback) { |
215 for (GuestInstanceMap::iterator it = | 192 if (!GetDelegate()) |
216 guest_web_contents_by_instance_id_.begin(); | 193 return false; |
217 it != guest_web_contents_by_instance_id_.end(); ++it) { | 194 return GetDelegate()->ForEachGuest(embedder_web_contents, |
218 BrowserPluginGuest* guest = it->second->GetBrowserPluginGuest(); | 195 base::Bind(&BrowserPluginGuestCallback, |
219 if (embedder_web_contents != guest->embedder_web_contents()) | 196 callback)); |
220 continue; | |
221 | |
222 if (callback.Run(guest)) | |
223 return true; | |
224 } | |
225 return false; | |
226 } | 197 } |
227 | 198 |
228 } // namespace content | 199 } // namespace content |
OLD | NEW |