1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/ui/content_settings/content_setting_bubble_model.h" 6 7 #include "base/command_line.h" 8 #include "base/prefs/pref_service.h" 9 #include "base/strings/utf_string_conversions.h" 10 #include "chrome/browser/chrome_notification_types.h" 11 #include "chrome/browser/content_settings/content_settings_utils.h" 12 #include "chrome/browser/content_settings/cookie_settings.h" 13 #include "chrome/browser/content_settings/tab_specific_content_settings.h" 14 #include "chrome/browser/custom_handlers/protocol_handler_registry.h" 15 #include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h" 16 #include "chrome/browser/favicon/favicon_tab_helper.h" 17 #include "chrome/browser/infobars/infobar_service.h" 18 #include "chrome/browser/media/media_capture_devices_dispatcher.h" 19 #include "chrome/browser/plugins/chrome_plugin_service_filter.h" 20 #include "chrome/browser/profiles/profile.h" 21 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper.h" 22 #include "chrome/browser/ui/blocked_content/blocked_content_tab_helper_delegate.h" 23 #include "chrome/browser/ui/blocked_content/popup_blocker_tab_helper.h" 24 #include "chrome/browser/ui/browser_navigator.h" 25 #include "chrome/browser/ui/collected_cookies_infobar_delegate.h" 26 #include "chrome/browser/ui/content_settings/content_setting_bubble_model_delegate.h" 27 #include "chrome/browser/ui/content_settings/media_setting_changed_infobar_delegate.h" 28 #include "chrome/common/chrome_switches.h" 29 #include "chrome/common/content_settings.h" 30 #include "chrome/common/pref_names.h" 31 #include "chrome/common/render_messages.h" 32 #include "content/public/browser/notification_service.h" 33 #include "content/public/browser/render_process_host.h" 34 #include "content/public/browser/render_view_host.h" 35 #include "content/public/browser/user_metrics.h" 36 #include "content/public/browser/web_contents.h" 37 #include "content/public/browser/web_contents_delegate.h" 38 #include "grit/generated_resources.h" 39 #include "grit/theme_resources.h" 40 #include "grit/ui_resources.h" 41 #include "net/base/net_util.h" 42 #include "ui/base/l10n/l10n_util.h" 43 #include "ui/base/resource/resource_bundle.h" 44 45 using content::UserMetricsAction; 46 using content::WebContents; 47 using content_settings::SettingInfo; 48 using content_settings::SettingSource; 49 using content_settings::SETTING_SOURCE_USER; 50 using content_settings::SETTING_SOURCE_NONE; 51 52 namespace { 53 struct ContentSettingsTypeIdEntry { 54 ContentSettingsType type; 55 int id; 56 }; 57 58 int GetIdForContentType(const ContentSettingsTypeIdEntry* entries, 59 size_t num_entries, 60 ContentSettingsType type) { 61 for (size_t i = 0; i < num_entries; ++i) { 62 if (entries[i].type == type) 63 return entries[i].id; 64 } 65 return 0; 66 } 67 68 const content::MediaStreamDevice& GetMediaDeviceById( 69 const std::string& device_id, 70 const content::MediaStreamDevices& devices) { 71 DCHECK(!devices.empty()); 72 for (content::MediaStreamDevices::const_iterator it = devices.begin(); 73 it != devices.end(); ++it) { 74 if (it->id == device_id) 75 return *(it); 76 } 77 78 // A device with the |device_id| was not found. It is likely that the device 79 // has been unplugged from the OS. Return the first device as the default 80 // device. 81 return *devices.begin(); 82 } 83 84 } // namespace 85 86 ContentSettingTitleAndLinkModel::ContentSettingTitleAndLinkModel( 87 Delegate* delegate, 88 WebContents* web_contents, 89 Profile* profile, 90 ContentSettingsType content_type) 91 : ContentSettingBubbleModel(web_contents, profile, content_type), 92 delegate_(delegate) { 93 // Notifications do not have a bubble. 94 DCHECK_NE(content_type, CONTENT_SETTINGS_TYPE_NOTIFICATIONS); 95 SetBlockedResources(); 96 SetTitle(); 97 SetManageLink(); 98 } 99 100 void ContentSettingTitleAndLinkModel::SetBlockedResources() { 101 TabSpecificContentSettings* settings = 102 TabSpecificContentSettings::FromWebContents(web_contents()); 103 const std::set<std::string>& resources = settings->BlockedResourcesForType( 104 content_type()); 105 for (std::set<std::string>::const_iterator it = resources.begin(); 106 it != resources.end(); ++it) { 107 AddBlockedResource(*it); 108 } 109 } 110 111 void ContentSettingTitleAndLinkModel::SetTitle() { 112 static const ContentSettingsTypeIdEntry kBlockedTitleIDs[] = { 113 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_TITLE}, 114 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_TITLE}, 115 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_TITLE}, 116 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_MESSAGE}, 117 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_TITLE}, 118 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, 119 IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT}, 120 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, 121 IDS_BLOCKED_PPAPI_BROKER_TITLE}, 122 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_TITLE}, 123 }; 124 // Fields as for kBlockedTitleIDs, above. 125 static const ContentSettingsTypeIdEntry 126 kResourceSpecificBlockedTitleIDs[] = { 127 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_TITLE}, 128 }; 129 static const ContentSettingsTypeIdEntry kAccessedTitleIDs[] = { 130 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE}, 131 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE}, 132 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_TITLE}, 133 }; 134 const ContentSettingsTypeIdEntry *title_ids = kBlockedTitleIDs; 135 size_t num_title_ids = arraysize(kBlockedTitleIDs); 136 if (web_contents() && 137 TabSpecificContentSettings::FromWebContents( 138 web_contents())->IsContentAllowed(content_type()) && 139 !TabSpecificContentSettings::FromWebContents( 140 web_contents())->IsContentBlocked(content_type())) { 141 title_ids = kAccessedTitleIDs; 142 num_title_ids = arraysize(kAccessedTitleIDs); 143 } else if (!bubble_content().resource_identifiers.empty()) { 144 title_ids = kResourceSpecificBlockedTitleIDs; 145 num_title_ids = arraysize(kResourceSpecificBlockedTitleIDs); 146 } 147 int title_id = 148 GetIdForContentType(title_ids, num_title_ids, content_type()); 149 if (title_id) 150 set_title(l10n_util::GetStringUTF8(title_id)); 151 } 152 153 void ContentSettingTitleAndLinkModel::SetManageLink() { 154 static const ContentSettingsTypeIdEntry kLinkIDs[] = { 155 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_LINK}, 156 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_LINK}, 157 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_LINK}, 158 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LINK}, 159 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_LINK}, 160 {CONTENT_SETTINGS_TYPE_GEOLOCATION, IDS_GEOLOCATION_BUBBLE_MANAGE_LINK}, 161 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_LEARN_MORE}, 162 {CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, IDS_HANDLERS_BUBBLE_MANAGE_LINK}, 163 {CONTENT_SETTINGS_TYPE_MEDIASTREAM, IDS_MEDIASTREAM_BUBBLE_MANAGE_LINK}, 164 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_PPAPI_BROKER_BUBBLE_MANAGE_LINK}, 165 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOADS_LINK}, 166 {CONTENT_SETTINGS_TYPE_MIDI_SYSEX, IDS_MIDI_SYSEX_BUBBLE_MANAGE_LINK}, 167 }; 168 set_manage_link(l10n_util::GetStringUTF8( 169 GetIdForContentType(kLinkIDs, arraysize(kLinkIDs), content_type()))); 170 } 171 172 void ContentSettingTitleAndLinkModel::OnManageLinkClicked() { 173 if (delegate_) 174 delegate_->ShowContentSettingsPage(content_type()); 175 } 176 177 class ContentSettingTitleLinkAndCustomModel 178 : public ContentSettingTitleAndLinkModel { 179 public: 180 ContentSettingTitleLinkAndCustomModel(Delegate* delegate, 181 WebContents* web_contents, 182 Profile* profile, 183 ContentSettingsType content_type); 184 virtual ~ContentSettingTitleLinkAndCustomModel() {} 185 186 private: 187 void SetCustomLink(); 188 virtual void OnCustomLinkClicked() OVERRIDE {} 189 }; 190 191 ContentSettingTitleLinkAndCustomModel::ContentSettingTitleLinkAndCustomModel( 192 Delegate* delegate, 193 WebContents* web_contents, 194 Profile* profile, 195 ContentSettingsType content_type) 196 : ContentSettingTitleAndLinkModel( 197 delegate, web_contents, profile, content_type) { 198 SetCustomLink(); 199 } 200 201 void ContentSettingTitleLinkAndCustomModel::SetCustomLink() { 202 static const ContentSettingsTypeIdEntry kCustomIDs[] = { 203 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_INFO}, 204 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_LOAD_ALL}, 205 {CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, IDS_ALLOW_INSECURE_CONTENT_BUTTON}, 206 }; 207 int custom_link_id = 208 GetIdForContentType(kCustomIDs, arraysize(kCustomIDs), content_type()); 209 if (custom_link_id) 210 set_custom_link(l10n_util::GetStringUTF8(custom_link_id)); 211 } 212 213 class ContentSettingSingleRadioGroup 214 : public ContentSettingTitleLinkAndCustomModel { 215 public: 216 ContentSettingSingleRadioGroup(Delegate* delegate, 217 WebContents* web_contents, 218 Profile* profile, 219 ContentSettingsType content_type); 220 virtual ~ContentSettingSingleRadioGroup(); 221 222 protected: 223 bool settings_changed() const; 224 225 private: 226 void SetRadioGroup(); 227 void AddException(ContentSetting setting, 228 const std::string& resource_identifier); 229 virtual void OnRadioClicked(int radio_index) OVERRIDE; 230 231 ContentSetting block_setting_; 232 int selected_item_; 233 }; 234 235 ContentSettingSingleRadioGroup::ContentSettingSingleRadioGroup( 236 Delegate* delegate, 237 WebContents* web_contents, 238 Profile* profile, 239 ContentSettingsType content_type) 240 : ContentSettingTitleLinkAndCustomModel(delegate, web_contents, profile, 241 content_type), 242 block_setting_(CONTENT_SETTING_BLOCK), 243 selected_item_(0) { 244 SetRadioGroup(); 245 } 246 247 ContentSettingSingleRadioGroup::~ContentSettingSingleRadioGroup() { 248 if (settings_changed()) { 249 ContentSetting setting = 250 selected_item_ == 0 ? CONTENT_SETTING_ALLOW : block_setting_; 251 const std::set<std::string>& resources = 252 bubble_content().resource_identifiers; 253 if (resources.empty()) { 254 AddException(setting, std::string()); 255 } else { 256 for (std::set<std::string>::const_iterator it = resources.begin(); 257 it != resources.end(); ++it) { 258 AddException(setting, *it); 259 } 260 } 261 } 262 } 263 264 bool ContentSettingSingleRadioGroup::settings_changed() const { 265 return selected_item_ != bubble_content().radio_group.default_item; 266 } 267 268 // Initialize the radio group by setting the appropriate labels for the 269 // content type and setting the default value based on the content setting. 270 void ContentSettingSingleRadioGroup::SetRadioGroup() { 271 GURL url = web_contents()->GetURL(); 272 string16 display_host; 273 net::AppendFormattedHost( 274 url, 275 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages), 276 &display_host); 277 278 if (display_host.empty()) 279 display_host = ASCIIToUTF16(url.spec()); 280 281 const std::set<std::string>& resources = 282 bubble_content().resource_identifiers; 283 284 TabSpecificContentSettings* content_settings = 285 TabSpecificContentSettings::FromWebContents(web_contents()); 286 bool allowed = 287 !content_settings->IsContentBlocked(content_type()); 288 DCHECK(!allowed || 289 content_settings->IsContentAllowed(content_type())); 290 291 RadioGroup radio_group; 292 radio_group.url = url; 293 294 static const ContentSettingsTypeIdEntry kBlockedAllowIDs[] = { 295 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK}, 296 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_UNBLOCK}, 297 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_UNBLOCK}, 298 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_UNBLOCK_ALL}, 299 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_UNBLOCK}, 300 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK}, 301 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_UNBLOCK}, 302 }; 303 // Fields as for kBlockedAllowIDs, above. 304 static const ContentSettingsTypeIdEntry kResourceSpecificBlockedAllowIDs[] = { 305 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_UNBLOCK}, 306 }; 307 static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = { 308 // TODO(bauerb): The string shouldn't be "unblock" (they weren't blocked). 309 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_UNBLOCK}, 310 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION}, 311 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_NO_ACTION}, 312 }; 313 314 std::string radio_allow_label; 315 if (allowed) { 316 int resource_id = GetIdForContentType(kAllowedAllowIDs, 317 arraysize(kAllowedAllowIDs), 318 content_type()); 319 radio_allow_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ? 320 l10n_util::GetStringFUTF8(resource_id, display_host) : 321 l10n_util::GetStringUTF8(resource_id); 322 } else if (resources.empty()) { 323 radio_allow_label = l10n_util::GetStringFUTF8( 324 GetIdForContentType(kBlockedAllowIDs, arraysize(kBlockedAllowIDs), 325 content_type()), 326 display_host); 327 } else { 328 radio_allow_label = l10n_util::GetStringFUTF8( 329 GetIdForContentType(kResourceSpecificBlockedAllowIDs, 330 arraysize(kResourceSpecificBlockedAllowIDs), 331 content_type()), 332 display_host); 333 } 334 335 static const ContentSettingsTypeIdEntry kBlockedBlockIDs[] = { 336 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION}, 337 {CONTENT_SETTINGS_TYPE_IMAGES, IDS_BLOCKED_IMAGES_NO_ACTION}, 338 {CONTENT_SETTINGS_TYPE_JAVASCRIPT, IDS_BLOCKED_JAVASCRIPT_NO_ACTION}, 339 {CONTENT_SETTINGS_TYPE_PLUGINS, IDS_BLOCKED_PLUGINS_NO_ACTION}, 340 {CONTENT_SETTINGS_TYPE_POPUPS, IDS_BLOCKED_POPUPS_NO_ACTION}, 341 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION}, 342 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_BLOCKED_DOWNLOAD_NO_ACTION}, 343 }; 344 static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = { 345 // TODO(bauerb): The string should say "block". 346 {CONTENT_SETTINGS_TYPE_COOKIES, IDS_BLOCKED_COOKIES_NO_ACTION}, 347 {CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK}, 348 {CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, IDS_ALLOWED_DOWNLOAD_BLOCK}, 349 }; 350 351 std::string radio_block_label; 352 if (allowed) { 353 int resource_id = GetIdForContentType(kAllowedBlockIDs, 354 arraysize(kAllowedBlockIDs), 355 content_type()); 356 radio_block_label = (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) ? 357 l10n_util::GetStringUTF8(resource_id) : 358 l10n_util::GetStringFUTF8(resource_id, display_host); 359 } else { 360 radio_block_label = l10n_util::GetStringUTF8( 361 GetIdForContentType(kBlockedBlockIDs, arraysize(kBlockedBlockIDs), 362 content_type())); 363 } 364 365 radio_group.radio_items.push_back(radio_allow_label); 366 radio_group.radio_items.push_back(radio_block_label); 367 HostContentSettingsMap* map = profile()->GetHostContentSettingsMap(); 368 CookieSettings* cookie_settings = 369 CookieSettings::Factory::GetForProfile(profile()).get(); 370 ContentSetting most_restrictive_setting; 371 SettingSource most_restrictive_setting_source = SETTING_SOURCE_NONE; 372 373 if (resources.empty()) { 374 if (content_type() == CONTENT_SETTINGS_TYPE_COOKIES) { 375 most_restrictive_setting = cookie_settings->GetCookieSetting( 376 url, url, true, &most_restrictive_setting_source); 377 } else { 378 SettingInfo info; 379 scoped_ptr<Value> value(map->GetWebsiteSetting( 380 url, url, content_type(), std::string(), &info)); 381 most_restrictive_setting = 382 content_settings::ValueToContentSetting(value.get()); 383 most_restrictive_setting_source = info.source; 384 } 385 } else { 386 most_restrictive_setting = CONTENT_SETTING_ALLOW; 387 for (std::set<std::string>::const_iterator it = resources.begin(); 388 it != resources.end(); ++it) { 389 SettingInfo info; 390 scoped_ptr<Value> value(map->GetWebsiteSetting( 391 url, url, content_type(), *it, &info)); 392 ContentSetting setting = 393 content_settings::ValueToContentSetting(value.get()); 394 if (setting == CONTENT_SETTING_BLOCK) { 395 most_restrictive_setting = CONTENT_SETTING_BLOCK; 396 most_restrictive_setting_source = info.source; 397 break; 398 } 399 if (setting == CONTENT_SETTING_ASK) { 400 most_restrictive_setting = CONTENT_SETTING_ASK; 401 most_restrictive_setting_source = info.source; 402 } 403 } 404 } 405 if (most_restrictive_setting == CONTENT_SETTING_ALLOW) { 406 radio_group.default_item = 0; 407 // |block_setting_| is already set to |CONTENT_SETTING_BLOCK|. 408 } else { 409 radio_group.default_item = 1; 410 block_setting_ = most_restrictive_setting; 411 } 412 if (most_restrictive_setting_source != SETTING_SOURCE_USER) { 413 set_radio_group_enabled(false); 414 } else { 415 set_radio_group_enabled(true); 416 } 417 selected_item_ = radio_group.default_item; 418 set_radio_group(radio_group); 419 } 420 421 void ContentSettingSingleRadioGroup::AddException( 422 ContentSetting setting, 423 const std::string& resource_identifier) { 424 if (profile()) { 425 profile()->GetHostContentSettingsMap()->AddExceptionForURL( 426 bubble_content().radio_group.url, 427 bubble_content().radio_group.url, 428 content_type(), 429 resource_identifier, 430 setting); 431 } 432 } 433 434 void ContentSettingSingleRadioGroup::OnRadioClicked(int radio_index) { 435 selected_item_ = radio_index; 436 } 437 438 class ContentSettingCookiesBubbleModel : public ContentSettingSingleRadioGroup { 439 public: 440 ContentSettingCookiesBubbleModel(Delegate* delegate, 441 WebContents* web_contents, 442 Profile* profile, 443 ContentSettingsType content_type); 444 445 virtual ~ContentSettingCookiesBubbleModel(); 446 447 private: 448 virtual void OnCustomLinkClicked() OVERRIDE; 449 }; 450 451 ContentSettingCookiesBubbleModel::ContentSettingCookiesBubbleModel( 452 Delegate* delegate, 453 WebContents* web_contents, 454 Profile* profile, 455 ContentSettingsType content_type) 456 : ContentSettingSingleRadioGroup( 457 delegate, web_contents, profile, content_type) { 458 DCHECK_EQ(CONTENT_SETTINGS_TYPE_COOKIES, content_type); 459 set_custom_link_enabled(true); 460 } 461 462 ContentSettingCookiesBubbleModel::~ContentSettingCookiesBubbleModel() { 463 // On some plattforms e.g. MacOS X it is possible to close a tab while the 464 // cookies settings bubble is open. This resets the web contents to NULL. 465 if (settings_changed() && web_contents()) { 466 CollectedCookiesInfoBarDelegate::Create( 467 InfoBarService::FromWebContents(web_contents())); 468 } 469 } 470 471 void ContentSettingCookiesBubbleModel::OnCustomLinkClicked() { 472 if (!web_contents()) 473 return; 474 content::NotificationService::current()->Notify( 475 chrome::NOTIFICATION_COLLECTED_COOKIES_SHOWN, 476 content::Source<TabSpecificContentSettings>( 477 TabSpecificContentSettings::FromWebContents(web_contents())), 478 content::NotificationService::NoDetails()); 479 delegate()->ShowCollectedCookiesDialog(web_contents()); 480 } 481 482 class ContentSettingPluginBubbleModel : public ContentSettingSingleRadioGroup { 483 public: 484 ContentSettingPluginBubbleModel(Delegate* delegate, 485 WebContents* web_contents, 486 Profile* profile, 487 ContentSettingsType content_type); 488 489 virtual ~ContentSettingPluginBubbleModel() {} 490 491 private: 492 virtual void OnCustomLinkClicked() OVERRIDE; 493 }; 494 495 ContentSettingPluginBubbleModel::ContentSettingPluginBubbleModel( 496 Delegate* delegate, 497 WebContents* web_contents, 498 Profile* profile, 499 ContentSettingsType content_type) 500 : ContentSettingSingleRadioGroup( 501 delegate, web_contents, profile, content_type) { 502 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_PLUGINS); 503 set_custom_link_enabled(web_contents && 504 TabSpecificContentSettings::FromWebContents( 505 web_contents)->load_plugins_link_enabled()); 506 } 507 508 void ContentSettingPluginBubbleModel::OnCustomLinkClicked() { 509 content::RecordAction(UserMetricsAction("ClickToPlay_LoadAll_Bubble")); 510 DCHECK(web_contents()); 511 content::RenderViewHost* host = web_contents()->GetRenderViewHost(); 512 #if defined(ENABLE_PLUGINS) 513 ChromePluginServiceFilter::GetInstance()->AuthorizeAllPlugins( 514 host->GetProcess()->GetID()); 515 #endif 516 // TODO(bauerb): We should send the identifiers of blocked plug-ins here. 517 host->Send(new ChromeViewMsg_LoadBlockedPlugins(host->GetRoutingID(), 518 std::string())); 519 set_custom_link_enabled(false); 520 TabSpecificContentSettings::FromWebContents(web_contents())-> 521 set_load_plugins_link_enabled(false); 522 } 523 524 class ContentSettingPopupBubbleModel : public ContentSettingSingleRadioGroup { 525 public: 526 ContentSettingPopupBubbleModel(Delegate* delegate, 527 WebContents* web_contents, 528 Profile* profile, 529 ContentSettingsType content_type); 530 virtual ~ContentSettingPopupBubbleModel() {} 531 532 private: 533 void SetPopups(); 534 virtual void OnPopupClicked(int index) OVERRIDE; 535 }; 536 537 ContentSettingPopupBubbleModel::ContentSettingPopupBubbleModel( 538 Delegate* delegate, 539 WebContents* web_contents, 540 Profile* profile, 541 ContentSettingsType content_type) 542 : ContentSettingSingleRadioGroup( 543 delegate, web_contents, profile, content_type) { 544 SetPopups(); 545 } 546 547 548 void ContentSettingPopupBubbleModel::SetPopups() { 549 if (!CommandLine::ForCurrentProcess()->HasSwitch( 550 switches::kDisableBetterPopupBlocking)) { 551 std::map<int32, GURL> blocked_popups = 552 PopupBlockerTabHelper::FromWebContents(web_contents()) 553 ->GetBlockedPopupRequests(); 554 for (std::map<int32, GURL>::const_iterator iter = blocked_popups.begin(); 555 iter != blocked_popups.end(); 556 ++iter) { 557 std::string title(iter->second.spec()); 558 // The popup may not have a valid URL. 559 if (title.empty()) 560 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE); 561 PopupItem popup_item( 562 ui::ResourceBundle::GetSharedInstance().GetImageNamed( 563 IDR_DEFAULT_FAVICON), 564 title, 565 iter->first); 566 add_popup(popup_item); 567 } 568 return; 569 } 570 std::vector<WebContents*> blocked_contents; 571 BlockedContentTabHelper::FromWebContents(web_contents())-> 572 GetBlockedContents(&blocked_contents); 573 for (std::vector<WebContents*>::const_iterator 574 i = blocked_contents.begin(); i != blocked_contents.end(); ++i) { 575 std::string title(UTF16ToUTF8((*i)->GetTitle())); 576 // The popup may not have committed a load yet, in which case it won't 577 // have a URL or title. 578 if (title.empty()) 579 title = l10n_util::GetStringUTF8(IDS_TAB_LOADING_TITLE); 580 PopupItem popup_item( 581 FaviconTabHelper::FromWebContents(*i)->GetFavicon(), title, *i); 582 add_popup(popup_item); 583 } 584 } 585 586 void ContentSettingPopupBubbleModel::OnPopupClicked(int index) { 587 if (web_contents()) { 588 if (!CommandLine::ForCurrentProcess()->HasSwitch( 589 switches::kDisableBetterPopupBlocking)) { 590 PopupBlockerTabHelper::FromWebContents(web_contents())-> 591 ShowBlockedPopup(bubble_content().popup_items[index].popup_id); 592 } else { 593 BlockedContentTabHelper::FromWebContents(web_contents())-> 594 LaunchForContents(bubble_content().popup_items[index].web_contents); 595 } 596 } 597 } 598 599 // The model of the content settings bubble for media settings. 600 class ContentSettingMediaStreamBubbleModel 601 : public ContentSettingTitleAndLinkModel { 602 public: 603 ContentSettingMediaStreamBubbleModel(Delegate* delegate, 604 WebContents* web_contents, 605 Profile* profile); 606 607 virtual ~ContentSettingMediaStreamBubbleModel(); 608 609 private: 610 // Sets the title of the bubble. 611 void SetTitle(); 612 // Sets the data for the radio buttons of the bubble. 613 void SetRadioGroup(); 614 // Sets the data for the media menus of the bubble. 615 void SetMediaMenus(); 616 // Updates the camera and microphone setting with the passed |setting|. 617 void UpdateSettings(ContentSetting setting); 618 // Updates the camera and microphone default device with the passed |type| 619 // and device. 620 void UpdateDefaultDeviceForType(content::MediaStreamType type, 621 const std::string& device); 622 623 // ContentSettingBubbleModel implementation. 624 virtual void OnRadioClicked(int radio_index) OVERRIDE; 625 virtual void OnMediaMenuClicked(content::MediaStreamType type, 626 const std::string& selected_device) OVERRIDE; 627 628 // The index of the selected radio item. 629 int selected_item_; 630 // The content settings that are associated with the individual radio 631 // buttons. 632 ContentSetting radio_item_setting_[2]; 633 // The state of the microphone and camera access. 634 TabSpecificContentSettings::MicrophoneCameraState state_; 635 }; 636 637 ContentSettingMediaStreamBubbleModel::ContentSettingMediaStreamBubbleModel( 638 Delegate* delegate, 639 WebContents* web_contents, 640 Profile* profile) 641 : ContentSettingTitleAndLinkModel( 642 delegate, web_contents, profile, CONTENT_SETTINGS_TYPE_MEDIASTREAM), 643 selected_item_(0), 644 state_(TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED) { 645 DCHECK(profile); 646 // Initialize the content settings associated with the individual radio 647 // buttons. 648 radio_item_setting_[0] = CONTENT_SETTING_ASK; 649 radio_item_setting_[1] = CONTENT_SETTING_BLOCK; 650 651 TabSpecificContentSettings* content_settings = 652 TabSpecificContentSettings::FromWebContents(web_contents); 653 state_ = content_settings->GetMicrophoneCameraState(); 654 655 SetTitle(); 656 SetRadioGroup(); 657 SetMediaMenus(); 658 } 659 660 ContentSettingMediaStreamBubbleModel::~ContentSettingMediaStreamBubbleModel() { 661 // On some platforms (e.g. MacOS X) it is possible to close a tab while the 662 // media stream bubble is open. This resets the web contents to NULL. 663 if (!web_contents()) 664 return; 665 666 bool media_setting_changed = false; 667 for (MediaMenuMap::const_iterator it = bubble_content().media_menus.begin(); 668 it != bubble_content().media_menus.end(); ++it) { 669 if (it->second.selected_device.id != it->second.default_device.id) { 670 UpdateDefaultDeviceForType(it->first, it->second.selected_device.id); 671 media_setting_changed = true; 672 } 673 } 674 675 // Update the media settings if the radio button selection was changed. 676 if (selected_item_ != bubble_content().radio_group.default_item) { 677 UpdateSettings(radio_item_setting_[selected_item_]); 678 media_setting_changed = true; 679 } 680 681 // Trigger the reload infobar if the media setting has been changed. 682 if (media_setting_changed) { 683 MediaSettingChangedInfoBarDelegate::Create( 684 InfoBarService::FromWebContents(web_contents())); 685 } 686 } 687 688 void ContentSettingMediaStreamBubbleModel::SetTitle() { 689 int title_id = 0; 690 switch (state_) { 691 case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED: 692 // If neither microphone nor camera stream was accessed, then there is no 693 // icon didplayed in the omnibox and no settings bubble availbale. Hence 694 // there is no title. 695 NOTREACHED(); 696 return; 697 case TabSpecificContentSettings::MICROPHONE_ACCESSED: 698 title_id = IDS_MICROPHONE_ACCESSED; 699 break; 700 case TabSpecificContentSettings::CAMERA_ACCESSED: 701 title_id = IDS_CAMERA_ACCESSED; 702 break; 703 case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED: 704 title_id = IDS_MICROPHONE_CAMERA_ALLOWED; 705 break; 706 case TabSpecificContentSettings::MICROPHONE_BLOCKED: 707 title_id = IDS_MICROPHONE_BLOCKED; 708 break; 709 case TabSpecificContentSettings::CAMERA_BLOCKED: 710 title_id = IDS_CAMERA_BLOCKED; 711 break; 712 case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED: 713 title_id = IDS_MICROPHONE_CAMERA_BLOCKED; 714 break; 715 } 716 set_title(l10n_util::GetStringUTF8(title_id)); 717 } 718 719 void ContentSettingMediaStreamBubbleModel::SetRadioGroup() { 720 GURL url = web_contents()->GetURL(); 721 RadioGroup radio_group; 722 radio_group.url = url; 723 724 string16 display_host_utf16; 725 net::AppendFormattedHost( 726 url, 727 profile()->GetPrefs()->GetString(prefs::kAcceptLanguages), 728 &display_host_utf16); 729 std::string display_host(UTF16ToUTF8(display_host_utf16)); 730 if (display_host.empty()) 731 display_host = url.spec(); 732 733 int radio_allow_label_id = 0; 734 int radio_block_label_id = 0; 735 switch (state_) { 736 case TabSpecificContentSettings::MICROPHONE_CAMERA_NOT_ACCESSED: 737 NOTREACHED(); 738 return; 739 case TabSpecificContentSettings::MICROPHONE_ACCESSED: 740 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_NO_ACTION; 741 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_BLOCK; 742 selected_item_ = 0; 743 break; 744 case TabSpecificContentSettings::CAMERA_ACCESSED: 745 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_NO_ACTION; 746 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_CAMERA_BLOCK; 747 selected_item_ = 0; 748 break; 749 case TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED: 750 radio_allow_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION; 751 radio_block_label_id = IDS_ALLOWED_MEDIASTREAM_MIC_AND_CAMERA_BLOCK; 752 selected_item_ = 0; 753 break; 754 case TabSpecificContentSettings::MICROPHONE_BLOCKED: 755 if (url.SchemeIsSecure()) { 756 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ALLOW; 757 radio_item_setting_[0] = CONTENT_SETTING_ALLOW; 758 } else { 759 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_ASK; 760 } 761 762 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_NO_ACTION; 763 selected_item_ = 1; 764 break; 765 case TabSpecificContentSettings::CAMERA_BLOCKED: 766 if (url.SchemeIsSecure()) { 767 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ALLOW; 768 radio_item_setting_[0] = CONTENT_SETTING_ALLOW; 769 } else { 770 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_ASK; 771 } 772 773 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_CAMERA_NO_ACTION; 774 selected_item_ = 1; 775 break; 776 case TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED: 777 if (url.SchemeIsSecure()) { 778 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ALLOW; 779 radio_item_setting_[0] = CONTENT_SETTING_ALLOW; 780 } else { 781 radio_allow_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_ASK; 782 } 783 784 radio_block_label_id = IDS_BLOCKED_MEDIASTREAM_MIC_AND_CAMERA_NO_ACTION; 785 selected_item_ = 1; 786 break; 787 } 788 789 std::string radio_allow_label = l10n_util::GetStringFUTF8( 790 radio_allow_label_id, UTF8ToUTF16(display_host)); 791 std::string radio_block_label = 792 l10n_util::GetStringUTF8(radio_block_label_id); 793 794 radio_group.default_item = selected_item_; 795 radio_group.radio_items.push_back(radio_allow_label); 796 radio_group.radio_items.push_back(radio_block_label); 797 798 set_radio_group(radio_group); 799 set_radio_group_enabled(true); 800 } 801 802 void ContentSettingMediaStreamBubbleModel::UpdateSettings( 803 ContentSetting setting) { 804 if (profile()) { 805 HostContentSettingsMap* content_settings = 806 profile()->GetHostContentSettingsMap(); 807 // The same patterns must be used as in other places (e.g. the infobar) in 808 // order to override the existing rule. Otherwise a new rule is created. 809 // TODO(markusheintz): Extract to a helper so that there is only a single 810 // place to touch. 811 ContentSettingsPattern primary_pattern = 812 ContentSettingsPattern::FromURLNoWildcard(web_contents()->GetURL()); 813 ContentSettingsPattern secondary_pattern = 814 ContentSettingsPattern::Wildcard(); 815 if (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED || 816 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 817 state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED || 818 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) { 819 content_settings->SetContentSetting( 820 primary_pattern, secondary_pattern, 821 CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, std::string(), setting); 822 } 823 if (state_ == TabSpecificContentSettings::CAMERA_ACCESSED || 824 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 825 state_ == TabSpecificContentSettings::CAMERA_BLOCKED || 826 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED) { 827 content_settings->SetContentSetting( 828 primary_pattern, secondary_pattern, 829 CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, std::string(), setting); 830 } 831 } 832 } 833 834 void ContentSettingMediaStreamBubbleModel::UpdateDefaultDeviceForType( 835 content::MediaStreamType type, 836 const std::string& device) { 837 PrefService* prefs = profile()->GetPrefs(); 838 if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { 839 prefs->SetString(prefs::kDefaultAudioCaptureDevice, device); 840 } else { 841 DCHECK_EQ(content::MEDIA_DEVICE_VIDEO_CAPTURE, type); 842 prefs->SetString(prefs::kDefaultVideoCaptureDevice, device); 843 } 844 } 845 846 void ContentSettingMediaStreamBubbleModel::SetMediaMenus() { 847 // Add microphone menu. 848 PrefService* prefs = profile()->GetPrefs(); 849 MediaCaptureDevicesDispatcher* dispatcher = 850 MediaCaptureDevicesDispatcher::GetInstance(); 851 const content::MediaStreamDevices& microphones = 852 dispatcher->GetAudioCaptureDevices(); 853 854 bool show_mic_menu = 855 (state_ == TabSpecificContentSettings::MICROPHONE_ACCESSED || 856 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 857 state_ == TabSpecificContentSettings::MICROPHONE_BLOCKED || 858 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED); 859 bool show_camera_menu = 860 (state_ == TabSpecificContentSettings::CAMERA_ACCESSED || 861 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_ACCESSED || 862 state_ == TabSpecificContentSettings::CAMERA_BLOCKED || 863 state_ == TabSpecificContentSettings::MICROPHONE_CAMERA_BLOCKED); 864 DCHECK(show_mic_menu || show_camera_menu); 865 866 if (show_mic_menu) { 867 MediaMenu mic_menu; 868 mic_menu.label = l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_MIC_LABEL); 869 if (!microphones.empty()) { 870 std::string preferred_mic = 871 prefs->GetString(prefs::kDefaultAudioCaptureDevice); 872 mic_menu.default_device = GetMediaDeviceById(preferred_mic, microphones); 873 mic_menu.selected_device = mic_menu.default_device; 874 } 875 add_media_menu(content::MEDIA_DEVICE_AUDIO_CAPTURE, mic_menu); 876 } 877 878 if (show_camera_menu) { 879 const content::MediaStreamDevices& cameras = 880 dispatcher->GetVideoCaptureDevices(); 881 MediaMenu camera_menu; 882 camera_menu.label = 883 l10n_util::GetStringUTF8(IDS_MEDIA_SELECTED_CAMERA_LABEL); 884 if (!cameras.empty()) { 885 std::string preferred_camera = 886 prefs->GetString(prefs::kDefaultVideoCaptureDevice); 887 camera_menu.default_device = 888 GetMediaDeviceById(preferred_camera, cameras); 889 camera_menu.selected_device = camera_menu.default_device; 890 } 891 add_media_menu(content::MEDIA_DEVICE_VIDEO_CAPTURE, camera_menu); 892 } 893 } 894 895 void ContentSettingMediaStreamBubbleModel::OnRadioClicked(int radio_index) { 896 selected_item_ = radio_index; 897 } 898 899 void ContentSettingMediaStreamBubbleModel::OnMediaMenuClicked( 900 content::MediaStreamType type, 901 const std::string& selected_device_id) { 902 DCHECK(type == content::MEDIA_DEVICE_AUDIO_CAPTURE || 903 type == content::MEDIA_DEVICE_VIDEO_CAPTURE); 904 DCHECK_EQ(1U, bubble_content().media_menus.count(type)); 905 MediaCaptureDevicesDispatcher* dispatcher = 906 MediaCaptureDevicesDispatcher::GetInstance(); 907 const content::MediaStreamDevices& devices = 908 (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) ? 909 dispatcher->GetAudioCaptureDevices() : 910 dispatcher->GetVideoCaptureDevices(); 911 set_selected_device(GetMediaDeviceById(selected_device_id, devices)); 912 } 913 914 class ContentSettingDomainListBubbleModel 915 : public ContentSettingTitleAndLinkModel { 916 public: 917 ContentSettingDomainListBubbleModel(Delegate* delegate, 918 WebContents* web_contents, 919 Profile* profile, 920 ContentSettingsType content_type); 921 virtual ~ContentSettingDomainListBubbleModel() {} 922 923 private: 924 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id); 925 void SetDomainsAndCustomLink(); 926 virtual void OnCustomLinkClicked() OVERRIDE; 927 }; 928 929 ContentSettingDomainListBubbleModel::ContentSettingDomainListBubbleModel( 930 Delegate* delegate, 931 WebContents* web_contents, 932 Profile* profile, 933 ContentSettingsType content_type) 934 : ContentSettingTitleAndLinkModel( 935 delegate, web_contents, profile, content_type) { 936 DCHECK_EQ(CONTENT_SETTINGS_TYPE_GEOLOCATION, content_type) << 937 "SetDomains currently only supports geolocation content type"; 938 SetDomainsAndCustomLink(); 939 } 940 941 void ContentSettingDomainListBubbleModel::MaybeAddDomainList( 942 const std::set<std::string>& hosts, int title_id) { 943 if (!hosts.empty()) { 944 DomainList domain_list; 945 domain_list.title = l10n_util::GetStringUTF8(title_id); 946 domain_list.hosts = hosts; 947 add_domain_list(domain_list); 948 } 949 } 950 951 void ContentSettingDomainListBubbleModel::SetDomainsAndCustomLink() { 952 TabSpecificContentSettings* content_settings = 953 TabSpecificContentSettings::FromWebContents(web_contents()); 954 const ContentSettingsUsagesState& usages = 955 content_settings->geolocation_usages_state(); 956 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state; 957 unsigned int tab_state_flags = 0; 958 usages.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags); 959 // Divide the tab's current geolocation users into sets according to their 960 // permission state. 961 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW], 962 IDS_GEOLOCATION_BUBBLE_SECTION_ALLOWED); 963 964 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK], 965 IDS_GEOLOCATION_BUBBLE_SECTION_DENIED); 966 967 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) { 968 set_custom_link(l10n_util::GetStringUTF8( 969 IDS_GEOLOCATION_BUBBLE_CLEAR_LINK)); 970 set_custom_link_enabled(true); 971 } else if (tab_state_flags & 972 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) { 973 set_custom_link(l10n_util::GetStringUTF8( 974 IDS_GEOLOCATION_BUBBLE_REQUIRE_RELOAD_TO_CLEAR)); 975 } 976 } 977 978 void ContentSettingDomainListBubbleModel::OnCustomLinkClicked() { 979 if (!web_contents()) 980 return; 981 // Reset this embedder's entry to default for each of the requesting 982 // origins currently on the page. 983 const GURL& embedder_url = web_contents()->GetURL(); 984 TabSpecificContentSettings* content_settings = 985 TabSpecificContentSettings::FromWebContents(web_contents()); 986 const ContentSettingsUsagesState::StateMap& state_map = 987 content_settings->geolocation_usages_state().state_map(); 988 HostContentSettingsMap* settings_map = 989 profile()->GetHostContentSettingsMap(); 990 991 for (ContentSettingsUsagesState::StateMap::const_iterator it = 992 state_map.begin(); it != state_map.end(); ++it) { 993 settings_map->SetContentSetting( 994 ContentSettingsPattern::FromURLNoWildcard(it->first), 995 ContentSettingsPattern::FromURLNoWildcard(embedder_url), 996 CONTENT_SETTINGS_TYPE_GEOLOCATION, 997 std::string(), 998 CONTENT_SETTING_DEFAULT); 999 } 1000 } 1001 1002 class ContentSettingMixedScriptBubbleModel 1003 : public ContentSettingTitleLinkAndCustomModel { 1004 public: 1005 ContentSettingMixedScriptBubbleModel(Delegate* delegate, 1006 WebContents* web_contents, 1007 Profile* profile, 1008 ContentSettingsType content_type); 1009 1010 virtual ~ContentSettingMixedScriptBubbleModel() {} 1011 1012 private: 1013 virtual void OnCustomLinkClicked() OVERRIDE; 1014 }; 1015 1016 ContentSettingMixedScriptBubbleModel::ContentSettingMixedScriptBubbleModel( 1017 Delegate* delegate, 1018 WebContents* web_contents, 1019 Profile* profile, 1020 ContentSettingsType content_type) 1021 : ContentSettingTitleLinkAndCustomModel( 1022 delegate, web_contents, profile, content_type) { 1023 DCHECK_EQ(content_type, CONTENT_SETTINGS_TYPE_MIXEDSCRIPT); 1024 set_custom_link_enabled(true); 1025 } 1026 1027 void ContentSettingMixedScriptBubbleModel::OnCustomLinkClicked() { 1028 content::RecordAction(UserMetricsAction("MixedScript_LoadAnyway_Bubble")); 1029 DCHECK(web_contents()); 1030 content::RenderViewHost* host = web_contents()->GetRenderViewHost(); 1031 host->Send(new ChromeViewMsg_SetAllowRunningInsecureContent( 1032 host->GetRoutingID(), true)); 1033 } 1034 1035 ContentSettingRPHBubbleModel::ContentSettingRPHBubbleModel( 1036 Delegate* delegate, 1037 WebContents* web_contents, 1038 Profile* profile, 1039 ProtocolHandlerRegistry* registry, 1040 ContentSettingsType content_type) 1041 : ContentSettingTitleAndLinkModel( 1042 delegate, web_contents, profile, content_type), 1043 selected_item_(0), 1044 registry_(registry), 1045 pending_handler_(ProtocolHandler::EmptyProtocolHandler()), 1046 previous_handler_(ProtocolHandler::EmptyProtocolHandler()) { 1047 1048 DCHECK_EQ(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, content_type); 1049 1050 TabSpecificContentSettings* content_settings = 1051 TabSpecificContentSettings::FromWebContents(web_contents); 1052 pending_handler_ = content_settings->pending_protocol_handler(); 1053 previous_handler_ = content_settings->previous_protocol_handler(); 1054 1055 string16 protocol; 1056 if (pending_handler_.protocol() == "mailto") { 1057 protocol = l10n_util::GetStringUTF16( 1058 IDS_REGISTER_PROTOCOL_HANDLER_MAILTO_NAME); 1059 } else if (pending_handler_.protocol() == "webcal") { 1060 protocol = l10n_util::GetStringUTF16( 1061 IDS_REGISTER_PROTOCOL_HANDLER_WEBCAL_NAME); 1062 } else { 1063 protocol = UTF8ToUTF16(pending_handler_.protocol()); 1064 } 1065 1066 if (previous_handler_.IsEmpty()) { 1067 set_title(l10n_util::GetStringFUTF8( 1068 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM, 1069 pending_handler_.title(), UTF8ToUTF16(pending_handler_.url().host()), 1070 protocol)); 1071 } else { 1072 set_title(l10n_util::GetStringFUTF8( 1073 IDS_REGISTER_PROTOCOL_HANDLER_CONFIRM_REPLACE, 1074 pending_handler_.title(), UTF8ToUTF16(pending_handler_.url().host()), 1075 protocol, previous_handler_.title())); 1076 } 1077 1078 std::string radio_allow_label = 1079 l10n_util::GetStringFUTF8(IDS_REGISTER_PROTOCOL_HANDLER_ACCEPT, 1080 pending_handler_.title()); 1081 std::string radio_deny_label = 1082 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_DENY); 1083 std::string radio_ignore_label = 1084 l10n_util::GetStringUTF8(IDS_REGISTER_PROTOCOL_HANDLER_IGNORE); 1085 1086 GURL url = web_contents->GetURL(); 1087 RadioGroup radio_group; 1088 radio_group.url = url; 1089 1090 radio_group.radio_items.push_back(radio_allow_label); 1091 radio_group.radio_items.push_back(radio_deny_label); 1092 radio_group.radio_items.push_back(radio_ignore_label); 1093 ContentSetting setting = 1094 content_settings->pending_protocol_handler_setting(); 1095 if (setting == CONTENT_SETTING_ALLOW) 1096 radio_group.default_item = RPH_ALLOW; 1097 else if (setting == CONTENT_SETTING_BLOCK) 1098 radio_group.default_item = RPH_BLOCK; 1099 else 1100 radio_group.default_item = RPH_IGNORE; 1101 1102 selected_item_ = radio_group.default_item; 1103 set_radio_group_enabled(true); 1104 set_radio_group(radio_group); 1105 } 1106 1107 void ContentSettingRPHBubbleModel::OnRadioClicked(int radio_index) { 1108 if (selected_item_ == radio_index) 1109 return; 1110 1111 selected_item_ = radio_index; 1112 1113 if (radio_index == RPH_ALLOW) 1114 RegisterProtocolHandler(); 1115 else if (radio_index == RPH_BLOCK) 1116 UnregisterProtocolHandler(); 1117 else if (radio_index == RPH_IGNORE) 1118 IgnoreProtocolHandler(); 1119 else 1120 NOTREACHED(); 1121 } 1122 1123 void ContentSettingRPHBubbleModel::OnDoneClicked() { 1124 // The user has one chance to deal with the RPH content setting UI, 1125 // then we remove it. 1126 TabSpecificContentSettings::FromWebContents(web_contents())-> 1127 ClearPendingProtocolHandler(); 1128 content::NotificationService::current()->Notify( 1129 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED, 1130 content::Source<WebContents>(web_contents()), 1131 content::NotificationService::NoDetails()); 1132 } 1133 1134 void ContentSettingRPHBubbleModel::RegisterProtocolHandler() { 1135 // A no-op if the handler hasn't been ignored, but needed in case the user 1136 // selects sequences like register/ignore/register. 1137 registry_->RemoveIgnoredHandler(pending_handler_); 1138 1139 registry_->OnAcceptRegisterProtocolHandler(pending_handler_); 1140 TabSpecificContentSettings::FromWebContents(web_contents())-> 1141 set_pending_protocol_handler_setting(CONTENT_SETTING_ALLOW); 1142 } 1143 1144 void ContentSettingRPHBubbleModel::UnregisterProtocolHandler() { 1145 registry_->OnDenyRegisterProtocolHandler(pending_handler_); 1146 TabSpecificContentSettings::FromWebContents(web_contents())-> 1147 set_pending_protocol_handler_setting(CONTENT_SETTING_BLOCK); 1148 ClearOrSetPreviousHandler(); 1149 } 1150 1151 void ContentSettingRPHBubbleModel::IgnoreProtocolHandler() { 1152 registry_->OnIgnoreRegisterProtocolHandler(pending_handler_); 1153 TabSpecificContentSettings::FromWebContents(web_contents())-> 1154 set_pending_protocol_handler_setting(CONTENT_SETTING_DEFAULT); 1155 ClearOrSetPreviousHandler(); 1156 } 1157 1158 void ContentSettingRPHBubbleModel::ClearOrSetPreviousHandler() { 1159 if (previous_handler_.IsEmpty()) { 1160 registry_->ClearDefault(pending_handler_.protocol()); 1161 } else { 1162 registry_->OnAcceptRegisterProtocolHandler(previous_handler_); 1163 } 1164 } 1165 1166 // TODO(toyoshim): Should share as many code with geolocation as possible. 1167 class ContentSettingMIDISysExBubbleModel 1168 : public ContentSettingTitleAndLinkModel { 1169 public: 1170 ContentSettingMIDISysExBubbleModel(Delegate* delegate, 1171 WebContents* web_contents, 1172 Profile* profile, 1173 ContentSettingsType content_type); 1174 virtual ~ContentSettingMIDISysExBubbleModel() {} 1175 1176 private: 1177 void MaybeAddDomainList(const std::set<std::string>& hosts, int title_id); 1178 void SetDomainsAndCustomLink(); 1179 virtual void OnCustomLinkClicked() OVERRIDE; 1180 }; 1181 1182 ContentSettingMIDISysExBubbleModel::ContentSettingMIDISysExBubbleModel( 1183 Delegate* delegate, 1184 WebContents* web_contents, 1185 Profile* profile, 1186 ContentSettingsType content_type) 1187 : ContentSettingTitleAndLinkModel( 1188 delegate, web_contents, profile, content_type) { 1189 DCHECK_EQ(CONTENT_SETTINGS_TYPE_MIDI_SYSEX, content_type); 1190 SetDomainsAndCustomLink(); 1191 } 1192 1193 void ContentSettingMIDISysExBubbleModel::MaybeAddDomainList( 1194 const std::set<std::string>& hosts, int title_id) { 1195 if (!hosts.empty()) { 1196 DomainList domain_list; 1197 domain_list.title = l10n_util::GetStringUTF8(title_id); 1198 domain_list.hosts = hosts; 1199 add_domain_list(domain_list); 1200 } 1201 } 1202 1203 void ContentSettingMIDISysExBubbleModel::SetDomainsAndCustomLink() { 1204 TabSpecificContentSettings* content_settings = 1205 TabSpecificContentSettings::FromWebContents(web_contents()); 1206 const ContentSettingsUsagesState& usages_state = 1207 content_settings->midi_usages_state(); 1208 ContentSettingsUsagesState::FormattedHostsPerState formatted_hosts_per_state; 1209 unsigned int tab_state_flags = 0; 1210 usages_state.GetDetailedInfo(&formatted_hosts_per_state, &tab_state_flags); 1211 // Divide the tab's current MIDI sysex users into sets according to their 1212 // permission state. 1213 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_ALLOW], 1214 IDS_MIDI_SYSEX_BUBBLE_ALLOWED); 1215 1216 MaybeAddDomainList(formatted_hosts_per_state[CONTENT_SETTING_BLOCK], 1217 IDS_MIDI_SYSEX_BUBBLE_DENIED); 1218 1219 if (tab_state_flags & ContentSettingsUsagesState::TABSTATE_HAS_EXCEPTION) { 1220 set_custom_link(l10n_util::GetStringUTF8( 1221 IDS_MIDI_SYSEX_BUBBLE_CLEAR_LINK)); 1222 set_custom_link_enabled(true); 1223 } else if (tab_state_flags & 1224 ContentSettingsUsagesState::TABSTATE_HAS_CHANGED) { 1225 set_custom_link(l10n_util::GetStringUTF8( 1226 IDS_MIDI_SYSEX_BUBBLE_REQUIRE_RELOAD_TO_CLEAR)); 1227 } 1228 } 1229 1230 void ContentSettingMIDISysExBubbleModel::OnCustomLinkClicked() { 1231 if (!web_contents()) 1232 return; 1233 // Reset this embedder's entry to default for each of the requesting 1234 // origins currently on the page. 1235 TabSpecificContentSettings* content_settings = 1236 TabSpecificContentSettings::FromWebContents(web_contents()); 1237 const ContentSettingsUsagesState::StateMap& state_map = 1238 content_settings->midi_usages_state().state_map(); 1239 HostContentSettingsMap* settings_map = 1240 profile()->GetHostContentSettingsMap(); 1241 1242 for (ContentSettingsUsagesState::StateMap::const_iterator it = 1243 state_map.begin(); it != state_map.end(); ++it) { 1244 settings_map->SetContentSetting( 1245 ContentSettingsPattern::FromURLNoWildcard(it->first), 1246 ContentSettingsPattern::Wildcard(), 1247 CONTENT_SETTINGS_TYPE_MIDI_SYSEX, 1248 std::string(), 1249 CONTENT_SETTING_DEFAULT); 1250 } 1251 } 1252 1253 // static 1254 ContentSettingBubbleModel* 1255 ContentSettingBubbleModel::CreateContentSettingBubbleModel( 1256 Delegate* delegate, 1257 WebContents* web_contents, 1258 Profile* profile, 1259 ContentSettingsType content_type) { 1260 if (content_type == CONTENT_SETTINGS_TYPE_COOKIES) { 1261 return new ContentSettingCookiesBubbleModel(delegate, web_contents, profile, 1262 content_type); 1263 } 1264 if (content_type == CONTENT_SETTINGS_TYPE_POPUPS) { 1265 return new ContentSettingPopupBubbleModel(delegate, web_contents, profile, 1266 content_type); 1267 } 1268 if (content_type == CONTENT_SETTINGS_TYPE_GEOLOCATION) { 1269 return new ContentSettingDomainListBubbleModel(delegate, web_contents, 1270 profile, content_type); 1271 } 1272 if (content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM) { 1273 return new ContentSettingMediaStreamBubbleModel(delegate, web_contents, 1274 profile); 1275 } 1276 if (content_type == CONTENT_SETTINGS_TYPE_PLUGINS) { 1277 return new ContentSettingPluginBubbleModel(delegate, web_contents, profile, 1278 content_type); 1279 } 1280 if (content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT) { 1281 return new ContentSettingMixedScriptBubbleModel(delegate, web_contents, 1282 profile, content_type); 1283 } 1284 if (content_type == CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS) { 1285 ProtocolHandlerRegistry* registry = 1286 ProtocolHandlerRegistryFactory::GetForProfile(profile); 1287 return new ContentSettingRPHBubbleModel(delegate, web_contents, profile, 1288 registry, content_type); 1289 } 1290 if (content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) { 1291 return new ContentSettingMIDISysExBubbleModel(delegate, web_contents, 1292 profile, content_type); 1293 } 1294 return new ContentSettingSingleRadioGroup(delegate, web_contents, profile, 1295 content_type); 1296 } 1297 1298 ContentSettingBubbleModel::ContentSettingBubbleModel( 1299 WebContents* web_contents, 1300 Profile* profile, 1301 ContentSettingsType content_type) 1302 : web_contents_(web_contents), 1303 profile_(profile), 1304 content_type_(content_type) { 1305 registrar_.Add(this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, 1306 content::Source<WebContents>(web_contents)); 1307 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED, 1308 content::Source<Profile>(profile_)); 1309 } 1310 1311 ContentSettingBubbleModel::~ContentSettingBubbleModel() { 1312 } 1313 1314 ContentSettingBubbleModel::RadioGroup::RadioGroup() : default_item(0) {} 1315 1316 ContentSettingBubbleModel::RadioGroup::~RadioGroup() {} 1317 1318 ContentSettingBubbleModel::DomainList::DomainList() {} 1319 1320 ContentSettingBubbleModel::DomainList::~DomainList() {} 1321 1322 ContentSettingBubbleModel::BubbleContent::BubbleContent() 1323 : radio_group_enabled(false), 1324 custom_link_enabled(false) { 1325 } 1326 1327 ContentSettingBubbleModel::BubbleContent::~BubbleContent() {} 1328 1329 1330 void ContentSettingBubbleModel::AddBlockedResource( 1331 const std::string& resource_identifier) { 1332 bubble_content_.resource_identifiers.insert(resource_identifier); 1333 } 1334 1335 void ContentSettingBubbleModel::Observe( 1336 int type, 1337 const content::NotificationSource& source, 1338 const content::NotificationDetails& details) { 1339 if (type == content::NOTIFICATION_WEB_CONTENTS_DESTROYED) { 1340 DCHECK_EQ(web_contents_, 1341 content::Source<WebContents>(source).ptr()); 1342 web_contents_ = NULL; 1343 } else { 1344 DCHECK_EQ(chrome::NOTIFICATION_PROFILE_DESTROYED, type); 1345 DCHECK_EQ(profile_, content::Source<Profile>(source).ptr()); 1346 profile_ = NULL; 1347 } 1348 } 1349