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