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 "content/browser/dom_storage/dom_storage_message_filter.h"
7 #include "base/auto_reset.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"
23 DOMStorageMessageFilter::DOMStorageMessageFilter(
24 int render_process_id,
25 DOMStorageContextWrapper* context)
26 : render_process_id_(render_process_id),
27 context_(context->context()),
28 connection_dispatching_message_for_(0) {
31 DOMStorageMessageFilter::~DOMStorageMessageFilter() {
35 void DOMStorageMessageFilter::InitializeInSequence() {
36 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
37 host_.reset(new DOMStorageHost(context_.get(), render_process_id_));
38 context_->AddEventObserver(this);
41 void DOMStorageMessageFilter::UninitializeInSequence() {
42 // TODO(michaeln): Restore this DCHECK once crbug/166470 and crbug/164403
44 // DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
45 context_->RemoveEventObserver(this);
49 void DOMStorageMessageFilter::OnFilterAdded(IPC::Channel* channel) {
50 context_->task_runner()->PostShutdownBlockingTask(
52 DOMStorageTaskRunner::PRIMARY_SEQUENCE,
53 base::Bind(&DOMStorageMessageFilter::InitializeInSequence, this));
56 void DOMStorageMessageFilter::OnFilterRemoved() {
57 context_->task_runner()->PostShutdownBlockingTask(
59 DOMStorageTaskRunner::PRIMARY_SEQUENCE,
60 base::Bind(&DOMStorageMessageFilter::UninitializeInSequence, this));
63 base::TaskRunner* DOMStorageMessageFilter::OverrideTaskRunnerForMessage(
64 const IPC::Message& message) {
65 if (IPC_MESSAGE_CLASS(message) == DOMStorageMsgStart)
66 return context_->task_runner();
70 bool DOMStorageMessageFilter::OnMessageReceived(const IPC::Message& message,
71 bool* message_was_ok) {
72 if (IPC_MESSAGE_CLASS(message) != DOMStorageMsgStart)
74 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
78 IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageMessageFilter, message, *message_was_ok)
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)
92 void DOMStorageMessageFilter::OnOpenStorageArea(int connection_id,
95 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
96 if (!host_->OpenStorageArea(connection_id, namespace_id, origin)) {
97 RecordAction(UserMetricsAction("BadMessageTerminate_DSMF_1"));
102 void DOMStorageMessageFilter::OnCloseStorageArea(int connection_id) {
103 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
104 host_->CloseStorageArea(connection_id);
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(UserMetricsAction("BadMessageTerminate_DSMF_2"));
113 BadMessageReceived();
115 Send(new DOMStorageMsg_AsyncOperationComplete(true));
118 void 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_,
125 base::NullableString16 not_used;
126 bool success = host_->SetAreaItem(connection_id, key, value,
127 page_url, ¬_used);
128 Send(new DOMStorageMsg_AsyncOperationComplete(success));
131 void DOMStorageMessageFilter::OnLogGetItem(
132 int connection_id, const string16& key,
133 const base::NullableString16& value) {
134 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
135 host_->LogGetAreaItem(connection_id, key, value);
138 void DOMStorageMessageFilter::OnRemoveItem(
139 int connection_id, const 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_,
146 host_->RemoveAreaItem(connection_id, key, page_url, ¬_used);
147 Send(new DOMStorageMsg_AsyncOperationComplete(true));
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_,
156 host_->ClearArea(connection_id, page_url);
157 Send(new DOMStorageMsg_AsyncOperationComplete(true));
160 void DOMStorageMessageFilter::OnFlushMessages() {
161 // Intentionally empty method body.
164 void DOMStorageMessageFilter::OnDOMStorageItemSet(
165 const DOMStorageArea* area,
167 const 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),
176 void DOMStorageMessageFilter::OnDOMStorageItemRemoved(
177 const DOMStorageArea* area,
179 const 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));
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());
196 void DOMStorageMessageFilter::SendDOMStorageEvent(
197 const DOMStorageArea* area,
198 const GURL& page_url,
199 const base::NullableString16& key,
200 const base::NullableString16& new_value,
201 const base::NullableString16& old_value) {
202 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
203 // Only send mutation events to processes which have the area open.
204 bool originated_in_process = connection_dispatching_message_for_ != 0;
205 if (originated_in_process ||
206 host_->HasAreaOpen(area->namespace_id(), area->origin())) {
207 DOMStorageMsg_Event_Params params;
208 params.origin = area->origin();
209 params.page_url = page_url;
210 params.connection_id = connection_dispatching_message_for_;
212 params.new_value = new_value;
213 params.old_value = old_value;
214 params.namespace_id = area->namespace_id();
215 Send(new DOMStorageMsg_Event(params));
219 } // namespace content