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