Index: content/browser/appcache/appcache_executable_handler_impl.cc |
diff --git a/content/browser/appcache/appcache_executable_handler_impl.cc b/content/browser/appcache/appcache_executable_handler_impl.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..4e7e354c899563cb8bb161e67f6cfb8d221fbde5 |
--- /dev/null |
+++ b/content/browser/appcache/appcache_executable_handler_impl.cc |
@@ -0,0 +1,172 @@ |
+// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "content/browser/appcache/appcache_executable_handler_impl.h" |
+ |
+#include "base/bind.h" |
+#include "base/lazy_instance.h" |
+#include "base/strings/stringprintf.h" |
+#include "base/message_loop/message_loop.h" |
+#include "content/browser/fileapi/chrome_blob_storage_context.h" |
+#include "content/browser/worker_host/worker_service_impl.h" |
+#include "content/common/worker_messages.h" |
+#include "net/url_request/url_request.h" |
+#include "content/common/appcache_messages.h" |
+ |
+namespace content { |
+ |
+namespace { |
+int g_last_request_id = 0; |
+ |
+typedef std::map<int, AppCacheExecutableHandlerImpl::ResponseCallback> |
+ CallbackMap; |
+ |
+base::LazyInstance<CallbackMap>::Leaky g_pending_response_callbacks = |
+ LAZY_INSTANCE_INITIALIZER; |
+ |
+ |
+CallbackMap& callback_map() { |
+ return g_pending_response_callbacks.Get(); |
+} |
+} // namespace |
+ |
+AppCacheExecutableHandlerFactoryImpl::AppCacheExecutableHandlerFactoryImpl( |
+ ResourceContext* resource_context, const WorkerStoragePartition& partition, |
+ ChromeBlobStorageContext* blob_context) |
+ : resource_context_(resource_context), partition_(partition), |
+ blob_context_(blob_context) { |
+ // To avoid reference cycles we don't store a reference to the appcache_service. |
+ appcache_service_ = partition.appcache_service(); |
+ partition_ = WorkerStoragePartition( |
+ partition.url_request_context(), |
+ partition.media_url_request_context(), |
+ NULL, |
+ partition.quota_manager(), |
+ partition.filesystem_context(), |
+ partition.database_tracker(), |
+ partition.indexed_db_context()); |
+} |
+ |
+AppCacheExecutableHandlerFactoryImpl::~AppCacheExecutableHandlerFactoryImpl() { |
+} |
+ |
+scoped_ptr<appcache::AppCacheExecutableHandler> |
+AppCacheExecutableHandlerFactoryImpl::CreateHandler( |
+ int64 appcache_id, |
+ const GURL& handler_url, |
+ const std::string& raw_handler_source) { |
+ // Construct a partition that includes a reference to the appcache service. |
+ return scoped_ptr<appcache::AppCacheExecutableHandler>( |
+ new AppCacheExecutableHandlerImpl(appcache_id, handler_url, raw_handler_source, |
+ resource_context_, appcache_service_, &partition_)); |
+} |
+ |
+webkit_blob::BlobStorageController* |
+AppCacheExecutableHandlerFactoryImpl::GetBlobStorageController() { |
+ return blob_context_->controller(); |
+} |
+ |
+fileapi::FileSystemContext* |
+AppCacheExecutableHandlerFactoryImpl::GetFileSystemContext() { |
+ return partition_.filesystem_context(); |
+} |
+ |
+AppCacheExecutableHandlerImpl::AppCacheExecutableHandlerImpl( |
+ int64 appcache_id, |
+ const GURL& handler_url, |
+ const std::string& raw_handler_source, |
+ ResourceContext* resource_context, |
+ ChromeAppCacheService* appcache_service, |
+ WorkerStoragePartition* partition) : |
+ worker_route_id_(-1), |
+ appcache_id_(appcache_id), |
+ handler_url_(handler_url), |
+ raw_handler_source_(raw_handler_source), |
+ resource_context_(resource_context), |
+ appcache_service_(appcache_service), |
+ partition_(partition) { |
+ EnsureWorkerStarted(); |
+} |
+ |
+void AppCacheExecutableHandlerImpl::EnsureWorkerStarted() { |
+ if (worker_route_id_ != -1) |
+ return; |
+ |
+ WorkerStoragePartition partition( |
+ partition_->url_request_context(), |
+ partition_->media_url_request_context(), |
+ appcache_service_, |
+ partition_->quota_manager(), |
+ partition_->filesystem_context(), |
+ partition_->database_tracker(), |
+ partition_->indexed_db_context()); |
+ |
+ worker_route_id_ = WorkerServiceImpl::GetInstance()-> |
+ CreateAndStartEmbeddedWorker(resource_context_, partition, handler_url_, |
+ raw_handler_source_, appcache_id_); |
+ WorkerServiceImpl::GetInstance()->AddObserver(this); |
+} |
+ |
+AppCacheExecutableHandlerImpl::~AppCacheExecutableHandlerImpl() { |
+ ClearCallbacks(); |
+ if (worker_route_id_ != -1) |
+ WorkerServiceImpl::GetInstance()->TerminateEmbeddedWorker( |
+ worker_route_id_); |
+} |
+ |
+void AppCacheExecutableHandlerImpl::HandleRequest( |
+ const Request& request, ResponseCallback user_callback) { |
+ // Invoke the handler scripts onRequest() method and wait for it to |
+ // respondWith something. |
+ int request_id = ++g_last_request_id; |
+ |
+ EnsureWorkerStarted(); |
+ |
+ WorkerServiceImpl::GetInstance()->SendToEmbeddedWorker( |
+ worker_route_id_, |
+ new AppCacheMsg_FetchEvent(worker_route_id_, |
+ request_id, |
+ request)); |
+ |
+ pending_request_ids_.insert(request_id); |
+ callback_map()[request_id] = |
+ base::Bind(&AppCacheExecutableHandlerImpl::CallbackAdapter, |
+ base::Unretained(this), |
+ request_id, user_callback); |
+ |
+ // TODO(michaeln): start a generous timer to complete the request if |
+ // the handler fails to. |
+} |
+ |
+void AppCacheExecutableHandlerImpl::CallbackAdapter( |
+ int request_id, ResponseCallback user_callback, const Response& resp) { |
+ user_callback.Run(resp); |
+ pending_request_ids_.erase(request_id); |
+ callback_map().erase(request_id); |
+} |
+ |
+//static |
+void AppCacheExecutableHandlerImpl::ProcessResponse( |
+ int request_id, const Response& resp) { |
+ CallbackMap::const_iterator found = callback_map().find(request_id); |
+ if (found != callback_map().end()) |
+ found->second.Run(resp); // CallbackAdapter() invocation. |
+} |
+ |
+void AppCacheExecutableHandlerImpl::WorkerDestroyed(int process_id, int route_id) { |
+ if (route_id != worker_route_id_) |
+ return; |
+ ClearCallbacks(); |
+ worker_route_id_ = -1; |
+} |
+ |
+void AppCacheExecutableHandlerImpl::ClearCallbacks() { |
+ WorkerServiceImpl::GetInstance()->RemoveObserver(this); |
+ for (std::set<int>::const_iterator iter = pending_request_ids_.begin(); |
+ iter != pending_request_ids_.end(); ++iter) { |
+ callback_map().erase(*iter); |
+ } |
+} |
+ |
+} // namespace content |