OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
3 // LICENSE file. | 3 // LICENSE file. |
4 | 4 |
5 #include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h" | 5 #include "chrome/browser/in_process_webkit/dom_storage_dispatcher_host.h" |
6 | 6 |
| 7 #include "base/stl_util-inl.h" |
| 8 #include "base/string16.h" |
7 #include "chrome/browser/chrome_thread.h" | 9 #include "chrome/browser/chrome_thread.h" |
8 #include "chrome/browser/in_process_webkit/webkit_context.h" | 10 #include "chrome/browser/in_process_webkit/webkit_context.h" |
9 #include "chrome/browser/in_process_webkit/webkit_thread.h" | 11 #include "chrome/browser/in_process_webkit/webkit_thread.h" |
| 12 #include "chrome/common/render_messages.h" |
| 13 #include "webkit/api/public/WebKit.h" |
| 14 #include "webkit/api/public/WebStorageArea.h" |
| 15 #include "webkit/api/public/WebStorageNamespace.h" |
| 16 #include "webkit/api/public/WebString.h" |
| 17 |
| 18 using WebKit::WebStorageArea; |
| 19 using WebKit::WebStorageNamespace; |
10 | 20 |
11 DOMStorageDispatcherHost::DOMStorageDispatcherHost( | 21 DOMStorageDispatcherHost::DOMStorageDispatcherHost( |
12 IPC::Message::Sender* message_sender, | 22 IPC::Message::Sender* message_sender, |
13 WebKitContext* webkit_context, | 23 WebKitContext* webkit_context, |
14 WebKitThread* webkit_thread) | 24 WebKitThread* webkit_thread) |
15 : webkit_context_(webkit_context), | 25 : webkit_context_(webkit_context), |
16 webkit_thread_(webkit_thread), | 26 webkit_thread_(webkit_thread), |
17 message_sender_(message_sender) { | 27 message_sender_(message_sender), |
| 28 last_storage_area_id_(0), |
| 29 last_storage_namespace_id_(0), |
| 30 ever_used_(false), |
| 31 shutdown_(false) { |
18 DCHECK(webkit_context_.get()); | 32 DCHECK(webkit_context_.get()); |
19 DCHECK(webkit_thread_); | 33 DCHECK(webkit_thread_); |
20 DCHECK(message_sender_); | 34 DCHECK(message_sender_); |
21 } | 35 } |
22 | 36 |
23 DOMStorageDispatcherHost::~DOMStorageDispatcherHost() { | 37 DOMStorageDispatcherHost::~DOMStorageDispatcherHost() { |
24 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); | 38 DCHECK(!ever_used_ || ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
25 message_sender_ = NULL; | 39 DCHECK(shutdown_); |
26 } | 40 } |
27 | 41 |
28 bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& msg) { | 42 void DOMStorageDispatcherHost::Shutdown() { |
29 // TODO(jorlow): Implement DOM Storage's message handler...and the rest | 43 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
30 // of DOM Storage. :-) | 44 message_sender_ = NULL; |
31 return false; | 45 if (!ever_used_) { |
| 46 shutdown_ = true; |
| 47 return; |
| 48 } |
| 49 |
| 50 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 51 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 52 &DOMStorageDispatcherHost::Shutdown)); |
| 53 return; |
| 54 } |
| 55 |
| 56 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 57 DCHECK(ever_used_); |
| 58 DCHECK(!message_sender_); |
| 59 DCHECK(!shutdown_); |
| 60 |
| 61 STLDeleteContainerPairSecondPointers(storage_area_map_.begin(), |
| 62 storage_area_map_.end()); |
| 63 STLDeleteContainerPairSecondPointers(storage_namespace_map_.begin(), |
| 64 storage_namespace_map_.end()); |
| 65 shutdown_ = true; |
| 66 } |
| 67 |
| 68 bool DOMStorageDispatcherHost::OnMessageReceived(const IPC::Message& message, |
| 69 bool *msg_is_ok) { |
| 70 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::IO)); |
| 71 DCHECK(!shutdown_); |
| 72 bool handled = true; |
| 73 IPC_BEGIN_MESSAGE_MAP_EX(DOMStorageDispatcherHost, message, *msg_is_ok) |
| 74 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageNamespaceId, |
| 75 OnNamespaceId) |
| 76 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageCloneNamespaceId, |
| 77 OnCloneNamespaceId) |
| 78 IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageDerefNamespaceId, |
| 79 OnDerefNamespaceId) |
| 80 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageStorageAreaId, |
| 81 OnStorageAreaId) |
| 82 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLock, OnLock) |
| 83 IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageUnlock, OnUnlock) |
| 84 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageLength, OnLength) |
| 85 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageKey, OnKey) |
| 86 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageGetItem, OnGetItem) |
| 87 IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageSetItem, OnSetItem) |
| 88 IPC_MESSAGE_HANDLER(ViewHostMsg_DOMStorageRemoveItem, OnRemoveItem) |
| 89 IPC_MESSAGE_HANDLER_DELAY_REPLY(ViewHostMsg_DOMStorageClear, OnClear) |
| 90 IPC_MESSAGE_UNHANDLED(handled = false) |
| 91 IPC_END_MESSAGE_MAP() |
| 92 if (handled) |
| 93 ever_used_ = true; |
| 94 return handled; |
32 } | 95 } |
33 | 96 |
34 void DOMStorageDispatcherHost::Send(IPC::Message* message) { | 97 void DOMStorageDispatcherHost::Send(IPC::Message* message) { |
| 98 DCHECK(!shutdown_); |
35 if (!message_sender_) { | 99 if (!message_sender_) { |
36 delete message; | 100 delete message; |
37 return; | 101 return; |
38 } | 102 } |
39 | 103 |
40 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { | 104 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
41 message_sender_->Send(message); | 105 message_sender_->Send(message); |
42 return; | 106 return; |
43 } | 107 } |
44 | 108 |
45 // The IO thread can't dissapear while the WebKit thread is still running. | 109 // The IO thread can't go away while the WebKit thread is still running. |
46 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); | 110 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
47 MessageLoop* io_loop = ChromeThread::GetMessageLoop(ChromeThread::IO); | 111 webkit_thread_->PostIOThreadTask(FROM_HERE, NewRunnableMethod(this, |
48 CancelableTask* task = NewRunnableMethod(this, | 112 &DOMStorageDispatcherHost::Send, message)); |
49 &DOMStorageDispatcherHost::Send, | 113 } |
50 message); | 114 |
51 io_loop->PostTask(FROM_HERE, task); | 115 void DOMStorageDispatcherHost::OnNamespaceId(bool is_local_storage, |
52 } | 116 IPC::Message* reply_msg) { |
| 117 DCHECK(!shutdown_); |
| 118 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 119 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 120 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 121 &DOMStorageDispatcherHost::OnNamespaceId, |
| 122 is_local_storage, reply_msg)); |
| 123 return; |
| 124 } |
| 125 |
| 126 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 127 WebStorageNamespace* new_namespace; |
| 128 if (is_local_storage) { |
| 129 new_namespace = WebStorageNamespace::createLocalStorageNamespace( |
| 130 GetLocalStoragePath()); |
| 131 } else { |
| 132 new_namespace = WebStorageNamespace::createSessionStorageNamespace(); |
| 133 } |
| 134 int64 new_namespace_id = AddStorageNamespace(new_namespace); |
| 135 ViewHostMsg_DOMStorageNamespaceId::WriteReplyParams(reply_msg, |
| 136 new_namespace_id); |
| 137 Send(reply_msg); |
| 138 } |
| 139 |
| 140 void DOMStorageDispatcherHost::OnCloneNamespaceId(int64 namespace_id, |
| 141 IPC::Message* reply_msg) { |
| 142 DCHECK(!shutdown_); |
| 143 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 144 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 145 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 146 &DOMStorageDispatcherHost::OnCloneNamespaceId, |
| 147 namespace_id, reply_msg)); |
| 148 return; |
| 149 } |
| 150 |
| 151 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 152 WebStorageNamespace* existing_namespace = GetStorageNamespace(namespace_id); |
| 153 CHECK(existing_namespace); // TODO(jorlow): Do better than this. |
| 154 WebStorageNamespace* new_namespace = existing_namespace->copy(); |
| 155 int64 new_namespace_id = AddStorageNamespace(new_namespace); |
| 156 ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg, |
| 157 new_namespace_id); |
| 158 Send(reply_msg); |
| 159 } |
| 160 |
| 161 void DOMStorageDispatcherHost::OnDerefNamespaceId(int64 namespace_id) { |
| 162 DCHECK(!shutdown_); |
| 163 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 164 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 165 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 166 &DOMStorageDispatcherHost::OnDerefNamespaceId, namespace_id)); |
| 167 return; |
| 168 } |
| 169 |
| 170 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 171 // TODO(jorlow): We need to track resources so we can free them. |
| 172 } |
| 173 |
| 174 void DOMStorageDispatcherHost::OnStorageAreaId(int64 namespace_id, |
| 175 const string16& origin, |
| 176 IPC::Message* reply_msg) { |
| 177 DCHECK(!shutdown_); |
| 178 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 179 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 180 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 181 &DOMStorageDispatcherHost::OnStorageAreaId, |
| 182 namespace_id, origin, reply_msg)); |
| 183 return; |
| 184 } |
| 185 |
| 186 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 187 WebStorageNamespace* storage_namespace = GetStorageNamespace(namespace_id); |
| 188 CHECK(storage_namespace); // TODO(jorlow): Do better than this. |
| 189 WebStorageArea* storage_area = storage_namespace->createStorageArea(origin); |
| 190 int64 storage_area_id = AddStorageArea(storage_area); |
| 191 ViewHostMsg_DOMStorageCloneNamespaceId::WriteReplyParams(reply_msg, |
| 192 storage_area_id); |
| 193 Send(reply_msg); |
| 194 } |
| 195 |
| 196 void DOMStorageDispatcherHost::OnLock(int64 storage_area_id, |
| 197 IPC::Message* reply_msg) { |
| 198 DCHECK(!shutdown_); |
| 199 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 200 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 201 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 202 &DOMStorageDispatcherHost::OnLock, storage_area_id, reply_msg)); |
| 203 return; |
| 204 } |
| 205 |
| 206 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 207 bool invalidate_cache; |
| 208 size_t bytes_left_in_quota; |
| 209 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 210 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 211 storage_area->lock(invalidate_cache, bytes_left_in_quota); |
| 212 ViewHostMsg_DOMStorageLock::WriteReplyParams(reply_msg, invalidate_cache, |
| 213 bytes_left_in_quota); |
| 214 Send(reply_msg); |
| 215 } |
| 216 |
| 217 void DOMStorageDispatcherHost::OnUnlock(int64 storage_area_id) { |
| 218 DCHECK(!shutdown_); |
| 219 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 220 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 221 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 222 &DOMStorageDispatcherHost::OnUnlock, storage_area_id)); |
| 223 return; |
| 224 } |
| 225 |
| 226 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 227 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 228 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 229 storage_area->unlock(); |
| 230 } |
| 231 |
| 232 void DOMStorageDispatcherHost::OnLength(int64 storage_area_id, |
| 233 IPC::Message* reply_msg) { |
| 234 DCHECK(!shutdown_); |
| 235 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 236 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 237 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 238 &DOMStorageDispatcherHost::OnLength, storage_area_id, reply_msg)); |
| 239 return; |
| 240 } |
| 241 |
| 242 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 243 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 244 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 245 unsigned length = storage_area->length(); |
| 246 ViewHostMsg_DOMStorageLength::WriteReplyParams(reply_msg, length); |
| 247 Send(reply_msg); |
| 248 } |
| 249 |
| 250 void DOMStorageDispatcherHost::OnKey(int64 storage_area_id, unsigned index, |
| 251 IPC::Message* reply_msg) { |
| 252 DCHECK(!shutdown_); |
| 253 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 254 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 255 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 256 &DOMStorageDispatcherHost::OnKey, storage_area_id, index, reply_msg)); |
| 257 return; |
| 258 } |
| 259 |
| 260 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 261 bool key_exception = false; |
| 262 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 263 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 264 string16 key = storage_area->key(index, key_exception); |
| 265 ViewHostMsg_DOMStorageKey::WriteReplyParams(reply_msg, key_exception, key); |
| 266 Send(reply_msg); |
| 267 } |
| 268 |
| 269 void DOMStorageDispatcherHost::OnGetItem(int64 storage_area_id, |
| 270 const string16& key, |
| 271 IPC::Message* reply_msg) { |
| 272 DCHECK(!shutdown_); |
| 273 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 274 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 275 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 276 &DOMStorageDispatcherHost::OnGetItem, |
| 277 storage_area_id, key, reply_msg)); |
| 278 return; |
| 279 } |
| 280 |
| 281 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 282 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 283 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 284 WebKit::WebString value = storage_area->getItem(key); |
| 285 ViewHostMsg_DOMStorageGetItem::WriteReplyParams(reply_msg, (string16)value, |
| 286 value.isNull()); |
| 287 Send(reply_msg); |
| 288 } |
| 289 |
| 290 void DOMStorageDispatcherHost::OnSetItem(int64 storage_area_id, |
| 291 const string16& key, |
| 292 const string16& value) { |
| 293 DCHECK(!shutdown_); |
| 294 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 295 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 296 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 297 &DOMStorageDispatcherHost::OnSetItem, storage_area_id, key, value)); |
| 298 return; |
| 299 } |
| 300 |
| 301 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 302 bool quota_exception = false; |
| 303 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 304 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 305 storage_area->setItem(key, value, quota_exception); |
| 306 DCHECK(!quota_exception); // This is tracked by the renderer. |
| 307 } |
| 308 |
| 309 void DOMStorageDispatcherHost::OnRemoveItem(int64 storage_area_id, |
| 310 const string16& key) { |
| 311 DCHECK(!shutdown_); |
| 312 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 313 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 314 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 315 &DOMStorageDispatcherHost::OnRemoveItem, storage_area_id, key)); |
| 316 return; |
| 317 } |
| 318 |
| 319 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 320 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 321 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 322 storage_area->removeItem(key); |
| 323 } |
| 324 |
| 325 void DOMStorageDispatcherHost::OnClear(int64 storage_area_id, |
| 326 IPC::Message* reply_msg) { |
| 327 DCHECK(!shutdown_); |
| 328 if (ChromeThread::CurrentlyOn(ChromeThread::IO)) { |
| 329 MessageLoop* webkit_loop = webkit_thread_->GetMessageLoop(); |
| 330 webkit_loop->PostTask(FROM_HERE, NewRunnableMethod(this, |
| 331 &DOMStorageDispatcherHost::OnClear, storage_area_id, reply_msg)); |
| 332 return; |
| 333 } |
| 334 |
| 335 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::WEBKIT)); |
| 336 // TODO(jorlow): Return the total quota for this domain. |
| 337 size_t bytes_left_in_quota = 0; |
| 338 WebStorageArea* storage_area = GetStorageArea(storage_area_id); |
| 339 CHECK(storage_area); // TODO(jorlow): Do better than this. |
| 340 storage_area->clear(); |
| 341 ViewHostMsg_DOMStorageClear::WriteReplyParams(reply_msg, |
| 342 bytes_left_in_quota); |
| 343 Send(reply_msg); |
| 344 } |
| 345 |
| 346 WebStorageArea* DOMStorageDispatcherHost::GetStorageArea(int64 id) { |
| 347 StorageAreaMap::iterator iterator = storage_area_map_.find(id); |
| 348 if (iterator == storage_area_map_.end()) |
| 349 return NULL; |
| 350 return iterator->second; |
| 351 } |
| 352 |
| 353 WebStorageNamespace* DOMStorageDispatcherHost::GetStorageNamespace(int64 id) { |
| 354 StorageNamespaceMap::iterator iterator = storage_namespace_map_.find(id); |
| 355 if (iterator == storage_namespace_map_.end()) |
| 356 return NULL; |
| 357 return iterator->second; |
| 358 } |
| 359 |
| 360 int64 DOMStorageDispatcherHost::AddStorageArea( |
| 361 WebStorageArea* new_storage_area) { |
| 362 // Create a new ID and insert it into our map. |
| 363 int64 new_storage_area_id = ++last_storage_area_id_; |
| 364 DCHECK(!GetStorageArea(new_storage_area_id)); |
| 365 storage_area_map_[new_storage_area_id] = new_storage_area; |
| 366 return new_storage_area_id; |
| 367 } |
| 368 |
| 369 int64 DOMStorageDispatcherHost::AddStorageNamespace( |
| 370 WebStorageNamespace* new_namespace) { |
| 371 // Create a new ID and insert it into our map. |
| 372 int64 new_namespace_id = ++last_storage_namespace_id_; |
| 373 DCHECK(!GetStorageNamespace(new_namespace_id)); |
| 374 storage_namespace_map_[new_namespace_id] = new_namespace; |
| 375 return new_namespace_id; |
| 376 } |
| 377 |
| 378 string16 DOMStorageDispatcherHost::GetLocalStoragePath() { |
| 379 // TODO(jorlow): Create a path based on the WebKitContext. |
| 380 string16 path; |
| 381 return path; |
| 382 } |
OLD | NEW |