// 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/ui/webui/options2/content_settings_handler2.h" #include #include #include #include "base/bind.h" #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/utf_string_conversions.h" #include "base/values.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/content_settings/content_settings_details.h" #include "chrome/browser/content_settings/content_settings_utils.h" #include "chrome/browser/content_settings/host_content_settings_map.h" #include "chrome/browser/custom_handlers/protocol_handler_registry.h" #include "chrome/browser/notifications/desktop_notification_service.h" #include "chrome/browser/notifications/desktop_notification_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_switches.h" #include "chrome/common/content_settings.h" #include "chrome/common/content_settings_pattern.h" #include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/user_metrics.h" #include "content/public/browser/web_ui.h" #include "content/public/common/content_switches.h" #include "grit/generated_resources.h" #include "grit/locale_settings.h" #include "ui/base/l10n/l10n_util.h" using content::UserMetricsAction; namespace { struct ContentSettingsTypeNameEntry { ContentSettingsType type; const char* name; }; typedef std::map OnePatternSettings; typedef std::map AllPatternsSettings; const char* kDisplayPattern = "displayPattern"; const char* kSetting = "setting"; const char* kOrigin = "origin"; const char* kSource = "source"; const char* kEmbeddingOrigin = "embeddingOrigin"; const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = { {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"}, {CONTENT_SETTINGS_TYPE_IMAGES, "images"}, {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"}, {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"}, {CONTENT_SETTINGS_TYPE_POPUPS, "popups"}, {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"}, {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"}, {CONTENT_SETTINGS_TYPE_INTENTS, "intents"}, {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"}, {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"}, {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"}, }; COMPILE_ASSERT(arraysize(kContentSettingsTypeGroupNames) == CONTENT_SETTINGS_NUM_TYPES, MISSING_CONTENT_SETTINGS_TYPE); ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) { for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { if (name == kContentSettingsTypeGroupNames[i].name) return kContentSettingsTypeGroupNames[i].type; } NOTREACHED() << name << " is not a recognized content settings type."; return CONTENT_SETTINGS_TYPE_DEFAULT; } std::string ContentSettingToString(ContentSetting setting) { switch (setting) { case CONTENT_SETTING_ALLOW: return "allow"; case CONTENT_SETTING_ASK: return "ask"; case CONTENT_SETTING_BLOCK: return "block"; case CONTENT_SETTING_SESSION_ONLY: return "session"; case CONTENT_SETTING_DEFAULT: return "default"; case CONTENT_SETTING_NUM_SETTINGS: NOTREACHED(); } return ""; } ContentSetting ContentSettingFromString(const std::string& name) { if (name == "allow") return CONTENT_SETTING_ALLOW; if (name == "ask") return CONTENT_SETTING_ASK; if (name == "block") return CONTENT_SETTING_BLOCK; if (name == "session") return CONTENT_SETTING_SESSION_ONLY; NOTREACHED() << name << " is not a recognized content setting."; return CONTENT_SETTING_DEFAULT; } std::string GeolocationExceptionToString( const ContentSettingsPattern& origin, const ContentSettingsPattern& embedding_origin) { if (origin == embedding_origin) return origin.ToString(); // TODO(estade): the page needs to use CSS to indent the string. std::string indent(" "); if (embedding_origin == ContentSettingsPattern::Wildcard()) { // NOTE: As long as the user cannot add/edit entries from the exceptions // dialog, it's impossible to actually have a non-default setting for some // origin "embedded on any other site", so this row will never appear. If // we add the ability to add/edit exceptions, we'll need to decide when to // display this and how "removing" it will function. return indent + l10n_util::GetStringUTF8(IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ANY_OTHER); } return indent + l10n_util::GetStringFUTF8( IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST, UTF8ToUTF16(embedding_origin.ToString())); } // Create a DictionaryValue* that will act as a data source for a single row // in a HostContentSettingsMap-controlled exceptions table (e.g., cookies). // Ownership of the pointer is passed to the caller. DictionaryValue* GetExceptionForPage( const ContentSettingsPattern& pattern, const ContentSetting& setting, const std::string& provider_name) { DictionaryValue* exception = new DictionaryValue(); exception->SetString(kDisplayPattern, pattern.ToString()); exception->SetString(kSetting, ContentSettingToString(setting)); exception->SetString(kSource, provider_name); return exception; } // Create a DictionaryValue* that will act as a data source for a single row // in the Geolocation exceptions table. Ownership of the pointer is passed to // the caller. DictionaryValue* GetGeolocationExceptionForPage( const ContentSettingsPattern& origin, const ContentSettingsPattern& embedding_origin, ContentSetting setting) { DictionaryValue* exception = new DictionaryValue(); exception->SetString(kDisplayPattern, GeolocationExceptionToString(origin, embedding_origin)); exception->SetString(kSetting, ContentSettingToString(setting)); exception->SetString(kOrigin, origin.ToString()); exception->SetString(kEmbeddingOrigin, embedding_origin.ToString()); return exception; } // Create a DictionaryValue* that will act as a data source for a single row // in the desktop notifications exceptions table. Ownership of the pointer is // passed to the caller. DictionaryValue* GetNotificationExceptionForPage( const ContentSettingsPattern& pattern, ContentSetting setting, const std::string& provider_name) { DictionaryValue* exception = new DictionaryValue(); exception->SetString(kDisplayPattern, pattern.ToString()); exception->SetString(kSetting, ContentSettingToString(setting)); exception->SetString(kOrigin, pattern.ToString()); exception->SetString(kSource, provider_name); return exception; } } // namespace namespace options2 { ContentSettingsHandler::ContentSettingsHandler() { } ContentSettingsHandler::~ContentSettingsHandler() { } void ContentSettingsHandler::GetLocalizedValues( DictionaryValue* localized_strings) { DCHECK(localized_strings); static OptionsStringResource resources[] = { { "content_exceptions", IDS_COOKIES_EXCEPTIONS_BUTTON }, { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON }, { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON }, { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON }, { "askException", IDS_EXCEPTIONS_ASK_BUTTON }, { "addExceptionRow", IDS_EXCEPTIONS_ADD_BUTTON }, { "removeExceptionRow", IDS_EXCEPTIONS_REMOVE_BUTTON }, { "editExceptionRow", IDS_EXCEPTIONS_EDIT_BUTTON }, { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL }, { "examplePattern", IDS_EXCEPTIONS_PATTERN_EXAMPLE }, { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS }, { "manage_exceptions", IDS_EXCEPTIONS_MANAGE }, { "manage_handlers", IDS_HANDLERS_MANAGE }, { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER }, { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER }, // Cookies filter. { "cookies_tab_label", IDS_COOKIES_TAB_LABEL }, { "cookies_header", IDS_COOKIES_HEADER }, { "cookies_allow", IDS_COOKIES_ALLOW_RADIO }, { "cookies_block", IDS_COOKIES_BLOCK_RADIO }, { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO }, { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX }, { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX }, { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX }, { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON }, { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS }, { "flash_storage_url", IDS_FLASH_STORAGE_URL }, // Image filter. { "images_tab_label", IDS_IMAGES_TAB_LABEL }, { "images_header", IDS_IMAGES_HEADER }, { "images_allow", IDS_IMAGES_LOAD_RADIO }, { "images_block", IDS_IMAGES_NOLOAD_RADIO }, // JavaScript filter. { "javascript_tab_label", IDS_JAVASCRIPT_TAB_LABEL }, { "javascript_header", IDS_JAVASCRIPT_HEADER }, { "javascript_allow", IDS_JS_ALLOW_RADIO }, { "javascript_block", IDS_JS_DONOTALLOW_RADIO }, // Plug-ins filter. { "plugins_tab_label", IDS_PLUGIN_TAB_LABEL }, { "plugins_header", IDS_PLUGIN_HEADER }, { "plugins_ask", IDS_PLUGIN_ASK_RADIO }, { "plugins_allow", IDS_PLUGIN_LOAD_RADIO }, { "plugins_block", IDS_PLUGIN_NOLOAD_RADIO }, { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE }, // Pop-ups filter. { "popups_tab_label", IDS_POPUP_TAB_LABEL }, { "popups_header", IDS_POPUP_HEADER }, { "popups_allow", IDS_POPUP_ALLOW_RADIO }, { "popups_block", IDS_POPUP_BLOCK_RADIO }, // Location filter. { "location_tab_label", IDS_GEOLOCATION_TAB_LABEL }, { "location_header", IDS_GEOLOCATION_HEADER }, { "location_allow", IDS_GEOLOCATION_ALLOW_RADIO }, { "location_ask", IDS_GEOLOCATION_ASK_RADIO }, { "location_block", IDS_GEOLOCATION_BLOCK_RADIO }, // Notifications filter. { "notifications_tab_label", IDS_NOTIFICATIONS_TAB_LABEL }, { "notifications_header", IDS_NOTIFICATIONS_HEADER }, { "notifications_allow", IDS_NOTIFICATIONS_ALLOW_RADIO }, { "notifications_ask", IDS_NOTIFICATIONS_ASK_RADIO }, { "notifications_block", IDS_NOTIFICATIONS_BLOCK_RADIO }, // Intents filter. { "intentsTabLabel", IDS_INTENTS_TAB_LABEL }, { "intentsAllow", IDS_INTENTS_ALLOW_RADIO }, { "intentsAsk", IDS_INTENTS_ASK_RADIO }, { "intentsBlock", IDS_INTENTS_BLOCK_RADIO }, { "intents_header", IDS_INTENTS_HEADER }, // Fullscreen filter. { "fullscreen_tab_label", IDS_FULLSCREEN_TAB_LABEL }, { "fullscreen_header", IDS_FULLSCREEN_HEADER }, // Mouse Lock filter. { "mouselock_tab_label", IDS_MOUSE_LOCK_TAB_LABEL }, { "mouselock_header", IDS_MOUSE_LOCK_HEADER }, { "mouselock_allow", IDS_MOUSE_LOCK_ALLOW_RADIO }, { "mouselock_ask", IDS_MOUSE_LOCK_ASK_RADIO }, { "mouselock_block", IDS_MOUSE_LOCK_BLOCK_RADIO }, }; RegisterStrings(localized_strings, resources, arraysize(resources)); RegisterTitle(localized_strings, "contentSettingsPage", IDS_CONTENT_SETTINGS_TITLE); localized_strings->SetBoolean("enable_web_intents", !CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableWebIntents)); } void ContentSettingsHandler::Initialize() { notification_registrar_.Add( this, chrome::NOTIFICATION_PROFILE_CREATED, content::NotificationService::AllSources()); notification_registrar_.Add( this, chrome::NOTIFICATION_PROFILE_DESTROYED, content::NotificationService::AllSources()); UpdateHandlersEnabledRadios(); UpdateAllExceptionsViewsFromModel(); notification_registrar_.Add( this, chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED, content::NotificationService::AllSources()); notification_registrar_.Add( this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED, content::NotificationService::AllSources()); Profile* profile = Profile::FromWebUI(web_ui()); notification_registrar_.Add( this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED, content::Source(profile)); PrefService* prefs = profile->GetPrefs(); pref_change_registrar_.Init(prefs); pref_change_registrar_.Add(prefs::kGeolocationContentSettings, this); } void ContentSettingsHandler::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case chrome::NOTIFICATION_PROFILE_DESTROYED: { if (content::Source(source).ptr()->IsOffTheRecord()) { web_ui()->CallJavascriptFunction( "ContentSettingsExceptionsArea.OTRProfileDestroyed"); } break; } case chrome::NOTIFICATION_PROFILE_CREATED: { if (content::Source(source).ptr()->IsOffTheRecord()) UpdateAllOTRExceptionsViewsFromModel(); break; } case chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED: { // Filter out notifications from other profiles. HostContentSettingsMap* map = content::Source(source).ptr(); if (map != GetContentSettingsMap() && map != GetOTRContentSettingsMap()) break; const ContentSettingsDetails* settings_details = content::Details(details).ptr(); // TODO(estade): we pretend update_all() is always true. if (settings_details->update_all_types()) UpdateAllExceptionsViewsFromModel(); else UpdateExceptionsViewFromModel(settings_details->type()); break; } case chrome::NOTIFICATION_PREF_CHANGED: { const std::string& pref_name = *content::Details(details).ptr(); if (pref_name == prefs::kGeolocationContentSettings) UpdateGeolocationExceptionsView(); break; } case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: { UpdateNotificationExceptionsView(); break; } case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: { UpdateHandlersEnabledRadios(); break; } default: OptionsPageUIHandler::Observe(type, source, details); } } void ContentSettingsHandler::UpdateSettingDefaultFromModel( ContentSettingsType type) { DictionaryValue filter_settings; std::string provider_id; filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value", GetSettingDefaultFromModel(type, &provider_id)); filter_settings.SetString( ContentSettingsTypeToGroupName(type) + ".managedBy", provider_id); web_ui()->CallJavascriptFunction( "ContentSettings.setContentFilterSettingsValue", filter_settings); } std::string ContentSettingsHandler::GetSettingDefaultFromModel( ContentSettingsType type, std::string* provider_id) { Profile* profile = Profile::FromWebUI(web_ui()); ContentSetting default_setting; if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { default_setting = DesktopNotificationServiceFactory::GetForProfile(profile)-> GetDefaultContentSetting(provider_id); } else { default_setting = profile->GetHostContentSettingsMap()-> GetDefaultContentSetting(type, provider_id); } return ContentSettingToString(default_setting); } void ContentSettingsHandler::UpdateHandlersEnabledRadios() { #if defined(ENABLE_REGISTER_PROTOCOL_HANDLER) base::FundamentalValue handlers_enabled( GetProtocolHandlerRegistry()->enabled()); web_ui()->CallJavascriptFunction( "ContentSettings.updateHandlersEnabledRadios", handlers_enabled); #endif // defined(ENABLE_REGISTER_PROTOCOL_HANDLER) } void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() { for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; type < CONTENT_SETTINGS_NUM_TYPES; ++type) { // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE // is supposed to be set by policy only. Hence there is no user facing UI // for this content type and we skip it here. if (type == CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE) continue; UpdateExceptionsViewFromModel(static_cast(type)); } } void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() { for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1; type < CONTENT_SETTINGS_NUM_TYPES; ++type) { UpdateOTRExceptionsViewFromModel(static_cast(type)); } } void ContentSettingsHandler::UpdateExceptionsViewFromModel( ContentSettingsType type) { // Don't update intents settings at this point. // Turn on when enable_web_intents_tag is enabled. if (type == CONTENT_SETTINGS_TYPE_INTENTS) return; switch (type) { case CONTENT_SETTINGS_TYPE_GEOLOCATION: UpdateGeolocationExceptionsView(); break; case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: UpdateNotificationExceptionsView(); break; default: UpdateExceptionsViewFromHostContentSettingsMap(type); break; } } void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel( ContentSettingsType type) { switch (type) { case CONTENT_SETTINGS_TYPE_GEOLOCATION: case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: case CONTENT_SETTINGS_TYPE_INTENTS: case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE: break; default: UpdateExceptionsViewFromOTRHostContentSettingsMap(type); break; } } void ContentSettingsHandler::UpdateGeolocationExceptionsView() { Profile* profile = Profile::FromWebUI(web_ui()); HostContentSettingsMap* map = profile->GetHostContentSettingsMap(); ContentSettingsForOneType all_settings; map->GetSettingsForOneType( CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), &all_settings); // Group geolocation settings by primary_pattern. AllPatternsSettings all_patterns_settings; for (ContentSettingsForOneType::iterator i = all_settings.begin(); i != all_settings.end(); ++i) { // Don't add default settings. if (i->primary_pattern == ContentSettingsPattern::Wildcard() && i->secondary_pattern == ContentSettingsPattern::Wildcard() && i->source != "preferences") { continue; } all_patterns_settings[i->primary_pattern][i->secondary_pattern] = i->setting; } ListValue exceptions; for (AllPatternsSettings::iterator i = all_patterns_settings.begin(); i != all_patterns_settings.end(); ++i) { const ContentSettingsPattern& primary_pattern = i->first; const OnePatternSettings& one_settings = i->second; OnePatternSettings::const_iterator parent = one_settings.find(primary_pattern); // Add the "parent" entry for the non-embedded setting. ContentSetting parent_setting = parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second; exceptions.Append(GetGeolocationExceptionForPage(primary_pattern, primary_pattern, parent_setting)); // Add the "children" for any embedded settings. for (OnePatternSettings::const_iterator j = one_settings.begin(); j != one_settings.end(); ++j) { // Skip the non-embedded setting which we already added above. if (j == parent) continue; exceptions.Append( GetGeolocationExceptionForPage(primary_pattern, j->first, j->second)); } } StringValue type_string( ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION)); web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string, exceptions); // This is mainly here to keep this function ideologically parallel to // UpdateExceptionsViewFromHostContentSettingsMap(). UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION); } void ContentSettingsHandler::UpdateNotificationExceptionsView() { Profile* profile = Profile::FromWebUI(web_ui()); DesktopNotificationService* service = DesktopNotificationServiceFactory::GetForProfile(profile); ContentSettingsForOneType settings; service->GetNotificationsSettings(&settings); ListValue exceptions; for (ContentSettingsForOneType::const_iterator i = settings.begin(); i != settings.end(); ++i) { // Don't add default settings. if (i->primary_pattern == ContentSettingsPattern::Wildcard() && i->secondary_pattern == ContentSettingsPattern::Wildcard() && i->source != "preferences") { continue; } exceptions.Append( GetNotificationExceptionForPage(i->primary_pattern, i->setting, i->source)); } StringValue type_string( ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS)); web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string, exceptions); // This is mainly here to keep this function ideologically parallel to // UpdateExceptionsViewFromHostContentSettingsMap(). UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS); } void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap( ContentSettingsType type) { ContentSettingsForOneType entries; GetContentSettingsMap()->GetSettingsForOneType(type, "", &entries); ListValue exceptions; for (size_t i = 0; i < entries.size(); ++i) { // Skip default settings from extensions and policy, and the default content // settings; all of them will affect the default setting UI. if (entries[i].primary_pattern == ContentSettingsPattern::Wildcard() && entries[i].secondary_pattern == ContentSettingsPattern::Wildcard() && entries[i].source != "preference") { continue; } // The content settings UI does not support secondary content settings // pattern yet. For content settings set through the content settings UI the // secondary pattern is by default a wildcard pattern. Hence users are not // able to modify content settings with a secondary pattern other than the // wildcard pattern. So only show settings that the user is able to modify. // TODO(bauerb): Support a read-only view for those patterns. if (entries[i].secondary_pattern == ContentSettingsPattern::Wildcard()) { exceptions.Append( GetExceptionForPage(entries[i].primary_pattern, entries[i].setting, entries[i].source)); } else { LOG(ERROR) << "Secondary content settings patterns are not " << "supported by the content settings UI"; } } StringValue type_string(ContentSettingsTypeToGroupName(type)); web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string, exceptions); UpdateExceptionsViewFromOTRHostContentSettingsMap(type); // TODO(koz): The default for fullscreen is always 'ask'. // http://crbug.com/104683 if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN) return; // The default may also have changed (we won't get a separate notification). // If it hasn't changed, this call will be harmless. UpdateSettingDefaultFromModel(type); } void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap( ContentSettingsType type) { const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap(); if (!otr_settings_map) return; ContentSettingsForOneType otr_entries; otr_settings_map->GetSettingsForOneType(type, "", &otr_entries); ListValue otr_exceptions; for (size_t i = 0; i < otr_entries.size(); ++i) { // Off-the-record HostContentSettingsMap contains incognito content settings // as well as normal content settings. Here, we use the incongnito settings // only. if (!otr_entries[i].incognito) continue; // The content settings UI does not support secondary content settings // pattern yet. For content settings set through the content settings UI the // secondary pattern is by default a wildcard pattern. Hence users are not // able to modify content settings with a secondary pattern other than the // wildcard pattern. So only show settings that the user is able to modify. // TODO(bauerb): Support a read-only view for those patterns. if (otr_entries[i].secondary_pattern == ContentSettingsPattern::Wildcard()) { otr_exceptions.Append( GetExceptionForPage(otr_entries[i].primary_pattern, otr_entries[i].setting, otr_entries[i].source)); } else { LOG(ERROR) << "Secondary content settings patterns are not " << "supported by the content settings UI"; } } StringValue type_string(ContentSettingsTypeToGroupName(type)); web_ui()->CallJavascriptFunction("ContentSettings.setOTRExceptions", type_string, otr_exceptions); } void ContentSettingsHandler::RegisterMessages() { web_ui()->RegisterMessageCallback("setContentFilter", base::Bind(&ContentSettingsHandler::SetContentFilter, base::Unretained(this))); web_ui()->RegisterMessageCallback("removeException", base::Bind(&ContentSettingsHandler::RemoveException, base::Unretained(this))); web_ui()->RegisterMessageCallback("setException", base::Bind(&ContentSettingsHandler::SetException, base::Unretained(this))); web_ui()->RegisterMessageCallback("checkExceptionPatternValidity", base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity, base::Unretained(this))); } void ContentSettingsHandler::SetContentFilter(const ListValue* args) { DCHECK_EQ(2U, args->GetSize()); std::string group, setting; if (!(args->GetString(0, &group) && args->GetString(1, &setting))) { NOTREACHED(); return; } ContentSetting default_setting = ContentSettingFromString(setting); ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group); if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { Profile* profile = Profile::FromWebUI(web_ui()); DesktopNotificationServiceFactory::GetForProfile(profile)-> SetDefaultContentSetting(default_setting); } else { GetContentSettingsMap()-> SetDefaultContentSetting(content_type, default_setting); } switch (content_type) { case CONTENT_SETTINGS_TYPE_COOKIES: content::RecordAction( UserMetricsAction("Options_DefaultCookieSettingChanged")); break; case CONTENT_SETTINGS_TYPE_IMAGES: content::RecordAction( UserMetricsAction("Options_DefaultImagesSettingChanged")); break; case CONTENT_SETTINGS_TYPE_JAVASCRIPT: content::RecordAction( UserMetricsAction("Options_DefaultJavaScriptSettingChanged")); break; case CONTENT_SETTINGS_TYPE_PLUGINS: content::RecordAction( UserMetricsAction("Options_DefaultPluginsSettingChanged")); break; case CONTENT_SETTINGS_TYPE_POPUPS: content::RecordAction( UserMetricsAction("Options_DefaultPopupsSettingChanged")); break; case CONTENT_SETTINGS_TYPE_NOTIFICATIONS: content::RecordAction( UserMetricsAction("Options_DefaultNotificationsSettingChanged")); break; case CONTENT_SETTINGS_TYPE_GEOLOCATION: content::RecordAction( UserMetricsAction("Options_DefaultGeolocationSettingChanged")); break; case CONTENT_SETTINGS_TYPE_INTENTS: content::RecordAction( UserMetricsAction("Options_DefaultHandlersSettingChanged")); break; case CONTENT_SETTINGS_TYPE_MOUSELOCK: content::RecordAction( UserMetricsAction("Options_DefaultMouseLockSettingChanged")); break; default: break; } } void ContentSettingsHandler::RemoveException(const ListValue* args) { size_t arg_i = 0; std::string type_string; CHECK(args->GetString(arg_i++, &type_string)); Profile* profile = Profile::FromWebUI(web_ui()); ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) { std::string origin; std::string embedding_origin; bool rv = args->GetString(arg_i++, &origin); DCHECK(rv); rv = args->GetString(arg_i++, &embedding_origin); DCHECK(rv); profile->GetHostContentSettingsMap()-> SetContentSetting(ContentSettingsPattern::FromString(origin), ContentSettingsPattern::FromString(embedding_origin), CONTENT_SETTINGS_TYPE_GEOLOCATION, std::string(), CONTENT_SETTING_DEFAULT); } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { std::string origin; std::string setting; bool rv = args->GetString(arg_i++, &origin); DCHECK(rv); rv = args->GetString(arg_i++, &setting); DCHECK(rv); ContentSetting content_setting = ContentSettingFromString(setting); DCHECK(content_setting == CONTENT_SETTING_ALLOW || content_setting == CONTENT_SETTING_BLOCK); DesktopNotificationServiceFactory::GetForProfile(profile)-> ClearSetting(ContentSettingsPattern::FromString(origin)); } else { std::string mode; bool rv = args->GetString(arg_i++, &mode); DCHECK(rv); std::string pattern; rv = args->GetString(arg_i++, &pattern); DCHECK(rv); HostContentSettingsMap* settings_map = mode == "normal" ? GetContentSettingsMap() : GetOTRContentSettingsMap(); // The settings map could be null if the mode was OTR but the OTR profile // got destroyed before we received this message. if (settings_map) { settings_map->SetContentSetting( ContentSettingsPattern::FromString(pattern), ContentSettingsPattern::Wildcard(), ContentSettingsTypeFromGroupName(type_string), "", CONTENT_SETTING_DEFAULT); } } } void ContentSettingsHandler::SetException(const ListValue* args) { size_t arg_i = 0; std::string type_string; CHECK(args->GetString(arg_i++, &type_string)); std::string mode; CHECK(args->GetString(arg_i++, &mode)); std::string pattern; CHECK(args->GetString(arg_i++, &pattern)); std::string setting; CHECK(args->GetString(arg_i++, &setting)); ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string); if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION || type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { NOTREACHED(); return; } HostContentSettingsMap* settings_map = mode == "normal" ? GetContentSettingsMap() : GetOTRContentSettingsMap(); // The settings map could be null if the mode was OTR but the OTR profile // got destroyed before we received this message. if (!settings_map) return; settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern), ContentSettingsPattern::Wildcard(), type, "", ContentSettingFromString(setting)); } void ContentSettingsHandler::CheckExceptionPatternValidity( const ListValue* args) { size_t arg_i = 0; Value* type; CHECK(args->Get(arg_i++, &type)); std::string mode_string; CHECK(args->GetString(arg_i++, &mode_string)); std::string pattern_string; CHECK(args->GetString(arg_i++, &pattern_string)); ContentSettingsPattern pattern = ContentSettingsPattern::FromString(pattern_string); scoped_ptr mode_value(Value::CreateStringValue(mode_string)); scoped_ptr pattern_value(Value::CreateStringValue(pattern_string)); scoped_ptr valid_value(Value::CreateBooleanValue(pattern.IsValid())); web_ui()->CallJavascriptFunction( "ContentSettings.patternValidityCheckComplete", *type, *mode_value.get(), *pattern_value.get(), *valid_value.get()); } // static std::string ContentSettingsHandler::ContentSettingsTypeToGroupName( ContentSettingsType type) { for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) { if (type == kContentSettingsTypeGroupNames[i].type) return kContentSettingsTypeGroupNames[i].name; } NOTREACHED(); return std::string(); } HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() { return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap(); } ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() { return Profile::FromWebUI(web_ui())->GetProtocolHandlerRegistry(); } HostContentSettingsMap* ContentSettingsHandler::GetOTRContentSettingsMap() { Profile* profile = Profile::FromWebUI(web_ui()); if (profile->HasOffTheRecordProfile()) return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap(); return NULL; } } // namespace options2