Home | History | Annotate | Download | only in media
      1 // Copyright 2013 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 "chrome/browser/media/protected_media_identifier_permission_context.h"
      6 
      7 #include <functional>
      8 #include <string>
      9 #include <vector>
     10 
     11 #include "base/bind.h"
     12 #include "base/prefs/pref_service.h"
     13 #include "base/strings/utf_string_conversions.h"
     14 #include "chrome/browser/content_settings/host_content_settings_map.h"
     15 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/tab_contents/tab_util.h"
     18 #include "chrome/common/pref_names.h"
     19 #include "components/content_settings/core/common/permission_request_id.h"
     20 #include "content/public/browser/browser_thread.h"
     21 #include "content/public/browser/render_process_host.h"
     22 #include "content/public/browser/render_view_host.h"
     23 #include "content/public/browser/web_contents.h"
     24 
     25 #if defined(ENABLE_EXTENSIONS)
     26 #include "chrome/browser/extensions/extension_service.h"
     27 #include "extensions/browser/extension_system.h"
     28 #include "extensions/browser/suggest_permission_util.h"
     29 #include "extensions/browser/view_type_utils.h"
     30 #include "extensions/common/extension.h"
     31 
     32 using extensions::APIPermission;
     33 #endif
     34 
     35 ProtectedMediaIdentifierPermissionContext::
     36     ProtectedMediaIdentifierPermissionContext(Profile* profile)
     37     : profile_(profile), shutting_down_(false) {}
     38 
     39 ProtectedMediaIdentifierPermissionContext::
     40     ~ProtectedMediaIdentifierPermissionContext() {
     41   // ProtectedMediaIdentifierPermissionContext may be destroyed on either
     42   // the UI thread or the IO thread, but the PermissionQueueController must have
     43   // been destroyed on the UI thread.
     44   DCHECK(!permission_queue_controller_.get());
     45 }
     46 
     47 void ProtectedMediaIdentifierPermissionContext::
     48     RequestProtectedMediaIdentifierPermission(
     49         content::WebContents* web_contents,
     50         const GURL& origin,
     51         base::Callback<void(bool)> result_callback,
     52         base::Closure* cancel_callback) {
     53   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     54   if (shutting_down_)
     55     return;
     56 
     57   int render_process_id = web_contents->GetRenderProcessHost()->GetID();
     58   int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
     59   if (cancel_callback) {
     60     *cancel_callback = base::Bind(
     61         &ProtectedMediaIdentifierPermissionContext::
     62             CancelProtectedMediaIdentifierPermissionRequests,
     63         this, render_process_id, render_view_id, origin);
     64   }
     65 
     66   const PermissionRequestID id(
     67       render_process_id, render_view_id, 0, origin);
     68 
     69 #if defined(ENABLE_EXTENSIONS)
     70   if (extensions::GetViewType(web_contents) !=
     71       extensions::VIEW_TYPE_TAB_CONTENTS) {
     72     // The tab may have gone away, or the request may not be from a tab at all.
     73     LOG(WARNING)
     74         << "Attempt to use protected media identifier in tabless renderer: "
     75         << id.ToString()
     76         << " (can't prompt user without a visible tab)";
     77     NotifyPermissionSet(id, origin, result_callback, false);
     78     return;
     79   }
     80 #endif
     81 
     82   GURL embedder = web_contents->GetLastCommittedURL();
     83   if (!origin.is_valid() || !embedder.is_valid()) {
     84     LOG(WARNING)
     85         << "Attempt to use protected media identifier from an invalid URL: "
     86         << origin << "," << embedder
     87         << " (proteced media identifier is not supported in popups)";
     88     NotifyPermissionSet(id, origin, result_callback, false);
     89     return;
     90   }
     91 
     92   content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
     93   DecidePermission(id, origin, embedder, rvh, result_callback);
     94 }
     95 
     96 void ProtectedMediaIdentifierPermissionContext::
     97     CancelProtectedMediaIdentifierPermissionRequests(
     98         int render_process_id,
     99         int render_view_id,
    100         const GURL& origin) {
    101   CancelPendingInfobarRequests(
    102       render_process_id, render_view_id, origin);
    103 }
    104 
    105 void ProtectedMediaIdentifierPermissionContext::DecidePermission(
    106     const PermissionRequestID& id,
    107     const GURL& origin,
    108     const GURL& embedder,
    109     content::RenderViewHost* rvh,
    110     const base::Callback<void(bool)>& callback) {
    111   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    112 
    113 #if defined(OS_ANDROID)
    114   // Check if the protected media identifier master switch is disabled.
    115   if (!profile()->GetPrefs()->GetBoolean(
    116         prefs::kProtectedMediaIdentifierEnabled)) {
    117     PermissionDecided(id, origin, embedder, callback, false);
    118     return;
    119   }
    120 #endif
    121 
    122   ContentSetting content_setting =
    123      profile_->GetHostContentSettingsMap()->GetContentSetting(
    124           origin,
    125           embedder,
    126           CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
    127           std::string());
    128   switch (content_setting) {
    129     case CONTENT_SETTING_BLOCK:
    130       PermissionDecided(id, origin, embedder, callback, false);
    131       break;
    132     case CONTENT_SETTING_ALLOW:
    133       PermissionDecided(id, origin, embedder, callback, true);
    134       break;
    135     case CONTENT_SETTING_ASK:
    136       QueueController()->CreateInfoBarRequest(
    137           id,
    138           origin,
    139           embedder,
    140           base::Bind(&ProtectedMediaIdentifierPermissionContext::
    141                           NotifyPermissionSet,
    142                      base::Unretained(this),
    143                      id,
    144                      origin,
    145                      callback));
    146       break;
    147     default:
    148       NOTREACHED();
    149   }
    150 }
    151 
    152 void ProtectedMediaIdentifierPermissionContext::ShutdownOnUIThread() {
    153   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    154   permission_queue_controller_.reset();
    155   shutting_down_ = true;
    156 }
    157 
    158 void ProtectedMediaIdentifierPermissionContext::PermissionDecided(
    159     const PermissionRequestID& id,
    160     const GURL& origin,
    161     const GURL& embedder,
    162     const base::Callback<void(bool)>& callback,
    163     bool allowed) {
    164   NotifyPermissionSet(id, origin, callback, allowed);
    165 }
    166 
    167 void ProtectedMediaIdentifierPermissionContext::NotifyPermissionSet(
    168     const PermissionRequestID& id,
    169     const GURL& origin,
    170     const base::Callback<void(bool)>& callback,
    171     bool allowed) {
    172   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    173 
    174   // WebContents may have gone away.
    175   TabSpecificContentSettings* content_settings =
    176       TabSpecificContentSettings::Get(id.render_process_id(),
    177                                       id.render_view_id());
    178   if (content_settings) {
    179     content_settings->OnProtectedMediaIdentifierPermissionSet(
    180         origin.GetOrigin(), allowed);
    181   }
    182 
    183   callback.Run(allowed);
    184 }
    185 
    186 PermissionQueueController*
    187     ProtectedMediaIdentifierPermissionContext::QueueController() {
    188   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    189   DCHECK(!shutting_down_);
    190   if (!permission_queue_controller_)
    191     permission_queue_controller_.reset(CreateQueueController());
    192   return permission_queue_controller_.get();
    193 }
    194 
    195 PermissionQueueController*
    196     ProtectedMediaIdentifierPermissionContext::CreateQueueController() {
    197   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    198   return new PermissionQueueController(
    199       profile(), CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
    200 }
    201 
    202 void
    203 ProtectedMediaIdentifierPermissionContext::CancelPendingInfobarRequests(
    204     int render_process_id,
    205     int render_view_id,
    206     const GURL& origin) {
    207   if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
    208     content::BrowserThread::PostTask(
    209         content::BrowserThread::UI,
    210         FROM_HERE,
    211         base::Bind(&ProtectedMediaIdentifierPermissionContext::
    212                         CancelPendingInfobarRequests,
    213                    this,
    214                    render_process_id,
    215                    render_view_id,
    216                    origin));
    217     return;
    218   }
    219   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
    220   if (shutting_down_)
    221     return;
    222   QueueController()->CancelInfoBarRequest(
    223       PermissionRequestID(render_process_id, render_view_id, 0,
    224                           origin));
    225 }
    226