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/content_settings/tab_specific_content_settings.h"
6
7#include <list>
8
9#include "base/command_line.h"
10#include "base/lazy_instance.h"
11#include "base/strings/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/chrome_notification_types.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/prerender/prerender_manager.h"
23#include "chrome/browser/profiles/profile.h"
24#include "chrome/common/chrome_switches.h"
25#include "chrome/common/render_messages.h"
26#include "components/content_settings/core/browser/content_settings_details.h"
27#include "content/public/browser/browser_thread.h"
28#include "content/public/browser/navigation_controller.h"
29#include "content/public/browser/navigation_details.h"
30#include "content/public/browser/navigation_entry.h"
31#include "content/public/browser/notification_registrar.h"
32#include "content/public/browser/notification_service.h"
33#include "content/public/browser/render_frame_host.h"
34#include "content/public/browser/render_view_host.h"
35#include "content/public/browser/web_contents.h"
36#include "content/public/browser/web_contents_delegate.h"
37#include "net/cookies/canonical_cookie.h"
38#include "storage/common/fileapi/file_system_types.h"
39
40using content::BrowserThread;
41using content::NavigationController;
42using content::NavigationEntry;
43using content::RenderViewHost;
44using content::WebContents;
45
46DEFINE_WEB_CONTENTS_USER_DATA_KEY(TabSpecificContentSettings);
47
48TabSpecificContentSettings::SiteDataObserver::SiteDataObserver(
49    TabSpecificContentSettings* tab_specific_content_settings)
50    : tab_specific_content_settings_(tab_specific_content_settings) {
51  tab_specific_content_settings_->AddSiteDataObserver(this);
52}
53
54TabSpecificContentSettings::SiteDataObserver::~SiteDataObserver() {
55  if (tab_specific_content_settings_)
56    tab_specific_content_settings_->RemoveSiteDataObserver(this);
57}
58
59void TabSpecificContentSettings::SiteDataObserver::ContentSettingsDestroyed() {
60  tab_specific_content_settings_ = NULL;
61}
62
63TabSpecificContentSettings::TabSpecificContentSettings(WebContents* tab)
64    : content::WebContentsObserver(tab),
65      profile_(Profile::FromBrowserContext(tab->GetBrowserContext())),
66      allowed_local_shared_objects_(profile_),
67      blocked_local_shared_objects_(profile_),
68      geolocation_usages_state_(profile_, CONTENT_SETTINGS_TYPE_GEOLOCATION),
69      midi_usages_state_(profile_, CONTENT_SETTINGS_TYPE_MIDI_SYSEX),
70      pending_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
71      previous_protocol_handler_(ProtocolHandler::EmptyProtocolHandler()),
72      pending_protocol_handler_setting_(CONTENT_SETTING_DEFAULT),
73      load_plugins_link_enabled_(true),
74      observer_(this) {
75  ClearBlockedContentSettingsExceptForCookies();
76  ClearCookieSpecificContentSettings();
77
78  observer_.Add(profile_->GetHostContentSettingsMap());
79}
80
81TabSpecificContentSettings::~TabSpecificContentSettings() {
82  FOR_EACH_OBSERVER(
83      SiteDataObserver, observer_list_, ContentSettingsDestroyed());
84}
85
86TabSpecificContentSettings* TabSpecificContentSettings::Get(
87    int render_process_id, int render_view_id) {
88  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89
90  RenderViewHost* view = RenderViewHost::FromID(render_process_id,
91                                                render_view_id);
92  if (!view)
93    return NULL;
94
95  WebContents* web_contents = WebContents::FromRenderViewHost(view);
96  if (!web_contents)
97    return NULL;
98
99  return TabSpecificContentSettings::FromWebContents(web_contents);
100}
101
102TabSpecificContentSettings* TabSpecificContentSettings::GetForFrame(
103    int render_process_id, int render_frame_id) {
104  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105
106  content::RenderFrameHost* frame = content::RenderFrameHost::FromID(
107      render_process_id, render_frame_id);
108  WebContents* web_contents = WebContents::FromRenderFrameHost(frame);
109  if (!web_contents)
110    return NULL;
111
112  return TabSpecificContentSettings::FromWebContents(web_contents);
113}
114
115// static
116void TabSpecificContentSettings::CookiesRead(int render_process_id,
117                                             int render_frame_id,
118                                             const GURL& url,
119                                             const GURL& frame_url,
120                                             const net::CookieList& cookie_list,
121                                             bool blocked_by_policy,
122                                             bool is_for_blocking_resource) {
123  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
124  TabSpecificContentSettings* settings =
125      GetForFrame(render_process_id, render_frame_id);
126  if (settings) {
127    settings->OnCookiesRead(url, frame_url, cookie_list,
128                            blocked_by_policy);
129  }
130  prerender::PrerenderManager::RecordCookieEvent(
131      render_process_id,
132      render_frame_id,
133      url,
134      frame_url,
135      is_for_blocking_resource,
136      prerender::PrerenderContents::COOKIE_EVENT_SEND,
137      &cookie_list);
138}
139
140// static
141void TabSpecificContentSettings::CookieChanged(
142    int render_process_id,
143    int render_frame_id,
144    const GURL& url,
145    const GURL& frame_url,
146    const std::string& cookie_line,
147    const net::CookieOptions& options,
148    bool blocked_by_policy) {
149  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
150  TabSpecificContentSettings* settings =
151      GetForFrame(render_process_id, render_frame_id);
152  if (settings)
153    settings->OnCookieChanged(url, frame_url, cookie_line, options,
154                              blocked_by_policy);
155  prerender::PrerenderManager::RecordCookieEvent(
156      render_process_id,
157      render_frame_id,
158      url,
159      frame_url,
160      false /*is_critical_request*/,
161      prerender::PrerenderContents::COOKIE_EVENT_CHANGE,
162      NULL);
163}
164
165// static
166void TabSpecificContentSettings::WebDatabaseAccessed(
167    int render_process_id,
168    int render_frame_id,
169    const GURL& url,
170    const base::string16& name,
171    const base::string16& display_name,
172    bool blocked_by_policy) {
173  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
174  TabSpecificContentSettings* settings = GetForFrame(
175      render_process_id, render_frame_id);
176  if (settings)
177    settings->OnWebDatabaseAccessed(url, name, display_name, blocked_by_policy);
178}
179
180// static
181void TabSpecificContentSettings::DOMStorageAccessed(int render_process_id,
182                                                    int render_frame_id,
183                                                    const GURL& url,
184                                                    bool local,
185                                                    bool blocked_by_policy) {
186  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
187  TabSpecificContentSettings* settings = GetForFrame(
188      render_process_id, render_frame_id);
189  if (settings)
190    settings->OnLocalStorageAccessed(url, local, blocked_by_policy);
191}
192
193// static
194void TabSpecificContentSettings::IndexedDBAccessed(
195    int render_process_id,
196    int render_frame_id,
197    const GURL& url,
198    const base::string16& description,
199    bool blocked_by_policy) {
200  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
201  TabSpecificContentSettings* settings = GetForFrame(
202      render_process_id, render_frame_id);
203  if (settings)
204    settings->OnIndexedDBAccessed(url, description, blocked_by_policy);
205}
206
207// static
208void TabSpecificContentSettings::FileSystemAccessed(int render_process_id,
209                                                    int render_frame_id,
210                                                    const GURL& url,
211                                                    bool blocked_by_policy) {
212  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
213  TabSpecificContentSettings* settings = GetForFrame(
214      render_process_id, render_frame_id);
215  if (settings)
216    settings->OnFileSystemAccessed(url, blocked_by_policy);
217}
218
219bool TabSpecificContentSettings::IsContentBlocked(
220    ContentSettingsType content_type) const {
221  DCHECK(content_type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
222      << "Geolocation settings handled by ContentSettingGeolocationImageModel";
223  DCHECK(content_type != CONTENT_SETTINGS_TYPE_NOTIFICATIONS)
224      << "Notifications settings handled by "
225      << "ContentSettingsNotificationsImageModel";
226
227  if (content_type == CONTENT_SETTINGS_TYPE_IMAGES ||
228      content_type == CONTENT_SETTINGS_TYPE_JAVASCRIPT ||
229      content_type == CONTENT_SETTINGS_TYPE_PLUGINS ||
230      content_type == CONTENT_SETTINGS_TYPE_COOKIES ||
231      content_type == CONTENT_SETTINGS_TYPE_POPUPS ||
232      content_type == CONTENT_SETTINGS_TYPE_MIXEDSCRIPT ||
233      content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM ||
234      content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC ||
235      content_type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA ||
236      content_type == CONTENT_SETTINGS_TYPE_PPAPI_BROKER ||
237      content_type == CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS ||
238      content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
239    return content_blocked_[content_type];
240  }
241
242  return false;
243}
244
245bool TabSpecificContentSettings::IsBlockageIndicated(
246    ContentSettingsType content_type) const {
247  return content_blockage_indicated_to_user_[content_type];
248}
249
250void TabSpecificContentSettings::SetBlockageHasBeenIndicated(
251    ContentSettingsType content_type) {
252  content_blockage_indicated_to_user_[content_type] = true;
253}
254
255bool TabSpecificContentSettings::IsContentAllowed(
256    ContentSettingsType content_type) const {
257  // This method currently only returns meaningful values for the content type
258  // cookies, mediastream, PPAPI broker, and downloads.
259  if (content_type != CONTENT_SETTINGS_TYPE_COOKIES &&
260      content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM &&
261      content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC &&
262      content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA &&
263      content_type != CONTENT_SETTINGS_TYPE_PPAPI_BROKER &&
264      content_type != CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS &&
265      content_type != CONTENT_SETTINGS_TYPE_MIDI_SYSEX) {
266    return false;
267  }
268
269  return content_allowed_[content_type];
270}
271
272void TabSpecificContentSettings::OnContentBlocked(ContentSettingsType type) {
273  DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
274      << "Geolocation settings handled by OnGeolocationPermissionSet";
275  if (type < 0 || type >= CONTENT_SETTINGS_NUM_TYPES)
276    return;
277
278  // Media is different from other content setting types since it allows new
279  // setting to kick in without reloading the page, and the UI for media is
280  // always reflecting the newest permission setting.
281  switch (type) {
282    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
283    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
284#if defined(OS_ANDROID)
285    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
286#endif
287      content_allowed_[type] = false;
288      break;
289    default:
290      content_allowed_[type] = true;
291      break;
292  }
293
294#if defined(OS_ANDROID)
295  if (type == CONTENT_SETTINGS_TYPE_POPUPS) {
296    // For Android we do not have a persistent button that will always be
297    // visible for blocked popups.  Instead we have info bars which could be
298    // dismissed.  Have to clear the blocked state so we properly notify the
299    // relevant pieces again.
300    content_blocked_[type] = false;
301    content_blockage_indicated_to_user_[type] = false;
302  }
303#endif
304
305  if (!content_blocked_[type]) {
306    content_blocked_[type] = true;
307    // TODO: it would be nice to have a way of mocking this in tests.
308    content::NotificationService::current()->Notify(
309        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
310        content::Source<WebContents>(web_contents()),
311        content::NotificationService::NoDetails());
312  }
313}
314
315void TabSpecificContentSettings::OnContentAllowed(ContentSettingsType type) {
316  DCHECK(type != CONTENT_SETTINGS_TYPE_GEOLOCATION)
317      << "Geolocation settings handled by OnGeolocationPermissionSet";
318  bool access_changed = false;
319  switch (type) {
320    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC:
321    case CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA:
322#if defined(OS_ANDROID)
323    case CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER:
324#endif
325      // The setting for media is overwritten here because media does not need
326      // to reload the page to have the new setting kick in. See issue/175993.
327      if (content_blocked_[type]) {
328        content_blocked_[type] = false;
329        access_changed = true;
330      }
331      break;
332    default:
333      break;
334  }
335
336  if (!content_allowed_[type]) {
337    content_allowed_[type] = true;
338    access_changed = true;
339  }
340
341  if (access_changed) {
342    content::NotificationService::current()->Notify(
343        chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
344        content::Source<WebContents>(web_contents()),
345        content::NotificationService::NoDetails());
346  }
347}
348
349void TabSpecificContentSettings::OnCookiesRead(
350    const GURL& url,
351    const GURL& frame_url,
352    const net::CookieList& cookie_list,
353    bool blocked_by_policy) {
354  if (cookie_list.empty())
355    return;
356  if (blocked_by_policy) {
357    blocked_local_shared_objects_.cookies()->AddReadCookies(
358        frame_url, url, cookie_list);
359    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
360  } else {
361    allowed_local_shared_objects_.cookies()->AddReadCookies(
362        frame_url, url, cookie_list);
363    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
364  }
365
366  NotifySiteDataObservers();
367}
368
369void TabSpecificContentSettings::OnCookieChanged(
370    const GURL& url,
371    const GURL& frame_url,
372    const std::string& cookie_line,
373    const net::CookieOptions& options,
374    bool blocked_by_policy) {
375  if (blocked_by_policy) {
376    blocked_local_shared_objects_.cookies()->AddChangedCookie(
377        frame_url, url, cookie_line, options);
378    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
379  } else {
380    allowed_local_shared_objects_.cookies()->AddChangedCookie(
381        frame_url, url, cookie_line, options);
382    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
383  }
384
385  NotifySiteDataObservers();
386}
387
388void TabSpecificContentSettings::OnIndexedDBAccessed(
389    const GURL& url,
390    const base::string16& description,
391    bool blocked_by_policy) {
392  if (blocked_by_policy) {
393    blocked_local_shared_objects_.indexed_dbs()->AddIndexedDB(
394        url, description);
395    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
396  } else {
397    allowed_local_shared_objects_.indexed_dbs()->AddIndexedDB(
398        url, description);
399    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
400  }
401
402  NotifySiteDataObservers();
403}
404
405void TabSpecificContentSettings::OnLocalStorageAccessed(
406    const GURL& url,
407    bool local,
408    bool blocked_by_policy) {
409  LocalSharedObjectsContainer& container = blocked_by_policy ?
410      blocked_local_shared_objects_ : allowed_local_shared_objects_;
411  CannedBrowsingDataLocalStorageHelper* helper =
412      local ? container.local_storages() : container.session_storages();
413  helper->AddLocalStorage(url);
414
415  if (blocked_by_policy)
416    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
417  else
418    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
419
420  NotifySiteDataObservers();
421}
422
423void TabSpecificContentSettings::OnWebDatabaseAccessed(
424    const GURL& url,
425    const base::string16& name,
426    const base::string16& display_name,
427    bool blocked_by_policy) {
428  if (blocked_by_policy) {
429    blocked_local_shared_objects_.databases()->AddDatabase(
430        url, base::UTF16ToUTF8(name), base::UTF16ToUTF8(display_name));
431    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
432  } else {
433    allowed_local_shared_objects_.databases()->AddDatabase(
434        url, base::UTF16ToUTF8(name), base::UTF16ToUTF8(display_name));
435    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
436  }
437
438  NotifySiteDataObservers();
439}
440
441void TabSpecificContentSettings::OnFileSystemAccessed(
442    const GURL& url,
443    bool blocked_by_policy) {
444  if (blocked_by_policy) {
445    blocked_local_shared_objects_.file_systems()->AddFileSystem(
446        url, storage::kFileSystemTypeTemporary, 0);
447    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
448  } else {
449    allowed_local_shared_objects_.file_systems()->AddFileSystem(
450        url, storage::kFileSystemTypeTemporary, 0);
451    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
452  }
453
454  NotifySiteDataObservers();
455}
456
457void TabSpecificContentSettings::OnGeolocationPermissionSet(
458    const GURL& requesting_origin,
459    bool allowed) {
460  geolocation_usages_state_.OnPermissionSet(requesting_origin, allowed);
461  content::NotificationService::current()->Notify(
462      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
463      content::Source<WebContents>(web_contents()),
464      content::NotificationService::NoDetails());
465}
466
467#if defined(OS_ANDROID)
468void TabSpecificContentSettings::OnProtectedMediaIdentifierPermissionSet(
469    const GURL& requesting_origin,
470    bool allowed) {
471  if (allowed) {
472    OnContentAllowed(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
473  } else {
474    OnContentBlocked(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER);
475  }
476}
477#endif
478
479TabSpecificContentSettings::MicrophoneCameraState
480TabSpecificContentSettings::GetMicrophoneCameraState() const {
481  if (IsContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) &&
482      IsContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)) {
483    return MICROPHONE_CAMERA_ACCESSED;
484  } else if (IsContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)) {
485    return MICROPHONE_ACCESSED;
486  } else if (IsContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)) {
487    return CAMERA_ACCESSED;
488  }
489
490  if (IsContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) &&
491      IsContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)) {
492    return MICROPHONE_CAMERA_BLOCKED;
493  } else if (IsContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC)) {
494    return MICROPHONE_BLOCKED;
495  } else if (IsContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA)) {
496    return CAMERA_BLOCKED;
497  }
498
499  return MICROPHONE_CAMERA_NOT_ACCESSED;
500}
501
502void TabSpecificContentSettings::OnMediaStreamPermissionSet(
503    const GURL& request_origin,
504    const MediaStreamDevicesController::MediaStreamTypeSettingsMap&
505        request_permissions) {
506  media_stream_access_origin_ = request_origin;
507
508  MediaStreamDevicesController::MediaStreamTypeSettingsMap::const_iterator it =
509      request_permissions.find(content::MEDIA_DEVICE_AUDIO_CAPTURE);
510  if (it != request_permissions.end()) {
511    media_stream_requested_audio_device_ = it->second.requested_device_id;
512    switch (it->second.permission) {
513      case MediaStreamDevicesController::MEDIA_NONE:
514        NOTREACHED();
515        break;
516      case MediaStreamDevicesController::MEDIA_ALLOWED:
517        OnContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
518        break;
519      // TODO(grunell): UI should show for what reason access has been blocked.
520      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_POLICY:
521      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER_SETTING:
522      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER:
523        OnContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC);
524        break;
525    }
526  }
527
528  it = request_permissions.find(content::MEDIA_DEVICE_VIDEO_CAPTURE);
529  if (it != request_permissions.end()) {
530    media_stream_requested_video_device_ = it->second.requested_device_id;
531    switch (it->second.permission) {
532      case MediaStreamDevicesController::MEDIA_NONE:
533        NOTREACHED();
534        break;
535      case MediaStreamDevicesController::MEDIA_ALLOWED:
536        OnContentAllowed(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
537        break;
538      // TODO(grunell): UI should show for what reason access has been blocked.
539      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_POLICY:
540      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER_SETTING:
541      case MediaStreamDevicesController::MEDIA_BLOCKED_BY_USER:
542        OnContentBlocked(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA);
543        break;
544    }
545  }
546}
547
548void TabSpecificContentSettings::OnMidiSysExAccessed(
549    const GURL& requesting_origin) {
550  midi_usages_state_.OnPermissionSet(requesting_origin, true);
551  OnContentAllowed(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
552}
553
554void TabSpecificContentSettings::OnMidiSysExAccessBlocked(
555    const GURL& requesting_origin) {
556  midi_usages_state_.OnPermissionSet(requesting_origin, false);
557  OnContentBlocked(CONTENT_SETTINGS_TYPE_MIDI_SYSEX);
558}
559
560void TabSpecificContentSettings::ClearBlockedContentSettingsExceptForCookies() {
561  for (size_t i = 0; i < arraysize(content_blocked_); ++i) {
562    if (i == CONTENT_SETTINGS_TYPE_COOKIES)
563      continue;
564    content_blocked_[i] = false;
565    content_allowed_[i] = false;
566    content_blockage_indicated_to_user_[i] = false;
567  }
568  load_plugins_link_enabled_ = true;
569  content::NotificationService::current()->Notify(
570      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
571      content::Source<WebContents>(web_contents()),
572      content::NotificationService::NoDetails());
573}
574
575void TabSpecificContentSettings::ClearCookieSpecificContentSettings() {
576  blocked_local_shared_objects_.Reset();
577  allowed_local_shared_objects_.Reset();
578  content_blocked_[CONTENT_SETTINGS_TYPE_COOKIES] = false;
579  content_allowed_[CONTENT_SETTINGS_TYPE_COOKIES] = false;
580  content_blockage_indicated_to_user_[CONTENT_SETTINGS_TYPE_COOKIES] = false;
581  content::NotificationService::current()->Notify(
582      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
583      content::Source<WebContents>(web_contents()),
584      content::NotificationService::NoDetails());
585}
586
587void TabSpecificContentSettings::SetDownloadsBlocked(bool blocked) {
588  content_blocked_[CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS] = blocked;
589  content_allowed_[CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS] = !blocked;
590  content_blockage_indicated_to_user_[
591    CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS] = false;
592  content::NotificationService::current()->Notify(
593      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
594      content::Source<WebContents>(web_contents()),
595      content::NotificationService::NoDetails());
596}
597
598void TabSpecificContentSettings::SetPopupsBlocked(bool blocked) {
599  content_blocked_[CONTENT_SETTINGS_TYPE_POPUPS] = blocked;
600  content_blockage_indicated_to_user_[CONTENT_SETTINGS_TYPE_POPUPS] = false;
601  content::NotificationService::current()->Notify(
602      chrome::NOTIFICATION_WEB_CONTENT_SETTINGS_CHANGED,
603      content::Source<WebContents>(web_contents()),
604      content::NotificationService::NoDetails());
605}
606
607void TabSpecificContentSettings::GeolocationDidNavigate(
608      const content::LoadCommittedDetails& details) {
609  geolocation_usages_state_.DidNavigate(details);
610}
611
612void TabSpecificContentSettings::MidiDidNavigate(
613    const content::LoadCommittedDetails& details) {
614  midi_usages_state_.DidNavigate(details);
615}
616
617void TabSpecificContentSettings::ClearGeolocationContentSettings() {
618  geolocation_usages_state_.ClearStateMap();
619}
620
621void TabSpecificContentSettings::ClearMidiContentSettings() {
622  midi_usages_state_.ClearStateMap();
623}
624
625void TabSpecificContentSettings::SetPepperBrokerAllowed(bool allowed) {
626  if (allowed) {
627    OnContentAllowed(CONTENT_SETTINGS_TYPE_PPAPI_BROKER);
628  } else {
629    OnContentBlocked(CONTENT_SETTINGS_TYPE_PPAPI_BROKER);
630  }
631}
632
633void TabSpecificContentSettings::RenderFrameForInterstitialPageCreated(
634    content::RenderFrameHost* render_frame_host) {
635  // We want to tell the renderer-side code to ignore content settings for this
636  // page.
637  render_frame_host->Send(new ChromeViewMsg_SetAsInterstitial(
638      render_frame_host->GetRoutingID()));
639}
640
641bool TabSpecificContentSettings::OnMessageReceived(
642    const IPC::Message& message,
643    content::RenderFrameHost* render_frame_host) {
644  bool handled = true;
645  IPC_BEGIN_MESSAGE_MAP(TabSpecificContentSettings, message)
646    IPC_MESSAGE_HANDLER(ChromeViewHostMsg_ContentBlocked, OnContentBlocked)
647    IPC_MESSAGE_UNHANDLED(handled = false)
648  IPC_END_MESSAGE_MAP()
649  return handled;
650}
651
652void TabSpecificContentSettings::DidNavigateMainFrame(
653    const content::LoadCommittedDetails& details,
654    const content::FrameNavigateParams& params) {
655  if (!details.is_in_page) {
656    // Clear "blocked" flags.
657    ClearBlockedContentSettingsExceptForCookies();
658    GeolocationDidNavigate(details);
659    MidiDidNavigate(details);
660  }
661}
662
663void TabSpecificContentSettings::DidStartProvisionalLoadForFrame(
664    content::RenderFrameHost* render_frame_host,
665    const GURL& validated_url,
666    bool is_error_page,
667    bool is_iframe_srcdoc) {
668  if (render_frame_host->GetParent())
669    return;
670
671  // If we're displaying a network error page do not reset the content
672  // settings delegate's cookies so the user has a chance to modify cookie
673  // settings.
674  if (!is_error_page)
675    ClearCookieSpecificContentSettings();
676  ClearGeolocationContentSettings();
677  ClearMidiContentSettings();
678  ClearPendingProtocolHandler();
679}
680
681void TabSpecificContentSettings::AppCacheAccessed(const GURL& manifest_url,
682                                                  bool blocked_by_policy) {
683  if (blocked_by_policy) {
684    blocked_local_shared_objects_.appcaches()->AddAppCache(manifest_url);
685    OnContentBlocked(CONTENT_SETTINGS_TYPE_COOKIES);
686  } else {
687    allowed_local_shared_objects_.appcaches()->AddAppCache(manifest_url);
688    OnContentAllowed(CONTENT_SETTINGS_TYPE_COOKIES);
689  }
690}
691
692void TabSpecificContentSettings::OnContentSettingChanged(
693    const ContentSettingsPattern& primary_pattern,
694    const ContentSettingsPattern& secondary_pattern,
695    ContentSettingsType content_type,
696    std::string resource_identifier) {
697  const ContentSettingsDetails details(
698      primary_pattern, secondary_pattern, content_type, resource_identifier);
699  const NavigationController& controller = web_contents()->GetController();
700  NavigationEntry* entry = controller.GetVisibleEntry();
701  GURL entry_url;
702  if (entry)
703    entry_url = entry->GetURL();
704  if (details.update_all() ||
705      // The visible NavigationEntry is the URL in the URL field of a tab.
706      // Currently this should be matched by the |primary_pattern|.
707      details.primary_pattern().Matches(entry_url)) {
708    Profile* profile =
709        Profile::FromBrowserContext(web_contents()->GetBrowserContext());
710    RendererContentSettingRules rules;
711    GetRendererContentSettingRules(profile->GetHostContentSettingsMap(),
712                                   &rules);
713    Send(new ChromeViewMsg_SetContentSettingRules(rules));
714  }
715}
716
717void TabSpecificContentSettings::AddSiteDataObserver(
718    SiteDataObserver* observer) {
719  observer_list_.AddObserver(observer);
720}
721
722void TabSpecificContentSettings::RemoveSiteDataObserver(
723    SiteDataObserver* observer) {
724  observer_list_.RemoveObserver(observer);
725}
726
727void TabSpecificContentSettings::NotifySiteDataObservers() {
728  FOR_EACH_OBSERVER(SiteDataObserver, observer_list_, OnSiteDataAccessed());
729}
730