1 // Copyright (c) 2012 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.
5 #include "chrome/browser/ui/webui/options/content_settings_handler.h"
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/command_line.h"
14 #include "base/prefs/pref_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/values.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/chrome_notification_types.h"
20 #include "chrome/browser/content_settings/content_settings_details.h"
21 #include "chrome/browser/content_settings/content_settings_utils.h"
22 #include "chrome/browser/content_settings/host_content_settings_map.h"
23 #include "chrome/browser/custom_handlers/protocol_handler_registry.h"
24 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
25 #include "chrome/browser/extensions/extension_service.h"
26 #include "chrome/browser/extensions/extension_special_storage_policy.h"
27 #include "chrome/browser/google/google_util.h"
28 #include "chrome/browser/notifications/desktop_notification_service.h"
29 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/browser/ui/browser_list.h"
32 #include "chrome/common/chrome_switches.h"
33 #include "chrome/common/content_settings.h"
34 #include "chrome/common/content_settings_pattern.h"
35 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
36 #include "chrome/common/pref_names.h"
37 #include "chrome/common/url_constants.h"
38 #include "content/public/browser/notification_service.h"
39 #include "content/public/browser/notification_source.h"
40 #include "content/public/browser/notification_types.h"
41 #include "content/public/browser/user_metrics.h"
42 #include "content/public/browser/web_ui.h"
43 #include "content/public/common/content_switches.h"
44 #include "content/public/common/page_zoom.h"
45 #include "content/public/common/url_constants.h"
46 #include "extensions/common/extension_set.h"
47 #include "extensions/common/permissions/api_permission.h"
48 #include "grit/generated_resources.h"
49 #include "grit/locale_settings.h"
50 #include "ui/base/l10n/l10n_util.h"
52 #if defined(OS_CHROMEOS)
53 #include "chrome/browser/chromeos/login/user_manager.h"
56 using base::UserMetricsAction;
57 using extensions::APIPermission;
61 struct ContentSettingsTypeNameEntry {
62 ContentSettingsType type;
66 // Maps from a secondary pattern to a setting.
67 typedef std::map<ContentSettingsPattern, ContentSetting>
69 // Maps from a primary pattern/source pair to a OnePatternSettings. All the
70 // mappings in OnePatternSettings share the given primary pattern and source.
71 typedef std::map<std::pair<ContentSettingsPattern, std::string>,
75 // The AppFilter is used in AddExceptionsGrantedByHostedApps() to choose
76 // extensions which should have their extent displayed.
77 typedef bool (*AppFilter)(const extensions::Extension& app, Profile* profile);
79 const char kExceptionsLearnMoreUrl[] =
80 "https://support.google.com/chrome/?p=settings_manage_exceptions";
82 const char* kSetting = "setting";
83 const char* kOrigin = "origin";
84 const char* kSource = "source";
85 const char* kAppName = "appName";
86 const char* kAppId = "appId";
87 const char* kEmbeddingOrigin = "embeddingOrigin";
88 const char* kPreferencesSource = "preference";
89 const char* kVideoSetting = "video";
90 const char* kZoom = "zoom";
92 const ContentSettingsTypeNameEntry kContentSettingsTypeGroupNames[] = {
93 {CONTENT_SETTINGS_TYPE_COOKIES, "cookies"},
94 {CONTENT_SETTINGS_TYPE_IMAGES, "images"},
95 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript"},
96 {CONTENT_SETTINGS_TYPE_PLUGINS, "plugins"},
97 {CONTENT_SETTINGS_TYPE_POPUPS, "popups"},
98 {CONTENT_SETTINGS_TYPE_GEOLOCATION, "location"},
99 {CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications"},
100 {CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE, "auto-select-certificate"},
101 {CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen"},
102 {CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock"},
103 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "register-protocol-handler"},
104 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, "media-stream"},
105 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, "media-stream-mic"},
106 {CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, "media-stream-camera"},
107 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker"},
108 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "multiple-automatic-downloads"},
109 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex"},
110 #if defined(OS_CHROMEOS)
111 {CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, "protectedContent"},
115 // A pseudo content type. We use it to display data like a content setting even
116 // though it is not a real content setting.
117 const char* kZoomContentType = "zoomlevels";
119 ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
120 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
121 if (name == kContentSettingsTypeGroupNames[i].name)
122 return kContentSettingsTypeGroupNames[i].type;
125 NOTREACHED() << name << " is not a recognized content settings type.";
126 return CONTENT_SETTINGS_TYPE_DEFAULT;
129 std::string ContentSettingToString(ContentSetting setting) {
131 case CONTENT_SETTING_ALLOW:
133 case CONTENT_SETTING_ASK:
135 case CONTENT_SETTING_BLOCK:
137 case CONTENT_SETTING_SESSION_ONLY:
139 case CONTENT_SETTING_DEFAULT:
141 case CONTENT_SETTING_NUM_SETTINGS:
145 return std::string();
148 ContentSetting ContentSettingFromString(const std::string& name) {
150 return CONTENT_SETTING_ALLOW;
152 return CONTENT_SETTING_ASK;
154 return CONTENT_SETTING_BLOCK;
155 if (name == "session")
156 return CONTENT_SETTING_SESSION_ONLY;
158 NOTREACHED() << name << " is not a recognized content setting.";
159 return CONTENT_SETTING_DEFAULT;
162 // Create a DictionaryValue* that will act as a data source for a single row
163 // in a HostContentSettingsMap-controlled exceptions table (e.g., cookies).
164 // Ownership of the pointer is passed to the caller.
165 base::DictionaryValue* GetExceptionForPage(
166 const ContentSettingsPattern& pattern,
167 const ContentSettingsPattern& secondary_pattern,
168 const ContentSetting& setting,
169 const std::string& provider_name) {
170 base::DictionaryValue* exception = new base::DictionaryValue();
171 exception->SetString(kOrigin, pattern.ToString());
172 exception->SetString(kEmbeddingOrigin,
173 secondary_pattern == ContentSettingsPattern::Wildcard()
175 : secondary_pattern.ToString());
176 exception->SetString(kSetting, ContentSettingToString(setting));
177 exception->SetString(kSource, provider_name);
181 // Create a DictionaryValue* that will act as a data source for a single row
182 // in the Geolocation exceptions table. Ownership of the pointer is passed to
184 base::DictionaryValue* GetGeolocationExceptionForPage(
185 const ContentSettingsPattern& origin,
186 const ContentSettingsPattern& embedding_origin,
187 ContentSetting setting) {
188 base::DictionaryValue* exception = new base::DictionaryValue();
189 exception->SetString(kSetting, ContentSettingToString(setting));
190 exception->SetString(kOrigin, origin.ToString());
191 exception->SetString(kEmbeddingOrigin, embedding_origin.ToString());
195 // Create a DictionaryValue* that will act as a data source for a single row
196 // in the desktop notifications exceptions table. Ownership of the pointer is
197 // passed to the caller.
198 base::DictionaryValue* GetNotificationExceptionForPage(
199 const ContentSettingsPattern& pattern,
200 ContentSetting setting,
201 const std::string& provider_name) {
202 base::DictionaryValue* exception = new base::DictionaryValue();
203 exception->SetString(kSetting, ContentSettingToString(setting));
204 exception->SetString(kOrigin, pattern.ToString());
205 exception->SetString(kSource, provider_name);
209 // Returns true whenever the |extension| is hosted and has |permission|.
210 // Must have the AppFilter signature.
211 template <APIPermission::ID permission>
212 bool HostedAppHasPermission(
213 const extensions::Extension& extension, Profile* /*profile*/) {
214 return extension.is_hosted_app() && extension.HasAPIPermission(permission);
217 // Add an "Allow"-entry to the list of |exceptions| for a |url_pattern| from
218 // the web extent of a hosted |app|.
219 void AddExceptionForHostedApp(const std::string& url_pattern,
220 const extensions::Extension& app, base::ListValue* exceptions) {
221 base::DictionaryValue* exception = new base::DictionaryValue();
222 exception->SetString(kSetting, ContentSettingToString(CONTENT_SETTING_ALLOW));
223 exception->SetString(kOrigin, url_pattern);
224 exception->SetString(kEmbeddingOrigin, url_pattern);
225 exception->SetString(kSource, "HostedApp");
226 exception->SetString(kAppName, app.name());
227 exception->SetString(kAppId, app.id());
228 exceptions->Append(exception);
231 // Asks the |profile| for hosted apps which have the |permission| set, and
232 // adds their web extent and launch URL to the |exceptions| list.
233 void AddExceptionsGrantedByHostedApps(
234 Profile* profile, AppFilter app_filter, base::ListValue* exceptions) {
235 const ExtensionService* extension_service = profile->GetExtensionService();
236 // After ExtensionSystem::Init has been called at the browser's start,
237 // GetExtensionService() should not return NULL, so this is safe:
238 const extensions::ExtensionSet* extensions = extension_service->extensions();
240 for (extensions::ExtensionSet::const_iterator extension = extensions->begin();
241 extension != extensions->end(); ++extension) {
242 if (!app_filter(*extension->get(), profile))
245 extensions::URLPatternSet web_extent = (*extension)->web_extent();
246 // Add patterns from web extent.
247 for (extensions::URLPatternSet::const_iterator pattern = web_extent.begin();
248 pattern != web_extent.end(); ++pattern) {
249 std::string url_pattern = pattern->GetAsString();
250 AddExceptionForHostedApp(url_pattern, *extension->get(), exceptions);
252 // Retrieve the launch URL.
254 extensions::AppLaunchInfo::GetLaunchWebURL(extension->get());
255 // Skip adding the launch URL if it is part of the web extent.
256 if (web_extent.MatchesURL(launch_url))
258 AddExceptionForHostedApp(launch_url.spec(), *extension->get(), exceptions);
262 // Sort ZoomLevelChanges by host and scheme
263 // (a.com < http://a.com < https://a.com < b.com).
264 bool HostZoomSort(const content::HostZoomMap::ZoomLevelChange& a,
265 const content::HostZoomMap::ZoomLevelChange& b) {
266 return a.host == b.host ? a.scheme < b.scheme : a.host < b.host;
273 ContentSettingsHandler::MediaSettingsInfo::MediaSettingsInfo()
274 : flash_default_setting(CONTENT_SETTING_DEFAULT),
275 flash_settings_initialized(false),
276 last_flash_refresh_request_id(0),
277 show_flash_default_link(false),
278 show_flash_exceptions_link(false),
279 default_setting(CONTENT_SETTING_DEFAULT),
280 policy_disable_audio(false),
281 policy_disable_video(false),
282 default_setting_initialized(false),
283 exceptions_initialized(false) {
286 ContentSettingsHandler::MediaSettingsInfo::~MediaSettingsInfo() {
289 ContentSettingsHandler::ContentSettingsHandler() {
292 ContentSettingsHandler::~ContentSettingsHandler() {
295 void ContentSettingsHandler::GetLocalizedValues(
296 base::DictionaryValue* localized_strings) {
297 DCHECK(localized_strings);
299 static OptionsStringResource resources[] = {
300 { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON },
301 { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON },
302 { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON },
303 { "askException", IDS_EXCEPTIONS_ASK_BUTTON },
304 { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL },
305 { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS },
306 { "manageExceptions", IDS_EXCEPTIONS_MANAGE },
307 { "manage_handlers", IDS_HANDLERS_MANAGE },
308 { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER },
309 { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER },
310 { "exceptionZoomHeader", IDS_EXCEPTIONS_ZOOM_HEADER },
311 { "embeddedOnHost", IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST },
313 { "cookies_tab_label", IDS_COOKIES_TAB_LABEL },
314 { "cookies_header", IDS_COOKIES_HEADER },
315 { "cookies_allow", IDS_COOKIES_ALLOW_RADIO },
316 { "cookies_block", IDS_COOKIES_BLOCK_RADIO },
317 { "cookies_session_only", IDS_COOKIES_SESSION_ONLY_RADIO },
318 { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX },
319 { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX },
320 { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX },
321 { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON },
322 { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS },
323 { "flash_storage_url", IDS_FLASH_STORAGE_URL },
324 #if defined(ENABLE_GOOGLE_NOW)
325 { "googleGeolocationAccessEnable",
326 IDS_GEOLOCATION_GOOGLE_ACCESS_ENABLE_CHKBOX },
329 { "images_tab_label", IDS_IMAGES_TAB_LABEL },
330 { "images_header", IDS_IMAGES_HEADER },
331 { "images_allow", IDS_IMAGES_LOAD_RADIO },
332 { "images_block", IDS_IMAGES_NOLOAD_RADIO },
333 // JavaScript filter.
334 { "javascript_tab_label", IDS_JAVASCRIPT_TAB_LABEL },
335 { "javascript_header", IDS_JAVASCRIPT_HEADER },
336 { "javascript_allow", IDS_JS_ALLOW_RADIO },
337 { "javascript_block", IDS_JS_DONOTALLOW_RADIO },
339 { "plugins_tab_label", IDS_PLUGIN_TAB_LABEL },
340 { "plugins_header", IDS_PLUGIN_HEADER },
341 { "plugins_ask", IDS_PLUGIN_ASK_RADIO },
342 { "plugins_allow", IDS_PLUGIN_LOAD_RADIO },
343 { "plugins_block", IDS_PLUGIN_NOLOAD_RADIO },
344 { "disableIndividualPlugins", IDS_PLUGIN_SELECTIVE_DISABLE },
346 { "popups_tab_label", IDS_POPUP_TAB_LABEL },
347 { "popups_header", IDS_POPUP_HEADER },
348 { "popups_allow", IDS_POPUP_ALLOW_RADIO },
349 { "popups_block", IDS_POPUP_BLOCK_RADIO },
351 { "location_tab_label", IDS_GEOLOCATION_TAB_LABEL },
352 { "location_header", IDS_GEOLOCATION_HEADER },
353 { "location_allow", IDS_GEOLOCATION_ALLOW_RADIO },
354 { "location_ask", IDS_GEOLOCATION_ASK_RADIO },
355 { "location_block", IDS_GEOLOCATION_BLOCK_RADIO },
356 { "set_by", IDS_GEOLOCATION_SET_BY_HOVER },
357 // Notifications filter.
358 { "notifications_tab_label", IDS_NOTIFICATIONS_TAB_LABEL },
359 { "notifications_header", IDS_NOTIFICATIONS_HEADER },
360 { "notifications_allow", IDS_NOTIFICATIONS_ALLOW_RADIO },
361 { "notifications_ask", IDS_NOTIFICATIONS_ASK_RADIO },
362 { "notifications_block", IDS_NOTIFICATIONS_BLOCK_RADIO },
363 // Fullscreen filter.
364 { "fullscreen_tab_label", IDS_FULLSCREEN_TAB_LABEL },
365 { "fullscreen_header", IDS_FULLSCREEN_HEADER },
366 // Mouse Lock filter.
367 { "mouselock_tab_label", IDS_MOUSE_LOCK_TAB_LABEL },
368 { "mouselock_header", IDS_MOUSE_LOCK_HEADER },
369 { "mouselock_allow", IDS_MOUSE_LOCK_ALLOW_RADIO },
370 { "mouselock_ask", IDS_MOUSE_LOCK_ASK_RADIO },
371 { "mouselock_block", IDS_MOUSE_LOCK_BLOCK_RADIO },
372 #if defined(OS_CHROMEOS) || defined(OS_WIN)
373 // Protected Content filter
374 { "protectedContentTabLabel", IDS_PROTECTED_CONTENT_TAB_LABEL },
375 { "protectedContentInfo", IDS_PROTECTED_CONTENT_INFO },
376 { "protectedContentEnable", IDS_PROTECTED_CONTENT_ENABLE },
377 { "protectedContent_header", IDS_PROTECTED_CONTENT_HEADER },
378 #endif // defined(OS_CHROMEOS) || defined(OS_WIN)
379 // Media stream capture device filter.
380 { "mediaStreamTabLabel", IDS_MEDIA_STREAM_TAB_LABEL },
381 { "media-stream_header", IDS_MEDIA_STREAM_HEADER },
382 { "mediaStreamAsk", IDS_MEDIA_STREAM_ASK_RADIO },
383 { "mediaStreamBlock", IDS_MEDIA_STREAM_BLOCK_RADIO },
384 { "mediaStreamAudioAsk", IDS_MEDIA_STREAM_ASK_AUDIO_ONLY_RADIO },
385 { "mediaStreamAudioBlock", IDS_MEDIA_STREAM_BLOCK_AUDIO_ONLY_RADIO },
386 { "mediaStreamVideoAsk", IDS_MEDIA_STREAM_ASK_VIDEO_ONLY_RADIO },
387 { "mediaStreamVideoBlock", IDS_MEDIA_STREAM_BLOCK_VIDEO_ONLY_RADIO },
388 { "mediaStreamBubbleAudio", IDS_MEDIA_STREAM_AUDIO_MANAGED },
389 { "mediaStreamBubbleVideo", IDS_MEDIA_STREAM_VIDEO_MANAGED },
390 { "mediaAudioExceptionHeader", IDS_MEDIA_AUDIO_EXCEPTION_HEADER },
391 { "mediaVideoExceptionHeader", IDS_MEDIA_VIDEO_EXCEPTION_HEADER },
392 { "mediaPepperFlashDefaultDivergedLabel",
393 IDS_MEDIA_PEPPER_FLASH_DEFAULT_DIVERGED_LABEL },
394 { "mediaPepperFlashExceptionsDivergedLabel",
395 IDS_MEDIA_PEPPER_FLASH_EXCEPTIONS_DIVERGED_LABEL },
396 { "mediaPepperFlashChangeLink", IDS_MEDIA_PEPPER_FLASH_CHANGE_LINK },
397 { "mediaPepperFlashGlobalPrivacyURL", IDS_FLASH_GLOBAL_PRIVACY_URL },
398 { "mediaPepperFlashWebsitePrivacyURL", IDS_FLASH_WEBSITE_PRIVACY_URL },
399 // PPAPI broker filter.
400 // TODO(bauerb): Use IDS_PPAPI_BROKER_HEADER.
401 { "ppapi-broker_header", IDS_PPAPI_BROKER_TAB_LABEL },
402 { "ppapiBrokerTabLabel", IDS_PPAPI_BROKER_TAB_LABEL },
403 { "ppapi_broker_allow", IDS_PPAPI_BROKER_ALLOW_RADIO },
404 { "ppapi_broker_ask", IDS_PPAPI_BROKER_ASK_RADIO },
405 { "ppapi_broker_block", IDS_PPAPI_BROKER_BLOCK_RADIO },
406 // Multiple automatic downloads
407 { "multiple-automatic-downloads_header",
408 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL },
409 { "multiple-automatic-downloads_allow",
410 IDS_AUTOMATIC_DOWNLOADS_ALLOW_RADIO },
411 { "multiple-automatic-downloads_ask",
412 IDS_AUTOMATIC_DOWNLOADS_ASK_RADIO },
413 { "multiple-automatic-downloads_block",
414 IDS_AUTOMATIC_DOWNLOADS_BLOCK_RADIO },
415 // MIDI system exclusive messages
416 { "midi-sysex_header", IDS_MIDI_SYSEX_TAB_LABEL },
417 { "midiSysExAllow", IDS_MIDI_SYSEX_ALLOW_RADIO },
418 { "midiSysExAsk", IDS_MIDI_SYSEX_ASK_RADIO },
419 { "midiSysExBlock", IDS_MIDI_SYSEX_BLOCK_RADIO },
420 { "zoomlevels_header", IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL },
421 { "zoomLevelsManage", IDS_ZOOMLEVELS_MANAGE_BUTTON },
424 RegisterStrings(localized_strings, resources, arraysize(resources));
425 RegisterTitle(localized_strings, "contentSettingsPage",
426 IDS_CONTENT_SETTINGS_TITLE);
428 // Register titles for each of the individual settings whose exception
429 // dialogs will be processed by |ContentSettingsHandler|.
430 RegisterTitle(localized_strings, "cookies",
431 IDS_COOKIES_TAB_LABEL);
432 RegisterTitle(localized_strings, "images",
433 IDS_IMAGES_TAB_LABEL);
434 RegisterTitle(localized_strings, "javascript",
435 IDS_JAVASCRIPT_TAB_LABEL);
436 RegisterTitle(localized_strings, "plugins",
437 IDS_PLUGIN_TAB_LABEL);
438 RegisterTitle(localized_strings, "popups",
439 IDS_POPUP_TAB_LABEL);
440 RegisterTitle(localized_strings, "location",
441 IDS_GEOLOCATION_TAB_LABEL);
442 RegisterTitle(localized_strings, "notifications",
443 IDS_NOTIFICATIONS_TAB_LABEL);
444 RegisterTitle(localized_strings, "fullscreen",
445 IDS_FULLSCREEN_TAB_LABEL);
446 RegisterTitle(localized_strings, "mouselock",
447 IDS_MOUSE_LOCK_TAB_LABEL);
448 #if defined(OS_CHROMEOS)
449 RegisterTitle(localized_strings, "protectedContent",
450 IDS_PROTECTED_CONTENT_TAB_LABEL);
452 RegisterTitle(localized_strings, "media-stream",
453 IDS_MEDIA_STREAM_TAB_LABEL);
454 RegisterTitle(localized_strings, "ppapi-broker",
455 IDS_PPAPI_BROKER_TAB_LABEL);
456 RegisterTitle(localized_strings, "multiple-automatic-downloads",
457 IDS_AUTOMATIC_DOWNLOADS_TAB_LABEL);
458 RegisterTitle(localized_strings, "midi-sysex",
459 IDS_MIDI_SYSEX_TAB_LABEL);
460 RegisterTitle(localized_strings, "zoomlevels",
461 IDS_ZOOMLEVELS_HEADER_AND_TAB_LABEL);
463 localized_strings->SetString(
464 "exceptionsLearnMoreUrl",
465 google_util::StringAppendGoogleLocaleParam(
466 kExceptionsLearnMoreUrl));
469 void ContentSettingsHandler::InitializeHandler() {
470 notification_registrar_.Add(
471 this, chrome::NOTIFICATION_PROFILE_CREATED,
472 content::NotificationService::AllSources());
473 notification_registrar_.Add(
474 this, chrome::NOTIFICATION_PROFILE_DESTROYED,
475 content::NotificationService::AllSources());
477 notification_registrar_.Add(
478 this, chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED,
479 content::NotificationService::AllSources());
480 notification_registrar_.Add(
481 this, chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
482 content::NotificationService::AllSources());
483 Profile* profile = Profile::FromWebUI(web_ui());
484 notification_registrar_.Add(
485 this, chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED,
486 content::Source<Profile>(profile));
488 PrefService* prefs = profile->GetPrefs();
489 pref_change_registrar_.Init(prefs);
490 pref_change_registrar_.Add(
491 prefs::kPepperFlashSettingsEnabled,
492 base::Bind(&ContentSettingsHandler::OnPepperFlashPrefChanged,
493 base::Unretained(this)));
494 pref_change_registrar_.Add(
495 prefs::kAudioCaptureAllowed,
496 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
497 base::Unretained(this)));
498 pref_change_registrar_.Add(
499 prefs::kVideoCaptureAllowed,
500 base::Bind(&ContentSettingsHandler::UpdateMediaSettingsView,
501 base::Unretained(this)));
502 pref_change_registrar_.Add(
505 &ContentSettingsHandler::UpdateProtectedContentExceptionsButton,
506 base::Unretained(this)));
508 content::HostZoomMap* host_zoom_map =
509 content::HostZoomMap::GetForBrowserContext(profile);
510 host_zoom_map_subscription_ =
511 host_zoom_map->AddZoomLevelChangedCallback(
512 base::Bind(&ContentSettingsHandler::OnZoomLevelChanged,
513 base::Unretained(this)));
515 flash_settings_manager_.reset(new PepperFlashSettingsManager(this, profile));
518 void ContentSettingsHandler::InitializePage() {
519 media_settings_ = MediaSettingsInfo();
520 RefreshFlashMediaSettings();
522 UpdateHandlersEnabledRadios();
523 UpdateAllExceptionsViewsFromModel();
524 UpdateProtectedContentExceptionsButton();
527 void ContentSettingsHandler::Observe(
529 const content::NotificationSource& source,
530 const content::NotificationDetails& details) {
532 case chrome::NOTIFICATION_PROFILE_DESTROYED: {
533 if (content::Source<Profile>(source).ptr()->IsOffTheRecord()) {
534 web_ui()->CallJavascriptFunction(
535 "ContentSettingsExceptionsArea.OTRProfileDestroyed");
540 case chrome::NOTIFICATION_PROFILE_CREATED: {
541 if (content::Source<Profile>(source).ptr()->IsOffTheRecord())
542 UpdateAllOTRExceptionsViewsFromModel();
546 case chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED: {
547 // Filter out notifications from other profiles.
548 HostContentSettingsMap* map =
549 content::Source<HostContentSettingsMap>(source).ptr();
550 if (map != GetContentSettingsMap() &&
551 map != GetOTRContentSettingsMap())
554 const ContentSettingsDetails* settings_details =
555 content::Details<const ContentSettingsDetails>(details).ptr();
557 // TODO(estade): we pretend update_all() is always true.
558 if (settings_details->update_all_types())
559 UpdateAllExceptionsViewsFromModel();
561 UpdateExceptionsViewFromModel(settings_details->type());
565 case chrome::NOTIFICATION_DESKTOP_NOTIFICATION_SETTINGS_CHANGED: {
566 UpdateNotificationExceptionsView();
570 case chrome::NOTIFICATION_PROTOCOL_HANDLER_REGISTRY_CHANGED: {
571 UpdateHandlersEnabledRadios();
577 void ContentSettingsHandler::OnGetPermissionSettingsCompleted(
580 PP_Flash_BrowserOperations_Permission default_permission,
581 const ppapi::FlashSiteSettings& sites) {
582 if (success && request_id == media_settings_.last_flash_refresh_request_id) {
583 media_settings_.flash_settings_initialized = true;
584 media_settings_.flash_default_setting =
585 PepperFlashContentSettingsUtils::FlashPermissionToContentSetting(
587 PepperFlashContentSettingsUtils::FlashSiteSettingsToMediaExceptions(
588 sites, &media_settings_.flash_exceptions);
589 PepperFlashContentSettingsUtils::SortMediaExceptions(
590 &media_settings_.flash_exceptions);
592 UpdateFlashMediaLinksVisibility();
596 void ContentSettingsHandler::UpdateSettingDefaultFromModel(
597 ContentSettingsType type) {
598 base::DictionaryValue filter_settings;
599 std::string provider_id;
600 filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value",
601 GetSettingDefaultFromModel(type, &provider_id));
602 filter_settings.SetString(
603 ContentSettingsTypeToGroupName(type) + ".managedBy", provider_id);
605 web_ui()->CallJavascriptFunction(
606 "ContentSettings.setContentFilterSettingsValue", filter_settings);
609 void ContentSettingsHandler::UpdateMediaSettingsView() {
610 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
611 bool audio_disabled = !prefs->GetBoolean(prefs::kAudioCaptureAllowed) &&
612 prefs->IsManagedPreference(prefs::kAudioCaptureAllowed);
613 bool video_disabled = !prefs->GetBoolean(prefs::kVideoCaptureAllowed) &&
614 prefs->IsManagedPreference(prefs::kVideoCaptureAllowed);
616 media_settings_.policy_disable_audio = audio_disabled;
617 media_settings_.policy_disable_video = video_disabled;
618 media_settings_.default_setting =
619 GetContentSettingsMap()->GetDefaultContentSetting(
620 CONTENT_SETTINGS_TYPE_MEDIASTREAM, NULL);
621 media_settings_.default_setting_initialized = true;
622 UpdateFlashMediaLinksVisibility();
624 base::DictionaryValue media_ui_settings;
625 media_ui_settings.SetBoolean("cameraDisabled", video_disabled);
626 media_ui_settings.SetBoolean("micDisabled", audio_disabled);
628 // In case only video is enabled change the text appropriately.
629 if (audio_disabled && !video_disabled) {
630 media_ui_settings.SetString("askText", "mediaStreamVideoAsk");
631 media_ui_settings.SetString("blockText", "mediaStreamVideoBlock");
632 media_ui_settings.SetBoolean("showBubble", true);
633 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleAudio");
635 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
640 // In case only audio is enabled change the text appropriately.
641 if (video_disabled && !audio_disabled) {
642 base::DictionaryValue media_ui_settings;
643 media_ui_settings.SetString("askText", "mediaStreamAudioAsk");
644 media_ui_settings.SetString("blockText", "mediaStreamAudioBlock");
645 media_ui_settings.SetBoolean("showBubble", true);
646 media_ui_settings.SetString("bubbleText", "mediaStreamBubbleVideo");
648 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
653 if (audio_disabled && video_disabled) {
654 // Fake policy controlled default because the user can not change anything
655 // until both audio and video are blocked.
656 base::DictionaryValue filter_settings;
657 std::string group_name =
658 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
659 filter_settings.SetString(group_name + ".value",
660 ContentSettingToString(CONTENT_SETTING_BLOCK));
661 filter_settings.SetString(group_name + ".managedBy", "policy");
662 web_ui()->CallJavascriptFunction(
663 "ContentSettings.setContentFilterSettingsValue", filter_settings);
666 media_ui_settings.SetString("askText", "mediaStreamAsk");
667 media_ui_settings.SetString("blockText", "mediaStreamBlock");
668 media_ui_settings.SetBoolean("showBubble", false);
669 media_ui_settings.SetString("bubbleText", std::string());
671 web_ui()->CallJavascriptFunction("ContentSettings.updateMediaUI",
675 std::string ContentSettingsHandler::GetSettingDefaultFromModel(
676 ContentSettingsType type, std::string* provider_id) {
677 Profile* profile = Profile::FromWebUI(web_ui());
678 ContentSetting default_setting;
679 if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
681 DesktopNotificationServiceFactory::GetForProfile(profile)->
682 GetDefaultContentSetting(provider_id);
685 profile->GetHostContentSettingsMap()->
686 GetDefaultContentSetting(type, provider_id);
689 return ContentSettingToString(default_setting);
692 void ContentSettingsHandler::UpdateHandlersEnabledRadios() {
693 base::FundamentalValue handlers_enabled(
694 GetProtocolHandlerRegistry()->enabled());
696 web_ui()->CallJavascriptFunction(
697 "ContentSettings.updateHandlersEnabledRadios",
701 void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
702 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
703 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
704 UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
706 // Zoom levels are not actually a content type so we need to handle them
708 UpdateZoomLevelsExceptionsView();
711 void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() {
712 for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
713 type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
714 UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
718 void ContentSettingsHandler::UpdateExceptionsViewFromModel(
719 ContentSettingsType type) {
721 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
722 UpdateGeolocationExceptionsView();
724 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
725 UpdateNotificationExceptionsView();
727 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
728 UpdateMediaSettingsView();
730 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
731 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
732 UpdateMediaExceptionsView();
734 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
735 // We don't yet support exceptions for mixed scripting.
737 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
738 // The content settings type CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE
739 // is supposed to be set by policy only. Hence there is no user facing UI
740 // for this content type and we skip it here.
742 case CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS:
743 // The RPH settings are retrieved separately.
745 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
746 UpdateMIDISysExExceptionsView();
749 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
753 UpdateExceptionsViewFromHostContentSettingsMap(type);
758 void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel(
759 ContentSettingsType type) {
761 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
762 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
763 case CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE:
764 case CONTENT_SETTINGS_TYPE_MIXEDSCRIPT:
766 case CONTENT_SETTINGS_TYPE_METRO_SWITCH_TO_DESKTOP:
768 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
769 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
770 case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
771 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
772 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
775 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
780 // TODO(estade): merge with GetExceptionsFromHostContentSettingsMap.
781 void ContentSettingsHandler::UpdateGeolocationExceptionsView() {
782 Profile* profile = Profile::FromWebUI(web_ui());
783 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
785 ContentSettingsForOneType all_settings;
786 map->GetSettingsForOneType(
787 CONTENT_SETTINGS_TYPE_GEOLOCATION,
791 // Group geolocation settings by primary_pattern.
792 AllPatternsSettings all_patterns_settings;
793 for (ContentSettingsForOneType::iterator i = all_settings.begin();
794 i != all_settings.end(); ++i) {
795 // Don't add default settings.
796 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
797 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
798 i->source != kPreferencesSource) {
801 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
802 [i->secondary_pattern] = i->setting;
805 base::ListValue exceptions;
806 AddExceptionsGrantedByHostedApps(
808 HostedAppHasPermission<APIPermission::kGeolocation>,
811 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
812 i != all_patterns_settings.end(); ++i) {
813 const ContentSettingsPattern& primary_pattern = i->first.first;
814 const OnePatternSettings& one_settings = i->second;
816 OnePatternSettings::const_iterator parent =
817 one_settings.find(primary_pattern);
819 // Add the "parent" entry for the non-embedded setting.
820 ContentSetting parent_setting =
821 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
822 exceptions.Append(GetGeolocationExceptionForPage(primary_pattern,
826 // Add the "children" for any embedded settings.
827 for (OnePatternSettings::const_iterator j = one_settings.begin();
828 j != one_settings.end();
830 // Skip the non-embedded setting which we already added above.
834 exceptions.Append(GetGeolocationExceptionForPage(
835 primary_pattern, j->first, j->second));
839 base::StringValue type_string(
840 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION));
841 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
842 type_string, exceptions);
844 // This is mainly here to keep this function ideologically parallel to
845 // UpdateExceptionsViewFromHostContentSettingsMap().
846 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
849 void ContentSettingsHandler::UpdateNotificationExceptionsView() {
850 Profile* profile = Profile::FromWebUI(web_ui());
851 DesktopNotificationService* service =
852 DesktopNotificationServiceFactory::GetForProfile(profile);
854 ContentSettingsForOneType settings;
855 service->GetNotificationsSettings(&settings);
857 base::ListValue exceptions;
858 AddExceptionsGrantedByHostedApps(profile,
859 HostedAppHasPermission<APIPermission::kNotification>,
862 for (ContentSettingsForOneType::const_iterator i =
866 // Don't add default settings.
867 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
868 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
869 i->source != kPreferencesSource) {
874 GetNotificationExceptionForPage(i->primary_pattern, i->setting,
878 base::StringValue type_string(
879 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
880 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
881 type_string, exceptions);
883 // This is mainly here to keep this function ideologically parallel to
884 // UpdateExceptionsViewFromHostContentSettingsMap().
885 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
888 void ContentSettingsHandler::UpdateMediaExceptionsView() {
889 base::ListValue media_exceptions;
890 GetExceptionsFromHostContentSettingsMap(
891 GetContentSettingsMap(),
892 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
895 base::ListValue video_exceptions;
896 GetExceptionsFromHostContentSettingsMap(
897 GetContentSettingsMap(),
898 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
901 // Merge the |video_exceptions| list to |media_exceptions| list.
902 std::map<std::string, base::DictionaryValue*> entries_map;
903 for (base::ListValue::const_iterator media_entry(media_exceptions.begin());
904 media_entry != media_exceptions.end(); ++media_entry) {
905 base::DictionaryValue* media_dict = NULL;
906 if (!(*media_entry)->GetAsDictionary(&media_dict))
909 media_dict->SetString(kVideoSetting,
910 ContentSettingToString(CONTENT_SETTING_ASK));
912 std::string media_origin;
913 media_dict->GetString(kOrigin, &media_origin);
914 entries_map[media_origin] = media_dict;
917 for (base::ListValue::iterator video_entry = video_exceptions.begin();
918 video_entry != video_exceptions.end(); ++video_entry) {
919 base::DictionaryValue* video_dict = NULL;
920 if (!(*video_entry)->GetAsDictionary(&video_dict))
923 std::string video_origin;
924 std::string video_setting;
925 video_dict->GetString(kOrigin, &video_origin);
926 video_dict->GetString(kSetting, &video_setting);
928 std::map<std::string, base::DictionaryValue*>::iterator iter =
929 entries_map.find(video_origin);
930 if (iter == entries_map.end()) {
931 base::DictionaryValue* exception = new base::DictionaryValue();
932 exception->SetString(kOrigin, video_origin);
933 exception->SetString(kSetting,
934 ContentSettingToString(CONTENT_SETTING_ASK));
935 exception->SetString(kVideoSetting, video_setting);
936 exception->SetString(kSource, kPreferencesSource);
938 // Append the new entry to the list and map.
939 media_exceptions.Append(exception);
940 entries_map[video_origin] = exception;
942 // Modify the existing entry.
943 iter->second->SetString(kVideoSetting, video_setting);
947 media_settings_.exceptions.clear();
948 for (base::ListValue::const_iterator media_entry = media_exceptions.begin();
949 media_entry != media_exceptions.end(); ++media_entry) {
950 base::DictionaryValue* media_dict = NULL;
951 bool result = (*media_entry)->GetAsDictionary(&media_dict);
955 std::string audio_setting;
956 std::string video_setting;
957 media_dict->GetString(kOrigin, &origin);
958 media_dict->GetString(kSetting, &audio_setting);
959 media_dict->GetString(kVideoSetting, &video_setting);
960 media_settings_.exceptions.push_back(MediaException(
961 ContentSettingsPattern::FromString(origin),
962 ContentSettingFromString(audio_setting),
963 ContentSettingFromString(video_setting)));
965 PepperFlashContentSettingsUtils::SortMediaExceptions(
966 &media_settings_.exceptions);
967 media_settings_.exceptions_initialized = true;
968 UpdateFlashMediaLinksVisibility();
970 base::StringValue type_string(
971 ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_MEDIASTREAM));
972 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
973 type_string, media_exceptions);
975 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MEDIASTREAM);
978 void ContentSettingsHandler::UpdateMIDISysExExceptionsView() {
979 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableWebMIDI)) {
980 web_ui()->CallJavascriptFunction(
981 "ContentSettings.showExperimentalWebMIDISettings",
982 base::FundamentalValue(true));
985 UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
986 UpdateExceptionsViewFromHostContentSettingsMap(
987 CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
990 void ContentSettingsHandler::UpdateZoomLevelsExceptionsView() {
991 base::ListValue zoom_levels_exceptions;
993 content::HostZoomMap* host_zoom_map =
994 content::HostZoomMap::GetForBrowserContext(Profile::FromWebUI(web_ui()));
995 content::HostZoomMap::ZoomLevelVector zoom_levels(
996 host_zoom_map->GetAllZoomLevels());
997 std::sort(zoom_levels.begin(), zoom_levels.end(), HostZoomSort);
999 for (content::HostZoomMap::ZoomLevelVector::const_iterator i =
1000 zoom_levels.begin();
1001 i != zoom_levels.end();
1003 scoped_ptr<base::DictionaryValue> exception(new base::DictionaryValue);
1005 case content::HostZoomMap::ZOOM_CHANGED_FOR_HOST:
1006 exception->SetString(kOrigin, i->host);
1008 case content::HostZoomMap::ZOOM_CHANGED_FOR_SCHEME_AND_HOST:
1009 exception->SetString(
1010 kOrigin, i->scheme + content::kStandardSchemeSeparator + i->host);
1012 case content::HostZoomMap::ZOOM_CHANGED_TEMPORARY_ZOOM:
1015 exception->SetString(kSetting,
1016 ContentSettingToString(CONTENT_SETTING_DEFAULT));
1018 // Calculate the zoom percent from the factor. Round up to the nearest whole
1020 int zoom_percent = static_cast<int>(
1021 content::ZoomLevelToZoomFactor(i->zoom_level) * 100 + 0.5);
1022 exception->SetString(
1024 l10n_util::GetStringFUTF16(IDS_ZOOM_PERCENT,
1025 base::IntToString16(zoom_percent)));
1026 exception->SetString(kSource, kPreferencesSource);
1027 // Append the new entry to the list and map.
1028 zoom_levels_exceptions.Append(exception.release());
1031 base::StringValue type_string(kZoomContentType);
1032 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions",
1033 type_string, zoom_levels_exceptions);
1036 void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap(
1037 ContentSettingsType type) {
1038 base::ListValue exceptions;
1039 GetExceptionsFromHostContentSettingsMap(
1040 GetContentSettingsMap(), type, &exceptions);
1041 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1042 web_ui()->CallJavascriptFunction("ContentSettings.setExceptions", type_string,
1045 UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
1047 // TODO(koz): The default for fullscreen is always 'ask'.
1048 // http://crbug.com/104683
1049 if (type == CONTENT_SETTINGS_TYPE_FULLSCREEN)
1052 #if defined(OS_CHROMEOS)
1053 // Also the default for protected contents is managed in another place.
1054 if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER)
1058 // The default may also have changed (we won't get a separate notification).
1059 // If it hasn't changed, this call will be harmless.
1060 UpdateSettingDefaultFromModel(type);
1063 void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap(
1064 ContentSettingsType type) {
1065 const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
1066 if (!otr_settings_map)
1068 base::ListValue exceptions;
1069 GetExceptionsFromHostContentSettingsMap(otr_settings_map, type, &exceptions);
1070 base::StringValue type_string(ContentSettingsTypeToGroupName(type));
1071 web_ui()->CallJavascriptFunction("ContentSettings.setOTRExceptions",
1072 type_string, exceptions);
1075 void ContentSettingsHandler::GetExceptionsFromHostContentSettingsMap(
1076 const HostContentSettingsMap* map,
1077 ContentSettingsType type,
1078 base::ListValue* exceptions) {
1079 ContentSettingsForOneType entries;
1080 map->GetSettingsForOneType(type, std::string(), &entries);
1081 // Group settings by primary_pattern.
1082 AllPatternsSettings all_patterns_settings;
1083 for (ContentSettingsForOneType::iterator i = entries.begin();
1084 i != entries.end(); ++i) {
1085 // Don't add default settings.
1086 if (i->primary_pattern == ContentSettingsPattern::Wildcard() &&
1087 i->secondary_pattern == ContentSettingsPattern::Wildcard() &&
1088 i->source != kPreferencesSource) {
1092 // Off-the-record HostContentSettingsMap contains incognito content settings
1093 // as well as normal content settings. Here, we use the incongnito settings
1095 if (map->is_off_the_record() && !i->incognito)
1098 all_patterns_settings[std::make_pair(i->primary_pattern, i->source)]
1099 [i->secondary_pattern] = i->setting;
1102 // Keep the exceptions sorted by provider so they will be displayed in
1103 // precedence order.
1104 std::vector<std::vector<base::Value*> > all_provider_exceptions;
1105 all_provider_exceptions.resize(HostContentSettingsMap::NUM_PROVIDER_TYPES);
1107 for (AllPatternsSettings::iterator i = all_patterns_settings.begin();
1108 i != all_patterns_settings.end();
1110 const ContentSettingsPattern& primary_pattern = i->first.first;
1111 const OnePatternSettings& one_settings = i->second;
1113 // The "parent" entry either has an identical primary and secondary pattern,
1114 // or has a wildcard secondary. The two cases are indistinguishable in the
1116 OnePatternSettings::const_iterator parent =
1117 one_settings.find(primary_pattern);
1118 if (parent == one_settings.end())
1119 parent = one_settings.find(ContentSettingsPattern::Wildcard());
1121 const std::string& source = i->first.second;
1122 std::vector<base::Value*>* this_provider_exceptions =
1123 &all_provider_exceptions.at(
1124 HostContentSettingsMap::GetProviderTypeFromSource(source));
1126 // Add the "parent" entry for the non-embedded setting.
1127 ContentSetting parent_setting =
1128 parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
1129 const ContentSettingsPattern& secondary_pattern =
1130 parent == one_settings.end() ? primary_pattern : parent->first;
1131 this_provider_exceptions->push_back(GetExceptionForPage(primary_pattern,
1136 // Add the "children" for any embedded settings.
1137 for (OnePatternSettings::const_iterator j = one_settings.begin();
1138 j != one_settings.end(); ++j) {
1139 // Skip the non-embedded setting which we already added above.
1143 ContentSetting content_setting = j->second;
1144 this_provider_exceptions->push_back(GetExceptionForPage(
1152 for (size_t i = 0; i < all_provider_exceptions.size(); ++i) {
1153 for (size_t j = 0; j < all_provider_exceptions[i].size(); ++j) {
1154 exceptions->Append(all_provider_exceptions[i][j]);
1159 void ContentSettingsHandler::RemoveNotificationException(
1160 const base::ListValue* args) {
1161 Profile* profile = Profile::FromWebUI(web_ui());
1163 std::string setting;
1164 bool rv = args->GetString(1, &origin);
1166 rv = args->GetString(2, &setting);
1168 ContentSetting content_setting = ContentSettingFromString(setting);
1170 DCHECK(content_setting == CONTENT_SETTING_ALLOW ||
1171 content_setting == CONTENT_SETTING_BLOCK);
1172 DesktopNotificationServiceFactory::GetForProfile(profile)->
1173 ClearSetting(ContentSettingsPattern::FromString(origin));
1176 void ContentSettingsHandler::RemoveMediaException(const base::ListValue* args) {
1178 bool rv = args->GetString(1, &mode);
1181 std::string pattern;
1182 rv = args->GetString(2, &pattern);
1185 HostContentSettingsMap* settings_map =
1186 mode == "normal" ? GetContentSettingsMap() :
1187 GetOTRContentSettingsMap();
1189 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1190 ContentSettingsPattern::Wildcard(),
1191 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
1194 settings_map->SetWebsiteSetting(ContentSettingsPattern::FromString(pattern),
1195 ContentSettingsPattern::Wildcard(),
1196 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
1202 void ContentSettingsHandler::RemoveExceptionFromHostContentSettingsMap(
1203 const base::ListValue* args,
1204 ContentSettingsType type) {
1206 bool rv = args->GetString(1, &mode);
1209 std::string pattern;
1210 rv = args->GetString(2, &pattern);
1213 std::string secondary_pattern;
1214 rv = args->GetString(3, &secondary_pattern);
1217 HostContentSettingsMap* settings_map =
1218 mode == "normal" ? GetContentSettingsMap() :
1219 GetOTRContentSettingsMap();
1221 settings_map->SetWebsiteSetting(
1222 ContentSettingsPattern::FromString(pattern),
1223 secondary_pattern.empty()
1224 ? ContentSettingsPattern::Wildcard()
1225 : ContentSettingsPattern::FromString(secondary_pattern),
1232 void ContentSettingsHandler::RemoveZoomLevelException(
1233 const base::ListValue* args) {
1235 bool rv = args->GetString(1, &mode);
1238 std::string pattern;
1239 rv = args->GetString(2, &pattern);
1242 content::HostZoomMap* host_zoom_map =
1243 content::HostZoomMap::GetForBrowserContext(Profile::FromWebUI(web_ui()));
1244 double default_level = host_zoom_map->GetDefaultZoomLevel();
1246 std::string::size_type scheme_separator_position =
1247 pattern.find(content::kStandardSchemeSeparator);
1248 if (scheme_separator_position == std::string::npos) {
1249 host_zoom_map->SetZoomLevelForHost(pattern, default_level);
1251 std::string scheme = pattern.substr(0, scheme_separator_position);
1252 std::string host = pattern.substr(
1253 scheme_separator_position + strlen(content::kStandardSchemeSeparator));
1254 host_zoom_map->SetZoomLevelForHostAndScheme(scheme, host, default_level);
1258 void ContentSettingsHandler::RegisterMessages() {
1259 web_ui()->RegisterMessageCallback("setContentFilter",
1260 base::Bind(&ContentSettingsHandler::SetContentFilter,
1261 base::Unretained(this)));
1262 web_ui()->RegisterMessageCallback("removeException",
1263 base::Bind(&ContentSettingsHandler::RemoveException,
1264 base::Unretained(this)));
1265 web_ui()->RegisterMessageCallback("setException",
1266 base::Bind(&ContentSettingsHandler::SetException,
1267 base::Unretained(this)));
1268 web_ui()->RegisterMessageCallback("checkExceptionPatternValidity",
1269 base::Bind(&ContentSettingsHandler::CheckExceptionPatternValidity,
1270 base::Unretained(this)));
1273 void ContentSettingsHandler::ApplyWhitelist(ContentSettingsType content_type,
1274 ContentSetting default_setting) {
1275 Profile* profile = Profile::FromWebUI(web_ui());
1276 HostContentSettingsMap* map = GetContentSettingsMap();
1277 if (content_type != CONTENT_SETTINGS_TYPE_PLUGINS)
1279 const int kDefaultWhitelistVersion = 1;
1280 PrefService* prefs = profile->GetPrefs();
1281 int version = prefs->GetInteger(
1282 prefs::kContentSettingsDefaultWhitelistVersion);
1283 if (version >= kDefaultWhitelistVersion)
1285 ContentSetting old_setting =
1286 map->GetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS, NULL);
1287 // TODO(bauerb): Remove this once the Google Talk plug-in works nicely with
1288 // click-to-play (b/6090625).
1289 if (old_setting == CONTENT_SETTING_ALLOW &&
1290 default_setting == CONTENT_SETTING_ASK) {
1291 map->SetWebsiteSetting(
1292 ContentSettingsPattern::Wildcard(),
1293 ContentSettingsPattern::Wildcard(),
1294 CONTENT_SETTINGS_TYPE_PLUGINS,
1296 new base::FundamentalValue(CONTENT_SETTING_ALLOW));
1298 prefs->SetInteger(prefs::kContentSettingsDefaultWhitelistVersion,
1299 kDefaultWhitelistVersion);
1302 void ContentSettingsHandler::SetContentFilter(const base::ListValue* args) {
1303 DCHECK_EQ(2U, args->GetSize());
1304 std::string group, setting;
1305 if (!(args->GetString(0, &group) &&
1306 args->GetString(1, &setting))) {
1311 ContentSetting default_setting = ContentSettingFromString(setting);
1312 ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
1313 Profile* profile = Profile::FromWebUI(web_ui());
1315 #if defined(OS_CHROMEOS)
1316 // ChromeOS special case : in Guest mode settings are opened in Incognito
1317 // mode, so we need original profile to actually modify settings.
1318 if (chromeos::UserManager::Get()->IsLoggedInAsGuest())
1319 profile = profile->GetOriginalProfile();
1322 if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
1323 DesktopNotificationServiceFactory::GetForProfile(profile)->
1324 SetDefaultContentSetting(default_setting);
1326 HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
1327 ApplyWhitelist(content_type, default_setting);
1328 map->SetDefaultContentSetting(content_type, default_setting);
1330 switch (content_type) {
1331 case CONTENT_SETTINGS_TYPE_COOKIES:
1332 content::RecordAction(
1333 UserMetricsAction("Options_DefaultCookieSettingChanged"));
1335 case CONTENT_SETTINGS_TYPE_IMAGES:
1336 content::RecordAction(
1337 UserMetricsAction("Options_DefaultImagesSettingChanged"));
1339 case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
1340 content::RecordAction(
1341 UserMetricsAction("Options_DefaultJavaScriptSettingChanged"));
1343 case CONTENT_SETTINGS_TYPE_PLUGINS:
1344 content::RecordAction(
1345 UserMetricsAction("Options_DefaultPluginsSettingChanged"));
1347 case CONTENT_SETTINGS_TYPE_POPUPS:
1348 content::RecordAction(
1349 UserMetricsAction("Options_DefaultPopupsSettingChanged"));
1351 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1352 content::RecordAction(
1353 UserMetricsAction("Options_DefaultNotificationsSettingChanged"));
1355 case CONTENT_SETTINGS_TYPE_GEOLOCATION:
1356 content::RecordAction(
1357 UserMetricsAction("Options_DefaultGeolocationSettingChanged"));
1359 case CONTENT_SETTINGS_TYPE_MOUSELOCK:
1360 content::RecordAction(
1361 UserMetricsAction("Options_DefaultMouseLockSettingChanged"));
1363 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1364 content::RecordAction(
1365 UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged"));
1367 case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
1368 content::RecordAction(
1369 UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange"));
1371 case CONTENT_SETTINGS_TYPE_MIDI_SYSEX:
1372 content::RecordAction(
1373 UserMetricsAction("Options_DefaultMIDISysExSettingChanged"));
1380 void ContentSettingsHandler::RemoveException(const base::ListValue* args) {
1381 std::string type_string;
1382 CHECK(args->GetString(0, &type_string));
1384 // Zoom levels are no actual content type so we need to handle them
1385 // separately. They would not be recognized by
1386 // ContentSettingsTypeFromGroupName.
1387 if (type_string == kZoomContentType) {
1388 RemoveZoomLevelException(args);
1392 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1394 case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
1395 RemoveNotificationException(args);
1397 case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
1398 RemoveMediaException(args);
1401 RemoveExceptionFromHostContentSettingsMap(args, type);
1406 void ContentSettingsHandler::SetException(const base::ListValue* args) {
1407 std::string type_string;
1408 CHECK(args->GetString(0, &type_string));
1410 CHECK(args->GetString(1, &mode));
1411 std::string pattern;
1412 CHECK(args->GetString(2, &pattern));
1413 std::string setting;
1414 CHECK(args->GetString(3, &setting));
1416 ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
1417 if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
1418 type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS ||
1419 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM ||
1420 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
1421 type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) {
1424 HostContentSettingsMap* settings_map =
1425 mode == "normal" ? GetContentSettingsMap() :
1426 GetOTRContentSettingsMap();
1428 // The settings map could be null if the mode was OTR but the OTR profile
1429 // got destroyed before we received this message.
1432 settings_map->SetContentSetting(ContentSettingsPattern::FromString(pattern),
1433 ContentSettingsPattern::Wildcard(),
1436 ContentSettingFromString(setting));
1440 void ContentSettingsHandler::CheckExceptionPatternValidity(
1441 const base::ListValue* args) {
1442 std::string type_string;
1443 CHECK(args->GetString(0, &type_string));
1444 std::string mode_string;
1445 CHECK(args->GetString(1, &mode_string));
1446 std::string pattern_string;
1447 CHECK(args->GetString(2, &pattern_string));
1449 ContentSettingsPattern pattern =
1450 ContentSettingsPattern::FromString(pattern_string);
1452 web_ui()->CallJavascriptFunction(
1453 "ContentSettings.patternValidityCheckComplete",
1454 base::StringValue(type_string),
1455 base::StringValue(mode_string),
1456 base::StringValue(pattern_string),
1457 base::FundamentalValue(pattern.IsValid()));
1461 std::string ContentSettingsHandler::ContentSettingsTypeToGroupName(
1462 ContentSettingsType type) {
1463 for (size_t i = 0; i < arraysize(kContentSettingsTypeGroupNames); ++i) {
1464 if (type == kContentSettingsTypeGroupNames[i].type)
1465 return kContentSettingsTypeGroupNames[i].name;
1469 return std::string();
1472 HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
1473 return Profile::FromWebUI(web_ui())->GetHostContentSettingsMap();
1476 ProtocolHandlerRegistry* ContentSettingsHandler::GetProtocolHandlerRegistry() {
1477 return ProtocolHandlerRegistryFactory::GetForProfile(
1478 Profile::FromWebUI(web_ui()));
1481 HostContentSettingsMap*
1482 ContentSettingsHandler::GetOTRContentSettingsMap() {
1483 Profile* profile = Profile::FromWebUI(web_ui());
1484 if (profile->HasOffTheRecordProfile())
1485 return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
1489 void ContentSettingsHandler::RefreshFlashMediaSettings() {
1490 media_settings_.flash_settings_initialized = false;
1492 media_settings_.last_flash_refresh_request_id =
1493 flash_settings_manager_->GetPermissionSettings(
1494 PP_FLASH_BROWSEROPERATIONS_SETTINGTYPE_CAMERAMIC);
1497 void ContentSettingsHandler::OnPepperFlashPrefChanged() {
1498 ShowFlashMediaLink(DEFAULT_SETTING, false);
1499 ShowFlashMediaLink(EXCEPTIONS, false);
1501 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
1502 if (prefs->GetBoolean(prefs::kPepperFlashSettingsEnabled))
1503 RefreshFlashMediaSettings();
1505 media_settings_.flash_settings_initialized = false;
1508 void ContentSettingsHandler::OnZoomLevelChanged(
1509 const content::HostZoomMap::ZoomLevelChange& change) {
1510 UpdateZoomLevelsExceptionsView();
1513 void ContentSettingsHandler::ShowFlashMediaLink(LinkType link_type, bool show) {
1514 bool& show_link = link_type == DEFAULT_SETTING ?
1515 media_settings_.show_flash_default_link :
1516 media_settings_.show_flash_exceptions_link;
1517 if (show_link != show) {
1518 web_ui()->CallJavascriptFunction(
1519 link_type == DEFAULT_SETTING ?
1520 "ContentSettings.showMediaPepperFlashDefaultLink" :
1521 "ContentSettings.showMediaPepperFlashExceptionsLink",
1522 base::FundamentalValue(show));
1527 void ContentSettingsHandler::UpdateFlashMediaLinksVisibility() {
1528 if (!media_settings_.flash_settings_initialized ||
1529 !media_settings_.default_setting_initialized ||
1530 !media_settings_.exceptions_initialized) {
1534 // Flash won't send us notifications when its settings get changed, which
1535 // means the Flash settings in |media_settings_| may be out-dated, especially
1536 // after we show links to change Flash settings.
1537 // In order to avoid confusion, we won't hide the links once they are showed.
1538 // One exception is that we will hide them when Pepper Flash is disabled
1539 // (handled in OnPepperFlashPrefChanged()).
1540 if (media_settings_.show_flash_default_link &&
1541 media_settings_.show_flash_exceptions_link) {
1545 if (!media_settings_.show_flash_default_link) {
1546 // If both audio and video capture are disabled by policy, the link
1547 // shouldn't be showed. Flash conforms to the policy in this case because
1548 // it cannot open those devices. We don't have to look at the Flash
1550 if (!(media_settings_.policy_disable_audio &&
1551 media_settings_.policy_disable_video) &&
1552 media_settings_.flash_default_setting !=
1553 media_settings_.default_setting) {
1554 ShowFlashMediaLink(DEFAULT_SETTING, true);
1557 if (!media_settings_.show_flash_exceptions_link) {
1558 // If audio or video capture is disabled by policy, we skip comparison of
1559 // exceptions for audio or video capture, respectively.
1560 if (!PepperFlashContentSettingsUtils::AreMediaExceptionsEqual(
1561 media_settings_.default_setting,
1562 media_settings_.exceptions,
1563 media_settings_.flash_default_setting,
1564 media_settings_.flash_exceptions,
1565 media_settings_.policy_disable_audio,
1566 media_settings_.policy_disable_video)) {
1567 ShowFlashMediaLink(EXCEPTIONS, true);
1572 void ContentSettingsHandler::UpdateProtectedContentExceptionsButton() {
1573 PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
1574 // Exceptions apply only when the feature is enabled.
1575 bool enable_exceptions = prefs->GetBoolean(prefs::kEnableDRM);
1576 web_ui()->CallJavascriptFunction(
1577 "ContentSettings.enableProtectedContentExceptions",
1578 base::FundamentalValue(enable_exceptions));
1581 } // namespace options