Home | History | Annotate | Download | only in geolocation
      1 // Copyright (c) 2011 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/geolocation/geolocation_permission_context.h"
      6 
      7 #include <functional>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/utf_string_conversions.h"
     12 #include "chrome/browser/extensions/extension_service.h"
     13 #include "chrome/browser/geolocation/geolocation_content_settings_map.h"
     14 #include "chrome/browser/google/google_util.h"
     15 #include "chrome/browser/prefs/pref_service.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/tab_contents/confirm_infobar_delegate.h"
     18 #include "chrome/browser/tab_contents/tab_util.h"
     19 #include "chrome/common/extensions/extension.h"
     20 #include "chrome/common/pref_names.h"
     21 #include "content/browser/browser_thread.h"
     22 #include "content/browser/geolocation/geolocation_provider.h"
     23 #include "content/browser/renderer_host/render_process_host.h"
     24 #include "content/browser/renderer_host/render_view_host.h"
     25 #include "content/browser/tab_contents/tab_contents.h"
     26 #include "content/common/geolocation_messages.h"
     27 #include "content/common/notification_registrar.h"
     28 #include "content/common/notification_source.h"
     29 #include "content/common/notification_type.h"
     30 #include "grit/generated_resources.h"
     31 #include "grit/locale_settings.h"
     32 #include "grit/theme_resources.h"
     33 #include "net/base/net_util.h"
     34 #include "ui/base/l10n/l10n_util.h"
     35 #include "ui/base/resource/resource_bundle.h"
     36 
     37 // GeolocationInfoBarQueueController ------------------------------------------
     38 
     39 // This class controls the geolocation infobar queue per profile, and it's an
     40 // internal class to GeolocationPermissionContext.
     41 // An alternate approach would be to have this queue per tab, and use
     42 // notifications to broadcast when permission is set / listen to notification to
     43 // cancel pending requests. This may be specially useful if there are other
     44 // things listening for such notifications.
     45 // For the time being this class is self-contained and it doesn't seem pulling
     46 // the notification infrastructure would simplify.
     47 class GeolocationInfoBarQueueController : NotificationObserver {
     48  public:
     49   GeolocationInfoBarQueueController(
     50       GeolocationPermissionContext* geolocation_permission_context,
     51       Profile* profile);
     52   ~GeolocationInfoBarQueueController();
     53 
     54   // The InfoBar will be displayed immediately if the tab is not already
     55   // displaying one, otherwise it'll be queued.
     56   void CreateInfoBarRequest(int render_process_id,
     57                             int render_view_id,
     58                             int bridge_id,
     59                             const GURL& requesting_frame,
     60                             const GURL& emebedder);
     61 
     62   // Cancels a specific infobar request.
     63   void CancelInfoBarRequest(int render_process_id,
     64                             int render_view_id,
     65                             int bridge_id);
     66 
     67   // Called by the InfoBarDelegate to notify it's closed. It'll display a new
     68   // InfoBar if there's any request pending for this tab.
     69   void OnInfoBarClosed(int render_process_id,
     70                        int render_view_id,
     71                        int bridge_id);
     72 
     73   // Called by the InfoBarDelegate to notify permission has been set.
     74   // It'll notify and dismiss any other pending InfoBar request for the same
     75   // |requesting_frame| and embedder.
     76   void OnPermissionSet(int render_process_id,
     77                        int render_view_id,
     78                        int bridge_id,
     79                        const GURL& requesting_frame,
     80                        const GURL& embedder,
     81                        bool allowed);
     82 
     83   // NotificationObserver
     84   virtual void Observe(NotificationType type,
     85                        const NotificationSource& source,
     86                        const NotificationDetails& details);
     87 
     88  private:
     89   struct PendingInfoBarRequest;
     90   class RequestEquals;
     91 
     92   typedef std::vector<PendingInfoBarRequest> PendingInfoBarRequests;
     93 
     94   // Shows the first pending infobar for this tab.
     95   void ShowQueuedInfoBar(int render_process_id, int render_view_id);
     96 
     97   // Cancels an InfoBar request and returns the next iterator position.
     98   PendingInfoBarRequests::iterator CancelInfoBarRequestInternal(
     99       PendingInfoBarRequests::iterator i);
    100 
    101   NotificationRegistrar registrar_;
    102 
    103   GeolocationPermissionContext* const geolocation_permission_context_;
    104   Profile* const profile_;
    105   PendingInfoBarRequests pending_infobar_requests_;
    106 };
    107 
    108 
    109 // GeolocationConfirmInfoBarDelegate ------------------------------------------
    110 
    111 namespace {
    112 
    113 class GeolocationConfirmInfoBarDelegate : public ConfirmInfoBarDelegate {
    114  public:
    115   GeolocationConfirmInfoBarDelegate(
    116       TabContents* tab_contents,
    117       GeolocationInfoBarQueueController* controller,
    118       int render_process_id,
    119       int render_view_id,
    120       int bridge_id,
    121       const GURL& requesting_frame_url,
    122       const std::string& display_languages);
    123 
    124  private:
    125   virtual ~GeolocationConfirmInfoBarDelegate();
    126 
    127   // ConfirmInfoBarDelegate:
    128   virtual void InfoBarClosed();
    129   virtual SkBitmap* GetIcon() const;
    130   virtual Type GetInfoBarType() const;
    131   virtual string16 GetMessageText() const;
    132   virtual string16 GetButtonLabel(InfoBarButton button) const;
    133   virtual bool Accept();
    134   virtual bool Cancel();
    135   virtual string16 GetLinkText();
    136   virtual bool LinkClicked(WindowOpenDisposition disposition);
    137 
    138   TabContents* tab_contents_;
    139   GeolocationInfoBarQueueController* controller_;
    140   int render_process_id_;
    141   int render_view_id_;
    142   int bridge_id_;
    143   GURL requesting_frame_url_;
    144   std::string display_languages_;
    145 
    146   DISALLOW_IMPLICIT_CONSTRUCTORS(GeolocationConfirmInfoBarDelegate);
    147 };
    148 
    149 GeolocationConfirmInfoBarDelegate::GeolocationConfirmInfoBarDelegate(
    150     TabContents* tab_contents,
    151     GeolocationInfoBarQueueController* controller,
    152     int render_process_id,
    153     int render_view_id,
    154     int bridge_id,
    155     const GURL& requesting_frame_url,
    156     const std::string& display_languages)
    157     : ConfirmInfoBarDelegate(tab_contents),
    158       tab_contents_(tab_contents),
    159       controller_(controller),
    160       render_process_id_(render_process_id),
    161       render_view_id_(render_view_id),
    162       bridge_id_(bridge_id),
    163       requesting_frame_url_(requesting_frame_url),
    164       display_languages_(display_languages) {
    165 }
    166 
    167 GeolocationConfirmInfoBarDelegate::~GeolocationConfirmInfoBarDelegate() {
    168 }
    169 
    170 void GeolocationConfirmInfoBarDelegate::InfoBarClosed() {
    171   controller_->OnInfoBarClosed(render_process_id_, render_view_id_,
    172                                bridge_id_);
    173   delete this;
    174 }
    175 
    176 SkBitmap* GeolocationConfirmInfoBarDelegate::GetIcon() const {
    177   return ResourceBundle::GetSharedInstance().GetBitmapNamed(
    178       IDR_GEOLOCATION_INFOBAR_ICON);
    179 }
    180 
    181 InfoBarDelegate::Type
    182     GeolocationConfirmInfoBarDelegate::GetInfoBarType() const {
    183   return PAGE_ACTION_TYPE;
    184 }
    185 
    186 string16 GeolocationConfirmInfoBarDelegate::GetMessageText() const {
    187   return l10n_util::GetStringFUTF16(IDS_GEOLOCATION_INFOBAR_QUESTION,
    188       net::FormatUrl(requesting_frame_url_.GetOrigin(), display_languages_));
    189 }
    190 
    191 string16 GeolocationConfirmInfoBarDelegate::GetButtonLabel(
    192     InfoBarButton button) const {
    193   return l10n_util::GetStringUTF16((button == BUTTON_OK) ?
    194       IDS_GEOLOCATION_ALLOW_BUTTON : IDS_GEOLOCATION_DENY_BUTTON);
    195 }
    196 
    197 bool GeolocationConfirmInfoBarDelegate::Accept() {
    198   controller_->OnPermissionSet(render_process_id_, render_view_id_, bridge_id_,
    199       requesting_frame_url_, tab_contents_->GetURL(), true);
    200   return true;
    201 }
    202 
    203 bool GeolocationConfirmInfoBarDelegate::Cancel() {
    204   controller_->OnPermissionSet(render_process_id_, render_view_id_, bridge_id_,
    205       requesting_frame_url_, tab_contents_->GetURL(), false);
    206   return true;
    207 }
    208 
    209 string16 GeolocationConfirmInfoBarDelegate::GetLinkText() {
    210   return l10n_util::GetStringUTF16(IDS_LEARN_MORE);
    211 }
    212 
    213 bool GeolocationConfirmInfoBarDelegate::LinkClicked(
    214     WindowOpenDisposition disposition) {
    215   const char kGeolocationLearnMoreUrl[] =
    216 #if defined(OS_CHROMEOS)
    217       "https://www.google.com/support/chromeos/bin/answer.py?answer=142065";
    218 #else
    219       "https://www.google.com/support/chrome/bin/answer.py?answer=142065";
    220 #endif
    221 
    222   // Ignore the click disposition and always open in a new top level tab.
    223   tab_contents_->OpenURL(
    224       google_util::AppendGoogleLocaleParam(GURL(kGeolocationLearnMoreUrl)),
    225       GURL(), NEW_FOREGROUND_TAB, PageTransition::LINK);
    226   return false;  // Do not dismiss the info bar.
    227 }
    228 
    229 }  // namespace
    230 
    231 
    232 // GeolocationInfoBarQueueController::PendingInfoBarRequest -------------------
    233 
    234 struct GeolocationInfoBarQueueController::PendingInfoBarRequest {
    235  public:
    236   PendingInfoBarRequest(int render_process_id,
    237                         int render_view_id,
    238                         int bridge_id,
    239                         const GURL& requesting_frame,
    240                         const GURL& embedder);
    241 
    242   bool IsForTab(int p_render_process_id, int p_render_view_id) const;
    243   bool IsForPair(const GURL& p_requesting_frame,
    244                  const GURL& p_embedder) const;
    245   bool Equals(int p_render_process_id,
    246               int p_render_view_id,
    247               int p_bridge_id) const;
    248 
    249   int render_process_id;
    250   int render_view_id;
    251   int bridge_id;
    252   GURL requesting_frame;
    253   GURL embedder;
    254   InfoBarDelegate* infobar_delegate;
    255 };
    256 
    257 GeolocationInfoBarQueueController::PendingInfoBarRequest::PendingInfoBarRequest(
    258     int render_process_id,
    259     int render_view_id,
    260     int bridge_id,
    261     const GURL& requesting_frame,
    262     const GURL& embedder)
    263     : render_process_id(render_process_id),
    264       render_view_id(render_view_id),
    265       bridge_id(bridge_id),
    266       requesting_frame(requesting_frame),
    267       embedder(embedder),
    268       infobar_delegate(NULL) {
    269 }
    270 
    271 bool GeolocationInfoBarQueueController::PendingInfoBarRequest::IsForTab(
    272     int p_render_process_id,
    273     int p_render_view_id) const {
    274   return (render_process_id == p_render_process_id) &&
    275       (render_view_id == p_render_view_id);
    276 }
    277 
    278 bool GeolocationInfoBarQueueController::PendingInfoBarRequest::IsForPair(
    279     const GURL& p_requesting_frame,
    280     const GURL& p_embedder) const {
    281   return (requesting_frame == p_requesting_frame) && (embedder == p_embedder);
    282 }
    283 
    284 bool GeolocationInfoBarQueueController::PendingInfoBarRequest::Equals(
    285     int p_render_process_id,
    286     int p_render_view_id,
    287     int p_bridge_id) const {
    288   return IsForTab(p_render_process_id, p_render_view_id) &&
    289      (bridge_id == p_bridge_id);
    290 }
    291 
    292 
    293 // GeolocationInfoBarQueueController::RequestEquals ---------------------------
    294 
    295 // Useful predicate for checking PendingInfoBarRequest equality.
    296 class GeolocationInfoBarQueueController::RequestEquals
    297     : public std::unary_function<PendingInfoBarRequest, bool> {
    298  public:
    299   RequestEquals(int render_process_id, int render_view_id, int bridge_id);
    300 
    301   bool operator()(const PendingInfoBarRequest& request) const;
    302 
    303  private:
    304   int render_process_id_;
    305   int render_view_id_;
    306   int bridge_id_;
    307 };
    308 
    309 GeolocationInfoBarQueueController::RequestEquals::RequestEquals(
    310     int render_process_id,
    311     int render_view_id,
    312     int bridge_id)
    313     : render_process_id_(render_process_id),
    314       render_view_id_(render_view_id),
    315       bridge_id_(bridge_id) {
    316 }
    317 
    318 bool GeolocationInfoBarQueueController::RequestEquals::operator()(
    319     const PendingInfoBarRequest& request) const {
    320   return request.Equals(render_process_id_, render_view_id_, bridge_id_);
    321 }
    322 
    323 
    324 // GeolocationInfoBarQueueController ------------------------------------------
    325 
    326 GeolocationInfoBarQueueController::GeolocationInfoBarQueueController(
    327     GeolocationPermissionContext* geolocation_permission_context,
    328     Profile* profile)
    329     : geolocation_permission_context_(geolocation_permission_context),
    330       profile_(profile) {
    331 }
    332 
    333 GeolocationInfoBarQueueController::~GeolocationInfoBarQueueController() {
    334 }
    335 
    336 void GeolocationInfoBarQueueController::CreateInfoBarRequest(
    337     int render_process_id,
    338     int render_view_id,
    339     int bridge_id,
    340     const GURL& requesting_frame,
    341     const GURL& embedder) {
    342   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    343 
    344   // We shouldn't get duplicate requests.
    345   DCHECK(std::find_if(pending_infobar_requests_.begin(),
    346       pending_infobar_requests_.end(),
    347       RequestEquals(render_process_id, render_view_id, bridge_id)) ==
    348       pending_infobar_requests_.end());
    349 
    350   pending_infobar_requests_.push_back(PendingInfoBarRequest(render_process_id,
    351       render_view_id, bridge_id, requesting_frame, embedder));
    352   ShowQueuedInfoBar(render_process_id, render_view_id);
    353 }
    354 
    355 void GeolocationInfoBarQueueController::CancelInfoBarRequest(
    356     int render_process_id,
    357     int render_view_id,
    358     int bridge_id) {
    359   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    360 
    361   PendingInfoBarRequests::iterator i = std::find_if(
    362       pending_infobar_requests_.begin(), pending_infobar_requests_.end(),
    363       RequestEquals(render_process_id, render_view_id, bridge_id));
    364   // TODO(pkasting): Can this conditional become a DCHECK()?
    365   if (i != pending_infobar_requests_.end())
    366     CancelInfoBarRequestInternal(i);
    367 }
    368 
    369 void GeolocationInfoBarQueueController::OnInfoBarClosed(int render_process_id,
    370                                                         int render_view_id,
    371                                                         int bridge_id) {
    372   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    373 
    374   PendingInfoBarRequests::iterator i = std::find_if(
    375       pending_infobar_requests_.begin(), pending_infobar_requests_.end(),
    376       RequestEquals(render_process_id, render_view_id, bridge_id));
    377   if (i != pending_infobar_requests_.end())
    378     pending_infobar_requests_.erase(i);
    379 
    380   ShowQueuedInfoBar(render_process_id, render_view_id);
    381 }
    382 
    383 void GeolocationInfoBarQueueController::OnPermissionSet(
    384     int render_process_id,
    385     int render_view_id,
    386     int bridge_id,
    387     const GURL& requesting_frame,
    388     const GURL& embedder,
    389     bool allowed) {
    390   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    391 
    392   ContentSetting content_setting =
    393       allowed ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK;
    394   profile_->GetGeolocationContentSettingsMap()->SetContentSetting(
    395       requesting_frame.GetOrigin(), embedder.GetOrigin(), content_setting);
    396 
    397   for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
    398        i != pending_infobar_requests_.end(); ) {
    399     if (i->IsForPair(requesting_frame, embedder)) {
    400       // Cancel this request first, then notify listeners.  TODO(pkasting): Why
    401       // is this order important?
    402       // NOTE: If the pending request had an infobar, TabContents will close it
    403       // either synchronously or asynchronously, which will then pump the queue
    404       // via OnInfoBarClosed().
    405       PendingInfoBarRequest copied_request = *i;
    406       // Don't let CancelInfoBarRequestInternal() call RemoveInfoBar() on the
    407       // delegate that's currently calling us.  That delegate is in either
    408       // Accept() or Cancel(), so its owning InfoBar will call RemoveInfoBar()
    409       // later on in this callstack anyway; and if we do it here, and it causes
    410       // the delegate to be deleted, our GURL& args will point to garbage and we
    411       // may also cause other problems during stack unwinding.
    412       if (i->Equals(render_process_id, render_view_id, bridge_id))
    413         i->infobar_delegate = NULL;
    414       i = CancelInfoBarRequestInternal(i);
    415 
    416       geolocation_permission_context_->NotifyPermissionSet(
    417           copied_request.render_process_id, copied_request.render_view_id,
    418           copied_request.bridge_id, copied_request.requesting_frame, allowed);
    419     } else {
    420       ++i;
    421     }
    422   }
    423 }
    424 
    425 void GeolocationInfoBarQueueController::Observe(
    426     NotificationType type, const NotificationSource& source,
    427     const NotificationDetails& details) {
    428   registrar_.Remove(this, NotificationType::TAB_CONTENTS_DESTROYED,
    429                     source);
    430   TabContents* tab_contents = Source<TabContents>(source).ptr();
    431   for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
    432        i != pending_infobar_requests_.end();) {
    433     if (i->infobar_delegate == NULL &&
    434         tab_contents == tab_util::GetTabContentsByID(i->render_process_id,
    435                                                      i->render_view_id)) {
    436       i = pending_infobar_requests_.erase(i);
    437     } else {
    438       ++i;
    439     }
    440   }
    441 }
    442 
    443 void GeolocationInfoBarQueueController::ShowQueuedInfoBar(int render_process_id,
    444                                                           int render_view_id) {
    445   TabContents* tab_contents =
    446       tab_util::GetTabContentsByID(render_process_id, render_view_id);
    447   for (PendingInfoBarRequests::iterator i = pending_infobar_requests_.begin();
    448        i != pending_infobar_requests_.end(); ) {
    449     if (i->IsForTab(render_process_id, render_view_id)) {
    450       if (!tab_contents) {
    451         i = pending_infobar_requests_.erase(i);
    452         continue;
    453       }
    454 
    455       if (!i->infobar_delegate) {
    456         if (!registrar_.IsRegistered(this,
    457                                      NotificationType::TAB_CONTENTS_DESTROYED,
    458                                      Source<TabContents>(tab_contents))) {
    459           registrar_.Add(this, NotificationType::TAB_CONTENTS_DESTROYED,
    460                          Source<TabContents>(tab_contents));
    461         }
    462         i->infobar_delegate = new GeolocationConfirmInfoBarDelegate(
    463             tab_contents, this, render_process_id, render_view_id, i->bridge_id,
    464             i->requesting_frame,
    465             profile_->GetPrefs()->GetString(prefs::kAcceptLanguages));
    466         tab_contents->AddInfoBar(i->infobar_delegate);
    467       }
    468       break;
    469     }
    470     ++i;
    471   }
    472 }
    473 
    474 GeolocationInfoBarQueueController::PendingInfoBarRequests::iterator
    475     GeolocationInfoBarQueueController::CancelInfoBarRequestInternal(
    476     PendingInfoBarRequests::iterator i) {
    477   InfoBarDelegate* delegate = i->infobar_delegate;
    478   if (!delegate)
    479     return pending_infobar_requests_.erase(i);
    480 
    481   TabContents* tab_contents =
    482       tab_util::GetTabContentsByID(i->render_process_id, i->render_view_id);
    483   if (!tab_contents)
    484     return pending_infobar_requests_.erase(i);
    485 
    486   // TabContents will destroy the InfoBar, which will remove from our vector
    487   // asynchronously.
    488   tab_contents->RemoveInfoBar(i->infobar_delegate);
    489   return ++i;
    490 }
    491 
    492 
    493 // GeolocationPermissionContext -----------------------------------------------
    494 
    495 GeolocationPermissionContext::GeolocationPermissionContext(
    496     Profile* profile)
    497     : profile_(profile),
    498       ALLOW_THIS_IN_INITIALIZER_LIST(geolocation_infobar_queue_controller_(
    499          new GeolocationInfoBarQueueController(this, profile))) {
    500 }
    501 
    502 GeolocationPermissionContext::~GeolocationPermissionContext() {
    503 }
    504 
    505 void GeolocationPermissionContext::RequestGeolocationPermission(
    506     int render_process_id, int render_view_id, int bridge_id,
    507     const GURL& requesting_frame) {
    508   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    509     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
    510         this, &GeolocationPermissionContext::RequestGeolocationPermission,
    511         render_process_id, render_view_id, bridge_id, requesting_frame));
    512     return;
    513   }
    514   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    515 
    516   ExtensionService* extensions = profile_->GetExtensionService();
    517   if (extensions) {
    518     const Extension* ext = extensions->GetExtensionByURL(requesting_frame);
    519     if (!ext)
    520       ext = extensions->GetExtensionByWebExtent(requesting_frame);
    521     if (ext && ext->HasApiPermission(Extension::kGeolocationPermission)) {
    522       ExtensionProcessManager* epm = profile_->GetExtensionProcessManager();
    523       RenderProcessHost* process = epm->GetExtensionProcess(requesting_frame);
    524       if (process && process->id() == render_process_id) {
    525         NotifyPermissionSet(render_process_id, render_view_id, bridge_id,
    526                             requesting_frame, true);
    527         return;
    528       }
    529     }
    530   }
    531 
    532   TabContents* tab_contents =
    533       tab_util::GetTabContentsByID(render_process_id, render_view_id);
    534   if (!tab_contents) {
    535     // The tab may have gone away, or the request may not be from a tab at all.
    536     LOG(WARNING) << "Attempt to use geolocation tabless renderer: "
    537                  << render_process_id << "," << render_view_id << ","
    538                  << bridge_id << " (can't prompt user without a visible tab)";
    539     NotifyPermissionSet(render_process_id, render_view_id, bridge_id,
    540                         requesting_frame, false);
    541     return;
    542   }
    543 
    544   GURL embedder = tab_contents->GetURL();
    545   if (!requesting_frame.is_valid() || !embedder.is_valid()) {
    546     LOG(WARNING) << "Attempt to use geolocation from an invalid URL: "
    547                  << requesting_frame << "," << embedder
    548                  << " (geolocation is not supported in popups)";
    549     NotifyPermissionSet(render_process_id, render_view_id, bridge_id,
    550                         requesting_frame, false);
    551     return;
    552   }
    553 
    554   ContentSetting content_setting =
    555       profile_->GetGeolocationContentSettingsMap()->GetContentSetting(
    556           requesting_frame, embedder);
    557   if (content_setting == CONTENT_SETTING_BLOCK) {
    558     NotifyPermissionSet(render_process_id, render_view_id, bridge_id,
    559                         requesting_frame, false);
    560   } else if (content_setting == CONTENT_SETTING_ALLOW) {
    561     NotifyPermissionSet(render_process_id, render_view_id, bridge_id,
    562                         requesting_frame, true);
    563   } else {  // setting == ask. Prompt the user.
    564     geolocation_infobar_queue_controller_->CreateInfoBarRequest(
    565         render_process_id, render_view_id, bridge_id, requesting_frame,
    566         embedder);
    567   }
    568 }
    569 
    570 void GeolocationPermissionContext::CancelGeolocationPermissionRequest(
    571     int render_process_id,
    572     int render_view_id,
    573     int bridge_id,
    574     const GURL& requesting_frame) {
    575   CancelPendingInfoBarRequest(render_process_id, render_view_id, bridge_id);
    576 }
    577 
    578 void GeolocationPermissionContext::NotifyPermissionSet(
    579     int render_process_id,
    580     int render_view_id,
    581     int bridge_id,
    582     const GURL& requesting_frame,
    583     bool allowed) {
    584   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    585 
    586   TabContents* tab_contents =
    587       tab_util::GetTabContentsByID(render_process_id, render_view_id);
    588 
    589   // TabContents may have gone away (or not exists for extension).
    590   if (tab_contents) {
    591     TabSpecificContentSettings* content_settings =
    592         tab_contents->GetTabSpecificContentSettings();
    593     content_settings->OnGeolocationPermissionSet(requesting_frame.GetOrigin(),
    594                                                  allowed);
    595   }
    596 
    597   RenderViewHost* r = RenderViewHost::FromID(render_process_id, render_view_id);
    598   if (r) {
    599     r->Send(new GeolocationMsg_PermissionSet(
    600         render_view_id, bridge_id, allowed));
    601   }
    602 
    603   if (allowed) {
    604     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, NewRunnableMethod(
    605         this, &GeolocationPermissionContext::NotifyArbitratorPermissionGranted,
    606         requesting_frame));
    607   }
    608 }
    609 
    610 void GeolocationPermissionContext::NotifyArbitratorPermissionGranted(
    611     const GURL& requesting_frame) {
    612   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    613   GeolocationProvider::GetInstance()->OnPermissionGranted(requesting_frame);
    614 }
    615 
    616 void GeolocationPermissionContext::CancelPendingInfoBarRequest(
    617     int render_process_id,
    618     int render_view_id,
    619     int bridge_id) {
    620   if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    621     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, NewRunnableMethod(
    622         this, &GeolocationPermissionContext::CancelPendingInfoBarRequest,
    623         render_process_id, render_view_id, bridge_id));
    624      return;
    625   }
    626   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    627   geolocation_infobar_queue_controller_->CancelInfoBarRequest(render_process_id,
    628       render_view_id, bridge_id);
    629 }
    630