1// Copyright 2014 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/website_settings_handler.h"
6
7#include "chrome/browser/content_settings/content_settings_utils.h"
8#include "chrome/browser/content_settings/host_content_settings_map.h"
9#include "chrome/browser/extensions/extension_service.h"
10#include "chrome/browser/profiles/profile.h"
11#include "chrome/browser/ui/browser.h"
12#include "chrome/browser/ui/browser_iterator.h"
13#include "chrome/browser/ui/tabs/tab_strip_model.h"
14#include "chrome/grit/generated_resources.h"
15#include "components/power/origin_power_map.h"
16#include "components/power/origin_power_map_factory.h"
17#include "content/public/browser/dom_storage_context.h"
18#include "content/public/browser/storage_partition.h"
19#include "content/public/browser/user_metrics.h"
20#include "content/public/browser/web_contents.h"
21#include "content/public/browser/web_ui.h"
22#include "extensions/browser/app_window/app_window_registry.h"
23#include "extensions/browser/extension_registry.h"
24#include "extensions/browser/extension_system.h"
25#include "extensions/common/constants.h"
26#include "extensions/common/extension.h"
27#include "ui/base/l10n/l10n_util.h"
28#include "ui/base/l10n/time_format.h"
29#include "ui/base/text/bytes_formatting.h"
30
31#if defined(OS_CHROMEOS)
32#include "components/user_manager/user_manager.h"
33#endif
34
35using base::UserMetricsAction;
36using power::OriginPowerMap;
37using power::OriginPowerMapFactory;
38
39namespace {
40
41const char kBattery[] = "battery";
42const int kHttpPort = 80;
43const int kHttpsPort = 443;
44const char kPreferencesSource[] = "preference";
45const char kStorage[] = "storage";
46const ContentSettingsType kValidTypes[] = {
47    CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
48    CONTENT_SETTINGS_TYPE_COOKIES,
49    CONTENT_SETTINGS_TYPE_GEOLOCATION,
50    CONTENT_SETTINGS_TYPE_IMAGES,
51    CONTENT_SETTINGS_TYPE_JAVASCRIPT,
52    CONTENT_SETTINGS_TYPE_NOTIFICATIONS,
53    CONTENT_SETTINGS_TYPE_MEDIASTREAM,
54    CONTENT_SETTINGS_TYPE_PLUGINS,
55    CONTENT_SETTINGS_TYPE_POPUPS};
56const size_t kValidTypesLength = arraysize(kValidTypes);
57
58}  // namespace
59
60namespace options {
61
62WebsiteSettingsHandler::WebsiteSettingsHandler()
63    : observer_(this),
64      weak_ptr_factory_(this) {
65}
66
67WebsiteSettingsHandler::~WebsiteSettingsHandler() {
68}
69
70void WebsiteSettingsHandler::GetLocalizedValues(
71    base::DictionaryValue* localized_strings) {
72  DCHECK(localized_strings);
73
74  static OptionsStringResource resources[] = {
75      {"websitesOptionsPageTabTitle", IDS_WEBSITE_SETTINGS_TITLE},
76      {"websitesSettingsEditPage", IDS_WEBSITE_SETTINGS_EDIT_TITLE},
77      {"websitesManage", IDS_WEBSITE_SETTINGS_MANAGE},
78      {"websitesSearch", IDS_WEBSITE_SETTINGS_SEARCH_ORIGINS},
79      {"websitesLabelLocation", IDS_WEBSITE_SETTINGS_TYPE_LOCATION},
80      {"websitesLabelMediaStream", IDS_WEBSITE_SETTINGS_TYPE_MEDIASTREAM},
81      {"websitesLabelNotifications", IDS_WEBSITE_SETTINGS_TYPE_NOTIFICATIONS},
82      {"websitesLabelOn", IDS_WEBSITE_SETTINGS_CONTENT_SETTING_ENABLED},
83      {"websitesLabelStorage", IDS_WEBSITE_SETTINGS_TYPE_STORAGE},
84      {"websitesLabelBattery", IDS_WEBSITE_SETTINGS_TYPE_BATTERY},
85      {"websitesCookiesDescription", IDS_WEBSITE_SETTINGS_COOKIES_DESCRIPTION},
86      {"websitesLocationDescription",
87       IDS_WEBSITE_SETTINGS_LOCATION_DESCRIPTION},
88      {"websitesMediaStreamDescription",
89       IDS_WEBSITE_SETTINGS_MEDIASTREAM_DESCRIPTION},
90      {"websitesNotificationsDescription",
91       IDS_WEBSITE_SETTINGS_NOTIFICATIONS_DESCRIPTION},
92      {"websitesDownloadsDescription",
93       IDS_WEBSITE_SETTINGS_DOWNLOAD_DESCRIPTION},
94      {"websitesPluginsDescription", IDS_WEBSITE_SETTINGS_PLUGINS_DESCRIPTION},
95      {"websitesPopupsDescription", IDS_WEBSITE_SETTINGS_POPUPS_DESCRIPTION},
96      {"websitesJavascriptDescription",
97       IDS_WEBSITE_SETTINGS_JAVASCRIPT_DESCRIPTION},
98      {"websitesImagesDescription", IDS_WEBSITE_SETTINGS_IMAGES_DESCRIPTION},
99      {"websitesButtonClear", IDS_WEBSITE_SETTINGS_STORAGE_CLEAR_BUTTON},
100      {"websitesButtonStop", IDS_WEBSITE_SETTINGS_BATTERY_STOP_BUTTON},
101      {"websitesAllowedListTitle", IDS_WEBSITE_SETTINGS_ALLOWED_LIST_TITLE},
102      {"websitesBlockedListTitle", IDS_WEBSITE_SETTINGS_BLOCKED_LIST_TITLE},
103      {"storageTabLabel", IDS_WEBSITE_SETTINGS_TYPE_STORAGE},
104      {"batteryTabLabel", IDS_WEBSITE_SETTINGS_TYPE_BATTERY},
105  };
106
107  RegisterStrings(localized_strings, resources, arraysize(resources));
108  RegisterTitle(
109      localized_strings, "websiteSettingsPage", IDS_WEBSITE_SETTINGS_TITLE);
110}
111
112void WebsiteSettingsHandler::InitializeHandler() {
113  Profile* profile = GetProfile();
114  HostContentSettingsMap* settings = profile->GetHostContentSettingsMap();
115  observer_.Add(settings);
116
117  power::OriginPowerMap* origin_power_map =
118      power::OriginPowerMapFactory::GetForBrowserContext(profile);
119  // OriginPowerMap may not be available in tests.
120  if (origin_power_map) {
121    subscription_ = origin_power_map->AddPowerConsumptionUpdatedCallback(
122        base::Bind(&WebsiteSettingsHandler::Update, base::Unretained(this)));
123  }
124}
125
126void WebsiteSettingsHandler::RegisterMessages() {
127  web_ui()->RegisterMessageCallback(
128      "updateOrigins",
129      base::Bind(&WebsiteSettingsHandler::HandleUpdateOrigins,
130                 base::Unretained(this)));
131
132  web_ui()->RegisterMessageCallback(
133      "updateOriginsSearchResults",
134      base::Bind(&WebsiteSettingsHandler::HandleUpdateSearchResults,
135                 base::Unretained(this)));
136
137  web_ui()->RegisterMessageCallback(
138      "updateLocalStorage",
139      base::Bind(&WebsiteSettingsHandler::HandleUpdateLocalStorage,
140                 base::Unretained(this)));
141
142  web_ui()->RegisterMessageCallback(
143      "updateBatteryUsage",
144      base::Bind(&WebsiteSettingsHandler::HandleUpdateBatteryUsage,
145                 base::Unretained(this)));
146
147  web_ui()->RegisterMessageCallback(
148      "getOriginInfo",
149      base::Bind(&WebsiteSettingsHandler::HandleGetOriginInfo,
150                 base::Unretained(this)));
151
152  web_ui()->RegisterMessageCallback(
153      "setOriginPermission",
154      base::Bind(&WebsiteSettingsHandler::HandleSetOriginPermission,
155                 base::Unretained(this)));
156
157  web_ui()->RegisterMessageCallback(
158      "maybeShowEditPage",
159      base::Bind(&WebsiteSettingsHandler::HandleMaybeShowEditPage,
160                 base::Unretained(this)));
161
162  web_ui()->RegisterMessageCallback(
163      "deleteLocalStorage",
164      base::Bind(&WebsiteSettingsHandler::HandleDeleteLocalStorage,
165                 base::Unretained(this)));
166
167  web_ui()->RegisterMessageCallback(
168      "stopOrigin",
169      base::Bind(&WebsiteSettingsHandler::HandleStopOrigin,
170                 base::Unretained(this)));
171
172  web_ui()->RegisterMessageCallback(
173      "updateDefaultSetting",
174      base::Bind(&WebsiteSettingsHandler::HandleUpdateDefaultSetting,
175                 base::Unretained(this)));
176
177  web_ui()->RegisterMessageCallback(
178      "setDefaultContentSetting",
179      base::Bind(&WebsiteSettingsHandler::HandleSetDefaultSetting,
180                 base::Unretained(this)));
181
182  web_ui()->RegisterMessageCallback(
183      "setGlobalEnabled",
184      base::Bind(&WebsiteSettingsHandler::HandleSetGlobalToggle,
185                 base::Unretained(this)));
186}
187
188// content_settings::Observer implementation.
189void WebsiteSettingsHandler::OnContentSettingChanged(
190    const ContentSettingsPattern& primary_pattern,
191    const ContentSettingsPattern& secondary_pattern,
192    ContentSettingsType content_type,
193    std::string resource_identifier) {
194  Update();
195}
196
197void WebsiteSettingsHandler::OnContentSettingUsed(
198    const ContentSettingsPattern& primary_pattern,
199    const ContentSettingsPattern& secondary_pattern,
200    ContentSettingsType content_type) {
201  Update();
202}
203
204void WebsiteSettingsHandler::HandleUpdateOrigins(const base::ListValue* args) {
205  std::string content_setting_name;
206  bool rv = args->GetString(0, &content_setting_name);
207  DCHECK(rv);
208
209  ContentSettingsType content_type;
210  if (!content_settings::GetTypeFromName(content_setting_name, &content_type))
211    return;
212  DCHECK_NE(
213      kValidTypes + kValidTypesLength,
214      std::find(kValidTypes, kValidTypes + kValidTypesLength, content_type));
215
216  last_setting_ = content_setting_name;
217  UpdateOrigins();
218}
219
220void WebsiteSettingsHandler::HandleUpdateSearchResults(
221    const base::ListValue* args) {
222  bool rv = args->GetString(0, &last_filter_);
223  DCHECK(rv);
224
225  Update();
226}
227
228void WebsiteSettingsHandler::HandleUpdateLocalStorage(
229    const base::ListValue* args) {
230  if (!local_storage_.get()) {
231    Profile* profile = GetProfile();
232    local_storage_ = new BrowsingDataLocalStorageHelper(profile);
233  }
234
235  last_setting_ = kStorage;
236
237  local_storage_->StartFetching(
238      base::Bind(&WebsiteSettingsHandler::OnLocalStorageFetched,
239                 weak_ptr_factory_.GetWeakPtr()));
240}
241
242void WebsiteSettingsHandler::HandleMaybeShowEditPage(
243    const base::ListValue* args) {
244  std::string site;
245  bool rv = args->GetString(0, &site);
246  DCHECK(rv);
247
248  GURL last_site(site);
249  if (!last_site.is_valid())
250    return;
251
252  last_site_ = last_site;
253  base::StringValue site_value(site);
254  web_ui()->CallJavascriptFunction("WebsiteSettingsEditor.showEditPage",
255                                   site_value);
256}
257
258void WebsiteSettingsHandler::OnLocalStorageFetched(const std::list<
259    BrowsingDataLocalStorageHelper::LocalStorageInfo>& storage) {
260  local_storage_list_ = storage;
261  Update();
262  GetInfoForOrigin(last_site_, false);
263}
264
265void WebsiteSettingsHandler::Update() {
266  DCHECK(!last_setting_.empty());
267  if (last_setting_ == kStorage)
268    UpdateLocalStorage();
269  else if (last_setting_ == kBattery)
270    UpdateBatteryUsage();
271  else
272    UpdateOrigins();
273}
274
275void WebsiteSettingsHandler::UpdateOrigins() {
276  Profile* profile = GetProfile();
277  HostContentSettingsMap* settings = profile->GetHostContentSettingsMap();
278
279  ContentSettingsForOneType all_settings;
280  ContentSettingsType last_setting;
281  if (!content_settings::GetTypeFromName(last_setting_, &last_setting))
282    return;
283
284  if (last_setting == CONTENT_SETTINGS_TYPE_MEDIASTREAM)
285    last_setting = CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC;
286
287  settings->GetSettingsForOneType(last_setting, std::string(), &all_settings);
288
289  base::DictionaryValue allowed_origins;
290  base::DictionaryValue blocked_origins;
291  for (ContentSettingsForOneType::const_iterator it = all_settings.begin();
292       it != all_settings.end();
293       ++it) {
294    // Don't add default settings.
295    if (it->primary_pattern == ContentSettingsPattern::Wildcard() &&
296        it->secondary_pattern == ContentSettingsPattern::Wildcard() &&
297        it->source != kPreferencesSource) {
298      continue;
299    }
300
301    GURL origin_url(it->primary_pattern.ToString());
302    std::string origin = origin_url.spec();
303
304    // Hide the port if it is using a standard URL scheme.
305    if ((origin_url.SchemeIs(url::kHttpScheme) &&
306         origin_url.IntPort() == kHttpPort) ||
307        (origin_url.SchemeIs(url::kHttpsScheme) &&
308         origin_url.IntPort() == kHttpsPort)) {
309      url::Replacements<char> replacements;
310      replacements.ClearPort();
311      origin = origin_url.ReplaceComponents(replacements).spec();
312    }
313
314    // Mediastream isn't set unless both mic and camera are set to the same.
315    if (last_setting == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) {
316      ContentSetting cam_setting = settings->GetContentSettingWithoutOverride(
317          origin_url,
318          origin_url,
319          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
320          std::string());
321      if (it->setting != cam_setting)
322        continue;
323    }
324
325    if (origin.find(last_filter_) == base::string16::npos)
326      continue;
327
328    base::Time last_usage = settings->GetLastUsageByPattern(
329        it->primary_pattern, it->secondary_pattern, last_setting);
330
331    base::DictionaryValue* origin_entry = new base::DictionaryValue();
332    origin_entry->SetDoubleWithoutPathExpansion("usage",
333                                                last_usage.ToDoubleT());
334    base::string16 usage_string;
335    if (last_usage.ToDoubleT()) {
336      usage_string = ui::TimeFormat::Simple(ui::TimeFormat::FORMAT_ELAPSED,
337                                            ui::TimeFormat::LENGTH_SHORT,
338                                            base::Time::Now() - last_usage);
339    }
340    origin_entry->SetStringWithoutPathExpansion("usageString", usage_string);
341    origin_entry->SetStringWithoutPathExpansion("readableName",
342                                                GetReadableName(origin_url));
343
344    if (it->setting == CONTENT_SETTING_BLOCK)
345      blocked_origins.SetWithoutPathExpansion(origin, origin_entry);
346    else
347      allowed_origins.SetWithoutPathExpansion(origin, origin_entry);
348  }
349
350  bool is_globally_allowed = settings->GetContentSettingOverride(last_setting);
351  web_ui()->CallJavascriptFunction("WebsiteSettingsManager.populateOrigins",
352                                   allowed_origins,
353                                   blocked_origins,
354                                   base::FundamentalValue(is_globally_allowed));
355}
356
357void WebsiteSettingsHandler::HandleGetOriginInfo(const base::ListValue* args) {
358  std::string url;
359  bool rv = args->GetString(0, &url);
360  DCHECK(rv);
361  GURL origin(url);
362
363  if (!origin.is_valid())
364    return;
365
366  GetInfoForOrigin(origin, true);
367}
368
369void WebsiteSettingsHandler::HandleSetOriginPermission(
370    const base::ListValue* args) {
371  std::string setting_name;
372  bool rv = args->GetString(0, &setting_name);
373  DCHECK(rv);
374  ContentSettingsType settings_type;
375  if (!content_settings::GetTypeFromName(setting_name, &settings_type))
376    return;
377
378  std::string value;
379  rv = args->GetString(1, &value);
380  DCHECK(rv);
381
382  ContentSetting setting = content_settings::ContentSettingFromString(value);
383  Profile* profile = GetProfile();
384  HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
385  ContentSetting default_value =
386      map->GetDefaultContentSetting(settings_type, NULL);
387
388  // Users are not allowed to be the source of the "ask" setting. It is an
389  // ephemeral setting which is removed once the question is asked.
390  if (setting == CONTENT_SETTING_ASK && setting == default_value)
391    setting = CONTENT_SETTING_DEFAULT;
392
393  ContentSettingsPattern primary_pattern;
394  ContentSettingsPattern secondary_pattern;
395  switch (settings_type) {
396    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
397      primary_pattern = ContentSettingsPattern::FromURLNoWildcard(last_site_);
398      secondary_pattern = ContentSettingsPattern::Wildcard();
399      break;
400    case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
401      primary_pattern = ContentSettingsPattern::FromURLNoWildcard(last_site_);
402      secondary_pattern = ContentSettingsPattern::Wildcard();
403      map->SetContentSetting(primary_pattern,
404                             secondary_pattern,
405                             CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
406                             std::string(),
407                             setting);
408      map->SetContentSetting(primary_pattern,
409                             secondary_pattern,
410                             CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
411                             std::string(),
412                             setting);
413      return;
414    case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
415    case CONTENT_SETTINGS_TYPE_COOKIES:
416    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
417    case CONTENT_SETTINGS_TYPE_IMAGES:
418    case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
419    case CONTENT_SETTINGS_TYPE_PLUGINS:
420    case CONTENT_SETTINGS_TYPE_POPUPS:
421      primary_pattern = ContentSettingsPattern::FromURLNoWildcard(last_site_);
422      secondary_pattern = ContentSettingsPattern::FromURLNoWildcard(last_site_);
423      break;
424    default:
425      NOTREACHED() << "Content settings type not yet supported.";
426      return;
427  }
428
429  content_settings::SettingInfo info;
430  scoped_ptr<base::Value> v(map->GetWebsiteSettingWithoutOverride(
431      last_site_, last_site_, settings_type, std::string(), &info));
432  map->SetNarrowestWebsiteSetting(primary_pattern,
433                                  secondary_pattern,
434                                  settings_type,
435                                  std::string(),
436                                  setting,
437                                  info);
438}
439
440void WebsiteSettingsHandler::HandleUpdateBatteryUsage(
441    const base::ListValue* args) {
442  last_setting_ = kBattery;
443  UpdateBatteryUsage();
444}
445
446void WebsiteSettingsHandler::HandleDeleteLocalStorage(
447    const base::ListValue* args) {
448  DCHECK(!last_site_.is_empty());
449  DeleteLocalStorage(last_site_);
450}
451
452void WebsiteSettingsHandler::HandleStopOrigin(const base::ListValue* args) {
453  DCHECK(!last_site_.is_empty());
454  StopOrigin(last_site_);
455}
456
457// TODO(dhnishi): Remove default settings duplication from the
458//                WebsiteSettingsHandler and the ContentSettingsHandler.
459void WebsiteSettingsHandler::HandleUpdateDefaultSetting(
460    const base::ListValue* args) {
461  ContentSettingsType last_setting;
462  if (!content_settings::GetTypeFromName(last_setting_, &last_setting))
463    return;
464
465  base::DictionaryValue filter_settings;
466  std::string provider_id;
467  filter_settings.SetString(
468      "value", GetSettingDefaultFromModel(last_setting, &provider_id));
469  filter_settings.SetString("managedBy", provider_id);
470
471  web_ui()->CallJavascriptFunction("WebsiteSettingsManager.updateDefault",
472                                   filter_settings);
473}
474
475void WebsiteSettingsHandler::HandleSetDefaultSetting(
476    const base::ListValue* args) {
477  DCHECK_EQ(1U, args->GetSize());
478  std::string setting;
479  if (!args->GetString(0, &setting)) {
480    NOTREACHED();
481    return;
482  }
483  ContentSetting new_default =
484      content_settings::ContentSettingFromString(setting);
485
486  ContentSettingsType last_setting;
487  if (!content_settings::GetTypeFromName(last_setting_, &last_setting))
488    return;
489  Profile* profile = GetProfile();
490
491  HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
492  map->SetDefaultContentSetting(last_setting, new_default);
493
494  switch (last_setting) {
495    case CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS:
496      content::RecordAction(
497          UserMetricsAction("Options_DefaultMultipleAutomaticDLSettingChange"));
498      break;
499    case CONTENT_SETTINGS_TYPE_COOKIES:
500      content::RecordAction(
501          UserMetricsAction("Options_DefaultCookieSettingChanged"));
502      break;
503    case CONTENT_SETTINGS_TYPE_GEOLOCATION:
504      content::RecordAction(
505          UserMetricsAction("Options_DefaultGeolocationSettingChanged"));
506      break;
507    case CONTENT_SETTINGS_TYPE_IMAGES:
508      content::RecordAction(
509          UserMetricsAction("Options_DefaultImagesSettingChanged"));
510      break;
511    case CONTENT_SETTINGS_TYPE_JAVASCRIPT:
512      content::RecordAction(
513          UserMetricsAction("Options_DefaultJavaScriptSettingChanged"));
514      break;
515    case CONTENT_SETTINGS_TYPE_MEDIASTREAM:
516      content::RecordAction(
517          UserMetricsAction("Options_DefaultMediaStreamMicSettingChanged"));
518      break;
519    case CONTENT_SETTINGS_TYPE_NOTIFICATIONS:
520      content::RecordAction(
521          UserMetricsAction("Options_DefaultNotificationsSettingChanged"));
522      break;
523    case CONTENT_SETTINGS_TYPE_PLUGINS:
524      content::RecordAction(
525          UserMetricsAction("Options_DefaultPluginsSettingChanged"));
526      break;
527    case CONTENT_SETTINGS_TYPE_POPUPS:
528      content::RecordAction(
529          UserMetricsAction("Options_DefaultPopupsSettingChanged"));
530      break;
531    default:
532      NOTREACHED();
533      return;
534  }
535}
536
537void WebsiteSettingsHandler::HandleSetGlobalToggle(
538    const base::ListValue* args) {
539  DCHECK_EQ(1U, args->GetSize());
540  bool is_enabled;
541  bool rv = args->GetBoolean(0, &is_enabled);
542  DCHECK(rv);
543
544  ContentSettingsType last_setting;
545  if (!content_settings::GetTypeFromName(last_setting_, &last_setting))
546    return;
547
548  Profile* profile = GetProfile();
549  HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
550  map->SetContentSettingOverride(last_setting, is_enabled);
551}
552
553void WebsiteSettingsHandler::GetInfoForOrigin(const GURL& site_url,
554                                              bool show_page) {
555  Profile* profile = GetProfile();
556  HostContentSettingsMap* map = profile->GetHostContentSettingsMap();
557
558  double storage = 0.0;
559  for (LocalStorageList::const_iterator it = local_storage_list_.begin();
560       it != local_storage_list_.end();
561       it++) {
562    if (it->origin_url == site_url) {
563      storage = static_cast<double>(it->size);
564      break;
565    }
566  }
567
568  int battery = 0;
569  battery = OriginPowerMapFactory::GetForBrowserContext(
570      GetProfile())->GetPowerForOrigin(site_url);
571
572  base::DictionaryValue* permissions = new base::DictionaryValue;
573  for (size_t i = 0; i < arraysize(kValidTypes); ++i) {
574    ContentSettingsType permission_type = kValidTypes[i];
575
576    // Append the possible settings.
577    base::ListValue* options = new base::ListValue;
578    ContentSetting default_value =
579        map->GetDefaultContentSetting(permission_type, NULL);
580    if (default_value != CONTENT_SETTING_ALLOW &&
581        default_value != CONTENT_SETTING_BLOCK) {
582      options->AppendString(
583          content_settings::ContentSettingToString(default_value));
584    }
585    options->AppendString(
586        content_settings::ContentSettingToString(CONTENT_SETTING_ALLOW));
587    options->AppendString(
588        content_settings::ContentSettingToString(CONTENT_SETTING_BLOCK));
589    if (permission_type == CONTENT_SETTINGS_TYPE_COOKIES) {
590      options->AppendString(content_settings::ContentSettingToString(
591          CONTENT_SETTING_SESSION_ONLY));
592    }
593
594    ContentSetting permission;
595    content_settings::SettingInfo info;
596    if (permission_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) {
597      scoped_ptr<base::Value> mic_value(map->GetWebsiteSettingWithoutOverride(
598          site_url,
599          site_url,
600          CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC,
601          std::string(),
602          &info));
603      ContentSetting mic_setting =
604          content_settings::ValueToContentSetting(mic_value.get());
605      ContentSetting cam_setting = map->GetContentSettingWithoutOverride(
606          site_url,
607          site_url,
608          CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA,
609          std::string());
610
611      if (mic_setting != cam_setting)
612        permission = CONTENT_SETTING_ASK;
613      else
614        permission = mic_setting;
615    } else {
616      scoped_ptr<base::Value> v(map->GetWebsiteSettingWithoutOverride(
617          site_url, site_url, permission_type, std::string(), &info));
618      permission = content_settings::ValueToContentSetting(v.get());
619    }
620
621    base::DictionaryValue* permission_info = new base::DictionaryValue;
622    permission_info->SetStringWithoutPathExpansion(
623        "setting", content_settings::ContentSettingToString(permission));
624    permission_info->SetWithoutPathExpansion("options", options);
625    permission_info->SetBooleanWithoutPathExpansion(
626        "editable", info.source == content_settings::SETTING_SOURCE_USER);
627    permissions->SetWithoutPathExpansion(
628        content_settings::GetTypeName(permission_type), permission_info);
629  }
630
631  base::Value* storage_used = new base::StringValue(l10n_util::GetStringFUTF16(
632      IDS_WEBSITE_SETTINGS_STORAGE_USED, ui::FormatBytes(storage)));
633  base::Value* battery_used =
634      new base::StringValue(l10n_util::GetStringFUTF16Int(
635          IDS_WEBSITE_SETTINGS_BATTERY_USED, battery));
636
637  web_ui()->CallJavascriptFunction("WebsiteSettingsEditor.populateOrigin",
638                                   *storage_used,
639                                   *battery_used,
640                                   *permissions,
641                                   base::FundamentalValue(show_page));
642}
643
644void WebsiteSettingsHandler::UpdateLocalStorage() {
645  base::DictionaryValue local_storage_map;
646  for (LocalStorageList::const_iterator it = local_storage_list_.begin();
647       it != local_storage_list_.end();
648       it++) {
649    std::string origin = it->origin_url.spec();
650
651    if (origin.find(last_filter_) == base::string16::npos)
652      continue;
653
654    base::DictionaryValue* origin_entry = new base::DictionaryValue();
655    origin_entry->SetWithoutPathExpansion(
656        "usage", new base::FundamentalValue(static_cast<double>(it->size)));
657    origin_entry->SetWithoutPathExpansion(
658        "usageString", new base::StringValue(ui::FormatBytes(it->size)));
659    origin_entry->SetStringWithoutPathExpansion(
660        "readableName", GetReadableName(it->origin_url));
661    local_storage_map.SetWithoutPathExpansion(origin, origin_entry);
662  }
663  web_ui()->CallJavascriptFunction("WebsiteSettingsManager.populateOrigins",
664                                   local_storage_map);
665}
666
667void WebsiteSettingsHandler::UpdateBatteryUsage() {
668  base::DictionaryValue power_map;
669  OriginPowerMap* origins =
670      OriginPowerMapFactory::GetForBrowserContext(GetProfile());
671  OriginPowerMap::PercentOriginMap percent_map = origins->GetPercentOriginMap();
672  for (std::map<GURL, int>::iterator it = percent_map.begin();
673       it != percent_map.end();
674       ++it) {
675    std::string origin = it->first.spec();
676
677    if (origin.find(last_filter_) == base::string16::npos)
678      continue;
679
680    base::DictionaryValue* origin_entry = new base::DictionaryValue();
681    origin_entry->SetInteger("usage", it->second);
682    if (it->second == 0) {
683      origin_entry->SetString(
684          "usageString",
685          l10n_util::GetStringUTF16(IDS_WEBSITE_SETTINGS_BATTERY_ZERO_PERCENT));
686    } else {
687      origin_entry->SetString(
688          "usageString",
689          l10n_util::GetStringFUTF16Int(IDS_WEBSITE_SETTINGS_BATTERY_PERCENT,
690                                        it->second));
691    }
692    origin_entry->SetStringWithoutPathExpansion("readableName",
693                                                GetReadableName(it->first));
694    power_map.SetWithoutPathExpansion(origin, origin_entry);
695  }
696  web_ui()->CallJavascriptFunction("WebsiteSettingsManager.populateOrigins",
697                                   power_map);
698}
699
700std::string WebsiteSettingsHandler::GetSettingDefaultFromModel(
701    ContentSettingsType type,
702    std::string* provider_id) {
703  Profile* profile = GetProfile();
704  ContentSetting default_setting =
705      profile->GetHostContentSettingsMap()->GetDefaultContentSetting(
706          type, provider_id);
707
708  return content_settings::ContentSettingToString(default_setting);
709}
710
711void WebsiteSettingsHandler::StopOrigin(const GURL& site_url) {
712  Profile* profile = GetProfile();
713  if (site_url.SchemeIs(extensions::kExtensionScheme)) {
714    const extensions::Extension* extension =
715        extensions::ExtensionRegistry::Get(profile)
716            ->enabled_extensions()
717            .GetHostedAppByURL(site_url);
718    if (extension) {
719      extensions::AppWindowRegistry::Get(profile)
720          ->CloseAllAppWindowsForApp(extension->id());
721    }
722  }
723
724  for (chrome::BrowserIterator it; !it.done(); it.Next()) {
725    Browser* browser = *it;
726    TabStripModel* model = browser->tab_strip_model();
727    for (int idx = 0; idx < model->count(); idx++) {
728      content::WebContents* web_contents = model->GetWebContentsAt(idx);
729      // Can't discard tabs that are already discarded or active.
730      if (model->IsTabDiscarded(idx) || (model->active_index() == idx))
731        continue;
732
733      // Don't discard tabs that belong to other profiles or other origins.
734      if (web_contents->GetLastCommittedURL().GetOrigin() != site_url ||
735          profile !=
736              Profile::FromBrowserContext(web_contents->GetBrowserContext())) {
737        continue;
738      }
739      model->DiscardWebContentsAt(idx);
740    }
741  }
742}
743
744void WebsiteSettingsHandler::DeleteLocalStorage(const GURL& site_url) {
745  Profile* profile = GetProfile();
746  content::DOMStorageContext* dom_storage_context_ =
747      content::BrowserContext::GetDefaultStoragePartition(profile)
748          ->GetDOMStorageContext();
749  dom_storage_context_->DeleteLocalStorage(site_url);
750
751  // Load a new BrowsingDataLocalStorageHelper to update.
752  local_storage_ = new BrowsingDataLocalStorageHelper(profile);
753
754  local_storage_->StartFetching(
755      base::Bind(&WebsiteSettingsHandler::OnLocalStorageFetched,
756                 weak_ptr_factory_.GetWeakPtr()));
757}
758
759const std::string& WebsiteSettingsHandler::GetReadableName(
760    const GURL& site_url) {
761  if (site_url.SchemeIs(extensions::kExtensionScheme)) {
762    Profile* profile = GetProfile();
763    ExtensionService* extension_service =
764        extensions::ExtensionSystem::Get(profile)->extension_service();
765
766    const extensions::Extension* extension =
767        extension_service->extensions()->GetExtensionOrAppByURL(site_url);
768    // If extension is NULL, it was removed and we cannot look up its name.
769    if (!extension)
770      return site_url.spec();
771
772    return extension->name();
773  }
774  return site_url.spec();
775}
776
777Profile* WebsiteSettingsHandler::GetProfile() {
778  Profile* profile = Profile::FromWebUI(web_ui());
779#if defined(OS_CHROMEOS)
780  // Chrome OS special case: in Guest mode settings are opened in Incognito
781  // mode, so we need original profile to actually modify settings.
782  if (user_manager::UserManager::Get()->IsLoggedInAsGuest())
783    profile = profile->GetOriginalProfile();
784#endif
785  return profile;
786}
787
788}  // namespace options
789