diff options
author | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-01 22:30:30 +0000 |
---|---|---|
committer | michaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-09-01 22:30:30 +0000 |
commit | 23f1ef1a445a53bcefc8ddab9f4184b1db7321c5 (patch) | |
tree | c9f17a33025ed5b5c5dee76a7b4fef9104e9a995 /webkit | |
parent | e143c823ce66af5a83a9a17b6f5938eb16e49392 (diff) | |
download | chromium_src-23f1ef1a445a53bcefc8ddab9f4184b1db7321c5.zip chromium_src-23f1ef1a445a53bcefc8ddab9f4184b1db7321c5.tar.gz chromium_src-23f1ef1a445a53bcefc8ddab9f4184b1db7321c5.tar.bz2 |
Plumb request interception into the appcache library for both chrome and test_shell.
AppCache library:
* Added AppCacheInterceptor, which is derived from URLRequest::Interceptor.
Chrome:
* Each UserProfile instantiates a ChromeAppCacheService, which is derived from an appcache library class.
* Each ChromeURLRequestContext associated with that profile has a reference to that instance.
* ResourceDispatcherHost pokes AppCacheInterceptor when initiating URLRequests and when returning the response head.
TestShell:
* Added SimpleAppCacheSystem which bundles together appcache lib components for use in a single process with an UI and IO thread.
* TestShellWebKit instantiates and initializes an instance of the above, aimed at at temp directory that will get cleaned up when the test run is over.
* SimpleResourceLoaderBridge pokes the system when initiating URLRequests and when returning the response head.
TEST=none, although many existing tests exercise this stuff
BUG=none
Review URL: http://codereview.chromium.org/173406
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@25099 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit')
-rw-r--r-- | webkit/appcache/appcache_backend_impl.cc | 48 | ||||
-rw-r--r-- | webkit/appcache/appcache_backend_impl.h | 44 | ||||
-rw-r--r-- | webkit/appcache/appcache_host.h | 4 | ||||
-rw-r--r-- | webkit/appcache/appcache_interceptor.cc | 125 | ||||
-rw-r--r-- | webkit/appcache/appcache_interceptor.h | 60 | ||||
-rw-r--r-- | webkit/appcache/appcache_service.cc | 15 | ||||
-rw-r--r-- | webkit/appcache/appcache_service.h | 27 | ||||
-rw-r--r-- | webkit/appcache/web_application_cache_host_impl.cc | 1 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_appcache_system.cc | 323 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_appcache_system.h | 108 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_resource_loader_bridge.cc | 49 | ||||
-rw-r--r-- | webkit/tools/test_shell/simple_resource_loader_bridge.h | 1 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell.gyp | 1 | ||||
-rw-r--r-- | webkit/tools/test_shell/test_shell_webkit_init.h | 12 | ||||
-rw-r--r-- | webkit/webkit.gyp | 2 |
15 files changed, 760 insertions, 60 deletions
diff --git a/webkit/appcache/appcache_backend_impl.cc b/webkit/appcache/appcache_backend_impl.cc index 1c0cfc7..82b40ee 100644 --- a/webkit/appcache/appcache_backend_impl.cc +++ b/webkit/appcache/appcache_backend_impl.cc @@ -4,29 +4,34 @@ #include "webkit/appcache/appcache_backend_impl.h" -#include "base/logging.h" +#include "webkit/appcache/appcache_host.h" +#include "webkit/appcache/appcache_service.h" #include "webkit/appcache/web_application_cache_host_impl.h" namespace appcache { AppCacheBackendImpl::~AppCacheBackendImpl() { - // TODO(michaeln): if (service_) service_->UnregisterFrontend(frontend_); + if (service_) + service_->UnregisterBackend(this); } void AppCacheBackendImpl::Initialize(AppCacheService* service, - AppCacheFrontend* frontend) { - DCHECK(!service_ && !frontend_ && frontend); // DCHECK(service) + AppCacheFrontend* frontend, + int process_id) { + DCHECK(!service_ && !frontend_ && frontend && service); service_ = service; frontend_ = frontend; - // TODO(michaeln): service_->RegisterFrontend(frontend_); + process_id_ = process_id; + service_->RegisterBackend(this); } -void AppCacheBackendImpl::RegisterHost(int host_id) { - // TODO(michaeln): plumb to service +void AppCacheBackendImpl::RegisterHost(int id) { + DCHECK(hosts_.find(id) == hosts_.end()); + hosts_.insert(HostMap::value_type(id, AppCacheHost(id, frontend_))); } -void AppCacheBackendImpl::UnregisterHost(int host_id) { - // TODO(michaeln): plumb to service +void AppCacheBackendImpl::UnregisterHost(int id) { + hosts_.erase(id); } void AppCacheBackendImpl::SelectCache( @@ -34,7 +39,7 @@ void AppCacheBackendImpl::SelectCache( const GURL& document_url, const int64 cache_document_was_loaded_from, const GURL& manifest_url) { - // TODO(michaeln): plumb to service + // TODO(michaeln): write me frontend_->OnCacheSelected(host_id, kNoCacheId, UNCACHED); } @@ -42,22 +47,25 @@ void AppCacheBackendImpl::MarkAsForeignEntry( int host_id, const GURL& document_url, int64 cache_document_was_loaded_from) { - // TODO(michaeln): plumb to service + // TODO(michaeln): write me } -Status AppCacheBackendImpl::GetStatus(int host_id) { - // TODO(michaeln): plumb to service - return UNCACHED; +void AppCacheBackendImpl::GetStatusWithCallback( + int host_id, GetStatusCallback* callback, void* callback_param) { + // TODO(michaeln): write me + callback->Run(UNCACHED, callback_param); } -bool AppCacheBackendImpl::StartUpdate(int host_id) { - // TODO(michaeln): plumb to service - return false; +void AppCacheBackendImpl::StartUpdateWithCallback( + int host_id, StartUpdateCallback* callback, void* callback_param) { + // TODO(michaeln): write me + callback->Run(false, callback_param); } -bool AppCacheBackendImpl::SwapCache(int host_id) { - // TODO(michaeln): plumb to service - return false; +void AppCacheBackendImpl::SwapCacheWithCallback( + int host_id, SwapCacheCallback* callback, void* callback_param) { + // TODO(michaeln): write me + callback->Run(false, callback_param); } } // namespace appcache diff --git a/webkit/appcache/appcache_backend_impl.h b/webkit/appcache/appcache_backend_impl.h index 93a7083..abf4247 100644 --- a/webkit/appcache/appcache_backend_impl.h +++ b/webkit/appcache/appcache_backend_impl.h @@ -5,20 +5,42 @@ #ifndef WEBKIT_APPCACHE_APPCACHE_BACKEND_IMPL_H_ #define WEBKIT_APPCACHE_APPCACHE_BACKEND_IMPL_H_ +#include <map> + +#include "base/logging.h" +#include "base/task.h" +#include "webkit/appcache/appcache_host.h" #include "webkit/appcache/appcache_interfaces.h" namespace appcache { class AppCacheService; +typedef Callback2<Status, void*>::Type GetStatusCallback; +typedef Callback2<bool, void*>::Type StartUpdateCallback; +typedef Callback2<bool, void*>::Type SwapCacheCallback; + class AppCacheBackendImpl : public AppCacheBackend { public: - AppCacheBackendImpl() : service_(NULL), frontend_(NULL) {} + AppCacheBackendImpl() : service_(NULL), frontend_(NULL), process_id_(0) {} ~AppCacheBackendImpl(); void Initialize(AppCacheService* service, - AppCacheFrontend* frontend); + AppCacheFrontend* frontend, + int process_id); + + int process_id() const { return process_id_; } + + // Returns a pointer to a registered host. The backend retains ownership. + AppCacheHost* GetHost(int host_id) { + HostMap::iterator it = hosts_.find(host_id); + return (it != hosts_.end()) ? &(it->second) : NULL; + } + typedef std::map<int, AppCacheHost> HostMap; + const HostMap& hosts() { return hosts_; } + + // AppCacheBackend methods virtual void RegisterHost(int host_id); virtual void UnregisterHost(int host_id); virtual void SelectCache(int host_id, @@ -27,13 +49,25 @@ class AppCacheBackendImpl : public AppCacheBackend { const GURL& manifest_url); virtual void MarkAsForeignEntry(int host_id, const GURL& document_url, int64 cache_document_was_loaded_from); - virtual Status GetStatus(int host_id); - virtual bool StartUpdate(int host_id); - virtual bool SwapCache(int host_id); + + // We don't use the sync variants in the backend, would block the IO thread. + virtual Status GetStatus(int host_id) { NOTREACHED(); return UNCACHED; } + virtual bool StartUpdate(int host_id) { NOTREACHED(); return false; } + virtual bool SwapCache(int host_id) { NOTREACHED(); return false; } + + // Async variants of the sync methods defined in the backend interface. + void GetStatusWithCallback(int host_id, GetStatusCallback* callback, + void* callback_param); + void StartUpdateWithCallback(int host_id, StartUpdateCallback* callback, + void* callback_param); + void SwapCacheWithCallback(int host_id, SwapCacheCallback* callback, + void* callback_param); private: AppCacheService* service_; AppCacheFrontend* frontend_; + int process_id_; + HostMap hosts_; }; } // namespace diff --git a/webkit/appcache/appcache_host.h b/webkit/appcache/appcache_host.h index 439e042..bebc22d 100644 --- a/webkit/appcache/appcache_host.h +++ b/webkit/appcache/appcache_host.h @@ -24,6 +24,10 @@ class AppCacheHost { selected_cache_ = cache; } + bool is_selection_pending() { + return false; // TODO(michaeln) + } + private: // identifies the corresponding appcache host in the child process int host_id_; diff --git a/webkit/appcache/appcache_interceptor.cc b/webkit/appcache/appcache_interceptor.cc new file mode 100644 index 0000000..a66fea8 --- /dev/null +++ b/webkit/appcache/appcache_interceptor.cc @@ -0,0 +1,125 @@ +// Copyright (c) 2009 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 "webkit/appcache/appcache_interceptor.h" + +#include "webkit/appcache/appcache_backend_impl.h" +#include "webkit/appcache/appcache_host.h" +#include "webkit/appcache/appcache_interfaces.h" +#include "webkit/appcache/appcache_service.h" + +namespace appcache { + +// Extra info we associate with requests for use at MaybeIntercept time. This +// info is deleted when the URLRequest is deleted which occurs after the +// request is complete and all data has been read. +struct AppCacheInterceptor::ExtraInfo : public URLRequest::UserData { + // Inputs, extra request info + AppCacheService* service; + int process_id; + int host_id; + ResourceType::Type resource_type; + + // Outputs, extra response info + int64 cache_id; + GURL manifest_url; + + // The host associated with the request + // TODO(michaeln): Be careful with this data member, its not clear + // if a URLRequest can outlive the associated host. As we get further + // along, we'll need to notify reqeust waiting on cache selection to + // allow them to continue upon completion of selection. But we also need + // to handle navigating away from the page away prior to selection being + // complete. + AppCacheHost* host_; + + ExtraInfo(AppCacheService* service, int process_id, int host_id, + ResourceType::Type resource_type, AppCacheHost* host) + : service(service), process_id(process_id), host_id(host_id), + resource_type(resource_type), cache_id(kNoCacheId), host_(host) { + } + + static void SetInfo(URLRequest* request, ExtraInfo* info) { + request->SetUserData(instance(), info); // request takes ownership + } + + static ExtraInfo* GetInfo(URLRequest* request) { + return static_cast<ExtraInfo*>(request->GetUserData(instance())); + } +}; + +static bool IsMainRequest(ResourceType::Type type) { + // TODO(michaeln): SHARED_WORKER type? + return ResourceType::IsFrame(type); +} + +void AppCacheInterceptor::SetExtraRequestInfo( + URLRequest* request, AppCacheService* service, int process_id, + int host_id, ResourceType::Type resource_type) { + if (service && (host_id != kNoHostId)) { + AppCacheHost* host = service->GetBackend(process_id)->GetHost(host_id); + DCHECK(host); + if (IsMainRequest(resource_type) || host->selected_cache() || + host->is_selection_pending()) { + ExtraInfo* info = new ExtraInfo(service, process_id, + host_id, resource_type, host); + ExtraInfo::SetInfo(request, info); + } + } +} + +void AppCacheInterceptor::GetExtraResponseInfo(URLRequest* request, + int64* cache_id, + GURL* manifest_url) { + ExtraInfo* info = ExtraInfo::GetInfo(request); + if (info) { + // TODO(michaeln): If this is a main request and it was retrieved from + // an appcache, ensure that appcache survives the frame navigation. The + // AppCacheHost should hold reference to that cache to prevent it from + // being dropped from the in-memory collection of AppCaches. When cache + // selection occurs, that extra reference should be dropped. + *cache_id = info->cache_id; + *manifest_url = info->manifest_url; + } else { + DCHECK(*cache_id == kNoCacheId); + DCHECK(manifest_url->is_empty()); + } +} + +AppCacheInterceptor::AppCacheInterceptor() { + URLRequest::RegisterRequestInterceptor(this); +} + +AppCacheInterceptor::~AppCacheInterceptor() { + URLRequest::UnregisterRequestInterceptor(this); +} + +URLRequestJob* AppCacheInterceptor::MaybeIntercept(URLRequest* request) { + ExtraInfo* info = ExtraInfo::GetInfo(request); + if (!info) + return NULL; + // TODO(michaeln): write me + return NULL; +} + +URLRequestJob* AppCacheInterceptor::MaybeInterceptRedirect( + URLRequest* request, + const GURL& location) { + ExtraInfo* info = ExtraInfo::GetInfo(request); + if (!info) + return NULL; + // TODO(michaeln): write me + return NULL; +} + +URLRequestJob* AppCacheInterceptor::MaybeInterceptResponse( + URLRequest* request) { + ExtraInfo* info = ExtraInfo::GetInfo(request); + if (!info) + return NULL; + // TODO(michaeln): write me + return NULL; +} + +} // namespace appcache diff --git a/webkit/appcache/appcache_interceptor.h b/webkit/appcache/appcache_interceptor.h new file mode 100644 index 0000000..51b9a89 --- /dev/null +++ b/webkit/appcache/appcache_interceptor.h @@ -0,0 +1,60 @@ +// Copyright (c) 2009 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. + +#ifndef WEBKIT_APPCACHE_APPCACHE_INTERCEPTOR_H_ +#define WEBKIT_APPCACHE_APPCACHE_INTERCEPTOR_H_ + +#include "base/singleton.h" +#include "googleurl/src/gurl.h" +#include "net/url_request/url_request.h" +#include "webkit/glue/resource_type.h" + +namespace appcache { + +class AppCacheService; + +// An interceptor to hijack requests and potentially service them out of +// the appcache. +class AppCacheInterceptor : public URLRequest::Interceptor { + public: + // Registers a singleton instance with the net library. + // Should be called early in the IO thread prior to initiating requests. + static void EnsureRegistered() { + CHECK(instance()); + } + + // Must be called to make a request eligible for retrieval from an appcache. + static void SetExtraRequestInfo(URLRequest* request, + AppCacheService* service, + int process_id, + int host_id, + ResourceType::Type resource_type); + + // May be called after response headers are complete to retrieve extra + // info about the response. + static void GetExtraResponseInfo(URLRequest* request, + int64* cache_id, + GURL* manifest_url); + + protected: + // URLRequest::Interceptor overrides + virtual URLRequestJob* MaybeIntercept(URLRequest* request); + virtual URLRequestJob* MaybeInterceptResponse(URLRequest* request); + virtual URLRequestJob* MaybeInterceptRedirect(URLRequest* request, + const GURL& location); + + private: + friend struct DefaultSingletonTraits<AppCacheInterceptor>; + static AppCacheInterceptor* instance() { + return Singleton<AppCacheInterceptor>::get(); + } + struct ExtraInfo; + AppCacheInterceptor(); + virtual ~AppCacheInterceptor(); + DISALLOW_COPY_AND_ASSIGN(AppCacheInterceptor); +}; + +} // namespace appcache + +#endif // WEBKIT_APPCACHE_APPCACHE_INTERCEPTOR_H_ diff --git a/webkit/appcache/appcache_service.cc b/webkit/appcache/appcache_service.cc index 0d3579b..0fd5356 100644 --- a/webkit/appcache/appcache_service.cc +++ b/webkit/appcache/appcache_service.cc @@ -17,14 +17,21 @@ AppCacheService::~AppCacheService() { DCHECK(groups_.empty()); } -void AppCacheService::RegisterBackendImpl( +void AppCacheService::Initialize(const FilePath& cache_directory) { + // An empty cache directory indicates chrome incognito. + cache_directory_ = cache_directory; +} + +void AppCacheService::RegisterBackend( AppCacheBackendImpl* backend_impl) { - backends_.insert(backend_impl); + DCHECK(backends_.find(backend_impl->process_id()) == backends_.end()); + backends_.insert( + BackendMap::value_type(backend_impl->process_id(), backend_impl)); } -void AppCacheService::UnregisterBackendImpl( +void AppCacheService::UnregisterBackend( AppCacheBackendImpl* backend_impl) { - backends_.erase(backend_impl); + backends_.erase(backend_impl->process_id()); } void AppCacheService::AddCache(AppCache* cache) { diff --git a/webkit/appcache/appcache_service.h b/webkit/appcache/appcache_service.h index 3eaa43d..bc8bee8 100644 --- a/webkit/appcache/appcache_service.h +++ b/webkit/appcache/appcache_service.h @@ -10,6 +10,7 @@ #include <vector> #include "base/hash_tables.h" +#include "base/file_path.h" #include "googleurl/src/gurl.h" namespace appcache { @@ -24,17 +25,34 @@ class AppCacheService { public: virtual ~AppCacheService(); + void Initialize(const FilePath& cache_directory); + // TODO(jennb): API to set service settings, like file paths for storage // track which processes are using this appcache service - void RegisterBackendImpl(AppCacheBackendImpl* backend_impl); - void UnregisterBackendImpl(AppCacheBackendImpl* backend_impl); + void RegisterBackend(AppCacheBackendImpl* backend_impl); + void UnregisterBackend(AppCacheBackendImpl* backend_impl); void AddCache(AppCache* cache); void RemoveCache(AppCache* cache); void AddGroup(AppCacheGroup* group); void RemoveGroup(AppCacheGroup* group); + AppCacheBackendImpl* GetBackend(int id) { + BackendMap::iterator it = backends_.find(id); + return (it != backends_.end()) ? it->second : NULL; + } + + AppCache* GetCache(int64 id) { + CacheMap::iterator it = caches_.find(id); + return (it != caches_.end()) ? it->second : NULL; + } + + AppCacheGroup* GetGroup(const GURL& manifest_url) { + GroupMap::iterator it = groups_.find(manifest_url); + return (it != groups_.end()) ? it->second : NULL; + } + private: // In-memory representation of stored appcache data. Represents a subset // of the appcache database currently in use. @@ -44,9 +62,10 @@ class AppCacheService { GroupMap groups_; // Track current processes. One 'backend' per child process. - typedef std::set<AppCacheBackendImpl*> BackendSet; - BackendSet backends_; + typedef std::map<int, AppCacheBackendImpl*> BackendMap; + BackendMap backends_; + FilePath cache_directory_; // TODO(jennb): info about appcache storage // AppCacheDatabase db_; // DiskCache response_storage_; diff --git a/webkit/appcache/web_application_cache_host_impl.cc b/webkit/appcache/web_application_cache_host_impl.cc index 02a698f..d5d50fb 100644 --- a/webkit/appcache/web_application_cache_host_impl.cc +++ b/webkit/appcache/web_application_cache_host_impl.cc @@ -43,6 +43,7 @@ WebApplicationCacheHostImpl::WebApplicationCacheHostImpl( WebApplicationCacheHostImpl::~WebApplicationCacheHostImpl() { backend_->UnregisterHost(host_id_); + all_hosts.Remove(host_id_); } void WebApplicationCacheHostImpl::OnCacheSelected(int64 selected_cache_id, diff --git a/webkit/tools/test_shell/simple_appcache_system.cc b/webkit/tools/test_shell/simple_appcache_system.cc new file mode 100644 index 0000000..5ab7fe2 --- /dev/null +++ b/webkit/tools/test_shell/simple_appcache_system.cc @@ -0,0 +1,323 @@ +// Copyright (c) 2009 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 "webkit/tools/test_shell/simple_appcache_system.h" + +#include "base/lock.h" +#include "base/task.h" +#include "base/waitable_event.h" +#include "webkit/appcache/appcache_interceptor.h" +#include "webkit/appcache/web_application_cache_host_impl.h" +#include "webkit/tools/test_shell/simple_resource_loader_bridge.h" + +using WebKit::WebApplicationCacheHost; +using WebKit::WebApplicationCacheHostClient; +using appcache::WebApplicationCacheHostImpl; +using appcache::AppCacheBackendImpl; +using appcache::AppCacheInterceptor; + + +// SimpleFrontendProxy -------------------------------------------------------- +// Proxies method calls from the backend IO thread to the frontend UI thread. + +class SimpleFrontendProxy + : public base::RefCountedThreadSafe<SimpleFrontendProxy>, + public appcache::AppCacheFrontend { + public: + explicit SimpleFrontendProxy(SimpleAppCacheSystem* appcache_system) + : system_(appcache_system) { + } + + void clear_appcache_system() { system_ = NULL; } + + virtual void OnCacheSelected(int host_id, int64 cache_id , + appcache::Status status) { + if (!system_) + return; + if (system_->is_io_thread()) + system_->ui_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleFrontendProxy::OnCacheSelected, + host_id, cache_id, status)); + else if (system_->is_ui_thread()) + system_->frontend_impl_.OnCacheSelected(host_id, cache_id, status); + else + NOTREACHED(); + } + + virtual void OnStatusChanged(const std::vector<int>& host_ids, + appcache::Status status) { + if (!system_) + return; + if (system_->is_io_thread()) + system_->ui_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleFrontendProxy::OnStatusChanged, host_ids, status)); + else if (system_->is_ui_thread()) + system_->frontend_impl_.OnStatusChanged(host_ids, status); + else + NOTREACHED(); + } + + virtual void OnEventRaised(const std::vector<int>& host_ids, + appcache::EventID event_id) { + if (!system_) + return; + if (system_->is_io_thread()) + system_->ui_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleFrontendProxy::OnEventRaised, host_ids, event_id)); + else if (system_->is_ui_thread()) + system_->frontend_impl_.OnEventRaised(host_ids, event_id); + else + NOTREACHED(); + } + + private: + SimpleAppCacheSystem* system_; +}; + + +// SimpleBackendProxy -------------------------------------------------------- +// Proxies method calls from the frontend UI thread to the backend IO thread. + +class SimpleBackendProxy + : public base::RefCountedThreadSafe<SimpleBackendProxy>, + public appcache::AppCacheBackend { + public: + explicit SimpleBackendProxy(SimpleAppCacheSystem* appcache_system) + : system_(appcache_system), event_(true, false) { + get_status_callback_.reset( + NewCallback(this, &SimpleBackendProxy::GetStatusCallback)); + start_update_callback_.reset( + NewCallback(this, &SimpleBackendProxy::StartUpdateCallback)); + swap_cache_callback_.reset( + NewCallback(this, &SimpleBackendProxy::SwapCacheCallback)); + } + + virtual void RegisterHost(int host_id) { + if (system_->is_ui_thread()) { + system_->io_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleBackendProxy::RegisterHost, host_id)); + } else if (system_->is_io_thread()) { + system_->backend_impl_->RegisterHost(host_id); + } else { + NOTREACHED(); + } + } + + virtual void UnregisterHost(int host_id) { + if (system_->is_ui_thread()) { + system_->io_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleBackendProxy::UnregisterHost, host_id)); + } else if (system_->is_io_thread()) { + system_->backend_impl_->UnregisterHost(host_id); + } else { + NOTREACHED(); + } + } + + virtual void SelectCache(int host_id, + const GURL& document_url, + const int64 cache_document_was_loaded_from, + const GURL& manifest_url) { + if (system_->is_ui_thread()) { + system_->io_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleBackendProxy::SelectCache, host_id, document_url, + cache_document_was_loaded_from, manifest_url)); + } else if (system_->is_io_thread()) { + system_->backend_impl_->SelectCache(host_id, document_url, + cache_document_was_loaded_from, + manifest_url); + } else { + NOTREACHED(); + } + } + + virtual void MarkAsForeignEntry(int host_id, const GURL& document_url, + int64 cache_document_was_loaded_from) { + if (system_->is_ui_thread()) { + system_->io_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleBackendProxy::MarkAsForeignEntry, host_id, document_url, + cache_document_was_loaded_from)); + } else if (system_->is_io_thread()) { + system_->backend_impl_->MarkAsForeignEntry( + host_id, document_url, + cache_document_was_loaded_from); + } else { + NOTREACHED(); + } + } + + virtual appcache::Status GetStatus(int host_id) { + if (system_->is_ui_thread()) { + status_result_ = appcache::UNCACHED; + event_.Reset(); + system_->io_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleBackendProxy::GetStatus, host_id)); + event_.Wait(); + } else if (system_->is_io_thread()) { + system_->backend_impl_->GetStatusWithCallback( + host_id, get_status_callback_.get(), NULL); + } else { + NOTREACHED(); + } + return status_result_; + } + + virtual bool StartUpdate(int host_id) { + if (system_->is_ui_thread()) { + bool_result_ = false; + event_.Reset(); + system_->io_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleBackendProxy::StartUpdate, host_id)); + event_.Wait(); + } else if (system_->is_io_thread()) { + system_->backend_impl_->StartUpdateWithCallback( + host_id, start_update_callback_.get(), NULL); + } else { + NOTREACHED(); + } + return bool_result_; + } + + virtual bool SwapCache(int host_id) { + if (system_->is_ui_thread()) { + bool_result_ = false; + event_.Reset(); + system_->io_message_loop()->PostTask(FROM_HERE, NewRunnableMethod( + this, &SimpleBackendProxy::SwapCache, host_id)); + event_.Wait(); + } else if (system_->is_io_thread()) { + system_->backend_impl_->SwapCacheWithCallback( + host_id, swap_cache_callback_.get(), NULL); + } else { + NOTREACHED(); + } + return bool_result_; + } + + void GetStatusCallback(appcache::Status status, void* param) { + status_result_ = status; + event_.Signal(); + } + + void StartUpdateCallback(bool result, void* param) { + bool_result_ = result; + event_.Signal(); + } + + void SwapCacheCallback(bool result, void* param) { + bool_result_ = result; + event_.Signal(); + } + + void SignalEvent() { + event_.Signal(); + } + + private: + SimpleAppCacheSystem* system_; + base::WaitableEvent event_; + bool bool_result_; + appcache::Status status_result_; + scoped_ptr<appcache::GetStatusCallback> get_status_callback_; + scoped_ptr<appcache::StartUpdateCallback> start_update_callback_; + scoped_ptr<appcache::SwapCacheCallback> swap_cache_callback_; +}; + + +// SimpleAppCacheSystem -------------------------------------------------------- + +// This class only works for a single process browser. +static const int kSingleProcessId = 1; + +// A not so thread safe singleton, but should work for test_shell. +SimpleAppCacheSystem* SimpleAppCacheSystem::instance_ = NULL; + +SimpleAppCacheSystem::SimpleAppCacheSystem() + : io_message_loop_(NULL), ui_message_loop_(NULL), + ALLOW_THIS_IN_INITIALIZER_LIST( + backend_proxy_(new SimpleBackendProxy(this))), + ALLOW_THIS_IN_INITIALIZER_LIST( + frontend_proxy_(new SimpleFrontendProxy(this))), + backend_impl_(NULL), service_(NULL) { + DCHECK(!instance_); + instance_ = this; +} + +SimpleAppCacheSystem::~SimpleAppCacheSystem() { + DCHECK(!io_message_loop_ && !backend_impl_ && !service_); + frontend_proxy_->clear_appcache_system(); // in case a task is in transit + instance_ = NULL; +} + +void SimpleAppCacheSystem::InitOnUIThread( + const FilePath& cache_directory) { + DCHECK(!ui_message_loop_); + DCHECK(!cache_directory.empty()); + ui_message_loop_ = MessageLoop::current(); + cache_directory_ = cache_directory; +} + +void SimpleAppCacheSystem::InitOnIOThread() { + if (!is_initailized_on_ui_thread()) + return; + + DCHECK(!io_message_loop_); + io_message_loop_ = MessageLoop::current(); + io_message_loop_->AddDestructionObserver(this); + + // Recreate and initialize per each IO thread. + service_ = new appcache::AppCacheService(); + backend_impl_ = new appcache::AppCacheBackendImpl(); + service_->Initialize(cache_directory_); + backend_impl_->Initialize(service_, frontend_proxy_.get(), kSingleProcessId); + + AppCacheInterceptor::EnsureRegistered(); +} + +WebApplicationCacheHost* SimpleAppCacheSystem::CreateCacheHostForWebKit( + WebApplicationCacheHostClient* client) { + if (!is_initailized_on_ui_thread()) + return NULL; + + DCHECK(is_ui_thread()); + + // The IO thread needs to be running for this system to work. + SimpleResourceLoaderBridge::EnsureIOThread(); + + if (!is_initialized()) + return NULL; + return new WebApplicationCacheHostImpl(client, backend_proxy_.get()); +} + +void SimpleAppCacheSystem::SetExtraRequestBits( + URLRequest* request, int host_id, ResourceType::Type resource_type) { + if (is_initialized()) { + DCHECK(is_io_thread()); + AppCacheInterceptor::SetExtraRequestInfo( + request, service_, kSingleProcessId, host_id, resource_type); + } +} + +void SimpleAppCacheSystem::GetExtraResponseBits( + URLRequest* request, int64* cache_id, GURL* manifest_url) { + if (is_initialized()) { + DCHECK(is_io_thread()); + AppCacheInterceptor::GetExtraResponseInfo( + request, cache_id, manifest_url); + } +} + +void SimpleAppCacheSystem::WillDestroyCurrentMessageLoop() { + DCHECK(is_io_thread()); + DCHECK(backend_impl_->hosts().empty()); + + io_message_loop_ = NULL; + delete backend_impl_; + delete service_; + backend_impl_ = NULL; + service_ = NULL; + + // Just in case the main thread is waiting on it. + backend_proxy_->SignalEvent(); +} diff --git a/webkit/tools/test_shell/simple_appcache_system.h b/webkit/tools/test_shell/simple_appcache_system.h index 6f53524..184842f 100644 --- a/webkit/tools/test_shell/simple_appcache_system.h +++ b/webkit/tools/test_shell/simple_appcache_system.h @@ -5,21 +5,117 @@ #ifndef WEBKIT_TOOLS_TEST_SHELL_SIMPLE_APPCACHE_SYSTEM_H_ #define WEBKIT_TOOLS_TEST_SHELL_SIMPLE_APPCACHE_SYSTEM_H_ +#include "base/file_path.h" +#include "base/message_loop.h" #include "webkit/appcache/appcache_backend_impl.h" #include "webkit/appcache/appcache_frontend_impl.h" +#include "webkit/appcache/appcache_service.h" +#include "webkit/glue/resource_type.h" -class SimpleAppCacheSystem { +namespace WebKit { +class WebApplicationCacheHost; +class WebApplicationCacheHostClient; +} +class SimpleBackendProxy; +class SimpleFrontendProxy; +class URLRequest; + +// A class that composes the constituent parts of an appcache system +// together for use in a single process with two relavant threads, +// a UI thread on which webkit runs and an IO thread on which URLRequests +// are handled. This class conspires with SimpleResourceLoaderBridge to +// retrieve resources from the appcache. +class SimpleAppCacheSystem : public MessageLoop::DestructionObserver { public: - void Initialize() { - backend_impl_.Initialize(NULL, &frontend_impl_); + // Should be instanced somewhere in main(). If not instanced, the public + // static methods are all safe no-ops. + SimpleAppCacheSystem(); + virtual ~SimpleAppCacheSystem(); + + // One-time main UI thread initialization. + static void InitializeOnUIThread(const FilePath& cache_directory) { + if (instance_) + instance_->InitOnUIThread(cache_directory); } - appcache::AppCacheBackend* backend() { return &backend_impl_; } - appcache::AppCacheFrontend* frontend() { return &frontend_impl_; } + // Called by SimpleResourceLoaderBridge's IOThread class. + // Per IO thread initialization. Only one IO thread can exist + // at a time, but after IO thread termination a new one can be + // started on which this method should be called. The instance + // is assumed to outlive the IO thread. + static void InitializeOnIOThread() { + if (instance_) + instance_->InitOnIOThread(); + } + + // Called by TestShellWebKitInit to manufacture a 'host' for webcore. + static WebKit::WebApplicationCacheHost* CreateApplicationCacheHost( + WebKit::WebApplicationCacheHostClient* client) { + return instance_ ? instance_->CreateCacheHostForWebKit(client) : NULL; + } + + // Called by SimpleResourceLoaderBridge to hook into resource loads. + static void SetExtraRequestInfo(URLRequest* request, + int host_id, + ResourceType::Type resource_type) { + if (instance_) + instance_->SetExtraRequestBits(request, host_id, resource_type); + } + + // Called by SimpleResourceLoaderBridge extract extra response bits. + static void GetExtraResponseInfo(URLRequest* request, + int64* cache_id, + GURL* manifest_url) { + if (instance_) + instance_->GetExtraResponseBits(request, cache_id, manifest_url); + } private: - appcache::AppCacheBackendImpl backend_impl_; + friend class SimpleBackendProxy; + friend class SimpleFrontendProxy; + + // A low-tech singleton. + static SimpleAppCacheSystem* instance_; + + // Instance methods called by our static public methods + void InitOnUIThread(const FilePath& cache_directory); + void InitOnIOThread(); + WebKit::WebApplicationCacheHost* CreateCacheHostForWebKit( + WebKit::WebApplicationCacheHostClient* client); + void SetExtraRequestBits(URLRequest* request, + int host_id, + ResourceType::Type resource_type); + void GetExtraResponseBits(URLRequest* request, + int64* cache_id, + GURL* manifest_url); + + // Helpers + MessageLoop* io_message_loop() { return io_message_loop_; } + MessageLoop* ui_message_loop() { return ui_message_loop_; } + bool is_io_thread() { return MessageLoop::current() == io_message_loop_; } + bool is_ui_thread() { return MessageLoop::current() == ui_message_loop_; } + bool is_initialized() { + return io_message_loop_ && is_initailized_on_ui_thread(); + } + bool is_initailized_on_ui_thread() { + return ui_message_loop_ && !cache_directory_.empty(); + } + + // IOThread DestructionObserver + virtual void WillDestroyCurrentMessageLoop(); + + FilePath cache_directory_; + MessageLoop* io_message_loop_; + MessageLoop* ui_message_loop_; + scoped_refptr<SimpleBackendProxy> backend_proxy_; + scoped_refptr<SimpleFrontendProxy> frontend_proxy_; appcache::AppCacheFrontendImpl frontend_impl_; + + // Created and used only on the IO thread, these do + // not survive IO thread termination. If a new IO thread + // is started new instances will be created. + appcache::AppCacheBackendImpl* backend_impl_; + appcache::AppCacheService* service_; }; #endif // WEBKIT_TOOLS_TEST_SHELL_SIMPLE_APPCACHE_SYSTEM_H_ diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.cc b/webkit/tools/test_shell/simple_resource_loader_bridge.cc index c27f061..46126a0 100644 --- a/webkit/tools/test_shell/simple_resource_loader_bridge.cc +++ b/webkit/tools/test_shell/simple_resource_loader_bridge.cc @@ -48,6 +48,7 @@ #include "net/url_request/url_request.h" #include "webkit/appcache/appcache_interfaces.h" #include "webkit/glue/resource_loader_bridge.h" +#include "webkit/tools/test_shell/simple_appcache_system.h" #include "webkit/tools/test_shell/test_shell_request_context.h" using webkit_glue::ResourceLoaderBridge; @@ -71,6 +72,10 @@ class IOThread : public base::Thread { Stop(); } + virtual void Init() { + SimpleAppCacheSystem::InitializeOnIOThread(); + } + virtual void CleanUp() { if (request_context) { request_context->Release(); @@ -79,19 +84,6 @@ class IOThread : public base::Thread { } }; -bool EnsureIOThread() { - if (io_thread) - return true; - - if (!request_context) - SimpleResourceLoaderBridge::Init(NULL); - - io_thread = new IOThread(); - base::Thread::Options options; - options.message_loop_type = MessageLoop::TYPE_IO; - return io_thread->StartWithOptions(options); -} - //----------------------------------------------------------------------------- struct RequestParams { @@ -101,6 +93,7 @@ struct RequestParams { GURL referrer; std::string headers; int load_flags; + ResourceType::Type request_type; int appcache_host_id; scoped_refptr<net::UploadData> upload; }; @@ -214,6 +207,9 @@ class RequestProxy : public URLRequest::Delegate, request_->set_load_flags(params->load_flags); request_->set_upload(params->upload.get()); request_->set_context(request_context); + SimpleAppCacheSystem::SetExtraRequestInfo( + request_.get(), params->appcache_host_id, params->request_type); + request_->Start(); if (request_->has_upload() && @@ -376,11 +372,13 @@ class RequestProxy : public URLRequest::Delegate, info->request_time = request->request_time(); info->response_time = request->response_time(); info->headers = request->response_headers(); - info->appcache_id = appcache::kNoCacheId; - // TODO(michaeln): info->appcache_manifest_url = GURL(); request->GetMimeType(&info->mime_type); request->GetCharset(&info->charset); info->content_length = request->GetExpectedContentSize(); + SimpleAppCacheSystem::GetExtraResponseInfo( + request, + &info->appcache_id, + &info->appcache_manifest_url); } scoped_ptr<URLRequest> request_; @@ -469,6 +467,7 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge { const GURL& referrer, const std::string& headers, int load_flags, + ResourceType::Type request_type, int appcache_host_id) : params_(new RequestParams), proxy_(NULL) { @@ -478,6 +477,7 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge { params_->referrer = referrer; params_->headers = headers; params_->load_flags = load_flags; + params_->request_type = request_type; params_->appcache_host_id = appcache_host_id; } @@ -517,7 +517,7 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge { virtual bool Start(Peer* peer) { DCHECK(!proxy_); - if (!EnsureIOThread()) + if (!SimpleResourceLoaderBridge::EnsureIOThread()) return false; proxy_ = new RequestProxy(); @@ -540,7 +540,7 @@ class ResourceLoaderBridgeImpl : public ResourceLoaderBridge { virtual void SyncLoad(SyncLoadResponse* response) { DCHECK(!proxy_); - if (!EnsureIOThread()) + if (!SimpleResourceLoaderBridge::EnsureIOThread()) return; // this may change as the result of a redirect @@ -616,7 +616,7 @@ ResourceLoaderBridge* ResourceLoaderBridge::Create( int routing_id) { return new ResourceLoaderBridgeImpl(method, url, first_party_for_cookies, referrer, headers, load_flags, - appcache_host_id); + request_type, appcache_host_id); } // Issue the proxy resolve request on the io thread, and wait @@ -696,3 +696,16 @@ std::string SimpleResourceLoaderBridge::GetCookies( return getter->GetResult(); } + +bool SimpleResourceLoaderBridge::EnsureIOThread() { + if (io_thread) + return true; + + if (!request_context) + SimpleResourceLoaderBridge::Init(NULL); + + io_thread = new IOThread(); + base::Thread::Options options; + options.message_loop_type = MessageLoop::TYPE_IO; + return io_thread->StartWithOptions(options); +} diff --git a/webkit/tools/test_shell/simple_resource_loader_bridge.h b/webkit/tools/test_shell/simple_resource_loader_bridge.h index 24df90c..460071b 100644 --- a/webkit/tools/test_shell/simple_resource_loader_bridge.h +++ b/webkit/tools/test_shell/simple_resource_loader_bridge.h @@ -33,6 +33,7 @@ class SimpleResourceLoaderBridge { const std::string& cookie); static std::string GetCookies(const GURL& url, const GURL& first_party_for_cookies); + static bool EnsureIOThread(); }; #endif // WEBKIT_TOOLS_TEST_SHELL_SIMPLE_RESOURCE_LOADER_BRIDGE_H__ diff --git a/webkit/tools/test_shell/test_shell.gyp b/webkit/tools/test_shell/test_shell.gyp index 73249ed..94d3863 100644 --- a/webkit/tools/test_shell/test_shell.gyp +++ b/webkit/tools/test_shell/test_shell.gyp @@ -63,6 +63,7 @@ 'mock_webclipboard_impl.cc', 'mock_webclipboard_impl.h', 'resource.h', + 'simple_appcache_system.cc', 'simple_appcache_system.h', 'simple_clipboard_impl.cc', 'simple_resource_loader_bridge.cc', diff --git a/webkit/tools/test_shell/test_shell_webkit_init.h b/webkit/tools/test_shell/test_shell_webkit_init.h index 2727d6b..354d949 100644 --- a/webkit/tools/test_shell/test_shell_webkit_init.h +++ b/webkit/tools/test_shell/test_shell_webkit_init.h @@ -7,6 +7,7 @@ #include "base/file_util.h" #include "base/path_service.h" +#include "base/scoped_temp_dir.h" #include "base/stats_counters.h" #include "base/string_util.h" #include "media/base/media.h" @@ -42,7 +43,6 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl { WebKit::enableV8SingleThreadMode(); WebKit::registerExtension(extensions_v8::GearsExtension::Get()); WebKit::registerExtension(extensions_v8::IntervalExtension::Get()); - appcache_system_.Initialize(); // Load libraries for media and enable the media player. FilePath module_path; @@ -50,6 +50,12 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl { media::InitializeMediaLibrary(module_path)) { WebKit::enableMediaPlayer(); } + + // Construct and initialize an appcache system for this scope. + // A new empty temp directory is created to house any cached + // content during the run. Upon exit that directory is deleted. + if (appcache_dir_.CreateUniqueTempDir()) + SimpleAppCacheSystem::InitializeOnUIThread(appcache_dir_.path()); } ~TestShellWebKitInit() { @@ -149,14 +155,14 @@ class TestShellWebKitInit : public webkit_glue::WebKitClientImpl { virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost( WebKit::WebApplicationCacheHostClient* client) { - return new appcache::WebApplicationCacheHostImpl( - client, appcache_system_.backend()); + return SimpleAppCacheSystem::CreateApplicationCacheHost(client); } private: webkit_glue::SimpleWebMimeRegistryImpl mime_registry_; MockWebClipboardImpl mock_clipboard_; webkit_glue::WebClipboardImpl real_clipboard_; + ScopedTempDir appcache_dir_; SimpleAppCacheSystem appcache_system_; }; diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp index 0a6fe18..397d56c 100644 --- a/webkit/webkit.gyp +++ b/webkit/webkit.gyp @@ -1258,6 +1258,8 @@ 'appcache/appcache_group.h', 'appcache/appcache_host.cc', 'appcache/appcache_host.h', + 'appcache/appcache_interceptor.cc', + 'appcache/appcache_interceptor.h', 'appcache/appcache_interfaces.cc', 'appcache/appcache_interfaces.h', 'appcache/appcache_service.cc', |