Home | History | Annotate | Download | only in options
      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 
     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 
     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 
     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 
     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.
    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.
    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.
    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 
    179 ContentSettingsHandler::ContentSettingsHandler() {
    180 }
    181 
    182 ContentSettingsHandler::~ContentSettingsHandler() {
    183 }
    184 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    587 void ContentSettingsHandler::SetAllowThirdPartyCookies(const ListValue* args) {
    588   string16 allow = ExtractStringValue(args);
    589 
    590   GetContentSettingsMap()->SetBlockThirdPartyCookies(
    591       LowerCaseEqualsASCII(allow, "true"));
    592 }
    593 
    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 
    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 
    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
    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 
    720 HostContentSettingsMap* ContentSettingsHandler::GetContentSettingsMap() {
    721   return web_ui_->GetProfile()->GetHostContentSettingsMap();
    722 }
    723 
    724 HostContentSettingsMap*
    725     ContentSettingsHandler::GetOTRContentSettingsMap() {
    726   Profile* profile = web_ui_->GetProfile();
    727   if (profile->HasOffTheRecordProfile())
    728     return profile->GetOffTheRecordProfile()->GetHostContentSettingsMap();
    729   return NULL;
    730 }
    731