| Index: webkit/appcache/appcache_host.cc
|
| ===================================================================
|
| --- webkit/appcache/appcache_host.cc (revision 26254)
|
| +++ webkit/appcache/appcache_host.cc (working copy)
|
| @@ -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);
|
| }
|
| }
|
|
|
|
|