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