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.
5 #include "chrome/browser/content_settings/tab_specific_content_settings.h"
9 #include "base/command_line.h"
10 #include "base/lazy_instance.h"
11 #include "base/utf_string_conversions.h"
12 #include "chrome/browser/browsing_data/browsing_data_appcache_helper.h"
13 #include "chrome/browser/browsing_data/browsing_data_cookie_helper.h"
14 #include "chrome/browser/browsing_data/browsing_data_database_helper.h"
15 #include "chrome/browser/browsing_data/browsing_data_file_system_helper.h"
16 #include "chrome/browser/browsing_data/browsing_data_indexed_db_helper.h"
17 #include "chrome/browser/browsing_data/browsing_data_local_storage_helper.h"
18 #include "chrome/browser/browsing_data/cookies_tree_model.h"
19 #include "chrome/browser/content_settings/content_settings_details.h"
20 #include "chrome/browser/content_settings/content_settings_utils.h"
21 #include "chrome/browser/content_settings/host_content_settings_map.h"
22 #include "chrome/browser/profiles/profile.h"
23 #include "chrome/common/chrome_notification_types.h"
24 #include "chrome/common/chrome_switches.h"
25 #include "chrome/common/render_messages.h"
26 #include "content/public/browser/navigation_controller.h"
27 #include "content/public/browser/navigation_details.h"
28 #include "content/public/browser/navigation_entry.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/render_view_host.h"
31 #include "content/public/browser/render_view_host_observer.h"
32 #include "content/public/browser/web_contents.h"
33 #include "content/public/browser/web_contents_delegate.h"
34 #include "net/cookies/canonical_cookie.h"
35 #include "webkit/fileapi/file_system_types.h"
37 using content::BrowserThread
;
38 using content::NavigationController
;
39 using content::NavigationEntry
;
40 using content::RenderViewHost
;
41 using content::WebContents
;
43 DEFINE_WEB_CONTENTS_USER_DATA_KEY(TabSpecificContentSettings
)
47 class InterstitialHostObserver
: public content::RenderViewHostObserver
{
49 explicit InterstitialHostObserver(RenderViewHost
* rvh
)
50 : content::RenderViewHostObserver(rvh
) {}
52 // content::RenderViewHostObserver overrides.
53 virtual void RenderViewHostInitialized() OVERRIDE
{
54 Send(new ChromeViewMsg_SetAsInterstitial(routing_id()));
61 TabSpecificContentSettings::SiteDataObserver::SiteDataObserver(
62 TabSpecificContentSettings
* tab_specific_content_settings
)
63 : tab_specific_content_settings_(tab_specific_content_settings
) {
64 tab_specific_content_settings_
->AddSiteDataObserver(this);
67 TabSpecificContentSettings::SiteDataObserver::~SiteDataObserver() {
68 if (tab_specific_content_settings_
)
69 tab_specific_content_settings_
->RemoveSiteDataObserver(this);
72 void TabSpecificContentSettings::SiteDataObserver::ContentSettingsDestroyed() {
73 tab_specific_content_settings_
= NULL
;
76 TabSpecificContentSettings::TabSpecificContentSettings(WebContents
* tab
)
77 : content::WebContentsObserver(tab
),
78 profile_(Profile::FromBrowserContext(tab
->GetBrowserContext())),
79 allowed_local_shared_objects_(profile_
),
80 blocked_local_shared_objects_(profile_
),
81 geolocation_settings_state_(profile_
),
82 pending_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
83 previous_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
84 pending_protocol_handler_setting_(CONTENT_SETTING_DEFAULT
),
85 load_plugins_link_enabled_(true) {
86 ClearBlockedContentSettingsExceptForCookies();
87 ClearCookieSpecificContentSettings();
89 registrar_
.Add(this, chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED
,
90 content::Source
<HostContentSettingsMap
>(
91 profile_
->GetHostContentSettingsMap()));
94 TabSpecificContentSettings::~TabSpecificContentSettings() {
96 SiteDataObserver
, observer_list_
, ContentSettingsDestroyed());
99 TabSpecificContentSettings
* TabSpecificContentSettings::Get(
100 int render_process_id
, int render_view_id
) {
101 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
103 RenderViewHost
* view
= RenderViewHost::FromID(render_process_id
,
108 return TabSpecificContentSettings::FromWebContents(
109 WebContents::FromRenderViewHost(view
));
113 void TabSpecificContentSettings::CookiesRead(int render_process_id
,
116 const GURL
& frame_url
,
117 const net::CookieList
& cookie_list
,
118 bool blocked_by_policy
) {
119 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
120 TabSpecificContentSettings
* settings
= Get(render_process_id
, render_view_id
);
122 settings
->OnCookiesRead(url
, frame_url
, cookie_list
,
128 void TabSpecificContentSettings::CookieChanged(
129 int render_process_id
,
132 const GURL
& frame_url
,
133 const std::string
& cookie_line
,
134 const net::CookieOptions
& options
,
135 bool blocked_by_policy
) {
136 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
137 TabSpecificContentSettings
* settings
= Get(render_process_id
, render_view_id
);
139 settings
->OnCookieChanged(url
, frame_url
, cookie_line
, options
,
144 void TabSpecificContentSettings::WebDatabaseAccessed(
145 int render_process_id
,
148 const string16
& name
,
149 const string16
& display_name
,
150 bool blocked_by_policy
) {
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
152 TabSpecificContentSettings
* settings
= Get(render_process_id
, render_view_id
);
154 settings
->OnWebDatabaseAccessed(url
, name
, display_name
, blocked_by_policy
);
158 void TabSpecificContentSettings::DOMStorageAccessed(int render_process_id
,
162 bool blocked_by_policy
) {
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
164 TabSpecificContentSettings
* settings
= Get(render_process_id
, render_view_id
);
166 settings
->OnLocalStorageAccessed(url
, local
, blocked_by_policy
);
170 void TabSpecificContentSettings::IndexedDBAccessed(int render_process_id
,
173 const string16
& description
,
174 bool blocked_by_policy
) {
175 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
176 TabSpecificContentSettings
* settings
= Get(render_process_id
, render_view_id
);
178 settings
->OnIndexedDBAccessed(url
, description
, blocked_by_policy
);
182 void TabSpecificContentSettings::FileSystemAccessed(int render_process_id
,
185 bool blocked_by_policy
) {
186 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
187 TabSpecificContentSettings
* settings
= Get(render_process_id
, render_view_id
);
189 settings
->OnFileSystemAccessed(url
, blocked_by_policy
);
192 bool TabSpecificContentSettings::IsContentBlocked(
193 ContentSettingsType content_type
) const {
194 DCHECK(content_type
!= CONTENT_SETTINGS_TYPE_GEOLOCATION
)
195 << "Geolocation settings handled by ContentSettingGeolocationImageModel";
196 DCHECK(content_type
!= CONTENT_SETTINGS_TYPE_NOTIFICATIONS
)
197 << "Notifications settings handled by "
198 << "ContentSettingsNotificationsImageModel";
200 if (content_type
== CONTENT_SETTINGS_TYPE_IMAGES
||
201 content_type
== CONTENT_SETTINGS_TYPE_JAVASCRIPT
||
202 content_type
== CONTENT_SETTINGS_TYPE_PLUGINS
||
203 content_type
== CONTENT_SETTINGS_TYPE_COOKIES
||
204 content_type
== CONTENT_SETTINGS_TYPE_POPUPS
||
205 content_type
== CONTENT_SETTINGS_TYPE_MIXEDSCRIPT
)
206 return content_blocked_
[content_type
];
211 bool TabSpecificContentSettings::IsBlockageIndicated(
212 ContentSettingsType content_type
) const {
213 return content_blockage_indicated_to_user_
[content_type
];
216 void TabSpecificContentSettings::SetBlockageHasBeenIndicated(
217 ContentSettingsType content_type
) {
218 content_blockage_indicated_to_user_
[content_type
] = true;
221 bool TabSpecificContentSettings::IsContentAccessed(
222 ContentSettingsType content_type
) const {
223 // This method currently only returns meaningful values for cookies.
224 if (content_type
!= CONTENT_SETTINGS_TYPE_COOKIES
)
227 return content_accessed_
[content_type
];
230 const std::set
<std::string
>&
231 TabSpecificContentSettings::BlockedResourcesForType(
232 ContentSettingsType content_type
) const {
233 if (blocked_resources_
[content_type
].get()) {
234 return *blocked_resources_
[content_type
];
236 CR_DEFINE_STATIC_LOCAL(std::set
<std::string
>, empty_set
, ());
241 void TabSpecificContentSettings::AddBlockedResource(
242 ContentSettingsType content_type
,
243 const std::string
& resource_identifier
) {
244 if (!blocked_resources_
[content_type
].get())
245 blocked_resources_
[content_type
].reset(new std::set
<std::string
>());
246 blocked_resources_
[content_type
]->insert(resource_identifier
);
249 void TabSpecificContentSettings::OnContentBlocked(
250 ContentSettingsType type
,
251 const std::string
& resource_identifier
) {
252 DCHECK(type
!= CONTENT_SETTINGS_TYPE_GEOLOCATION
)
253 << "Geolocation settings handled by OnGeolocationPermissionSet";
254 content_accessed_
[type
] = true;
255 // Unless UI for resource content settings is enabled, ignore the resource
257 // TODO(bauerb): The UI to unblock content should be disabled if the content
258 // setting was not set by the user.
259 std::string identifier
;
260 if (CommandLine::ForCurrentProcess()->HasSwitch(
261 switches::kEnableResourceContentSettings
)) {
262 identifier
= resource_identifier
;
264 if (!identifier
.empty())
265 AddBlockedResource(type
, identifier
);
267 #if defined (OS_ANDROID)
268 if (type
== CONTENT_SETTINGS_TYPE_POPUPS
) {
269 // For Android we do not have a persistent button that will always be
270 // visible for blocked popups. Instead we have info bars which could be
271 // dismissed. Have to clear the blocked state so we properly notify the
272 // relevant pieces again.
273 content_blocked_
[type
] = false;
274 content_blockage_indicated_to_user_
[type
] = false;
278 if (!content_blocked_
[type
]) {
279 content_blocked_
[type
] = true;
280 // TODO: it would be nice to have a way of mocking this in tests.
281 content::NotificationService::current()->Notify(
282 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
283 content::Source
<WebContents
>(web_contents()),
284 content::NotificationService::NoDetails());
288 void TabSpecificContentSettings::OnContentAccessed(ContentSettingsType type
) {
289 DCHECK(type
!= CONTENT_SETTINGS_TYPE_GEOLOCATION
)
290 << "Geolocation settings handled by OnGeolocationPermissionSet";
291 if (!content_accessed_
[type
]) {
292 content_accessed_
[type
] = true;
293 content::NotificationService::current()->Notify(
294 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
295 content::Source
<WebContents
>(web_contents()),
296 content::NotificationService::NoDetails());
300 void TabSpecificContentSettings::OnCookiesRead(
302 const GURL
& frame_url
,
303 const net::CookieList
& cookie_list
,
304 bool blocked_by_policy
) {
305 if (cookie_list
.empty())
307 if (blocked_by_policy
) {
308 blocked_local_shared_objects_
.cookies()->AddReadCookies(
309 frame_url
, url
, cookie_list
);
310 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES
, std::string());
312 allowed_local_shared_objects_
.cookies()->AddReadCookies(
313 frame_url
, url
, cookie_list
);
314 OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES
);
317 NotifySiteDataObservers();
320 void TabSpecificContentSettings::OnCookieChanged(
322 const GURL
& frame_url
,
323 const std::string
& cookie_line
,
324 const net::CookieOptions
& options
,
325 bool blocked_by_policy
) {
326 if (blocked_by_policy
) {
327 blocked_local_shared_objects_
.cookies()->AddChangedCookie(
328 frame_url
, url
, cookie_line
, options
);
329 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES
, std::string());
331 allowed_local_shared_objects_
.cookies()->AddChangedCookie(
332 frame_url
, url
, cookie_line
, options
);
333 OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES
);
336 NotifySiteDataObservers();
339 void TabSpecificContentSettings::OnIndexedDBAccessed(
341 const string16
& description
,
342 bool blocked_by_policy
) {
343 if (blocked_by_policy
) {
344 blocked_local_shared_objects_
.indexed_dbs()->AddIndexedDB(
346 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES
, std::string());
348 allowed_local_shared_objects_
.indexed_dbs()->AddIndexedDB(
350 OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES
);
353 NotifySiteDataObservers();
356 void TabSpecificContentSettings::OnLocalStorageAccessed(
359 bool blocked_by_policy
) {
360 LocalSharedObjectsContainer
& container
= blocked_by_policy
?
361 blocked_local_shared_objects_
: allowed_local_shared_objects_
;
362 CannedBrowsingDataLocalStorageHelper
* helper
=
363 local
? container
.local_storages() : container
.session_storages();
364 helper
->AddLocalStorage(url
);
366 if (blocked_by_policy
)
367 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES
, std::string());
369 OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES
);
371 NotifySiteDataObservers();
374 void TabSpecificContentSettings::OnWebDatabaseAccessed(
376 const string16
& name
,
377 const string16
& display_name
,
378 bool blocked_by_policy
) {
379 if (blocked_by_policy
) {
380 blocked_local_shared_objects_
.databases()->AddDatabase(
381 url
, UTF16ToUTF8(name
), UTF16ToUTF8(display_name
));
382 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES
, std::string());
384 allowed_local_shared_objects_
.databases()->AddDatabase(
385 url
, UTF16ToUTF8(name
), UTF16ToUTF8(display_name
));
386 OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES
);
389 NotifySiteDataObservers();
392 void TabSpecificContentSettings::OnFileSystemAccessed(
394 bool blocked_by_policy
) {
395 if (blocked_by_policy
) {
396 blocked_local_shared_objects_
.file_systems()->AddFileSystem(url
,
397 fileapi::kFileSystemTypeTemporary
, 0);
398 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES
, std::string());
400 allowed_local_shared_objects_
.file_systems()->AddFileSystem(url
,
401 fileapi::kFileSystemTypeTemporary
, 0);
402 OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES
);
405 NotifySiteDataObservers();
408 void TabSpecificContentSettings::OnGeolocationPermissionSet(
409 const GURL
& requesting_origin
,
411 geolocation_settings_state_
.OnGeolocationPermissionSet(requesting_origin
,
413 content::NotificationService::current()->Notify(
414 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
415 content::Source
<WebContents
>(web_contents()),
416 content::NotificationService::NoDetails());
419 void TabSpecificContentSettings::ClearBlockedContentSettingsExceptForCookies() {
420 for (size_t i
= 0; i
< arraysize(content_blocked_
); ++i
) {
421 if (i
== CONTENT_SETTINGS_TYPE_COOKIES
)
423 blocked_resources_
[i
].reset();
424 content_blocked_
[i
] = false;
425 content_accessed_
[i
] = false;
426 content_blockage_indicated_to_user_
[i
] = false;
428 load_plugins_link_enabled_
= true;
429 content::NotificationService::current()->Notify(
430 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
431 content::Source
<WebContents
>(web_contents()),
432 content::NotificationService::NoDetails());
435 void TabSpecificContentSettings::ClearCookieSpecificContentSettings() {
436 blocked_local_shared_objects_
.Reset();
437 allowed_local_shared_objects_
.Reset();
438 content_blocked_
[CONTENT_SETTINGS_TYPE_COOKIES
] = false;
439 content_accessed_
[CONTENT_SETTINGS_TYPE_COOKIES
] = false;
440 content_blockage_indicated_to_user_
[CONTENT_SETTINGS_TYPE_COOKIES
] = false;
441 content::NotificationService::current()->Notify(
442 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
443 content::Source
<WebContents
>(web_contents()),
444 content::NotificationService::NoDetails());
447 void TabSpecificContentSettings::SetPopupsBlocked(bool blocked
) {
448 content_blocked_
[CONTENT_SETTINGS_TYPE_POPUPS
] = blocked
;
449 content_blockage_indicated_to_user_
[CONTENT_SETTINGS_TYPE_POPUPS
] = false;
450 content::NotificationService::current()->Notify(
451 chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED
,
452 content::Source
<WebContents
>(web_contents()),
453 content::NotificationService::NoDetails());
456 void TabSpecificContentSettings::GeolocationDidNavigate(
457 const content::LoadCommittedDetails
& details
) {
458 geolocation_settings_state_
.DidNavigate(details
);
461 void TabSpecificContentSettings::ClearGeolocationContentSettings() {
462 geolocation_settings_state_
.ClearStateMap();
465 void TabSpecificContentSettings::RenderViewForInterstitialPageCreated(
466 RenderViewHost
* render_view_host
) {
467 // We want to tell the renderer-side code to ignore content settings for this
468 // page but we must wait until the RenderView is created.
469 new InterstitialHostObserver(render_view_host
);
472 bool TabSpecificContentSettings::OnMessageReceived(
473 const IPC::Message
& message
) {
475 IPC_BEGIN_MESSAGE_MAP(TabSpecificContentSettings
, message
)
476 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ContentBlocked
, OnContentBlocked
)
477 IPC_MESSAGE_UNHANDLED(handled
= false)
478 IPC_END_MESSAGE_MAP()
482 void TabSpecificContentSettings::DidNavigateMainFrame(
483 const content::LoadCommittedDetails
& details
,
484 const content::FrameNavigateParams
& params
) {
485 if (!details
.is_in_page
) {
486 // Clear "blocked" flags.
487 ClearBlockedContentSettingsExceptForCookies();
488 GeolocationDidNavigate(details
);
492 void TabSpecificContentSettings::DidStartProvisionalLoadForFrame(
494 int64 parent_frame_id
,
496 const GURL
& validated_url
,
498 RenderViewHost
* render_view_host
) {
502 // If we're displaying a network error page do not reset the content
503 // settings delegate's cookies so the user has a chance to modify cookie
506 ClearCookieSpecificContentSettings();
507 ClearGeolocationContentSettings();
510 void TabSpecificContentSettings::AppCacheAccessed(const GURL
& manifest_url
,
511 bool blocked_by_policy
) {
512 if (blocked_by_policy
) {
513 blocked_local_shared_objects_
.appcaches()->AddAppCache(manifest_url
);
514 OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES
, std::string());
516 allowed_local_shared_objects_
.appcaches()->AddAppCache(manifest_url
);
517 OnContentAccessed(CONTENT_SETTINGS_TYPE_COOKIES
);
521 void TabSpecificContentSettings::Observe(
523 const content::NotificationSource
& source
,
524 const content::NotificationDetails
& details
) {
525 DCHECK(type
== chrome::NOTIFICATION_CONTENT_SETTINGS_CHANGED
);
527 content::Details
<const ContentSettingsDetails
> settings_details(details
);
528 const NavigationController
& controller
= web_contents()->GetController();
529 NavigationEntry
* entry
= controller
.GetActiveEntry();
532 entry_url
= entry
->GetURL();
533 if (settings_details
.ptr()->update_all() ||
534 // The active NavigationEntry is the URL in the URL field of a tab.
535 // Currently this should be matched by the |primary_pattern|.
536 settings_details
.ptr()->primary_pattern().Matches(entry_url
)) {
538 Profile::FromBrowserContext(web_contents()->GetBrowserContext());
539 RendererContentSettingRules rules
;
540 GetRendererContentSettingRules(profile
->GetHostContentSettingsMap(),
542 Send(new ChromeViewMsg_SetContentSettingRules(rules
));
546 void TabSpecificContentSettings::AddSiteDataObserver(
547 SiteDataObserver
* observer
) {
548 observer_list_
.AddObserver(observer
);
551 void TabSpecificContentSettings::RemoveSiteDataObserver(
552 SiteDataObserver
* observer
) {
553 observer_list_
.RemoveObserver(observer
);
556 void TabSpecificContentSettings::NotifySiteDataObservers() {
557 FOR_EACH_OBSERVER(SiteDataObserver
, observer_list_
, OnSiteDataAccessed());