| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011 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 "webkit/support/simple_appcache_system.h" | |
| 6 | |
| 7 #include <string> | |
| 8 #include <vector> | |
| 9 | |
| 10 #include "base/bind.h" | |
| 11 #include "base/bind_helpers.h" | |
| 12 #include "base/callback.h" | |
| 13 #include "base/synchronization/waitable_event.h" | |
| 14 #include "webkit/browser/appcache/appcache_interceptor.h" | |
| 15 #include "webkit/renderer/appcache/web_application_cache_host_impl.h" | |
| 16 #include "webkit/support/simple_resource_loader_bridge.h" | |
| 17 | |
| 18 using WebKit::WebApplicationCacheHost; | |
| 19 using WebKit::WebApplicationCacheHostClient; | |
| 20 using appcache::WebApplicationCacheHostImpl; | |
| 21 using appcache::AppCacheBackendImpl; | |
| 22 using appcache::AppCacheInterceptor; | |
| 23 | |
| 24 // SimpleFrontendProxy -------------------------------------------------------- | |
| 25 // Proxies method calls from the backend IO thread to the frontend UI thread. | |
| 26 | |
| 27 class SimpleFrontendProxy | |
| 28 : public base::RefCountedThreadSafe<SimpleFrontendProxy>, | |
| 29 public appcache::AppCacheFrontend { | |
| 30 public: | |
| 31 explicit SimpleFrontendProxy(SimpleAppCacheSystem* appcache_system) | |
| 32 : system_(appcache_system) { | |
| 33 } | |
| 34 | |
| 35 void clear_appcache_system() { system_ = NULL; } | |
| 36 | |
| 37 virtual void OnCacheSelected(int host_id, | |
| 38 const appcache::AppCacheInfo& info) OVERRIDE { | |
| 39 if (!system_) | |
| 40 return; | |
| 41 if (system_->is_io_thread()) { | |
| 42 system_->ui_message_loop()->PostTask( | |
| 43 FROM_HERE, | |
| 44 base::Bind(&SimpleFrontendProxy::OnCacheSelected, this, host_id, | |
| 45 info)); | |
| 46 } else if (system_->is_ui_thread()) { | |
| 47 system_->frontend_impl_.OnCacheSelected(host_id, info); | |
| 48 } else { | |
| 49 NOTREACHED(); | |
| 50 } | |
| 51 } | |
| 52 | |
| 53 virtual void OnStatusChanged(const std::vector<int>& host_ids, | |
| 54 appcache::Status status) OVERRIDE { | |
| 55 if (!system_) | |
| 56 return; | |
| 57 if (system_->is_io_thread()) | |
| 58 system_->ui_message_loop()->PostTask( | |
| 59 FROM_HERE, | |
| 60 base::Bind(&SimpleFrontendProxy::OnStatusChanged, this, host_ids, | |
| 61 status)); | |
| 62 else if (system_->is_ui_thread()) | |
| 63 system_->frontend_impl_.OnStatusChanged(host_ids, status); | |
| 64 else | |
| 65 NOTREACHED(); | |
| 66 } | |
| 67 | |
| 68 virtual void OnEventRaised(const std::vector<int>& host_ids, | |
| 69 appcache::EventID event_id) OVERRIDE { | |
| 70 if (!system_) | |
| 71 return; | |
| 72 if (system_->is_io_thread()) | |
| 73 system_->ui_message_loop()->PostTask( | |
| 74 FROM_HERE, | |
| 75 base::Bind(&SimpleFrontendProxy::OnEventRaised, this, host_ids, | |
| 76 event_id)); | |
| 77 else if (system_->is_ui_thread()) | |
| 78 system_->frontend_impl_.OnEventRaised(host_ids, event_id); | |
| 79 else | |
| 80 NOTREACHED(); | |
| 81 } | |
| 82 | |
| 83 virtual void OnProgressEventRaised(const std::vector<int>& host_ids, | |
| 84 const GURL& url, | |
| 85 int num_total, int num_complete) OVERRIDE { | |
| 86 if (!system_) | |
| 87 return; | |
| 88 if (system_->is_io_thread()) | |
| 89 system_->ui_message_loop()->PostTask( | |
| 90 FROM_HERE, | |
| 91 base::Bind(&SimpleFrontendProxy::OnProgressEventRaised, this, | |
| 92 host_ids, url, num_total, num_complete)); | |
| 93 else if (system_->is_ui_thread()) | |
| 94 system_->frontend_impl_.OnProgressEventRaised( | |
| 95 host_ids, url, num_total, num_complete); | |
| 96 else | |
| 97 NOTREACHED(); | |
| 98 } | |
| 99 | |
| 100 virtual void OnErrorEventRaised(const std::vector<int>& host_ids, | |
| 101 const std::string& message) OVERRIDE { | |
| 102 if (!system_) | |
| 103 return; | |
| 104 if (system_->is_io_thread()) | |
| 105 system_->ui_message_loop()->PostTask( | |
| 106 FROM_HERE, | |
| 107 base::Bind(&SimpleFrontendProxy::OnErrorEventRaised, this, host_ids, | |
| 108 message)); | |
| 109 else if (system_->is_ui_thread()) | |
| 110 system_->frontend_impl_.OnErrorEventRaised( | |
| 111 host_ids, message); | |
| 112 else | |
| 113 NOTREACHED(); | |
| 114 } | |
| 115 | |
| 116 virtual void OnLogMessage(int host_id, | |
| 117 appcache::LogLevel log_level, | |
| 118 const std::string& message) OVERRIDE { | |
| 119 if (!system_) | |
| 120 return; | |
| 121 if (system_->is_io_thread()) | |
| 122 system_->ui_message_loop()->PostTask( | |
| 123 FROM_HERE, | |
| 124 base::Bind(&SimpleFrontendProxy::OnLogMessage, this, host_id, | |
| 125 log_level, message)); | |
| 126 else if (system_->is_ui_thread()) | |
| 127 system_->frontend_impl_.OnLogMessage( | |
| 128 host_id, log_level, message); | |
| 129 else | |
| 130 NOTREACHED(); | |
| 131 } | |
| 132 | |
| 133 virtual void OnContentBlocked(int host_id, | |
| 134 const GURL& manifest_url) OVERRIDE {} | |
| 135 | |
| 136 private: | |
| 137 friend class base::RefCountedThreadSafe<SimpleFrontendProxy>; | |
| 138 | |
| 139 virtual ~SimpleFrontendProxy() {} | |
| 140 | |
| 141 SimpleAppCacheSystem* system_; | |
| 142 }; | |
| 143 | |
| 144 | |
| 145 // SimpleBackendProxy -------------------------------------------------------- | |
| 146 // Proxies method calls from the frontend UI thread to the backend IO thread. | |
| 147 | |
| 148 class SimpleBackendProxy | |
| 149 : public base::RefCountedThreadSafe<SimpleBackendProxy>, | |
| 150 public appcache::AppCacheBackend { | |
| 151 public: | |
| 152 explicit SimpleBackendProxy(SimpleAppCacheSystem* appcache_system) | |
| 153 : system_(appcache_system), event_(true, false) { | |
| 154 get_status_callback_ = | |
| 155 base::Bind(&SimpleBackendProxy::GetStatusCallback, | |
| 156 base::Unretained(this)); | |
| 157 start_update_callback_ = | |
| 158 base::Bind(&SimpleBackendProxy::StartUpdateCallback, | |
| 159 base::Unretained(this)); | |
| 160 swap_cache_callback_= | |
| 161 base::Bind(&SimpleBackendProxy::SwapCacheCallback, | |
| 162 base::Unretained(this)); | |
| 163 } | |
| 164 | |
| 165 virtual void RegisterHost(int host_id) OVERRIDE { | |
| 166 if (system_->is_ui_thread()) { | |
| 167 system_->io_message_loop()->PostTask( | |
| 168 FROM_HERE, | |
| 169 base::Bind(&SimpleBackendProxy::RegisterHost, this, host_id)); | |
| 170 } else if (system_->is_io_thread()) { | |
| 171 system_->backend_impl_->RegisterHost(host_id); | |
| 172 } else { | |
| 173 NOTREACHED(); | |
| 174 } | |
| 175 } | |
| 176 | |
| 177 virtual void UnregisterHost(int host_id) OVERRIDE { | |
| 178 if (system_->is_ui_thread()) { | |
| 179 system_->io_message_loop()->PostTask( | |
| 180 FROM_HERE, | |
| 181 base::Bind(&SimpleBackendProxy::UnregisterHost, this, host_id)); | |
| 182 } else if (system_->is_io_thread()) { | |
| 183 system_->backend_impl_->UnregisterHost(host_id); | |
| 184 } else { | |
| 185 NOTREACHED(); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 virtual void SetSpawningHostId(int host_id, int spawning_host_id) OVERRIDE { | |
| 190 if (system_->is_ui_thread()) { | |
| 191 system_->io_message_loop()->PostTask( | |
| 192 FROM_HERE, | |
| 193 base::Bind(&SimpleBackendProxy::SetSpawningHostId, this, host_id, | |
| 194 spawning_host_id)); | |
| 195 } else if (system_->is_io_thread()) { | |
| 196 system_->backend_impl_->SetSpawningHostId(host_id, spawning_host_id); | |
| 197 } else { | |
| 198 NOTREACHED(); | |
| 199 } | |
| 200 } | |
| 201 | |
| 202 virtual void SelectCache(int host_id, | |
| 203 const GURL& document_url, | |
| 204 const int64 cache_document_was_loaded_from, | |
| 205 const GURL& manifest_url) OVERRIDE { | |
| 206 if (system_->is_ui_thread()) { | |
| 207 system_->io_message_loop()->PostTask( | |
| 208 FROM_HERE, | |
| 209 base::Bind(&SimpleBackendProxy::SelectCache, this, host_id, | |
| 210 document_url, cache_document_was_loaded_from, | |
| 211 manifest_url)); | |
| 212 } else if (system_->is_io_thread()) { | |
| 213 system_->backend_impl_->SelectCache(host_id, document_url, | |
| 214 cache_document_was_loaded_from, | |
| 215 manifest_url); | |
| 216 } else { | |
| 217 NOTREACHED(); | |
| 218 } | |
| 219 } | |
| 220 | |
| 221 virtual void GetResourceList( | |
| 222 int host_id, | |
| 223 std::vector<appcache::AppCacheResourceInfo>* resource_infos) OVERRIDE { | |
| 224 if (system_->is_ui_thread()) { | |
| 225 system_->io_message_loop()->PostTask( | |
| 226 FROM_HERE, | |
| 227 base::Bind(&SimpleBackendProxy::GetResourceList, this, host_id, | |
| 228 resource_infos)); | |
| 229 } else if (system_->is_io_thread()) { | |
| 230 system_->backend_impl_->GetResourceList(host_id, resource_infos); | |
| 231 } else { | |
| 232 NOTREACHED(); | |
| 233 } | |
| 234 } | |
| 235 | |
| 236 virtual void SelectCacheForWorker( | |
| 237 int host_id, | |
| 238 int parent_process_id, | |
| 239 int parent_host_id) OVERRIDE { | |
| 240 NOTIMPLEMENTED(); // Workers are not supported in test_shell. | |
| 241 } | |
| 242 | |
| 243 virtual void SelectCacheForSharedWorker( | |
| 244 int host_id, | |
| 245 int64 appcache_id) OVERRIDE { | |
| 246 NOTIMPLEMENTED(); // Workers are not supported in test_shell. | |
| 247 } | |
| 248 | |
| 249 virtual void MarkAsForeignEntry( | |
| 250 int host_id, | |
| 251 const GURL& document_url, | |
| 252 int64 cache_document_was_loaded_from) OVERRIDE { | |
| 253 if (system_->is_ui_thread()) { | |
| 254 system_->io_message_loop()->PostTask( | |
| 255 FROM_HERE, | |
| 256 base::Bind(&SimpleBackendProxy::MarkAsForeignEntry, this, host_id, | |
| 257 document_url, cache_document_was_loaded_from)); | |
| 258 } else if (system_->is_io_thread()) { | |
| 259 system_->backend_impl_->MarkAsForeignEntry( | |
| 260 host_id, document_url, | |
| 261 cache_document_was_loaded_from); | |
| 262 } else { | |
| 263 NOTREACHED(); | |
| 264 } | |
| 265 } | |
| 266 | |
| 267 virtual appcache::Status GetStatus(int host_id) OVERRIDE { | |
| 268 if (system_->is_ui_thread()) { | |
| 269 status_result_ = appcache::UNCACHED; | |
| 270 event_.Reset(); | |
| 271 system_->io_message_loop()->PostTask( | |
| 272 FROM_HERE, | |
| 273 base::Bind(base::IgnoreResult(&SimpleBackendProxy::GetStatus), | |
| 274 this, host_id)); | |
| 275 event_.Wait(); | |
| 276 } else if (system_->is_io_thread()) { | |
| 277 system_->backend_impl_->GetStatusWithCallback( | |
| 278 host_id, get_status_callback_, NULL); | |
| 279 } else { | |
| 280 NOTREACHED(); | |
| 281 } | |
| 282 return status_result_; | |
| 283 } | |
| 284 | |
| 285 virtual bool StartUpdate(int host_id) OVERRIDE { | |
| 286 if (system_->is_ui_thread()) { | |
| 287 bool_result_ = false; | |
| 288 event_.Reset(); | |
| 289 system_->io_message_loop()->PostTask( | |
| 290 FROM_HERE, | |
| 291 base::Bind(base::IgnoreResult(&SimpleBackendProxy::StartUpdate), | |
| 292 this, host_id)); | |
| 293 event_.Wait(); | |
| 294 } else if (system_->is_io_thread()) { | |
| 295 system_->backend_impl_->StartUpdateWithCallback( | |
| 296 host_id, start_update_callback_, NULL); | |
| 297 } else { | |
| 298 NOTREACHED(); | |
| 299 } | |
| 300 return bool_result_; | |
| 301 } | |
| 302 | |
| 303 virtual bool SwapCache(int host_id) OVERRIDE { | |
| 304 if (system_->is_ui_thread()) { | |
| 305 bool_result_ = false; | |
| 306 event_.Reset(); | |
| 307 system_->io_message_loop()->PostTask( | |
| 308 FROM_HERE, | |
| 309 base::Bind(base::IgnoreResult(&SimpleBackendProxy::SwapCache), | |
| 310 this, host_id)); | |
| 311 event_.Wait(); | |
| 312 } else if (system_->is_io_thread()) { | |
| 313 system_->backend_impl_->SwapCacheWithCallback( | |
| 314 host_id, swap_cache_callback_, NULL); | |
| 315 } else { | |
| 316 NOTREACHED(); | |
| 317 } | |
| 318 return bool_result_; | |
| 319 } | |
| 320 | |
| 321 void GetStatusCallback(appcache::Status status, void* param) { | |
| 322 status_result_ = status; | |
| 323 event_.Signal(); | |
| 324 } | |
| 325 | |
| 326 void StartUpdateCallback(bool result, void* param) { | |
| 327 bool_result_ = result; | |
| 328 event_.Signal(); | |
| 329 } | |
| 330 | |
| 331 void SwapCacheCallback(bool result, void* param) { | |
| 332 bool_result_ = result; | |
| 333 event_.Signal(); | |
| 334 } | |
| 335 | |
| 336 void SignalEvent() { | |
| 337 event_.Signal(); | |
| 338 } | |
| 339 | |
| 340 private: | |
| 341 friend class base::RefCountedThreadSafe<SimpleBackendProxy>; | |
| 342 | |
| 343 virtual ~SimpleBackendProxy() {} | |
| 344 | |
| 345 SimpleAppCacheSystem* system_; | |
| 346 base::WaitableEvent event_; | |
| 347 bool bool_result_; | |
| 348 appcache::Status status_result_; | |
| 349 appcache::GetStatusCallback get_status_callback_; | |
| 350 appcache::StartUpdateCallback start_update_callback_; | |
| 351 appcache::SwapCacheCallback swap_cache_callback_; | |
| 352 }; | |
| 353 | |
| 354 | |
| 355 // SimpleAppCacheSystem -------------------------------------------------------- | |
| 356 | |
| 357 // This class only works for a single process browser. | |
| 358 static const int kSingleProcessId = 1; | |
| 359 | |
| 360 // A not so thread safe singleton, but should work for test_shell. | |
| 361 SimpleAppCacheSystem* SimpleAppCacheSystem::instance_ = NULL; | |
| 362 | |
| 363 SimpleAppCacheSystem::SimpleAppCacheSystem() | |
| 364 : io_message_loop_(NULL), ui_message_loop_(NULL), | |
| 365 backend_proxy_(new SimpleBackendProxy(this)), | |
| 366 frontend_proxy_(new SimpleFrontendProxy(this)), | |
| 367 backend_impl_(NULL), service_(NULL), db_thread_("AppCacheDBThread") { | |
| 368 DCHECK(!instance_); | |
| 369 instance_ = this; | |
| 370 } | |
| 371 | |
| 372 static void SignalEvent(base::WaitableEvent* event) { | |
| 373 event->Signal(); | |
| 374 } | |
| 375 | |
| 376 SimpleAppCacheSystem::~SimpleAppCacheSystem() { | |
| 377 DCHECK(!io_message_loop_ && !backend_impl_ && !service_); | |
| 378 frontend_proxy_->clear_appcache_system(); // in case a task is in transit | |
| 379 instance_ = NULL; | |
| 380 | |
| 381 if (db_thread_.IsRunning()) { | |
| 382 // We pump a task thru the db thread to ensure any tasks previously | |
| 383 // scheduled on that thread have been performed prior to return. | |
| 384 base::WaitableEvent event(false, false); | |
| 385 db_thread_.message_loop()->PostTask( | |
| 386 FROM_HERE, base::Bind(&SignalEvent, &event)); | |
| 387 event.Wait(); | |
| 388 } | |
| 389 } | |
| 390 | |
| 391 void SimpleAppCacheSystem::InitOnUIThread( | |
| 392 const base::FilePath& cache_directory) { | |
| 393 DCHECK(!ui_message_loop_); | |
| 394 ui_message_loop_ = base::MessageLoop::current(); | |
| 395 cache_directory_ = cache_directory; | |
| 396 } | |
| 397 | |
| 398 void SimpleAppCacheSystem::InitOnIOThread( | |
| 399 net::URLRequestContext* request_context) { | |
| 400 if (!is_initailized_on_ui_thread()) | |
| 401 return; | |
| 402 | |
| 403 DCHECK(!io_message_loop_); | |
| 404 io_message_loop_ = base::MessageLoop::current(); | |
| 405 | |
| 406 if (!db_thread_.IsRunning()) | |
| 407 db_thread_.Start(); | |
| 408 | |
| 409 // Recreate and initialize per each IO thread. | |
| 410 service_ = new appcache::AppCacheService(NULL); | |
| 411 backend_impl_ = new appcache::AppCacheBackendImpl(); | |
| 412 service_->Initialize(cache_directory_, | |
| 413 db_thread_.message_loop_proxy().get(), | |
| 414 SimpleResourceLoaderBridge::GetCacheThread().get()); | |
| 415 service_->set_request_context(request_context); | |
| 416 backend_impl_->Initialize(service_, frontend_proxy_.get(), kSingleProcessId); | |
| 417 | |
| 418 AppCacheInterceptor::EnsureRegistered(); | |
| 419 } | |
| 420 | |
| 421 void SimpleAppCacheSystem::CleanupIOThread() { | |
| 422 DCHECK(is_io_thread()); | |
| 423 | |
| 424 delete backend_impl_; | |
| 425 delete service_; | |
| 426 backend_impl_ = NULL; | |
| 427 service_ = NULL; | |
| 428 io_message_loop_ = NULL; | |
| 429 | |
| 430 // Just in case the main thread is waiting on it. | |
| 431 backend_proxy_->SignalEvent(); | |
| 432 } | |
| 433 | |
| 434 WebApplicationCacheHost* SimpleAppCacheSystem::CreateCacheHostForWebKit( | |
| 435 WebApplicationCacheHostClient* client) { | |
| 436 if (!is_initailized_on_ui_thread()) | |
| 437 return NULL; | |
| 438 | |
| 439 DCHECK(is_ui_thread()); | |
| 440 | |
| 441 // The IO thread needs to be running for this system to work. | |
| 442 SimpleResourceLoaderBridge::EnsureIOThread(); | |
| 443 | |
| 444 if (!is_initialized()) | |
| 445 return NULL; | |
| 446 return new WebApplicationCacheHostImpl(client, backend_proxy_.get()); | |
| 447 } | |
| 448 | |
| 449 void SimpleAppCacheSystem::SetExtraRequestBits( | |
| 450 net::URLRequest* request, int host_id, ResourceType::Type resource_type) { | |
| 451 if (is_initialized()) { | |
| 452 DCHECK(is_io_thread()); | |
| 453 AppCacheInterceptor::SetExtraRequestInfo( | |
| 454 request, service_, kSingleProcessId, host_id, resource_type); | |
| 455 } | |
| 456 } | |
| 457 | |
| 458 void SimpleAppCacheSystem::GetExtraResponseBits( | |
| 459 net::URLRequest* request, int64* cache_id, GURL* manifest_url) { | |
| 460 if (is_initialized()) { | |
| 461 DCHECK(is_io_thread()); | |
| 462 AppCacheInterceptor::GetExtraResponseInfo( | |
| 463 request, cache_id, manifest_url); | |
| 464 } | |
| 465 } | |
| OLD | NEW |