| 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 |