Home | History | Annotate | Download | only in guest_view
      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.
      4 
      5 #include "extensions/browser/guest_view/guest_view_manager.h"
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "content/public/browser/browser_context.h"
      9 #include "content/public/browser/render_process_host.h"
     10 #include "content/public/browser/render_view_host.h"
     11 #include "content/public/browser/user_metrics.h"
     12 #include "content/public/browser/web_contents_observer.h"
     13 #include "content/public/common/result_codes.h"
     14 #include "content/public/common/url_constants.h"
     15 #include "extensions/browser/extension_system.h"
     16 #include "extensions/browser/guest_view/guest_view_base.h"
     17 #include "extensions/browser/guest_view/guest_view_manager_factory.h"
     18 #include "extensions/common/guest_view/guest_view_constants.h"
     19 #include "net/base/escape.h"
     20 #include "url/gurl.h"
     21 
     22 using content::BrowserContext;
     23 using content::SiteInstance;
     24 using content::WebContents;
     25 
     26 namespace extensions {
     27 
     28 // static
     29 GuestViewManagerFactory* GuestViewManager::factory_ = NULL;
     30 
     31 GuestViewManager::GuestViewManager(content::BrowserContext* context)
     32     : current_instance_id_(0), last_instance_id_removed_(0), context_(context) {
     33 }
     34 
     35 GuestViewManager::~GuestViewManager() {}
     36 
     37 // static.
     38 GuestViewManager* GuestViewManager::FromBrowserContext(
     39     BrowserContext* context) {
     40   GuestViewManager* guest_manager =
     41       static_cast<GuestViewManager*>(context->GetUserData(
     42           guestview::kGuestViewManagerKeyName));
     43   if (!guest_manager) {
     44     if (factory_) {
     45       guest_manager = factory_->CreateGuestViewManager(context);
     46     } else {
     47       guest_manager = new GuestViewManager(context);
     48     }
     49     context->SetUserData(guestview::kGuestViewManagerKeyName, guest_manager);
     50   }
     51   return guest_manager;
     52 }
     53 
     54 content::WebContents* GuestViewManager::GetGuestByInstanceIDSafely(
     55     int guest_instance_id,
     56     int embedder_render_process_id) {
     57   if (!CanEmbedderAccessInstanceIDMaybeKill(embedder_render_process_id,
     58                                             guest_instance_id)) {
     59     return NULL;
     60   }
     61   return GetGuestByInstanceID(guest_instance_id);
     62 }
     63 
     64 void GuestViewManager::AttachGuest(
     65     int embedder_render_process_id,
     66     int embedder_routing_id,
     67     int element_instance_id,
     68     int guest_instance_id,
     69     const base::DictionaryValue& attach_params) {
     70   content::WebContents* guest_web_contents =
     71       GetGuestByInstanceIDSafely(guest_instance_id, embedder_render_process_id);
     72   if (!guest_web_contents)
     73     return;
     74 
     75   GuestViewBase* guest_view =
     76       GuestViewBase::FromWebContents(guest_web_contents);
     77   DCHECK(guest_view);
     78 
     79   content::RenderViewHost* rvh =
     80       content::RenderViewHost::FromID(embedder_render_process_id,
     81                                       embedder_routing_id);
     82   content::WebContents* embedder_web_contents =
     83       content::WebContents::FromRenderViewHost(rvh);
     84   if (!embedder_web_contents)
     85     return;
     86   ElementInstanceKey key(embedder_web_contents, element_instance_id);
     87 
     88   GuestInstanceIDMap::iterator it = instance_id_map_.find(key);
     89   if (it != instance_id_map_.end()) {
     90     int old_guest_instance_id = it->second;
     91     // Reattachment to the same guest is not currently supported.
     92     if (old_guest_instance_id == guest_instance_id)
     93       return;
     94 
     95     content::WebContents* old_guest_web_contents =
     96         GetGuestByInstanceIDSafely(old_guest_instance_id,
     97                                    embedder_render_process_id);
     98     if (!old_guest_web_contents)
     99       return;
    100 
    101     GuestViewBase* old_guest_view =
    102         GuestViewBase::FromWebContents(old_guest_web_contents);
    103 
    104     old_guest_view->Destroy();
    105   }
    106   instance_id_map_[key] = guest_instance_id;
    107   reverse_instance_id_map_.insert(std::make_pair(guest_instance_id, key));
    108   guest_view->SetAttachParams(attach_params);
    109 }
    110 
    111 int GuestViewManager::GetNextInstanceID() {
    112   return ++current_instance_id_;
    113 }
    114 
    115 void GuestViewManager::CreateGuest(const std::string& view_type,
    116                                    const std::string& embedder_extension_id,
    117                                    content::WebContents* embedder_web_contents,
    118                                    const base::DictionaryValue& create_params,
    119                                    const WebContentsCreatedCallback& callback) {
    120   int guest_instance_id = GetNextInstanceID();
    121   GuestViewBase* guest =
    122       GuestViewBase::Create(context_, guest_instance_id, view_type);
    123   if (!guest) {
    124     callback.Run(NULL);
    125     return;
    126   }
    127   guest->Init(
    128       embedder_extension_id, embedder_web_contents, create_params, callback);
    129 }
    130 
    131 content::WebContents* GuestViewManager::CreateGuestWithWebContentsParams(
    132     const std::string& view_type,
    133     const std::string& embedder_extension_id,
    134     int embedder_render_process_id,
    135     const content::WebContents::CreateParams& create_params) {
    136   int guest_instance_id = GetNextInstanceID();
    137   GuestViewBase* guest =
    138       GuestViewBase::Create(context_, guest_instance_id, view_type);
    139   if (!guest)
    140     return NULL;
    141   content::WebContents::CreateParams guest_create_params(create_params);
    142   guest_create_params.guest_delegate = guest;
    143   content::WebContents* guest_web_contents =
    144       WebContents::Create(guest_create_params);
    145   guest->InitWithWebContents(embedder_extension_id,
    146                              embedder_render_process_id,
    147                              guest_web_contents);
    148   return guest_web_contents;
    149 }
    150 
    151 content::WebContents* GuestViewManager::GetGuestByInstanceID(
    152     content::WebContents* embedder_web_contents,
    153     int element_instance_id) {
    154   int guest_instance_id = GetGuestInstanceIDForElementID(embedder_web_contents,
    155                                                          element_instance_id);
    156   if (guest_instance_id == guestview::kInstanceIDNone)
    157     return NULL;
    158 
    159   return GetGuestByInstanceID(guest_instance_id);
    160 }
    161 
    162 int GuestViewManager::GetGuestInstanceIDForElementID(
    163     content::WebContents* embedder_web_contents,
    164     int element_instance_id) {
    165   GuestInstanceIDMap::iterator iter = instance_id_map_.find(
    166       ElementInstanceKey(embedder_web_contents, element_instance_id));
    167   if (iter == instance_id_map_.end())
    168     return guestview::kInstanceIDNone;
    169   return iter->second;
    170 }
    171 
    172 SiteInstance* GuestViewManager::GetGuestSiteInstance(
    173     const GURL& guest_site) {
    174   for (GuestInstanceMap::const_iterator it =
    175        guest_web_contents_by_instance_id_.begin();
    176        it != guest_web_contents_by_instance_id_.end(); ++it) {
    177     if (it->second->GetSiteInstance()->GetSiteURL() == guest_site)
    178       return it->second->GetSiteInstance();
    179   }
    180   return NULL;
    181 }
    182 
    183 bool GuestViewManager::ForEachGuest(WebContents* embedder_web_contents,
    184                                     const GuestCallback& callback) {
    185   for (GuestInstanceMap::iterator it =
    186            guest_web_contents_by_instance_id_.begin();
    187        it != guest_web_contents_by_instance_id_.end(); ++it) {
    188     WebContents* guest = it->second;
    189     GuestViewBase* guest_view = GuestViewBase::FromWebContents(guest);
    190     if (embedder_web_contents != guest_view->embedder_web_contents())
    191       continue;
    192 
    193     if (callback.Run(guest))
    194       return true;
    195   }
    196   return false;
    197 }
    198 
    199 void GuestViewManager::AddGuest(int guest_instance_id,
    200                                 WebContents* guest_web_contents) {
    201   CHECK(!ContainsKey(guest_web_contents_by_instance_id_, guest_instance_id));
    202   CHECK(CanUseGuestInstanceID(guest_instance_id));
    203   guest_web_contents_by_instance_id_[guest_instance_id] = guest_web_contents;
    204 }
    205 
    206 void GuestViewManager::RemoveGuest(int guest_instance_id) {
    207   GuestInstanceMap::iterator it =
    208       guest_web_contents_by_instance_id_.find(guest_instance_id);
    209   DCHECK(it != guest_web_contents_by_instance_id_.end());
    210   guest_web_contents_by_instance_id_.erase(it);
    211 
    212   GuestInstanceIDReverseMap::iterator id_iter =
    213       reverse_instance_id_map_.find(guest_instance_id);
    214   if (id_iter != reverse_instance_id_map_.end()) {
    215     const ElementInstanceKey& instance_id_key = id_iter->second;
    216     instance_id_map_.erase(instance_id_map_.find(instance_id_key));
    217     reverse_instance_id_map_.erase(id_iter);
    218   }
    219 
    220   // All the instance IDs that lie within [0, last_instance_id_removed_]
    221   // are invalid.
    222   // The remaining sparse invalid IDs are kept in |removed_instance_ids_| set.
    223   // The following code compacts the set by incrementing
    224   // |last_instance_id_removed_|.
    225   if (guest_instance_id == last_instance_id_removed_ + 1) {
    226     ++last_instance_id_removed_;
    227     // Compact.
    228     std::set<int>::iterator iter = removed_instance_ids_.begin();
    229     while (iter != removed_instance_ids_.end()) {
    230       int instance_id = *iter;
    231       // The sparse invalid IDs must not lie within
    232       // [0, last_instance_id_removed_]
    233       DCHECK(instance_id > last_instance_id_removed_);
    234       if (instance_id != last_instance_id_removed_ + 1)
    235         break;
    236       ++last_instance_id_removed_;
    237       removed_instance_ids_.erase(iter++);
    238     }
    239   } else {
    240     removed_instance_ids_.insert(guest_instance_id);
    241   }
    242 }
    243 
    244 content::WebContents* GuestViewManager::GetGuestByInstanceID(
    245     int guest_instance_id) {
    246   GuestInstanceMap::const_iterator it =
    247       guest_web_contents_by_instance_id_.find(guest_instance_id);
    248   if (it == guest_web_contents_by_instance_id_.end())
    249     return NULL;
    250   return it->second;
    251 }
    252 
    253 bool GuestViewManager::CanEmbedderAccessInstanceIDMaybeKill(
    254     int embedder_render_process_id,
    255     int guest_instance_id) {
    256   if (!CanEmbedderAccessInstanceID(embedder_render_process_id,
    257                                    guest_instance_id)) {
    258     // The embedder process is trying to access a guest it does not own.
    259     content::RecordAction(
    260         base::UserMetricsAction("BadMessageTerminate_BPGM"));
    261     base::KillProcess(
    262         content::RenderProcessHost::FromID(embedder_render_process_id)->
    263             GetHandle(),
    264         content::RESULT_CODE_KILLED_BAD_MESSAGE, false);
    265     return false;
    266   }
    267   return true;
    268 }
    269 
    270 bool GuestViewManager::CanUseGuestInstanceID(int guest_instance_id) {
    271   if (guest_instance_id <= last_instance_id_removed_)
    272     return false;
    273   return !ContainsKey(removed_instance_ids_, guest_instance_id);
    274 }
    275 
    276 bool GuestViewManager::CanEmbedderAccessInstanceID(
    277     int embedder_render_process_id,
    278     int guest_instance_id) {
    279   // The embedder is trying to access a guest with a negative or zero
    280   // instance ID.
    281   if (guest_instance_id <= guestview::kInstanceIDNone)
    282     return false;
    283 
    284   // The embedder is trying to access an instance ID that has not yet been
    285   // allocated by GuestViewManager. This could cause instance ID
    286   // collisions in the future, and potentially give one embedder access to a
    287   // guest it does not own.
    288   if (guest_instance_id > current_instance_id_)
    289     return false;
    290 
    291   // We might get some late arriving messages at tear down. Let's let the
    292   // embedder tear down in peace.
    293   GuestInstanceMap::const_iterator it =
    294       guest_web_contents_by_instance_id_.find(guest_instance_id);
    295   if (it == guest_web_contents_by_instance_id_.end())
    296     return true;
    297 
    298   GuestViewBase* guest_view = GuestViewBase::FromWebContents(it->second);
    299   if (!guest_view)
    300     return false;
    301 
    302   return embedder_render_process_id == guest_view->embedder_render_process_id();
    303 }
    304 
    305 }  // namespace extensions
    306