OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h" | |
6 | |
7 #include "base/nullable_string16.h" | |
8 #include "chrome/browser/browser_thread.h" | |
9 #include "chrome/browser/in_process_webkit/dom_storage_area.h" | |
10 #include "chrome/browser/in_process_webkit/dom_storage_context.h" | |
11 #include "chrome/browser/in_process_webkit/dom_storage_namespace.h" | |
12 #include "chrome/browser/net/chrome_url_request_context.h" | |
13 #include "chrome/browser/renderer_host/browser_render_process_host.h" | |
14 #include "chrome/browser/renderer_host/render_view_host_notification_task.h" | |
15 #include "chrome/browser/renderer_host/resource_message_filter.h" | |
16 #include "chrome/common/render_messages.h" | |
17 #include "chrome/common/render_messages_params.h" | |
18 #include "googleurl/src/gurl.h" | |
19 | |
20 using WebKit::WebStorageArea; | |
21 | |
22 DOMStorageDispatcherHost* DOMStorageDispatcherHost::storage_event_host_ = NULL; | |
23 const GURL* DOMStorageDispatcherHost::storage_event_url_ = NULL; | |
24 | |
25 DOMStorageDispatcherHost:: | |
26 ScopedStorageEventContext::ScopedStorageEventContext( | |
27 DOMStorageDispatcherHost* dispatcher_host, const GURL* url) { | |
28 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
29 DCHECK(!storage_event_host_); | |
30 DCHECK(!storage_event_url_); | |
31 storage_event_host_ = dispatcher_host; | |
32 storage_event_url_ = url; | |
33 DCHECK(storage_event_host_); | |
34 DCHECK(storage_event_url_); | |
35 } | |
36 | |
37 DOMStorageDispatcherHost:: | |
38 ScopedStorageEventContext::~ScopedStorageEventContext() { | |
39 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
40 DCHECK(storage_event_host_); | |
41 DCHECK(storage_event_url_); | |
42 storage_event_host_ = NULL; | |
43 storage_event_url_ = NULL; | |
44 } | |
45 | |
46 DOMStorageDispatcherHost::DOMStorageDispatcherHost( | |
47 ResourceMessageFilter* resource_message_filter, | |
48 WebKitContext* webkit_context) | |
49 : webkit_context_(webkit_context), | |
50 resource_message_filter_(resource_message_filter), | |
51 process_handle_(0), | |
52 process_id_(0) { | |
53 DCHECK(webkit_context_.get()); | |
54 DCHECK(resource_message_filter_); | |
55 } | |
56 | |
57 DOMStorageDispatcherHost::~DOMStorageDispatcherHost() { | |
58 } | |
59 | |
60 void DOMStorageDispatcherHost::Init(int process_id, | |
61 base::ProcessHandle process_handle) { | |
62 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
63 DCHECK(resource_message_filter_); // Ensure Shutdown() has not been called. | |
64 DCHECK(!process_handle_); // Make sure Init() has not yet been called. | |
65 DCHECK(process_handle); | |
66 Context()->RegisterDispatcherHost(this); | |
67 process_id_ = process_id; | |
68 process_handle_ = process_handle; | |
69 } | |
70 | |
71 void DOMStorageDispatcherHost::Shutdown() { | |
72 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
73 // This is not always true during testing. | |
74 if (process_handle_) | |
75 Context()->UnregisterDispatcherHost(this); | |
76 resource_message_filter_ = NULL; | |
77 } | |
78 | |
79 /* static */ | |
80 void DOMStorageDispatcherHost::DispatchStorageEvent(const NullableString16& key, | |
81 const NullableString16& old_value, const NullableString16& new_value, | |
82 const string16& origin, const GURL& url, bool is_local_storage) { | |
83 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
84 DCHECK(is_local_storage); // Only LocalStorage is implemented right now. | |
85 DCHECK(storage_event_host_); | |
86 ViewMsg_DOMStorageEvent_Params params; | |
87 params.key_ = key; | |
88 params.old_value_ = old_value; | |
89 params.new_value_ = new_value; | |
90 params.origin_ = origin; | |
91 params.url_ = *storage_event_url_; // The url passed in is junk. | |
92 params.storage_type_ = is_local_storage ? DOM_STORAGE_LOCAL | |
93 : DOM_STORAGE_SESSION; | |
94 // The storage_event_host_ is the DOMStorageDispatcherHost that is up in the | |
95 // current call stack since it caused the storage event to fire. | |
96 BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, | |
97 NewRunnableMethod(storage_event_host_, | |
98 &DOMStorageDispatcherHost::OnStorageEvent, params)); | |
99 } | |
100 | |
101 bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& message, | |
102 bool* msg_is_ok) { | |
103 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
104 DCHECK(process_handle_); | |
105 | |
106 bool handled = true; | |
107 IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageDispatcherHost, message, *msg_is_ok) | |
108 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageStorageAreaId, | |
109 OnStorageAreaId) | |
110 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLength, OnLength) | |
111 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageKey, OnKey) | |
112 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageGetItem, OnGetItem) | |
113 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageSetItem, OnSetItem) | |
114 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageRemoveItem, | |
115 OnRemoveItem) | |
116 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageClear, OnClear) | |
117 IPC_MESSAGE_UNHANDLED(handled = false) | |
118 IPC_END_MESSAGE_MAP() | |
119 return handled; | |
120 } | |
121 | |
122 int64 DOMStorageDispatcherHost::CloneSessionStorage(int64 original_id) { | |
123 return Context()->CloneSessionStorage(original_id); | |
124 } | |
125 | |
126 void DOMStorageDispatcherHost::Send(IPC::Message* message) { | |
127 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
128 // TODO(jorlow): Even if we successfully post, I believe it's possible for | |
129 // the task to never run (if the IO thread is already shutting | |
130 // down). We may want to handle this case, though | |
131 // realistically it probably doesn't matter. | |
132 if (!BrowserThread::PostTask( | |
133 BrowserThread::IO, FROM_HERE, NewRunnableMethod( | |
134 this, &DOMStorageDispatcherHost::Send, message))) { | |
135 // The IO thread is dead. | |
136 delete message; | |
137 } | |
138 return; | |
139 } | |
140 | |
141 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
142 if (!resource_message_filter_) | |
143 delete message; | |
144 else | |
145 resource_message_filter_->Send(message); | |
146 } | |
147 | |
148 void DOMStorageDispatcherHost::OnStorageAreaId(int64 namespace_id, | |
149 const string16& origin, | |
150 IPC::Message* reply_msg) { | |
151 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
152 ChromeURLRequestContext* url_request_context = | |
153 resource_message_filter_->GetRequestContextForURL(GURL(origin)); | |
154 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod( | |
155 this, &DOMStorageDispatcherHost::OnStorageAreaIdWebKit, namespace_id, | |
156 origin, reply_msg, | |
157 make_scoped_refptr(url_request_context->host_content_settings_map()))); | |
158 } | |
159 | |
160 void DOMStorageDispatcherHost::OnStorageAreaIdWebKit( | |
161 int64 namespace_id, const string16& origin, IPC::Message* reply_msg, | |
162 HostContentSettingsMap* host_content_settings_map) { | |
163 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
164 DOMStorageNamespace* storage_namespace = | |
165 Context()->GetStorageNamespace(namespace_id, true); | |
166 if (!storage_namespace) { | |
167 BrowserRenderProcessHost::BadMessageTerminateProcess( | |
168 ViewHostMsg_DOMStorageStorageAreaId::ID, process_handle_); | |
169 delete reply_msg; | |
170 return; | |
171 } | |
172 DOMStorageArea* storage_area = storage_namespace->GetStorageArea( | |
173 origin, host_content_settings_map); | |
174 ViewHostMsg_DOMStorageStorageAreaId::WriteReplyParams(reply_msg, | |
175 storage_area->id()); | |
176 Send(reply_msg); | |
177 } | |
178 | |
179 void DOMStorageDispatcherHost::OnLength(int64 storage_area_id, | |
180 IPC::Message* reply_msg) { | |
181 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
182 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod( | |
183 this, &DOMStorageDispatcherHost::OnLength, storage_area_id, reply_msg)); | |
184 return; | |
185 } | |
186 | |
187 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
188 DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id); | |
189 if (!storage_area) { | |
190 BrowserRenderProcessHost::BadMessageTerminateProcess( | |
191 ViewHostMsg_DOMStorageLength::ID, process_handle_); | |
192 delete reply_msg; | |
193 return; | |
194 } | |
195 unsigned length = storage_area->Length(); | |
196 ViewHostMsg_DOMStorageLength::WriteReplyParams(reply_msg, length); | |
197 Send(reply_msg); | |
198 } | |
199 | |
200 void DOMStorageDispatcherHost::OnKey(int64 storage_area_id, unsigned index, | |
201 IPC::Message* reply_msg) { | |
202 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
203 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod( | |
204 this, &DOMStorageDispatcherHost::OnKey, storage_area_id, index, | |
205 reply_msg)); | |
206 return; | |
207 } | |
208 | |
209 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
210 DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id); | |
211 if (!storage_area) { | |
212 BrowserRenderProcessHost::BadMessageTerminateProcess( | |
213 ViewHostMsg_DOMStorageKey::ID, process_handle_); | |
214 delete reply_msg; | |
215 return; | |
216 } | |
217 const NullableString16& key = storage_area->Key(index); | |
218 ViewHostMsg_DOMStorageKey::WriteReplyParams(reply_msg, key); | |
219 Send(reply_msg); | |
220 } | |
221 | |
222 void DOMStorageDispatcherHost::OnGetItem(int64 storage_area_id, | |
223 const string16& key, | |
224 IPC::Message* reply_msg) { | |
225 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
226 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod( | |
227 this, &DOMStorageDispatcherHost::OnGetItem, storage_area_id, key, | |
228 reply_msg)); | |
229 return; | |
230 } | |
231 | |
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
233 DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id); | |
234 if (!storage_area) { | |
235 BrowserRenderProcessHost::BadMessageTerminateProcess( | |
236 ViewHostMsg_DOMStorageGetItem::ID, process_handle_); | |
237 delete reply_msg; | |
238 return; | |
239 } | |
240 const NullableString16& value = storage_area->GetItem(key); | |
241 ViewHostMsg_DOMStorageGetItem::WriteReplyParams(reply_msg, value); | |
242 Send(reply_msg); | |
243 } | |
244 | |
245 void DOMStorageDispatcherHost::OnSetItem( | |
246 int64 storage_area_id, const string16& key, const string16& value, | |
247 const GURL& url, IPC::Message* reply_msg) { | |
248 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
249 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod( | |
250 this, &DOMStorageDispatcherHost::OnSetItem, storage_area_id, key, value, | |
251 url, reply_msg)); | |
252 return; | |
253 } | |
254 | |
255 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
256 DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id); | |
257 if (!storage_area) { | |
258 BrowserRenderProcessHost::BadMessageTerminateProcess( | |
259 ViewHostMsg_DOMStorageSetItem::ID, process_handle_); | |
260 return; | |
261 } | |
262 | |
263 ScopedStorageEventContext scope(this, &url); | |
264 WebStorageArea::Result result; | |
265 NullableString16 old_value = storage_area->SetItem(key, value, &result, this); | |
266 | |
267 // If content was blocked, tell the UI to display the blocked content icon. | |
268 if (reply_msg->routing_id() == MSG_ROUTING_CONTROL) { | |
269 DLOG(WARNING) << "setItem was not given a proper routing id"; | |
270 } else { | |
271 CallRenderViewHostContentSettingsDelegate( | |
272 process_id_, reply_msg->routing_id(), | |
273 &RenderViewHostDelegate::ContentSettings::OnLocalStorageAccessed, | |
274 url, storage_area->owner()->dom_storage_type(), | |
275 result == WebStorageArea::ResultBlockedByPolicy); | |
276 } | |
277 | |
278 ViewHostMsg_DOMStorageSetItem::WriteReplyParams(reply_msg, result, old_value); | |
279 Send(reply_msg); | |
280 } | |
281 | |
282 void DOMStorageDispatcherHost::OnRemoveItem( | |
283 int64 storage_area_id, const string16& key, const GURL& url, | |
284 IPC::Message* reply_msg) { | |
285 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
286 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod( | |
287 this, &DOMStorageDispatcherHost::OnRemoveItem, storage_area_id, key, | |
288 url, reply_msg)); | |
289 return; | |
290 } | |
291 | |
292 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
293 DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id); | |
294 if (!storage_area) { | |
295 BrowserRenderProcessHost::BadMessageTerminateProcess( | |
296 ViewHostMsg_DOMStorageRemoveItem::ID, process_handle_); | |
297 return; | |
298 } | |
299 | |
300 ScopedStorageEventContext scope(this, &url); | |
301 NullableString16 old_value = storage_area->RemoveItem(key); | |
302 ViewHostMsg_DOMStorageRemoveItem::WriteReplyParams(reply_msg, old_value); | |
303 Send(reply_msg); | |
304 } | |
305 | |
306 void DOMStorageDispatcherHost::OnClear(int64 storage_area_id, const GURL& url, | |
307 IPC::Message* reply_msg) { | |
308 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
309 BrowserThread::PostTask(BrowserThread::WEBKIT, FROM_HERE, NewRunnableMethod( | |
310 this, &DOMStorageDispatcherHost::OnClear, storage_area_id, url, | |
311 reply_msg)); | |
312 return; | |
313 } | |
314 | |
315 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::WEBKIT)); | |
316 DOMStorageArea* storage_area = Context()->GetStorageArea(storage_area_id); | |
317 if (!storage_area) { | |
318 BrowserRenderProcessHost::BadMessageTerminateProcess( | |
319 ViewHostMsg_DOMStorageClear::ID, process_handle_); | |
320 return; | |
321 } | |
322 | |
323 ScopedStorageEventContext scope(this, &url); | |
324 bool something_cleared = storage_area->Clear(); | |
325 ViewHostMsg_DOMStorageClear::WriteReplyParams(reply_msg, something_cleared); | |
326 Send(reply_msg); | |
327 } | |
328 | |
329 void DOMStorageDispatcherHost::OnStorageEvent( | |
330 const ViewMsg_DOMStorageEvent_Params& params) { | |
331 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
332 const DOMStorageContext::DispatcherHostSet* set = | |
333 Context()->GetDispatcherHostSet(); | |
334 DOMStorageContext::DispatcherHostSet::const_iterator cur = set->begin(); | |
335 while (cur != set->end()) { | |
336 // The renderer that generates the event handles it itself. | |
337 if (*cur != this) | |
338 (*cur)->Send(new ViewMsg_DOMStorageEvent(params)); | |
339 ++cur; | |
340 } | |
341 } | |
OLD | NEW |