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 32using extensions::APIPermission; 33#endif 34 35ProtectedMediaIdentifierPermissionContext:: 36 ProtectedMediaIdentifierPermissionContext(Profile* profile) 37 : profile_(profile), shutting_down_(false) {} 38 39ProtectedMediaIdentifierPermissionContext:: 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 47void 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 96void 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 105void 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 152void ProtectedMediaIdentifierPermissionContext::ShutdownOnUIThread() { 153 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 154 permission_queue_controller_.reset(); 155 shutting_down_ = true; 156} 157 158void 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 167void 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 186PermissionQueueController* 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 195PermissionQueueController* 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 202void 203ProtectedMediaIdentifierPermissionContext::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