blob: 8adbab20f4896aaf85375fd96736cd6d6998509a [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include <list>
#include "base/command_line.h"
#include "base/lazy_instance.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
#include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
#include "chrome/browser/browsing_data/browsing_data_database_helper.h"
#include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
#include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
#include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
#include "chrome/browser/browsing_data/cookies_tree_model.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/content_settings/chrome_content_settings_utils.h"
#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
#include "chrome/browser/media/media_capture_devices_dispatcher.h"
#include "chrome/browser/media/media_stream_capture_indicator.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/render_messages.h"
#include "components/content_settings/content/common/content_settings_messages.h"
#include "components/content_settings/core/browser/content_settings_details.h"
#include "components/content_settings/core/browser/content_settings_info.h"
#include "components/content_settings/core/browser/content_settings_registry.h"
#include "components/content_settings/core/browser/content_settings_utils.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_details.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_delegate.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/cookies/canonical_cookie.h"
#include "storage/common/fileapi/file_system_types.h"
using content::BrowserThread;
using content::NavigationController;
using content::NavigationEntry;
using content::WebContents;
DEFINE_WEB_CONTENTS_USER_DATA_KEY(TabSpecificContentSettings);
namespace {
ContentSettingsUsagesState::CommittedDetails GetCommittedDetails(
const content::LoadCommittedDetails& details) {
ContentSettingsUsagesState::CommittedDetails committed_details;
committed_details.current_url_valid = !!details.entry;
if (details.entry)
committed_details.current_url = details.entry->GetURL();
committed_details.previous_url = details.previous_url;
return committed_details;
}
} // namespace
TabSpecificContentSettings::SiteDataObserver::SiteDataObserver(
TabSpecificContentSettings* tab_specific_content_settings)
: tab_specific_content_settings_(tab_specific_content_settings) {
tab_specific_content_settings_->AddSiteDataObserver(this);
}
TabSpecificContentSettings::SiteDataObserver::~SiteDataObserver() {
if (tab_specific_content_settings_)
tab_specific_content_settings_->RemoveSiteDataObserver(this);
}
void TabSpecificContentSettings::SiteDataObserver::ContentSettingsDestroyed() {
tab_specific_content_settings_ = NULL;
}
TabSpecificContentSettings::TabSpecificContentSettings(WebContents* tab)
: content::WebContentsObserver(tab),
allowed_local_shared_objects_(
Profile::FromBrowserContext(tab->GetBrowserContext())),
blocked_local_shared_objects_(
Profile::FromBrowserContext(tab->GetBrowserContext())),
geolocation_usages_state_(
HostContentSettingsMapFactory::GetForProfile(
Profile::FromBrowserContext(tab->GetBrowserContext())),
CONTENT_SETTINGS_TYPE_GEOLOCATION,
prefs::kAcceptLanguages,
Profile::FromBrowserContext(tab->GetBrowserContext())->GetPrefs()),
midi_usages_state_(
HostContentSettingsMapFactory::GetForProfile(
Profile::FromBrowserContext(tab->GetBrowserContext())),
CONTENT_SETTINGS_TYPE_MIDI_SYSEX,
prefs::kAcceptLanguages,
Profile::FromBrowserContext(tab->GetBrowserContext())->GetPrefs()),
pending_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
previous_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
pending_protocol_handler_setting_(CONTENT_SETTING_DEFAULT),
load_plugins_link_enabled_(true),
microphone_camera_state_(MICROPHONE_CAMERA_NOT_ACCESSED),
observer_(this) {
ClearBlockedContentSettingsExceptForCookies();
ClearCookieSpecificContentSettings();
observer_.Add(HostContentSettingsMapFactory::GetForProfile(
Profile::FromBrowserContext(tab->GetBrowserContext())));
}
TabSpecificContentSettings::~TabSpecificContentSettings() {
FOR_EACH_OBSERVER(
SiteDataObserver, observer_list_, ContentSettingsDestroyed());
}
TabSpecificContentSettings* TabSpecificContentSettings::GetForFrame(
int render_process_id,
int render_frame_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
content::RenderFrameHost* frame = content::RenderFrameHost::FromID(
render_process_id, render_frame_id);
WebContents* web_contents = WebContents::FromRenderFrameHost(frame);
if (!web_contents)
return nullptr;
return TabSpecificContentSettings::FromWebContents(web_contents);
}
// static
void TabSpecificContentSettings::CookiesRead(int render_process_id,
int render_frame_id,
const GURL& url,
const GURL& frame_url,
const net::CookieList& cookie_list,
bool blocked_by_policy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TabSpecificContentSettings* settings =
GetForFrame(render_process_id, render_frame_id);
if (settings) {
settings->OnCookiesRead(url, frame_url, cookie_list,
blocked_by_policy);
}
}
// static
void TabSpecificContentSettings::CookieChanged(
int render_process_id,
int render_frame_id,
const GURL& url,
const GURL& frame_url,
const std::string& cookie_line,
const net::CookieOptions& options,
bool blocked_by_policy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TabSpecificContentSettings* settings =
GetForFrame(render_process_id, render_frame_id);
if (settings)
settings->OnCookieChanged(url, frame_url, cookie_line, options,
blocked_by_policy);
}
// static
void TabSpecificContentSettings::WebDatabaseAccessed(
int render_process_id,
int render_frame_id,
const GURL& url,
const base::string16& name,
const base::string16& display_name,
bool blocked_by_policy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TabSpecificContentSettings* settings = GetForFrame(
render_process_id, render_frame_id);
if (settings)
settings->OnWebDatabaseAccessed(url, name, display_name, blocked_by_policy);
}
// static
void TabSpecificContentSettings::DOMStorageAccessed(int render_process_id,
int render_frame_id,
const GURL& url,
bool local,
bool blocked_by_policy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TabSpecificContentSettings* settings = GetForFrame(
render_process_id, render_frame_id);
if (settings)
settings->OnLocalStorageAccessed(url, local, blocked_by_policy);
}
// static
void TabSpecificContentSettings::IndexedDBAccessed(
int render_process_id,
int render_frame_id,
const GURL& url,
const base::string16& description,
bool blocked_by_policy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TabSpecificContentSettings* settings = GetForFrame(
render_process_id, render_frame_id);
if (settings)
settings->OnIndexedDBAccessed(url, description, blocked_by_policy);
}
// static
void TabSpecificContentSettings::FileSystemAccessed(int render_process_id,
int render_frame_id,
const GURL& url,
bool blocked_by_policy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TabSpecificContentSettings* settings = GetForFrame(
render_process_id, render_frame_id);
if (settings)
settings->OnFileSystemAccessed(url, blocked_by_policy);
}
// static
void TabSpecificContentSettings::ServiceWorkerAccessed(int render_process_id,
int render_frame_id,
const GURL& scope,
bool blocked_by_policy) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
TabSpecificContentSettings* settings =
GetForFrame(render_process_id, render_frame_id);
if (settings)
settings->OnServiceWorkerAccessed(scope, blocked_by_policy);
}
bool TabSpecificContentSettings::IsContentBlocked(
ContentSettingsType content_type) const {
DCHECK_NE(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type)
<< "Geolocation settings handled by ContentSettingGeolocationImageModel";
DCHECK_NE(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, content_type)
<< "Notifications settings handled by "
<< "ContentSettingsNotificationsImageModel";
if (content_type == CONTENT_SETTINGS_TYPE_IMAGES ||
content_type == CONTENT_SETTINGS_TYPE_JAVASCRIPT ||
content_type == CONTENT_SETTINGS_TYPE_PLUGINS ||
content_type == CONTENT_SETTINGS_TYPE_COOKIES ||
content_type == CONTENT_SETTINGS_TYPE_POPUPS ||
content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT ||
content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA ||
content_type == CONTENT_SETTINGS_TYPE_PPAPI_BROKER ||
content_type == CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS ||
content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX ||
content_type == CONTENT_SETTINGS_TYPE_KEYGEN) {
const auto& it = content_settings_status_.find(content_type);
if (it != content_settings_status_.end())
return it->second.blocked;
}
return false;
}
bool TabSpecificContentSettings::IsBlockageIndicated(
ContentSettingsType content_type) const {
const auto& it = content_settings_status_.find(content_type);
if (it != content_settings_status_.end())
return it->second.blockage_indicated_to_user;
return false;
}
void TabSpecificContentSettings::SetBlockageHasBeenIndicated(
ContentSettingsType content_type) {
content_settings_status_[content_type].blockage_indicated_to_user = true;
}
bool TabSpecificContentSettings::IsContentAllowed(
ContentSettingsType content_type) const {
// This method currently only returns meaningful values for the content type
// cookies, media, PPAPI broker, downloads, and MIDI sysex.
if (content_type != CONTENT_SETTINGS_TYPE_COOKIES &&
content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC &&
content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA &&
content_type != CONTENT_SETTINGS_TYPE_PPAPI_BROKER &&
content_type != CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS &&
content_type != CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
return false;
}
const auto& it = content_settings_status_.find(content_type);
if (it != content_settings_status_.end())
return it->second.allowed;
return false;
}
void TabSpecificContentSettings::OnContentBlocked(ContentSettingsType type) {
OnContentBlockedWithDetail(type, base::string16());
}
void TabSpecificContentSettings::OnContentBlockedWithDetail(
ContentSettingsType type,
const base::string16& details) {
DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
<< "Geolocation settings handled by OnGeolocationPermissionSet";
DCHECK(type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC &&
type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)
<< "Media stream settings handled by OnMediaStreamPermissionSet";
if (!content_settings::ContentSettingsRegistry::GetInstance()->Get(type))
return;
// TODO(robwu): Should this be restricted to cookies only?
// In the past, content_settings_status_[type].allowed was set to false, but
// this logic was inverted in https://codereview.chromium.org/13375004 to
// fix an issue with the cookie permission UI. This unconditional assignment
// seems incorrect, because the flag will now always be true after calling
// either OnContentBlocked or OnContentAllowed. Consequently IsContentAllowed
// will always return true for every supported setting that is not handled
// elsewhere.
ContentSettingsStatus& status = content_settings_status_[type];
status.allowed = true;
#if defined(OS_ANDROID)
if (type == CONTENT_SETTINGS_TYPE_POPUPS) {
// For Android we do not have a persistent button that will always be
// visible for blocked popups. Instead we have info bars which could be
// dismissed. Have to clear the blocked state so we properly notify the
// relevant pieces again.
status.blocked = false;
status.blockage_indicated_to_user = false;
}
#endif
if (type == CONTENT_SETTINGS_TYPE_PLUGINS && !details.empty() &&
std::find(blocked_plugin_names_.begin(), blocked_plugin_names_.end(),
details) == blocked_plugin_names_.end()) {
blocked_plugin_names_.push_back(details);
}
if (!status.blocked) {
status.blocked = true;
// TODO: it would be nice to have a way of mocking this in tests.
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
if (type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) {
content_settings::RecordMixedScriptAction(
content_settings::MIXED_SCRIPT_ACTION_DISPLAYED_SHIELD);
content_settings::RecordMixedScriptActionWithRAPPOR(
content_settings::MIXED_SCRIPT_ACTION_DISPLAYED_SHIELD,
GURL(base::UTF16ToUTF8(details)));
}
}
}
void TabSpecificContentSettings::OnContentAllowed(ContentSettingsType type) {
DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
<< "Geolocation settings handled by OnGeolocationPermissionSet";
DCHECK(type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC &&
type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)
<< "Media stream settings handled by OnMediaStreamPermissionSet";
bool access_changed = false;
ContentSettingsStatus& status = content_settings_status_[type];
#if defined(OS_ANDROID)
if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER &&
status.blocked) {
// content_settings_status_[type].allowed is always set to true in
// OnContentBlocked, so we have to use
// content_settings_status_[type].blocked to detect whether the protected
// media setting has changed.
status.blocked = false;
access_changed = true;
}
#endif
if (!status.allowed) {
status.allowed = true;
access_changed = true;
}
if (access_changed) {
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
}
void TabSpecificContentSettings::OnCookiesRead(
const GURL& url,
const GURL& frame_url,
const net::CookieList& cookie_list,
bool blocked_by_policy) {
if (cookie_list.empty())
return;
if (blocked_by_policy) {
blocked_local_shared_objects_.cookies()->AddReadCookies(
frame_url, url, cookie_list);
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
} else {
allowed_local_shared_objects_.cookies()->AddReadCookies(
frame_url, url, cookie_list);
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
}
NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnCookieChanged(
const GURL& url,
const GURL& frame_url,
const std::string& cookie_line,
const net::CookieOptions& options,
bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_local_shared_objects_.cookies()->AddChangedCookie(
frame_url, url, cookie_line, options);
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
} else {
allowed_local_shared_objects_.cookies()->AddChangedCookie(
frame_url, url, cookie_line, options);
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
}
NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnIndexedDBAccessed(
const GURL& url,
const base::string16& description,
bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_local_shared_objects_.indexed_dbs()->AddIndexedDB(
url, description);
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
} else {
allowed_local_shared_objects_.indexed_dbs()->AddIndexedDB(
url, description);
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
}
NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnLocalStorageAccessed(
const GURL& url,
bool local,
bool blocked_by_policy) {
LocalSharedObjectsContainer& container = blocked_by_policy ?
blocked_local_shared_objects_ : allowed_local_shared_objects_;
CannedBrowsingDataLocalStorageHelper* helper =
local ? container.local_storages() : container.session_storages();
helper->AddLocalStorage(url);
if (blocked_by_policy)
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
else
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnServiceWorkerAccessed(
const GURL& scope,
bool blocked_by_policy) {
DCHECK(scope.is_valid());
if (blocked_by_policy) {
blocked_local_shared_objects_.service_workers()->AddServiceWorker(
scope.GetOrigin(), std::vector<GURL>(1, scope));
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
} else {
allowed_local_shared_objects_.service_workers()->AddServiceWorker(
scope.GetOrigin(), std::vector<GURL>(1, scope));
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
}
}
void TabSpecificContentSettings::OnWebDatabaseAccessed(
const GURL& url,
const base::string16& name,
const base::string16& display_name,
bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_local_shared_objects_.databases()->AddDatabase(
url, base::UTF16ToUTF8(name), base::UTF16ToUTF8(display_name));
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
} else {
allowed_local_shared_objects_.databases()->AddDatabase(
url, base::UTF16ToUTF8(name), base::UTF16ToUTF8(display_name));
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
}
NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnFileSystemAccessed(
const GURL& url,
bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_local_shared_objects_.file_systems()->AddFileSystem(
url, storage::kFileSystemTypeTemporary, 0);
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
} else {
allowed_local_shared_objects_.file_systems()->AddFileSystem(
url, storage::kFileSystemTypeTemporary, 0);
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
}
NotifySiteDataObservers();
}
void TabSpecificContentSettings::OnGeolocationPermissionSet(
const GURL& requesting_origin,
bool allowed) {
geolocation_usages_state_.OnPermissionSet(requesting_origin, allowed);
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
#if defined(OS_ANDROID) || defined(OS_CHROMEOS)
void TabSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet(
const GURL& requesting_origin,
bool allowed) {
if (allowed) {
OnContentAllowed(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
} else {
OnContentBlocked(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
}
}
#endif
TabSpecificContentSettings::MicrophoneCameraState
TabSpecificContentSettings::GetMicrophoneCameraState() const {
MicrophoneCameraState state = microphone_camera_state_;
// Include capture devices in the state if there are still consumers of the
// approved media stream.
scoped_refptr<MediaStreamCaptureIndicator> media_indicator =
MediaCaptureDevicesDispatcher::GetInstance()->
GetMediaStreamCaptureIndicator();
if (media_indicator->IsCapturingAudio(web_contents()))
state |= MICROPHONE_ACCESSED;
if (media_indicator->IsCapturingVideo(web_contents()))
state |= CAMERA_ACCESSED;
return state;
}
bool TabSpecificContentSettings::IsMicrophoneCameraStateChanged() const {
if ((microphone_camera_state_ & MICROPHONE_ACCESSED) &&
((microphone_camera_state_& MICROPHONE_BLOCKED) ?
!IsContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) :
!IsContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)))
return true;
if ((microphone_camera_state_ & CAMERA_ACCESSED) &&
((microphone_camera_state_ & CAMERA_BLOCKED) ?
!IsContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) :
!IsContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)))
return true;
PrefService* prefs =
Profile::FromBrowserContext(web_contents()->GetBrowserContext())->
GetPrefs();
scoped_refptr<MediaStreamCaptureIndicator> media_indicator =
MediaCaptureDevicesDispatcher::GetInstance()->
GetMediaStreamCaptureIndicator();
if ((microphone_camera_state_ & MICROPHONE_ACCESSED) &&
prefs->GetString(prefs::kDefaultAudioCaptureDevice) !=
media_stream_selected_audio_device() &&
media_indicator->IsCapturingAudio(web_contents()))
return true;
if ((microphone_camera_state_ & CAMERA_ACCESSED) &&
prefs->GetString(prefs::kDefaultVideoCaptureDevice) !=
media_stream_selected_video_device() &&
media_indicator->IsCapturingVideo(web_contents()))
return true;
return false;
}
void TabSpecificContentSettings::OnMediaStreamPermissionSet(
const GURL& request_origin,
MicrophoneCameraState new_microphone_camera_state,
const std::string& media_stream_selected_audio_device,
const std::string& media_stream_selected_video_device,
const std::string& media_stream_requested_audio_device,
const std::string& media_stream_requested_video_device) {
media_stream_access_origin_ = request_origin;
if (new_microphone_camera_state & MICROPHONE_ACCESSED) {
media_stream_requested_audio_device_ = media_stream_requested_audio_device;
media_stream_selected_audio_device_ = media_stream_selected_audio_device;
bool mic_blocked = (new_microphone_camera_state & MICROPHONE_BLOCKED) != 0;
ContentSettingsStatus& status =
content_settings_status_[CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC];
status.allowed = !mic_blocked;
status.blocked = mic_blocked;
}
if (new_microphone_camera_state & CAMERA_ACCESSED) {
media_stream_requested_video_device_ = media_stream_requested_video_device;
media_stream_selected_video_device_ = media_stream_selected_video_device;
bool cam_blocked = (new_microphone_camera_state & CAMERA_BLOCKED) != 0;
ContentSettingsStatus& status =
content_settings_status_[CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA];
status.allowed = !cam_blocked;
status.blocked = cam_blocked;
}
if (microphone_camera_state_ != new_microphone_camera_state) {
microphone_camera_state_ = new_microphone_camera_state;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
}
void TabSpecificContentSettings::OnMidiSysExAccessed(
const GURL& requesting_origin) {
midi_usages_state_.OnPermissionSet(requesting_origin, true);
OnContentAllowed(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
}
void TabSpecificContentSettings::OnMidiSysExAccessBlocked(
const GURL& requesting_origin) {
midi_usages_state_.OnPermissionSet(requesting_origin, false);
OnContentBlocked(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
}
void TabSpecificContentSettings::ClearBlockedContentSettingsExceptForCookies() {
for (auto& status : content_settings_status_) {
if (status.first == CONTENT_SETTINGS_TYPE_COOKIES)
continue;
status.second.blocked = false;
status.second.blockage_indicated_to_user = false;
status.second.allowed = false;
}
microphone_camera_state_ = MICROPHONE_CAMERA_NOT_ACCESSED;
load_plugins_link_enabled_ = true;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
void TabSpecificContentSettings::ClearCookieSpecificContentSettings() {
blocked_local_shared_objects_.Reset();
allowed_local_shared_objects_.Reset();
ContentSettingsStatus& status =
content_settings_status_[CONTENT_SETTINGS_TYPE_COOKIES];
status.blocked = false;
status.blockage_indicated_to_user = false;
status.allowed = false;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
void TabSpecificContentSettings::SetDownloadsBlocked(bool blocked) {
ContentSettingsStatus& status =
content_settings_status_[CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS];
status.blocked = blocked;
status.allowed = !blocked;
status.blockage_indicated_to_user = false;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
void TabSpecificContentSettings::SetPopupsBlocked(bool blocked) {
ContentSettingsStatus& status =
content_settings_status_[CONTENT_SETTINGS_TYPE_POPUPS];
status.blocked = blocked;
status.blockage_indicated_to_user = false;
content::NotificationService::current()->Notify(
chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
content::Source<WebContents>(web_contents()),
content::NotificationService::NoDetails());
}
void TabSpecificContentSettings::SetPepperBrokerAllowed(bool allowed) {
if (allowed) {
OnContentAllowed(CONTENT_SETTINGS_TYPE_PPAPI_BROKER);
} else {
OnContentBlocked(CONTENT_SETTINGS_TYPE_PPAPI_BROKER);
}
}
void TabSpecificContentSettings::OnContentSettingChanged(
const ContentSettingsPattern& primary_pattern,
const ContentSettingsPattern& secondary_pattern,
ContentSettingsType content_type,
std::string resource_identifier) {
const ContentSettingsDetails details(
primary_pattern, secondary_pattern, content_type, resource_identifier);
const NavigationController& controller = web_contents()->GetController();
NavigationEntry* entry = controller.GetVisibleEntry();
GURL entry_url;
if (entry)
entry_url = entry->GetURL();
if (details.update_all() ||
// The visible NavigationEntry is the URL in the URL field of a tab.
// Currently this should be matched by the |primary_pattern|.
details.primary_pattern().Matches(entry_url)) {
Profile* profile =
Profile::FromBrowserContext(web_contents()->GetBrowserContext());
const HostContentSettingsMap* map =
HostContentSettingsMapFactory::GetForProfile(profile);
if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
const GURL media_origin = media_stream_access_origin();
ContentSetting setting = map->GetContentSetting(media_origin,
media_origin,
content_type,
std::string());
ContentSettingsStatus& status = content_settings_status_[content_type];
status.allowed = setting == CONTENT_SETTING_ALLOW;
status.blocked = setting == CONTENT_SETTING_BLOCK;
}
RendererContentSettingRules rules;
GetRendererContentSettingRules(map, &rules);
Send(new ChromeViewMsg_SetContentSettingRules(rules));
}
}
void TabSpecificContentSettings::RenderFrameForInterstitialPageCreated(
content::RenderFrameHost* render_frame_host) {
// We want to tell the renderer-side code to ignore content settings for this
// page.
render_frame_host->Send(new ChromeViewMsg_SetAsInterstitial(
render_frame_host->GetRoutingID()));
}
bool TabSpecificContentSettings::OnMessageReceived(
const IPC::Message& message,
content::RenderFrameHost* render_frame_host) {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(TabSpecificContentSettings, message)
IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ContentBlocked,
OnContentBlockedWithDetail)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
void TabSpecificContentSettings::DidNavigateMainFrame(
const content::LoadCommittedDetails& details,
const content::FrameNavigateParams& params) {
if (!details.is_in_page) {
// Clear "blocked" flags.
ClearBlockedContentSettingsExceptForCookies();
blocked_plugin_names_.clear();
GeolocationDidNavigate(details);
MidiDidNavigate(details);
}
}
void TabSpecificContentSettings::DidStartProvisionalLoadForFrame(
content::RenderFrameHost* render_frame_host,
const GURL& validated_url,
bool is_error_page,
bool is_iframe_srcdoc) {
if (render_frame_host->GetParent())
return;
// If we're displaying a network error page do not reset the content
// settings delegate's cookies so the user has a chance to modify cookie
// settings.
if (!is_error_page)
ClearCookieSpecificContentSettings();
ClearGeolocationContentSettings();
ClearMidiContentSettings();
ClearPendingProtocolHandler();
}
void TabSpecificContentSettings::AppCacheAccessed(const GURL& manifest_url,
bool blocked_by_policy) {
if (blocked_by_policy) {
blocked_local_shared_objects_.appcaches()->AddAppCache(manifest_url);
OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
} else {
allowed_local_shared_objects_.appcaches()->AddAppCache(manifest_url);
OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
}
}
void TabSpecificContentSettings::AddSiteDataObserver(
SiteDataObserver* observer) {
observer_list_.AddObserver(observer);
}
void TabSpecificContentSettings::RemoveSiteDataObserver(
SiteDataObserver* observer) {
observer_list_.RemoveObserver(observer);
}
void TabSpecificContentSettings::NotifySiteDataObservers() {
FOR_EACH_OBSERVER(SiteDataObserver, observer_list_, OnSiteDataAccessed());
}
void TabSpecificContentSettings::ClearGeolocationContentSettings() {
geolocation_usages_state_.ClearStateMap();
}
void TabSpecificContentSettings::ClearMidiContentSettings() {
midi_usages_state_.ClearStateMap();
}
void TabSpecificContentSettings::GeolocationDidNavigate(
const content::LoadCommittedDetails& details) {
geolocation_usages_state_.DidNavigate(GetCommittedDetails(details));
}
void TabSpecificContentSettings::MidiDidNavigate(
const content::LoadCommittedDetails& details) {
midi_usages_state_.DidNavigate(GetCommittedDetails(details));
}
void TabSpecificContentSettings::BlockAllContentForTesting() {
content_settings::ContentSettingsRegistry* registry =
content_settings::ContentSettingsRegistry::GetInstance();
for (const content_settings::ContentSettingsInfo* info : *registry) {
ContentSettingsType type = info->website_settings_info()->type();
if (type != CONTENT_SETTINGS_TYPE_GEOLOCATION &&
type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC &&
type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
OnContentBlocked(type);
}
}
// Geolocation and media must be blocked separately, as the generic
// TabSpecificContentSettings::OnContentBlocked does not apply to them.
OnGeolocationPermissionSet(web_contents()->GetLastCommittedURL(), false);
MicrophoneCameraStateFlags media_blocked =
static_cast<MicrophoneCameraStateFlags>(
TabSpecificContentSettings::MICROPHONE_ACCESSED |
TabSpecificContentSettings::MICROPHONE_BLOCKED |
TabSpecificContentSettings::CAMERA_ACCESSED |
TabSpecificContentSettings::CAMERA_BLOCKED);
OnMediaStreamPermissionSet(
web_contents()->GetLastCommittedURL(),
media_blocked,
std::string(), std::string(), std::string(), std::string());
}