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
DOMStorageMessageFilter(int render_process_id,DOMStorageContextWrapper * context)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
~DOMStorageMessageFilter()32 DOMStorageMessageFilter::~DOMStorageMessageFilter() {
33 DCHECK(!host_.get());
34 }
35
InitializeInSequence()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
UninitializeInSequence()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
OnFilterAdded(IPC::Sender * sender)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
OnFilterRemoved()57 void DOMStorageMessageFilter::OnFilterRemoved() {
58 context_->task_runner()->PostShutdownBlockingTask(
59 FROM_HERE,
60 DOMStorageTaskRunner::PRIMARY_SEQUENCE,
61 base::Bind(&DOMStorageMessageFilter::UninitializeInSequence, this));
62 }
63
OverrideTaskRunnerForMessage(const IPC::Message & message)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
OnMessageReceived(const IPC::Message & message)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
OnOpenStorageArea(int connection_id,int64 namespace_id,const GURL & origin)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
OnCloseStorageArea(int connection_id)102 void DOMStorageMessageFilter::OnCloseStorageArea(int connection_id) {
103 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::IO));
104 host_->CloseStorageArea(connection_id);
105 }
106
OnLoadStorageArea(int connection_id,DOMStorageValuesMap * map,bool * send_log_get_messages)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
OnSetItem(int connection_id,const base::string16 & key,const base::string16 & value,const GURL & page_url)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, ¬_used);
128 Send(new DOMStorageMsg_AsyncOperationComplete(success));
129 }
130
OnLogGetItem(int connection_id,const base::string16 & key,const base::NullableString16 & value)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
OnRemoveItem(int connection_id,const base::string16 & key,const GURL & page_url)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, ¬_used);
147 Send(new DOMStorageMsg_AsyncOperationComplete(true));
148 }
149
OnClear(int connection_id,const GURL & page_url)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
OnFlushMessages()160 void DOMStorageMessageFilter::OnFlushMessages() {
161 // Intentionally empty method body.
162 }
163
OnDOMStorageItemSet(const DOMStorageArea * area,const base::string16 & key,const base::string16 & new_value,const base::NullableString16 & old_value,const GURL & page_url)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
OnDOMStorageItemRemoved(const DOMStorageArea * area,const base::string16 & key,const base::string16 & old_value,const GURL & page_url)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
OnDOMStorageAreaCleared(const DOMStorageArea * area,const GURL & page_url)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
OnDOMSessionStorageReset(int64 namespace_id)196 void DOMStorageMessageFilter::OnDOMSessionStorageReset(int64 namespace_id) {
197 if (host_->ResetOpenAreasForNamespace(namespace_id))
198 Send(new DOMStorageMsg_ResetCachedValues(namespace_id));
199 }
200
SendDOMStorageEvent(const DOMStorageArea * area,const GURL & page_url,const base::NullableString16 & key,const base::NullableString16 & new_value,const base::NullableString16 & old_value)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