| 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 |