Home | History | Annotate | Download | only in dom_storage
      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 "content/browser/dom_storage/dom_storage_message_filter.h"
      6 
      7 #include "base/auto_reset.h"
      8 #include "base/bind.h"
      9 #include "base/strings/nullable_string16.h"
     10 #include "base/strings/utf_string_conversions.h"
     11 #include "base/threading/sequenced_worker_pool.h"
     12 #include "content/browser/dom_storage/dom_storage_area.h"
     13 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
     14 #include "content/browser/dom_storage/dom_storage_host.h"
     15 #include "content/browser/dom_storage/dom_storage_namespace.h"
     16 #include "content/browser/dom_storage/dom_storage_task_runner.h"
     17 #include "content/common/dom_storage/dom_storage_messages.h"
     18 #include "content/public/browser/user_metrics.h"
     19 #include "url/gurl.h"
     20 
     21 namespace content {
     22 
     23 DOMStorageMessageFilter::DOMStorageMessageFilter(
     24     int unused,
     25     DOMStorageContextWrapper* context)
     26     : context_(context->context()),
     27       connection_dispatching_message_for_(0) {
     28 }
     29 
     30 DOMStorageMessageFilter::~DOMStorageMessageFilter() {
     31   DCHECK(!host_.get());
     32 }
     33 
     34 void DOMStorageMessageFilter::InitializeInSequence() {
     35   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     36   host_.reset(new DOMStorageHost(context_.get()));
     37   context_->AddEventObserver(this);
     38 }
     39 
     40 void DOMStorageMessageFilter::UninitializeInSequence() {
     41   // TODO(michaeln): Restore this DCHECK once crbug/166470 and crbug/164403
     42   // are resolved.
     43   // DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     44   context_->RemoveEventObserver(this);
     45   host_.reset();
     46 }
     47 
     48 void DOMStorageMessageFilter::OnFilterAdded(IPC::Channel* channel) {
     49   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     50   BrowserMessageFilter::OnFilterAdded(channel);
     51   context_->task_runner()->PostShutdownBlockingTask(
     52       FROM_HERE,
     53       DOMStorageTaskRunner::PRIMARY_SEQUENCE,
     54       base::Bind(&DOMStorageMessageFilter::InitializeInSequence, this));
     55 }
     56 
     57 void DOMStorageMessageFilter::OnFilterRemoved() {
     58   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     59   BrowserMessageFilter::OnFilterRemoved();
     60   context_->task_runner()->PostShutdownBlockingTask(
     61       FROM_HERE,
     62       DOMStorageTaskRunner::PRIMARY_SEQUENCE,
     63       base::Bind(&DOMStorageMessageFilter::UninitializeInSequence, this));
     64 }
     65 
     66 base::TaskRunner* DOMStorageMessageFilter::OverrideTaskRunnerForMessage(
     67     const IPC::Message& message) {
     68   if (IPC_MESSAGE_CLASS(message) == DOMStorageMsgStart)
     69     return context_->task_runner();
     70   return NULL;
     71 }
     72 
     73 bool DOMStorageMessageFilter::OnMessageReceived(const IPC::Message& message,
     74                                                 bool* message_was_ok) {
     75   if (IPC_MESSAGE_CLASS(message) != DOMStorageMsgStart)
     76     return false;
     77   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     78   DCHECK(host_.get());
     79 
     80   bool handled = true;
     81   IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageMessageFilter, message, *message_was_ok)
     82     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_OpenStorageArea, OnOpenStorageArea)
     83     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_CloseStorageArea, OnCloseStorageArea)
     84     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_LoadStorageArea, OnLoadStorageArea)
     85     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_SetItem, OnSetItem)
     86     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_RemoveItem, OnRemoveItem)
     87     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Clear, OnClear)
     88     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_FlushMessages, OnFlushMessages)
     89     IPC_MESSAGE_UNHANDLED(handled = false)
     90   IPC_END_MESSAGE_MAP()
     91   return handled;
     92 }
     93 
     94 void DOMStorageMessageFilter::OnOpenStorageArea(int connection_id,
     95                                                 int64 namespace_id,
     96                                                 const GURL& origin) {
     97   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     98   if (!host_->OpenStorageArea(connection_id, namespace_id, origin)) {
     99     RecordAction(UserMetricsAction("BadMessageTerminate_DSMF_1"));
    100     BadMessageReceived();
    101   }
    102 }
    103 
    104 void DOMStorageMessageFilter::OnCloseStorageArea(int connection_id) {
    105   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    106   host_->CloseStorageArea(connection_id);
    107 }
    108 
    109 void DOMStorageMessageFilter::OnLoadStorageArea(int connection_id,
    110                                                 DOMStorageValuesMap* map) {
    111   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    112   if (!host_->ExtractAreaValues(connection_id, map)) {
    113     RecordAction(UserMetricsAction("BadMessageTerminate_DSMF_2"));
    114     BadMessageReceived();
    115   }
    116   Send(new DOMStorageMsg_AsyncOperationComplete(true));
    117 }
    118 
    119 void DOMStorageMessageFilter::OnSetItem(
    120     int connection_id, const string16& key,
    121     const string16& value, const GURL& page_url) {
    122   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    123   DCHECK_EQ(0, connection_dispatching_message_for_);
    124   base::AutoReset<int> auto_reset(&connection_dispatching_message_for_,
    125                             connection_id);
    126   base::NullableString16 not_used;
    127   bool success = host_->SetAreaItem(connection_id, key, value,
    128                                     page_url, &not_used);
    129   Send(new DOMStorageMsg_AsyncOperationComplete(success));
    130 }
    131 
    132 void DOMStorageMessageFilter::OnRemoveItem(
    133     int connection_id, const string16& key,
    134     const GURL& page_url) {
    135   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    136   DCHECK_EQ(0, connection_dispatching_message_for_);
    137   base::AutoReset<int> auto_reset(&connection_dispatching_message_for_,
    138                             connection_id);
    139   string16 not_used;
    140   host_->RemoveAreaItem(connection_id, key, page_url, &not_used);
    141   Send(new DOMStorageMsg_AsyncOperationComplete(true));
    142 }
    143 
    144 void DOMStorageMessageFilter::OnClear(
    145     int connection_id, const GURL& page_url) {
    146   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    147   DCHECK_EQ(0, connection_dispatching_message_for_);
    148   base::AutoReset<int> auto_reset(&connection_dispatching_message_for_,
    149                             connection_id);
    150   host_->ClearArea(connection_id, page_url);
    151   Send(new DOMStorageMsg_AsyncOperationComplete(true));
    152 }
    153 
    154 void DOMStorageMessageFilter::OnFlushMessages() {
    155   // Intentionally empty method body.
    156 }
    157 
    158 void DOMStorageMessageFilter::OnDOMStorageItemSet(
    159     const DOMStorageArea* area,
    160     const string16& key,
    161     const string16& new_value,
    162     const base::NullableString16& old_value,
    163     const GURL& page_url) {
    164   SendDOMStorageEvent(area, page_url,
    165                       base::NullableString16(key, false),
    166                       base::NullableString16(new_value, false),
    167                       old_value);
    168 }
    169 
    170 void DOMStorageMessageFilter::OnDOMStorageItemRemoved(
    171     const DOMStorageArea* area,
    172     const string16& key,
    173     const string16& old_value,
    174     const GURL& page_url) {
    175   SendDOMStorageEvent(area, page_url,
    176                       base::NullableString16(key, false),
    177                       base::NullableString16(),
    178                       base::NullableString16(old_value, false));
    179 }
    180 
    181 void DOMStorageMessageFilter::OnDOMStorageAreaCleared(
    182     const DOMStorageArea* area,
    183     const GURL& page_url) {
    184   SendDOMStorageEvent(area, page_url,
    185                       base::NullableString16(),
    186                       base::NullableString16(),
    187                       base::NullableString16());
    188 }
    189 
    190 void DOMStorageMessageFilter::SendDOMStorageEvent(
    191     const DOMStorageArea* area,
    192     const GURL& page_url,
    193     const base::NullableString16& key,
    194     const base::NullableString16& new_value,
    195     const base::NullableString16& old_value) {
    196   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    197   // Only send mutation events to processes which have the area open.
    198   bool originated_in_process = connection_dispatching_message_for_ != 0;
    199   if (originated_in_process ||
    200       host_->HasAreaOpen(area->namespace_id(), area->origin())) {
    201     DOMStorageMsg_Event_Params params;
    202     params.origin = area->origin();
    203     params.page_url = page_url;
    204     params.connection_id = connection_dispatching_message_for_;
    205     params.key = key;
    206     params.new_value = new_value;
    207     params.old_value = old_value;
    208     params.namespace_id = area->namespace_id();
    209     Send(new DOMStorageMsg_Event(params));
    210   }
    211 }
    212 
    213 }  // namespace content
    214