• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chrome/browser/ui/webui/options/content_settings_handler.h"
6 
7 #include "base/callback.h"
8 #include "base/command_line.h"
9 #include "base/utf_string_conversions.h"
10 #include "base/values.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/content_settings/content_settings_details.h"
13 #include "chrome/browser/content_settings/host_content_settings_map.h"
14 #include "chrome/browser/geolocation/geolocation_content_settings_map.h"
15 #include "chrome/browser/notifications/desktop_notification_service.h"
16 #include "chrome/browser/notifications/desktop_notification_service_factory.h"
17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/ui/browser_list.h"
19 #include "chrome/common/chrome_switches.h"
20 #include "chrome/common/content_settings_helper.h"
21 #include "chrome/common/pref_names.h"
22 #include "chrome/common/url_constants.h"
23 #include "content/common/notification_service.h"
24 #include "content/common/notification_source.h"
25 #include "content/common/notification_type.h"
26 #include "grit/generated_resources.h"
27 #include "grit/locale_settings.h"
28 #include "ui/base/l10n/l10n_util.h"
29 
30 namespace {
31 
32 const char* kDisplayPattern = "displayPattern";
33 const char* kSetting = "setting";
34 const char* kOrigin = "origin";
35 const char* kEmbeddingOrigin = "embeddingOrigin";
36 
37 const char* const kContentSettingsTypeGroupNames[] = {
38   "cookies",
39   "images",
40   "javascript",
41   "plugins",
42   "popups",
43   "location",
44   "notifications",
45   "prerender",
46 };
47 COMPILE_ASSERT(arraysize(kContentSettingsTypeGroupNames) ==
48                CONTENT_SETTINGS_NUM_TYPES,
49                invalid_content_settings_type_group_names_size);
50 
51 
ContentSettingsTypeFromGroupName(const std::string & name)52 ContentSettingsType ContentSettingsTypeFromGroupName(const std::string& name) {
53 
54   for (int content_settings_type = CONTENT_SETTINGS_TYPE_COOKIES;
55        content_settings_type < CONTENT_SETTINGS_NUM_TYPES;
56        ++content_settings_type) {
57     if (name == kContentSettingsTypeGroupNames[content_settings_type])
58       return static_cast<ContentSettingsType>(content_settings_type);
59   }
60 
61   NOTREACHED() << name << " is not a recognized content settings type.";
62   return CONTENT_SETTINGS_TYPE_DEFAULT;
63 }
64 
ContentSettingToString(ContentSetting setting)65 std::string ContentSettingToString(ContentSetting setting) {
66   switch (setting) {
67     case CONTENT_SETTING_ALLOW:
68       return "allow";
69     case CONTENT_SETTING_ASK:
70       return "ask";
71     case CONTENT_SETTING_BLOCK:
72       return "block";
73     case CONTENT_SETTING_SESSION_ONLY:
74       return "session";
75     case CONTENT_SETTING_DEFAULT:
76       return "default";
77     case CONTENT_SETTING_NUM_SETTINGS:
78       NOTREACHED();
79   }
80 
81   return "";
82 }
83 
ContentSettingFromString(const std::string & name)84 ContentSetting ContentSettingFromString(const std::string& name) {
85   if (name == "allow")
86     return CONTENT_SETTING_ALLOW;
87   if (name == "ask")
88     return CONTENT_SETTING_ASK;
89   if (name == "block")
90     return CONTENT_SETTING_BLOCK;
91   if (name == "session")
92     return CONTENT_SETTING_SESSION_ONLY;
93 
94   NOTREACHED() << name << " is not a recognized content setting.";
95   return CONTENT_SETTING_DEFAULT;
96 }
97 
GeolocationExceptionToString(const GURL & origin,const GURL & embedding_origin)98 std::string GeolocationExceptionToString(const GURL& origin,
99                                          const GURL& embedding_origin) {
100   if (origin == embedding_origin)
101     return content_settings_helper::OriginToString(origin);
102 
103   // TODO(estade): the page needs to use CSS to indent the string.
104   std::string indent(" ");
105   if (embedding_origin.is_empty()) {
106     // NOTE: As long as the user cannot add/edit entries from the exceptions
107     // dialog, it's impossible to actually have a non-default setting for some
108     // origin "embedded on any other site", so this row will never appear.  If
109     // we add the ability to add/edit exceptions, we'll need to decide when to
110     // display this and how "removing" it will function.
111     return indent +
112         l10n_util::GetStringUTF8(IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ANY_OTHER);
113   }
114 
115   return indent + l10n_util::GetStringFUTF8(
116       IDS_EXCEPTIONS_GEOLOCATION_EMBEDDED_ON_HOST,
117       UTF8ToUTF16(content_settings_helper::OriginToString(embedding_origin)));
118 }
119 
120 // Create a DictionaryValue* that will act as a data source for a single row
121 // in a HostContentSettingsMap-controlled exceptions table (e.g., cookies).
122 // Ownership of the pointer is passed to the caller.
GetExceptionForPage(const ContentSettingsPattern & pattern,ContentSetting setting)123 DictionaryValue* GetExceptionForPage(
124     const ContentSettingsPattern& pattern,
125     ContentSetting setting) {
126   DictionaryValue* exception = new DictionaryValue();
127   exception->Set(
128       kDisplayPattern,
129       new StringValue(pattern.AsString()));
130   exception->Set(
131       kSetting,
132       new StringValue(ContentSettingToString(setting)));
133   return exception;
134 }
135 
136 // Create a DictionaryValue* that will act as a data source for a single row
137 // in the Geolocation exceptions table. Ownership of the pointer is passed to
138 // the caller.
GetGeolocationExceptionForPage(const GURL & origin,const GURL & embedding_origin,ContentSetting setting)139 DictionaryValue* GetGeolocationExceptionForPage(const GURL& origin,
140                                                 const GURL& embedding_origin,
141                                                 ContentSetting setting) {
142   DictionaryValue* exception = new DictionaryValue();
143   exception->Set(
144       kDisplayPattern,
145       new StringValue(GeolocationExceptionToString(origin, embedding_origin)));
146   exception->Set(
147       kSetting,
148       new StringValue(ContentSettingToString(setting)));
149   exception->Set(
150       kOrigin,
151       new StringValue(origin.spec()));
152   exception->Set(
153       kEmbeddingOrigin,
154       new StringValue(embedding_origin.spec()));
155   return exception;
156 }
157 
158 // Create a DictionaryValue* that will act as a data source for a single row
159 // in the desktop notifications exceptions table. Ownership of the pointer is
160 // passed to the caller.
GetNotificationExceptionForPage(const GURL & url,ContentSetting setting)161 DictionaryValue* GetNotificationExceptionForPage(
162     const GURL& url,
163     ContentSetting setting) {
164   DictionaryValue* exception = new DictionaryValue();
165   exception->Set(
166       kDisplayPattern,
167       new StringValue(content_settings_helper::OriginToString(url)));
168   exception->Set(
169       kSetting,
170       new StringValue(ContentSettingToString(setting)));
171   exception->Set(
172       kOrigin,
173       new StringValue(url.spec()));
174   return exception;
175 }
176 
177 }  // namespace
178 
ContentSettingsHandler()179 ContentSettingsHandler::ContentSettingsHandler() {
180 }
181 
~ContentSettingsHandler()182 ContentSettingsHandler::~ContentSettingsHandler() {
183 }
184 
GetLocalizedValues(DictionaryValue * localized_strings)185 void ContentSettingsHandler::GetLocalizedValues(
186     DictionaryValue* localized_strings) {
187   DCHECK(localized_strings);
188 
189   static OptionsStringResource resources[] = {
190     { "content_exceptions", IDS_COOKIES_EXCEPTIONS_BUTTON },
191     { "allowException", IDS_EXCEPTIONS_ALLOW_BUTTON },
192     { "blockException", IDS_EXCEPTIONS_BLOCK_BUTTON },
193     { "sessionException", IDS_EXCEPTIONS_SESSION_ONLY_BUTTON },
194     { "askException", IDS_EXCEPTIONS_ASK_BUTTON },
195     { "addExceptionRow", IDS_EXCEPTIONS_ADD_BUTTON },
196     { "removeExceptionRow", IDS_EXCEPTIONS_REMOVE_BUTTON },
197     { "editExceptionRow", IDS_EXCEPTIONS_EDIT_BUTTON },
198     { "otr_exceptions_explanation", IDS_EXCEPTIONS_OTR_LABEL },
199     { "examplePattern", IDS_EXCEPTIONS_PATTERN_EXAMPLE },
200     { "addNewExceptionInstructions", IDS_EXCEPTIONS_ADD_NEW_INSTRUCTIONS },
201     { "manage_exceptions", IDS_EXCEPTIONS_MANAGE },
202     { "exceptionPatternHeader", IDS_EXCEPTIONS_PATTERN_HEADER },
203     { "exceptionBehaviorHeader", IDS_EXCEPTIONS_ACTION_HEADER },
204     // Cookies filter.
205     { "cookies_tab_label", IDS_COOKIES_TAB_LABEL },
206     { "cookies_header", IDS_COOKIES_HEADER },
207     { "cookies_allow", IDS_COOKIES_ALLOW_RADIO },
208     { "cookies_ask", IDS_COOKIES_ASK_EVERY_TIME_RADIO },
209     { "cookies_block", IDS_COOKIES_BLOCK_RADIO },
210     { "cookies_block_3rd_party", IDS_COOKIES_BLOCK_3RDPARTY_CHKBOX },
211     { "cookies_clear_when_close", IDS_COOKIES_CLEAR_WHEN_CLOSE_CHKBOX },
212     { "cookies_lso_clear_when_close", IDS_COOKIES_LSO_CLEAR_WHEN_CLOSE_CHKBOX },
213     { "cookies_show_cookies", IDS_COOKIES_SHOW_COOKIES_BUTTON },
214     { "flash_storage_settings", IDS_FLASH_STORAGE_SETTINGS },
215     { "flash_storage_url", IDS_FLASH_STORAGE_URL },
216     // Image filter.
217     { "images_tab_label", IDS_IMAGES_TAB_LABEL },
218     { "images_header", IDS_IMAGES_HEADER },
219     { "images_allow", IDS_IMAGES_LOAD_RADIO },
220     { "images_block", IDS_IMAGES_NOLOAD_RADIO },
221     // JavaScript filter.
222     { "javascript_tab_label", IDS_JAVASCRIPT_TAB_LABEL },
223     { "javascript_header", IDS_JAVASCRIPT_HEADER },
224     { "javascript_allow", IDS_JS_ALLOW_RADIO },
225     { "javascript_block", IDS_JS_DONOTALLOW_RADIO },
226     // Plug-ins filter.
227     { "plugins_tab_label", IDS_PLUGIN_TAB_LABEL },
228     { "plugins_header", IDS_PLUGIN_HEADER },
229     { "plugins_ask", IDS_PLUGIN_ASK_RADIO },
230     { "plugins_allow", IDS_PLUGIN_LOAD_RADIO },
231     { "plugins_block", IDS_PLUGIN_NOLOAD_RADIO },
232     { "disable_individual_plugins", IDS_PLUGIN_SELECTIVE_DISABLE },
233     // Pop-ups filter.
234     { "popups_tab_label", IDS_POPUP_TAB_LABEL },
235     { "popups_header", IDS_POPUP_HEADER },
236     { "popups_allow", IDS_POPUP_ALLOW_RADIO },
237     { "popups_block", IDS_POPUP_BLOCK_RADIO },
238     // Location filter.
239     { "location_tab_label", IDS_GEOLOCATION_TAB_LABEL },
240     { "location_header", IDS_GEOLOCATION_HEADER },
241     { "location_allow", IDS_GEOLOCATION_ALLOW_RADIO },
242     { "location_ask", IDS_GEOLOCATION_ASK_RADIO },
243     { "location_block", IDS_GEOLOCATION_BLOCK_RADIO },
244     // Notifications filter.
245     { "notifications_tab_label", IDS_NOTIFICATIONS_TAB_LABEL },
246     { "notifications_header", IDS_NOTIFICATIONS_HEADER },
247     { "notifications_allow", IDS_NOTIFICATIONS_ALLOW_RADIO },
248     { "notifications_ask", IDS_NOTIFICATIONS_ASK_RADIO },
249     { "notifications_block", IDS_NOTIFICATIONS_BLOCK_RADIO },
250   };
251 
252   RegisterStrings(localized_strings, resources, arraysize(resources));
253   RegisterTitle(localized_strings, "contentSettingsPage",
254                 IDS_CONTENT_SETTINGS_TITLE);
255   localized_strings->SetBoolean("enable_click_to_play",
256       CommandLine::ForCurrentProcess()->HasSwitch(
257           switches::kEnableClickToPlay));
258 }
259 
Initialize()260 void ContentSettingsHandler::Initialize() {
261   const HostContentSettingsMap* settings_map = GetContentSettingsMap();
262   scoped_ptr<Value> block_3rd_party(Value::CreateBooleanValue(
263       settings_map->BlockThirdPartyCookies()));
264   web_ui_->CallJavascriptFunction("ContentSettings.setBlockThirdPartyCookies",
265                                   *block_3rd_party.get());
266 
267   notification_registrar_.Add(
268       this, NotificationType::OTR_PROFILE_CREATED,
269       NotificationService::AllSources());
270   notification_registrar_.Add(
271       this, NotificationType::PROFILE_DESTROYED,
272       NotificationService::AllSources());
273 
274   UpdateAllExceptionsViewsFromModel();
275   notification_registrar_.Add(
276       this, NotificationType::CONTENT_SETTINGS_CHANGED,
277       NotificationService::AllSources());
278   notification_registrar_.Add(
279       this, NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED,
280       NotificationService::AllSources());
281   notification_registrar_.Add(
282       this, NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED,
283       NotificationService::AllSources());
284 
285   PrefService* prefs = web_ui_->GetProfile()->GetPrefs();
286   pref_change_registrar_.Init(prefs);
287   pref_change_registrar_.Add(prefs::kGeolocationDefaultContentSetting, this);
288   pref_change_registrar_.Add(prefs::kGeolocationContentSettings, this);
289 }
290 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)291 void ContentSettingsHandler::Observe(NotificationType type,
292                                      const NotificationSource& source,
293                                      const NotificationDetails& details) {
294   switch (type.value) {
295     case NotificationType::PROFILE_DESTROYED: {
296       Profile* profile = static_cast<Source<Profile> >(source).ptr();
297       if (profile->IsOffTheRecord()) {
298         web_ui_->CallJavascriptFunction(
299             "ContentSettingsExceptionsArea.OTRProfileDestroyed");
300       }
301       break;
302     }
303 
304     case NotificationType::OTR_PROFILE_CREATED: {
305       UpdateAllOTRExceptionsViewsFromModel();
306       break;
307     }
308 
309     case NotificationType::CONTENT_SETTINGS_CHANGED: {
310       const ContentSettingsDetails* settings_details =
311           Details<const ContentSettingsDetails>(details).ptr();
312 
313       // TODO(estade): we pretend update_all() is always true.
314       if (settings_details->update_all_types())
315         UpdateAllExceptionsViewsFromModel();
316       else
317         UpdateExceptionsViewFromModel(settings_details->type());
318       break;
319     }
320 
321     case NotificationType::PREF_CHANGED: {
322       const std::string& pref_name = *Details<std::string>(details).ptr();
323       if (pref_name == prefs::kGeolocationDefaultContentSetting)
324         UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
325       else if (pref_name == prefs::kGeolocationContentSettings)
326         UpdateGeolocationExceptionsView();
327       break;
328     }
329 
330     case NotificationType::DESKTOP_NOTIFICATION_DEFAULT_CHANGED: {
331       UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
332       break;
333     }
334 
335     case NotificationType::DESKTOP_NOTIFICATION_SETTINGS_CHANGED: {
336       UpdateNotificationExceptionsView();
337       break;
338     }
339 
340     default:
341       OptionsPageUIHandler::Observe(type, source, details);
342   }
343 }
344 
UpdateSettingDefaultFromModel(ContentSettingsType type)345 void ContentSettingsHandler::UpdateSettingDefaultFromModel(
346     ContentSettingsType type) {
347   DictionaryValue filter_settings;
348   filter_settings.SetString(ContentSettingsTypeToGroupName(type) + ".value",
349       GetSettingDefaultFromModel(type));
350   filter_settings.SetBoolean(ContentSettingsTypeToGroupName(type) + ".managed",
351       GetDefaultSettingManagedFromModel(type));
352 
353   web_ui_->CallJavascriptFunction(
354       "ContentSettings.setContentFilterSettingsValue", filter_settings);
355 }
356 
GetSettingDefaultFromModel(ContentSettingsType type)357 std::string ContentSettingsHandler::GetSettingDefaultFromModel(
358     ContentSettingsType type) {
359   ContentSetting default_setting;
360   if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
361     default_setting = web_ui_->GetProfile()->
362         GetGeolocationContentSettingsMap()->GetDefaultContentSetting();
363   } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
364     default_setting = DesktopNotificationServiceFactory::GetForProfile(
365         web_ui_->GetProfile())->GetDefaultContentSetting();
366   } else {
367     default_setting = GetContentSettingsMap()->GetDefaultContentSetting(type);
368   }
369 
370   return ContentSettingToString(default_setting);
371 }
372 
GetDefaultSettingManagedFromModel(ContentSettingsType type)373 bool ContentSettingsHandler::GetDefaultSettingManagedFromModel(
374     ContentSettingsType type) {
375   if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
376     return web_ui_->GetProfile()->
377         GetGeolocationContentSettingsMap()->IsDefaultContentSettingManaged();
378   } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
379     return DesktopNotificationServiceFactory::GetForProfile(
380         web_ui_->GetProfile())->IsDefaultContentSettingManaged();
381   } else {
382     return GetContentSettingsMap()->IsDefaultContentSettingManaged(type);
383   }
384 }
385 
UpdateAllExceptionsViewsFromModel()386 void ContentSettingsHandler::UpdateAllExceptionsViewsFromModel() {
387   for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
388        type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
389     UpdateExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
390   }
391 }
392 
UpdateAllOTRExceptionsViewsFromModel()393 void ContentSettingsHandler::UpdateAllOTRExceptionsViewsFromModel() {
394   for (int type = CONTENT_SETTINGS_TYPE_DEFAULT + 1;
395        type < CONTENT_SETTINGS_NUM_TYPES; ++type) {
396     UpdateOTRExceptionsViewFromModel(static_cast<ContentSettingsType>(type));
397   }
398 }
399 
UpdateExceptionsViewFromModel(ContentSettingsType type)400 void ContentSettingsHandler::UpdateExceptionsViewFromModel(
401     ContentSettingsType type) {
402   switch (type) {
403     case CONTENT_SETTINGS_TYPE_GEOLOCATION:
404       UpdateGeolocationExceptionsView();
405       break;
406     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
407       UpdateNotificationExceptionsView();
408       break;
409     case CONTENT_SETTINGS_TYPE_PRERENDER:
410       // Prerender is currently (02/24/2011) an experimental feature which is
411       // only turned on via about:flags. There is intentionally no UI in
412       // chrome://preferences for CONTENT_SETTINGS_TYPE_PRERENDER.
413       // TODO(cbentzel): Change once prerender moves out of about:flags.
414       break;
415     default:
416       UpdateExceptionsViewFromHostContentSettingsMap(type);
417       break;
418   }
419 }
420 
UpdateOTRExceptionsViewFromModel(ContentSettingsType type)421 void ContentSettingsHandler::UpdateOTRExceptionsViewFromModel(
422     ContentSettingsType type) {
423   switch (type) {
424     case CONTENT_SETTINGS_TYPE_GEOLOCATION:
425     case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
426     case CONTENT_SETTINGS_TYPE_PRERENDER:
427       break;
428     default:
429       UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
430       break;
431   }
432 }
433 
UpdateGeolocationExceptionsView()434 void ContentSettingsHandler::UpdateGeolocationExceptionsView() {
435   GeolocationContentSettingsMap* map =
436       web_ui_->GetProfile()->GetGeolocationContentSettingsMap();
437   GeolocationContentSettingsMap::AllOriginsSettings all_settings =
438       map->GetAllOriginsSettings();
439   GeolocationContentSettingsMap::AllOriginsSettings::const_iterator i;
440 
441   ListValue exceptions;
442   for (i = all_settings.begin(); i != all_settings.end(); ++i) {
443     const GURL& origin = i->first;
444     const GeolocationContentSettingsMap::OneOriginSettings& one_settings =
445         i->second;
446 
447     GeolocationContentSettingsMap::OneOriginSettings::const_iterator parent =
448         one_settings.find(origin);
449 
450     // Add the "parent" entry for the non-embedded setting.
451     ContentSetting parent_setting =
452         parent == one_settings.end() ? CONTENT_SETTING_DEFAULT : parent->second;
453     exceptions.Append(
454         GetGeolocationExceptionForPage(origin, origin, parent_setting));
455 
456     // Add the "children" for any embedded settings.
457     GeolocationContentSettingsMap::OneOriginSettings::const_iterator j;
458     for (j = one_settings.begin(); j != one_settings.end(); ++j) {
459       // Skip the non-embedded setting which we already added above.
460       if (j == parent)
461         continue;
462 
463       exceptions.Append(
464           GetGeolocationExceptionForPage(origin, j->first, j->second));
465     }
466   }
467 
468   StringValue type_string(
469       ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_GEOLOCATION));
470   web_ui_->CallJavascriptFunction("ContentSettings.setExceptions",
471                                   type_string, exceptions);
472 
473   // This is mainly here to keep this function ideologically parallel to
474   // UpdateExceptionsViewFromHostContentSettingsMap().
475   UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_GEOLOCATION);
476 }
477 
UpdateNotificationExceptionsView()478 void ContentSettingsHandler::UpdateNotificationExceptionsView() {
479   DesktopNotificationService* service =
480       DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile());
481 
482   std::vector<GURL> allowed(service->GetAllowedOrigins());
483   std::vector<GURL> blocked(service->GetBlockedOrigins());
484 
485   ListValue exceptions;
486   for (size_t i = 0; i < allowed.size(); ++i) {
487     exceptions.Append(
488         GetNotificationExceptionForPage(allowed[i], CONTENT_SETTING_ALLOW));
489   }
490   for (size_t i = 0; i < blocked.size(); ++i) {
491     exceptions.Append(
492         GetNotificationExceptionForPage(blocked[i], CONTENT_SETTING_BLOCK));
493   }
494 
495   StringValue type_string(
496       ContentSettingsTypeToGroupName(CONTENT_SETTINGS_TYPE_NOTIFICATIONS));
497   web_ui_->CallJavascriptFunction("ContentSettings.setExceptions",
498                                   type_string, exceptions);
499 
500   // This is mainly here to keep this function ideologically parallel to
501   // UpdateExceptionsViewFromHostContentSettingsMap().
502   UpdateSettingDefaultFromModel(CONTENT_SETTINGS_TYPE_NOTIFICATIONS);
503 }
504 
UpdateExceptionsViewFromHostContentSettingsMap(ContentSettingsType type)505 void ContentSettingsHandler::UpdateExceptionsViewFromHostContentSettingsMap(
506     ContentSettingsType type) {
507   HostContentSettingsMap::SettingsForOneType entries;
508   GetContentSettingsMap()->GetSettingsForOneType(type, "", &entries);
509 
510   ListValue exceptions;
511   for (size_t i = 0; i < entries.size(); ++i) {
512     exceptions.Append(GetExceptionForPage(entries[i].first, entries[i].second));
513   }
514 
515   StringValue type_string(ContentSettingsTypeToGroupName(type));
516   web_ui_->CallJavascriptFunction("ContentSettings.setExceptions", type_string,
517                                   exceptions);
518 
519   UpdateExceptionsViewFromOTRHostContentSettingsMap(type);
520 
521   // The default may also have changed (we won't get a separate notification).
522   // If it hasn't changed, this call will be harmless.
523   UpdateSettingDefaultFromModel(type);
524 }
525 
UpdateExceptionsViewFromOTRHostContentSettingsMap(ContentSettingsType type)526 void ContentSettingsHandler::UpdateExceptionsViewFromOTRHostContentSettingsMap(
527     ContentSettingsType type) {
528   const HostContentSettingsMap* otr_settings_map = GetOTRContentSettingsMap();
529   if (!otr_settings_map)
530     return;
531 
532   HostContentSettingsMap::SettingsForOneType otr_entries;
533   otr_settings_map->GetSettingsForOneType(type, "", &otr_entries);
534 
535   ListValue otr_exceptions;
536   for (size_t i = 0; i < otr_entries.size(); ++i) {
537     otr_exceptions.Append(GetExceptionForPage(otr_entries[i].first,
538                                               otr_entries[i].second));
539   }
540 
541   StringValue type_string(ContentSettingsTypeToGroupName(type));
542   web_ui_->CallJavascriptFunction("ContentSettings.setOTRExceptions",
543                                   type_string, otr_exceptions);
544 }
545 
RegisterMessages()546 void ContentSettingsHandler::RegisterMessages() {
547   web_ui_->RegisterMessageCallback("setContentFilter",
548       NewCallback(this,
549                   &ContentSettingsHandler::SetContentFilter));
550   web_ui_->RegisterMessageCallback("setAllowThirdPartyCookies",
551       NewCallback(this,
552                   &ContentSettingsHandler::SetAllowThirdPartyCookies));
553   web_ui_->RegisterMessageCallback("removeException",
554       NewCallback(this,
555                   &ContentSettingsHandler::RemoveException));
556   web_ui_->RegisterMessageCallback("setException",
557       NewCallback(this,
558                   &ContentSettingsHandler::SetException));
559   web_ui_->RegisterMessageCallback("checkExceptionPatternValidity",
560       NewCallback(this,
561                   &ContentSettingsHandler::CheckExceptionPatternValidity));
562 }
563 
SetContentFilter(const ListValue * args)564 void ContentSettingsHandler::SetContentFilter(const ListValue* args) {
565   DCHECK_EQ(2U, args->GetSize());
566   std::string group, setting;
567   if (!(args->GetString(0, &group) &&
568         args->GetString(1, &setting))) {
569     NOTREACHED();
570     return;
571   }
572 
573   ContentSetting default_setting = ContentSettingFromString(setting);
574   ContentSettingsType content_type = ContentSettingsTypeFromGroupName(group);
575   if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
576     web_ui_->GetProfile()->GetGeolocationContentSettingsMap()->
577         SetDefaultContentSetting(default_setting);
578   } else if (content_type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
579     DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile())->
580         SetDefaultContentSetting(default_setting);
581   } else {
582     GetContentSettingsMap()->
583         SetDefaultContentSetting(content_type, default_setting);
584   }
585 }
586 
SetAllowThirdPartyCookies(const ListValue * args)587 void ContentSettingsHandler::SetAllowThirdPartyCookies(const ListValue* args) {
588   string16 allow = ExtractStringValue(args);
589 
590   GetContentSettingsMap()->SetBlockThirdPartyCookies(
591       LowerCaseEqualsASCII(allow, "true"));
592 }
593 
RemoveException(const ListValue * args)594 void ContentSettingsHandler::RemoveException(const ListValue* args) {
595   size_t arg_i = 0;
596   std::string type_string;
597   CHECK(args->GetString(arg_i++, &type_string));
598 
599   ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
600   if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) {
601     std::string origin;
602     std::string embedding_origin;
603     bool rv = args->GetString(arg_i++, &origin);
604     DCHECK(rv);
605     rv = args->GetString(arg_i++, &embedding_origin);
606     DCHECK(rv);
607 
608     web_ui_->GetProfile()->GetGeolocationContentSettingsMap()->
609         SetContentSetting(GURL(origin),
610                           GURL(embedding_origin),
611                           CONTENT_SETTING_DEFAULT);
612   } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
613     std::string origin;
614     std::string setting;
615     bool rv = args->GetString(arg_i++, &origin);
616     DCHECK(rv);
617     rv = args->GetString(arg_i++, &setting);
618     DCHECK(rv);
619     ContentSetting content_setting = ContentSettingFromString(setting);
620     if (content_setting == CONTENT_SETTING_ALLOW) {
621       DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile())->
622           ResetAllowedOrigin(GURL(origin));
623     } else {
624       DCHECK_EQ(content_setting, CONTENT_SETTING_BLOCK);
625       DesktopNotificationServiceFactory::GetForProfile(web_ui_->GetProfile())->
626           ResetBlockedOrigin(GURL(origin));
627     }
628   } else {
629     std::string mode;
630     bool rv = args->GetString(arg_i++, &mode);
631     DCHECK(rv);
632 
633     std::string pattern;
634     rv = args->GetString(arg_i++, &pattern);
635     DCHECK(rv);
636 
637     HostContentSettingsMap* settings_map =
638         mode == "normal" ? GetContentSettingsMap() :
639                            GetOTRContentSettingsMap();
640     // The settings map could be null if the mode was OTR but the OTR profile
641     // got destroyed before we received this message.
642     if (settings_map) {
643       settings_map->SetContentSetting(
644           ContentSettingsPattern(pattern),
645           ContentSettingsTypeFromGroupName(type_string),
646           "",
647           CONTENT_SETTING_DEFAULT);
648     }
649   }
650 }
651 
SetException(const ListValue * args)652 void ContentSettingsHandler::SetException(const ListValue* args) {
653   size_t arg_i = 0;
654   std::string type_string;
655   CHECK(args->GetString(arg_i++, &type_string));
656   std::string mode;
657   CHECK(args->GetString(arg_i++, &mode));
658   std::string pattern;
659   CHECK(args->GetString(arg_i++, &pattern));
660   std::string setting;
661   CHECK(args->GetString(arg_i++, &setting));
662 
663   ContentSettingsType type = ContentSettingsTypeFromGroupName(type_string);
664   if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION ||
665       type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) {
666     NOTREACHED();
667     return;
668   }
669 
670   HostContentSettingsMap* settings_map =
671       mode == "normal" ? GetContentSettingsMap() :
672                          GetOTRContentSettingsMap();
673 
674   // The settings map could be null if the mode was OTR but the OTR profile
675   // got destroyed before we received this message.
676   if (!settings_map)
677     return;
678 
679   settings_map->SetContentSetting(ContentSettingsPattern(pattern),
680                                   type,
681                                   "",
682                                   ContentSettingFromString(setting));
683 }
684 
CheckExceptionPatternValidity(const ListValue * args)685 void ContentSettingsHandler::CheckExceptionPatternValidity(
686     const ListValue* args) {
687   size_t arg_i = 0;
688   Value* type;
689   CHECK(args->Get(arg_i++, &type));
690   std::string mode_string;
691   CHECK(args->GetString(arg_i++, &mode_string));
692   std::string pattern_string;
693   CHECK(args->GetString(arg_i++, &pattern_string));
694 
695   ContentSettingsPattern pattern(pattern_string);
696 
697   scoped_ptr<Value> mode_value(Value::CreateStringValue(mode_string));
698   scoped_ptr<Value> pattern_value(Value::CreateStringValue(pattern_string));
699   scoped_ptr<Value> valid_value(Value::CreateBooleanValue(pattern.IsValid()));
700 
701   web_ui_->CallJavascriptFunction(
702       "ContentSettings.patternValidityCheckComplete",
703       *type,
704       *mode_value.get(),
705       *pattern_value.get(),
706       *valid_value.get());
707 }
708 
709 // static
ContentSettingsTypeToGroupName(ContentSettingsType type)710 std::string ContentSettingsHandler::ContentSettingsTypeToGroupName(
711     ContentSettingsType type) {
712   if (type < CONTENT_SETTINGS_TYPE_COOKIES ||
713       type >= CONTENT_SETTINGS_NUM_TYPES) {
714     NOTREACHED();
715     return "";
716   }
717   return kContentSettingsTypeGroupNames[type];
718 }
719 
GetContentSettingsMap()720 HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
721   return web_ui_->GetProfile()->GetHostContentSettingsMap();
722 }
723 
724 HostContentSettingsMap*
GetOTRContentSettingsMap()725     ContentSettingsHandler::GetOTRContentSettingsMap() {
726   Profile* profile = web_ui_->GetProfile();
727   if (profile->HasOffTheRecordProfile())
728     return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
729   return NULL;
730 }
731