summaryrefslogtreecommitdiffstats
path: root/webkit/appcache/appcache_host.cc
diff options
context:
space:
mode:
authormichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-15 22:07:15 +0000
committermichaeln@google.com <michaeln@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-09-15 22:07:15 +0000
commit97e3edc23314c476859c22c8db601f9b3dec552d (patch)
tree9c589f47545b88c1453c2481a7844a921636485c /webkit/appcache/appcache_host.cc
parent34fce2a5030cb53a1e2decb37b5f7517f98457f7 (diff)
downloadchromium_src-97e3edc23314c476859c22c8db601f9b3dec552d.zip
chromium_src-97e3edc23314c476859c22c8db601f9b3dec552d.tar.gz
chromium_src-97e3edc23314c476859c22c8db601f9b3dec552d.tar.bz2
* Fleshed out AppCacheHost class a fair amount, in particular the cache selection algorithm.
* Added some AppCacheHost unit tests. * Introduced AppCacheRequestHandler class, which replaces the clunkyApp CacheInterceptor::ExtraInfo struct. This impl is entirely skeletal stubs for now. TEST=appcache_unittest.cc, but really needs more BUG=none Review URL: http://codereview.chromium.org/192043 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@26275 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache/appcache_host.cc')
-rw-r--r--webkit/appcache/appcache_host.cc247
1 files changed, 234 insertions, 13 deletions
diff --git a/webkit/appcache/appcache_host.cc b/webkit/appcache/appcache_host.cc
index 99f0544..252c618 100644
--- a/webkit/appcache/appcache_host.cc
+++ b/webkit/appcache/appcache_host.cc
@@ -8,33 +8,254 @@
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_interfaces.h"
+#include "webkit/appcache/appcache_request_handler.h"
+#include "webkit/appcache/appcache_service.h"
namespace appcache {
-AppCacheHost::AppCacheHost(int host_id, AppCacheFrontend* frontend)
- : host_id_(host_id),
- selected_cache_(NULL),
- group_(NULL),
- frontend_(frontend) {
+AppCacheHost::AppCacheHost(int host_id, AppCacheFrontend* frontend,
+ AppCacheService* service)
+ : host_id_(host_id), pending_selected_cache_id_(kNoCacheId),
+ frontend_(frontend), service_(service),
+ pending_get_status_callback_(NULL), pending_start_update_callback_(NULL),
+ pending_swap_cache_callback_(NULL), pending_callback_param_(NULL) {
}
AppCacheHost::~AppCacheHost() {
- if (selected_cache_)
- set_selected_cache(NULL);
- DCHECK(!group_);
+ if (associated_cache_.get())
+ associated_cache_->UnassociateHost(this);
+ service_->CancelLoads(this);
}
-void AppCacheHost::set_selected_cache(AppCache *cache) {
- if (selected_cache_)
- selected_cache_->UnassociateHost(this);
+void AppCacheHost::SelectCache(const GURL& document_url,
+ const int64 cache_document_was_loaded_from,
+ const GURL& manifest_url) {
+ DCHECK(!pending_start_update_callback_ &&
+ !pending_swap_cache_callback_ &&
+ !pending_get_status_callback_);
- selected_cache_ = cache;
+ // First we handle an unusual case of SelectCache being called a second
+ // time. Generally this shouldn't happen, but with bad content I think
+ // this can occur... <html manifest=foo> <html manifest=bar></html></html>
+ // We handle this by killing whatever loading we have initiated, and by
+ // unassociating any hosts we currently have associated... and starting
+ // anew with the inputs to this SelectCache call.
+ // TODO(michaeln): at some point determine what behavior the algorithms
+ // described in the HTML5 draft produce and have our impl produce those
+ // results (or suggest changes to the algorihtms described in the spec
+ // if the resulting behavior is just too insane).
+ if (is_selection_pending()) {
+ service_->CancelLoads(this);
+ pending_selected_manifest_url_ = GURL::EmptyGURL();
+ pending_selected_cache_id_ = kNoCacheId;
+ } else if (associated_cache()) {
+ AssociateCache(NULL);
+ }
+ new_master_entry_url_ = GURL::EmptyGURL();
+
+ // 6.9.6 The application cache selection algorithm.
+ // The algorithm is started here and continues in FinishCacheSelection,
+ // after cache or group loading is complete.
+ // Note: foriegn entries are detected on the client side and
+ // MarkAsForeignEntry is called in that case, so that detection
+ // step is skipped here.
+
+ if (cache_document_was_loaded_from != kNoCacheId) {
+ LoadCache(cache_document_was_loaded_from);
+ return;
+ }
+
+ if (!manifest_url.is_empty() &&
+ (manifest_url.GetOrigin() == document_url.GetOrigin())) {
+ new_master_entry_url_ = document_url;
+ LoadOrCreateGroup(manifest_url);
+ return;
+ }
+
+ // TODO(michaeln): If there was a manifest URL, the user agent may report
+ // to the user that it was ignored, to aid in application development.
+ FinishCacheSelection(NULL, NULL);
+}
+
+void AppCacheHost::MarkAsForeignEntry(const GURL& document_url,
+ int64 cache_document_was_loaded_from) {
+ service_->MarkAsForeignEntry(document_url, cache_document_was_loaded_from);
+ SelectCache(document_url, kNoCacheId, GURL::EmptyGURL());
+}
+
+void AppCacheHost::GetStatusWithCallback(GetStatusCallback* callback,
+ void* callback_param) {
+ DCHECK(!pending_start_update_callback_ &&
+ !pending_swap_cache_callback_ &&
+ !pending_get_status_callback_);
+
+ pending_get_status_callback_ = callback;
+ pending_callback_param_ = callback_param;
+ if (is_selection_pending())
+ return;
+
+ DoPendingGetStatus();
+}
+
+void AppCacheHost::DoPendingGetStatus() {
+ DCHECK(pending_get_status_callback_);
+
+ pending_get_status_callback_->Run(
+ GetStatus(), pending_callback_param_);
+
+ pending_get_status_callback_ = NULL;
+ pending_callback_param_ = NULL;
+}
+
+void AppCacheHost::StartUpdateWithCallback(StartUpdateCallback* callback,
+ void* callback_param) {
+ DCHECK(!pending_start_update_callback_ &&
+ !pending_swap_cache_callback_ &&
+ !pending_get_status_callback_);
+
+ pending_start_update_callback_ = callback;
+ pending_callback_param_ = callback_param;
+ if (is_selection_pending())
+ return;
+
+ DoPendingStartUpdate();
+}
+
+void AppCacheHost::DoPendingStartUpdate() {
+ DCHECK(pending_start_update_callback_);
+
+ // TODO(michaeln): start an update if appropiate to do so
+ pending_start_update_callback_->Run(
+ false, pending_callback_param_);
+
+ pending_start_update_callback_ = NULL;
+ pending_callback_param_ = NULL;
+}
+
+void AppCacheHost::SwapCacheWithCallback(SwapCacheCallback* callback,
+ void* callback_param) {
+ DCHECK(!pending_start_update_callback_ &&
+ !pending_swap_cache_callback_ &&
+ !pending_get_status_callback_);
+
+ pending_swap_cache_callback_ = callback;
+ pending_callback_param_ = callback_param;
+ if (is_selection_pending())
+ return;
+
+ DoPendingSwapCache();
+}
+
+void AppCacheHost::DoPendingSwapCache() {
+ DCHECK(pending_swap_cache_callback_);
+
+ // TODO(michaeln): swap if we have a cache that can be swapped.
+ pending_swap_cache_callback_->Run(
+ false, pending_callback_param_);
+
+ pending_swap_cache_callback_ = NULL;
+ pending_callback_param_ = NULL;
+}
+
+AppCacheRequestHandler* AppCacheHost::CreateRequestHandler(
+ URLRequest* request,
+ bool is_main_request) {
+ if (is_main_request)
+ return new AppCacheRequestHandler(this);
+
+ if (associated_cache() && associated_cache()->is_complete())
+ return new AppCacheRequestHandler(associated_cache());
+
+ return NULL;
+}
+
+Status AppCacheHost::GetStatus() {
+ // TODO(michaeln): determine a real status value
+ Status status = associated_cache() ? IDLE : UNCACHED;
+ return status;
+}
+
+void AppCacheHost::LoadOrCreateGroup(const GURL& manifest_url) {
+ DCHECK(manifest_url.is_valid());
+ pending_selected_manifest_url_ = manifest_url;
+ service_->LoadOrCreateGroup(manifest_url, this);
+}
+
+void AppCacheHost::GroupLoadedCallback(
+ AppCacheGroup* group, const GURL& manifest_url) {
+ DCHECK(manifest_url == pending_selected_manifest_url_);
+ pending_selected_manifest_url_ = GURL::EmptyGURL();
+ FinishCacheSelection(NULL, group);
+}
+
+void AppCacheHost::LoadCache(int64 cache_id) {
+ DCHECK(cache_id != kNoCacheId);
+ pending_selected_cache_id_ = cache_id;
+ service_->LoadCache(cache_id, this);
+}
+
+void AppCacheHost::CacheLoadedCallback(AppCache* cache, int64 cache_id) {
+ DCHECK(cache_id == pending_selected_cache_id_);
+ pending_selected_cache_id_ = kNoCacheId;
+ if (cache)
+ FinishCacheSelection(cache, NULL);
+ else
+ FinishCacheSelection(NULL, NULL);
+}
+
+void AppCacheHost::FinishCacheSelection(
+ AppCache *cache, AppCacheGroup* group) {
+ DCHECK(!associated_cache());
+
+ // 6.9.6 The application cache selection algorithm
+ if (cache) {
+ // If document was loaded from an application cache, Associate document
+ // with the application cache from which it was loaded. Invoke the
+ // application cache update process for that cache and with the browsing
+ // context being navigated.
+ DCHECK(cache->owning_group());
+ DCHECK(new_master_entry_url_.is_empty());
+ AssociateCache(cache);
+ cache->owning_group()->StartUpdateWithHost(this);
+
+ } else if (group) {
+ // If document was loaded using HTTP GET or equivalent, and, there is a
+ // manifest URL, and manifest URL has the same origin as document.
+ // Invoke the application cache update process for manifest URL, with
+ // the browsing context being navigated, and with document and the
+ // resource from which document was loaded as the new master resourse.
+ DCHECK(new_master_entry_url_.is_valid());
+ AssociateCache(NULL); // The UpdateJob may produce one for us later.
+ group->StartUpdateWithNewMasterEntry(this, new_master_entry_url_);
+
+ } else {
+ // Otherwise, the Document is not associated with any application cache.
+ AssociateCache(NULL);
+ }
+
+ // Respond to pending callbacks now that we have a selection.
+ if (pending_get_status_callback_)
+ DoPendingGetStatus();
+ else if (pending_start_update_callback_)
+ DoPendingStartUpdate();
+ else if (pending_swap_cache_callback_)
+ DoPendingSwapCache();
+}
+
+void AppCacheHost::AssociateCache(AppCache* cache) {
+ if (associated_cache_.get()) {
+ associated_cache_->UnassociateHost(this);
+ group_ = NULL;
+ }
+
+ associated_cache_ = cache;
if (cache) {
cache->AssociateHost(this);
group_ = cache->owning_group();
+ frontend_->OnCacheSelected(host_id_, cache->cache_id(), GetStatus());
} else {
- group_ = NULL;
+ frontend_->OnCacheSelected(host_id_, kNoCacheId, UNCACHED);
}
}