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 render_process_id,
     25     DOMStorageContextWrapper* context)
     26     : BrowserMessageFilter(DOMStorageMsgStart),
     27       render_process_id_(render_process_id),
     28       context_(context->context()),
     29       connection_dispatching_message_for_(0) {
     30 }
     31 
     32 DOMStorageMessageFilter::~DOMStorageMessageFilter() {
     33   DCHECK(!host_.get());
     34 }
     35 
     36 void DOMStorageMessageFilter::InitializeInSequence() {
     37   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     38   host_.reset(new DOMStorageHost(context_.get(), render_process_id_));
     39   context_->AddEventObserver(this);
     40 }
     41 
     42 void DOMStorageMessageFilter::UninitializeInSequence() {
     43   // TODO(michaeln): Restore this DCHECK once crbug/166470 and crbug/164403
     44   // are resolved.
     45   // DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     46   context_->RemoveEventObserver(this);
     47   host_.reset();
     48 }
     49 
     50 void DOMStorageMessageFilter::OnFilterAdded(IPC::Sender* sender) {
     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   context_->task_runner()->PostShutdownBlockingTask(
     59       FROM_HERE,
     60       DOMStorageTaskRunner::PRIMARY_SEQUENCE,
     61       base::Bind(&DOMStorageMessageFilter::UninitializeInSequence, this));
     62 }
     63 
     64 base::TaskRunner* DOMStorageMessageFilter::OverrideTaskRunnerForMessage(
     65     const IPC::Message& message) {
     66   if (IPC_MESSAGE_CLASS(message) == DOMStorageMsgStart)
     67     return context_->task_runner();
     68   return NULL;
     69 }
     70 
     71 bool DOMStorageMessageFilter::OnMessageReceived(const IPC::Message& message) {
     72   if (IPC_MESSAGE_CLASS(message) != DOMStorageMsgStart)
     73     return false;
     74   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     75   DCHECK(host_.get());
     76 
     77   bool handled = true;
     78   IPC_BEGIN_MESSAGE_MAP(DOMStorageMessageFilter, message)
     79     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_OpenStorageArea, OnOpenStorageArea)
     80     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_CloseStorageArea, OnCloseStorageArea)
     81     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_LoadStorageArea, OnLoadStorageArea)
     82     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_SetItem, OnSetItem)
     83     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_LogGetItem, OnLogGetItem)
     84     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_RemoveItem, OnRemoveItem)
     85     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_Clear, OnClear)
     86     IPC_MESSAGE_HANDLER(DOMStorageHostMsg_FlushMessages, OnFlushMessages)
     87     IPC_MESSAGE_UNHANDLED(handled = false)
     88   IPC_END_MESSAGE_MAP()
     89   return handled;
     90 }
     91 
     92 void DOMStorageMessageFilter::OnOpenStorageArea(int connection_id,
     93                                                 int64 namespace_id,
     94                                                 const GURL& origin) {
     95   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
     96   if (!host_->OpenStorageArea(connection_id, namespace_id, origin)) {
     97     RecordAction(base::UserMetricsAction("BadMessageTerminate_DSMF_1"));
     98     BadMessageReceived();
     99   }
    100 }
    101 
    102 void DOMStorageMessageFilter::OnCloseStorageArea(int connection_id) {
    103   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    104   host_->CloseStorageArea(connection_id);
    105 }
    106 
    107 void DOMStorageMessageFilter::OnLoadStorageArea(int connection_id,
    108                                                 DOMStorageValuesMap* map,
    109                                                 bool* send_log_get_messages) {
    110   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    111   if (!host_->ExtractAreaValues(connection_id, map, send_log_get_messages)) {
    112     RecordAction(base::UserMetricsAction("BadMessageTerminate_DSMF_2"));
    113     BadMessageReceived();
    114   }
    115   Send(new DOMStorageMsg_AsyncOperationComplete(true));
    116 }
    117 
    118 void DOMStorageMessageFilter::OnSetItem(
    119     int connection_id, const base::string16& key,
    120     const base::string16& value, const GURL& page_url) {
    121   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    122   DCHECK_EQ(0, connection_dispatching_message_for_);
    123   base::AutoReset<int> auto_reset(&connection_dispatching_message_for_,
    124                             connection_id);
    125   base::NullableString16 not_used;
    126   bool success = host_->SetAreaItem(connection_id, key, value,
    127                                     page_url, &not_used);
    128   Send(new DOMStorageMsg_AsyncOperationComplete(success));
    129 }
    130 
    131 void DOMStorageMessageFilter::OnLogGetItem(
    132     int connection_id, const base::string16& key,
    133     const base::NullableString16& value) {
    134   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    135   host_->LogGetAreaItem(connection_id, key, value);
    136 }
    137 
    138 void DOMStorageMessageFilter::OnRemoveItem(
    139     int connection_id, const base::string16& key,
    140     const GURL& page_url) {
    141   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    142   DCHECK_EQ(0, connection_dispatching_message_for_);
    143   base::AutoReset<int> auto_reset(&connection_dispatching_message_for_,
    144                             connection_id);
    145   base::string16 not_used;
    146   host_->RemoveAreaItem(connection_id, key, page_url, &not_used);
    147   Send(new DOMStorageMsg_AsyncOperationComplete(true));
    148 }
    149 
    150 void DOMStorageMessageFilter::OnClear(
    151     int connection_id, const GURL& page_url) {
    152   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    153   DCHECK_EQ(0, connection_dispatching_message_for_);
    154   base::AutoReset<int> auto_reset(&connection_dispatching_message_for_,
    155                             connection_id);
    156   host_->ClearArea(connection_id, page_url);
    157   Send(new DOMStorageMsg_AsyncOperationComplete(true));
    158 }
    159 
    160 void DOMStorageMessageFilter::OnFlushMessages() {
    161   // Intentionally empty method body.
    162 }
    163 
    164 void DOMStorageMessageFilter::OnDOMStorageItemSet(
    165     const DOMStorageArea* area,
    166     const base::string16& key,
    167     const base::string16& new_value,
    168     const base::NullableString16& old_value,
    169     const GURL& page_url) {
    170   SendDOMStorageEvent(area, page_url,
    171                       base::NullableString16(key, false),
    172                       base::NullableString16(new_value, false),
    173                       old_value);
    174 }
    175 
    176 void DOMStorageMessageFilter::OnDOMStorageItemRemoved(
    177     const DOMStorageArea* area,
    178     const base::string16& key,
    179     const base::string16& old_value,
    180     const GURL& page_url) {
    181   SendDOMStorageEvent(area, page_url,
    182                       base::NullableString16(key, false),
    183                       base::NullableString16(),
    184                       base::NullableString16(old_value, false));
    185 }
    186 
    187 void DOMStorageMessageFilter::OnDOMStorageAreaCleared(
    188     const DOMStorageArea* area,
    189     const GURL& page_url) {
    190   SendDOMStorageEvent(area, page_url,
    191                       base::NullableString16(),
    192                       base::NullableString16(),
    193                       base::NullableString16());
    194 }
    195 
    196 void DOMStorageMessageFilter::OnDOMSessionStorageReset(int64 namespace_id) {
    197   if (host_->ResetOpenAreasForNamespace(namespace_id))
    198     Send(new DOMStorageMsg_ResetCachedValues(namespace_id));
    199 }
    200 
    201 void DOMStorageMessageFilter::SendDOMStorageEvent(
    202     const DOMStorageArea* area,
    203     const GURL& page_url,
    204     const base::NullableString16& key,
    205     const base::NullableString16& new_value,
    206     const base::NullableString16& old_value) {
    207   DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
    208   // Only send mutation events to processes which have the area open.
    209   bool originated_in_process = connection_dispatching_message_for_ != 0;
    210   int64 alias_namespace_id = area->namespace_id();
    211   if (host_->HasAreaOpen(area->namespace_id(), area->origin(),
    212                          &alias_namespace_id) ||
    213       originated_in_process) {
    214     DOMStorageMsg_Event_Params params;
    215     params.origin = area->origin();
    216     params.page_url = page_url;
    217     params.connection_id = connection_dispatching_message_for_;
    218     params.key = key;
    219     params.new_value = new_value;
    220     params.old_value = old_value;
    221     params.namespace_id = alias_namespace_id;
    222     Send(new DOMStorageMsg_Event(params));
    223   }
    224 }
    225 
    226 }  // namespace content
    227