Index: webkit/appcache/appcache_update_job.cc |
=================================================================== |
--- webkit/appcache/appcache_update_job.cc (revision 52160) |
+++ webkit/appcache/appcache_update_job.cc (working copy) |
@@ -106,6 +106,15 @@ |
} |
} |
+ void SendErrorNotifications(const std::string& error_message) { |
+ DCHECK(!error_message.empty()); |
+ for (NotifyHostMap::iterator it = hosts_to_notify.begin(); |
+ it != hosts_to_notify.end(); ++it) { |
+ AppCacheFrontend* frontend = it->first; |
+ frontend->OnErrorEventRaised(it->second, error_message); |
+ } |
+ } |
+ |
private: |
NotifyHostMap hosts_to_notify; |
}; |
@@ -236,20 +245,25 @@ |
group_->NotifyContentBlocked(); |
+ const char* kErrorMessage = |
+ "Cache creation was blocked by the content policy"; |
MessageLoop::current()->PostTask(FROM_HERE, |
method_factory_.NewRunnableMethod( |
- &AppCacheUpdateJob::HandleCacheFailure)); |
+ &AppCacheUpdateJob::HandleCacheFailure, |
+ kErrorMessage)); |
} |
-void AppCacheUpdateJob::HandleCacheFailure() { |
- // TODO(michaeln): For now this is only invoked from one point |
- // of failure. Overtime, attempt the migrate the various places |
- // where we can detect a failure condition to use this same |
- // method to enter the cache_failure state. |
+void AppCacheUpdateJob::HandleCacheFailure(const std::string& error_message) { |
+ // 6.9.4 cache failure steps 2-8. |
+ DCHECK(internal_state_ != CACHE_FAILURE); |
+ DCHECK(!error_message.empty()); |
internal_state_ = CACHE_FAILURE; |
CancelAllUrlFetches(); |
- CancelAllMasterEntryFetches(); |
- MaybeCompleteUpdate(); |
+ CancelAllMasterEntryFetches(error_message); |
+ NotifyAllError(error_message); |
+ DiscardInprogressCache(); |
+ internal_state_ = COMPLETED; |
+ DeleteSoon(); // To unwind the stack prior to deletion. |
} |
void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) { |
@@ -512,25 +526,26 @@ |
} else if (response_code == 404 || response_code == 410) { |
service_->storage()->MakeGroupObsolete(group_, this); // async |
} else { |
- internal_state_ = CACHE_FAILURE; |
- CancelAllMasterEntryFetches(); |
- MaybeCompleteUpdate(); // if not done, run async cache failure steps |
+ const char* kFormatString = "Manifest fetch failed (%d) %s"; |
+ const std::string message = StringPrintf(kFormatString, response_code, |
+ manifest_url_.spec().c_str()); |
+ HandleCacheFailure(message); |
} |
} |
void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group, |
bool success) { |
DCHECK(master_entry_fetches_.empty()); |
- CancelAllMasterEntryFetches(); |
+ CancelAllMasterEntryFetches("The group has been made obsolete"); |
if (success) { |
DCHECK(group->is_obsolete()); |
NotifyAllAssociatedHosts(OBSOLETE_EVENT); |
internal_state_ = COMPLETED; |
+ MaybeCompleteUpdate(); |
} else { |
// Treat failure to mark group obsolete as a cache failure. |
- internal_state_ = CACHE_FAILURE; |
+ HandleCacheFailure("Failed to make the group as obsolete"); |
} |
- MaybeCompleteUpdate(); |
} |
void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) { |
@@ -549,10 +564,11 @@ |
Manifest manifest; |
if (!ParseManifest(manifest_url_, manifest_data_.data(), |
manifest_data_.length(), manifest)) { |
- LOG(INFO) << "Failed to parse manifest: " << manifest_url_; |
- internal_state_ = CACHE_FAILURE; |
- CancelAllMasterEntryFetches(); |
- MaybeCompleteUpdate(); // if not done, run async cache failure steps |
+ const char* kFormatString = "Failed to parse manifest %s"; |
+ const std::string message = StringPrintf(kFormatString, |
+ manifest_url_.spec().c_str()); |
+ HandleCacheFailure(message); |
+ LOG(INFO) << message; |
return; |
} |
@@ -585,7 +601,7 @@ |
const GURL& url = request->original_url(); |
pending_url_fetches_.erase(url); |
- NotifyProgress(url); |
+ NotifyAllProgress(url); |
++url_fetches_completed_; |
int response_code = request->status().is_success() |
@@ -613,9 +629,11 @@ |
<< " os_error: " << request->status().os_error() |
<< " response code: " << response_code; |
if (entry.IsExplicit() || entry.IsFallback()) { |
- internal_state_ = CACHE_FAILURE; |
- CancelAllUrlFetches(); |
- CancelAllMasterEntryFetches(); |
+ const char* kFormatString = "Resource fetch failed (%d) %s"; |
+ const std::string message = StringPrintf(kFormatString, response_code, |
+ request->url().spec().c_str()); |
+ HandleCacheFailure(message); |
+ return; |
} else if (response_code == 404 || response_code == 410) { |
// Entry is skipped. They are dropped from the cache. |
} else if (update_type_ == UPGRADE_ATTEMPT) { |
@@ -631,9 +649,8 @@ |
} |
// Fetch another URL now that one request has completed. |
- if (internal_state_ != CACHE_FAILURE) |
- FetchUrls(); |
- |
+ DCHECK(internal_state_ != CACHE_FAILURE); |
+ FetchUrls(); |
MaybeCompleteUpdate(); |
} |
@@ -693,8 +710,12 @@ |
host->RemoveObserver(this); |
} |
hosts.clear(); |
- host_notifier.SendNotifications(ERROR_EVENT); |
+ const char* kFormatString = "Master entry fetch failed (%d) %s"; |
+ const std::string message = StringPrintf(kFormatString, response_code, |
+ request->url().spec().c_str()); |
+ host_notifier.SendErrorNotifications(message); |
+ |
// In downloading case, update result is different if all master entries |
// failed vs. only some failing. |
if (inprogress_cache_) { |
@@ -704,15 +725,14 @@ |
// Section 6.9.4, step 22.3. |
if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) { |
- CancelAllUrlFetches(); |
- internal_state_ = CACHE_FAILURE; |
+ HandleCacheFailure(message); |
+ return; |
} |
} |
} |
- if (internal_state_ != CACHE_FAILURE) |
- FetchMasterEntries(); |
- |
+ DCHECK(internal_state_ != CACHE_FAILURE); |
+ FetchMasterEntries(); |
MaybeCompleteUpdate(); |
} |
@@ -743,8 +763,7 @@ |
<< " os_error: " << request->status().os_error() |
<< " response code: " << response_code; |
ScheduleUpdateRetry(kRerunDelayMs); |
- internal_state_ = CACHE_FAILURE; |
- MaybeCompleteUpdate(); // will definitely complete |
+ HandleCacheFailure("Manifest changed during update, scheduling retry"); |
} |
} |
@@ -755,8 +774,7 @@ |
manifest_response_writer_->WriteData(io_buffer, manifest_data_.length(), |
&manifest_data_write_callback_); |
} else { |
- internal_state_ = CACHE_FAILURE; |
- MaybeCompleteUpdate(); // will definitely complete |
+ HandleCacheFailure("Failed to write the manifest headers to storage"); |
} |
} |
@@ -769,8 +787,7 @@ |
duplicate_response_ids_.push_back(entry.response_id()); |
StoreGroupAndCache(); |
} else { |
- internal_state_ = CACHE_FAILURE; |
- MaybeCompleteUpdate(); // will definitely complete |
+ HandleCacheFailure("Failed to write the manifest data to storage"); |
} |
} |
@@ -793,15 +810,15 @@ |
DCHECK(stored_state_ == STORING); |
if (success) { |
stored_state_ = STORED; |
+ MaybeCompleteUpdate(); // will definitely complete |
} else { |
- internal_state_ = CACHE_FAILURE; |
- |
// Restore inprogress_cache_ to get the proper events delivered |
// and the proper cleanup to occur. |
if (newest_cache != group->newest_complete_cache()) |
inprogress_cache_ = newest_cache; |
+ |
+ HandleCacheFailure("Failed to commit new cache to storage"); |
} |
- MaybeCompleteUpdate(); // will definitely complete |
} |
void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, |
@@ -810,41 +827,30 @@ |
host->frontend()->OnEventRaised(ids, event_id); |
} |
-void AppCacheUpdateJob::NotifyAllPendingMasterHosts(EventID event_id) { |
- // Collect hosts so we only send one notification per frontend. |
- // A host can only be associated with a single pending master entry |
- // so no need to worry about duplicate hosts being added to the notifier. |
- HostNotifier host_notifier; |
- for (PendingMasters::iterator it = pending_master_entries_.begin(); |
- it != pending_master_entries_.end(); ++it) { |
- PendingHosts& hosts = it->second; |
- for (PendingHosts::iterator host_it = hosts.begin(); |
- host_it != hosts.end(); ++host_it) { |
- host_notifier.AddHost(*host_it); |
- } |
- } |
- |
- host_notifier.SendNotifications(event_id); |
-} |
- |
void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) { |
HostNotifier host_notifier; |
AddAllAssociatedHostsToNotifier(&host_notifier); |
host_notifier.SendNotifications(event_id); |
} |
-void AppCacheUpdateJob::NotifyProgress(const GURL& url) { |
+void AppCacheUpdateJob::NotifyAllProgress(const GURL& url) { |
HostNotifier host_notifier; |
AddAllAssociatedHostsToNotifier(&host_notifier); |
host_notifier.SendProgressNotifications( |
url, url_file_list_.size(), url_fetches_completed_); |
} |
-void AppCacheUpdateJob::NotifyFinalProgress() { |
+void AppCacheUpdateJob::NotifyAllFinalProgress() { |
DCHECK(url_file_list_.size() == url_fetches_completed_); |
- NotifyProgress(GURL()); |
+ NotifyAllProgress(GURL()); |
} |
+void AppCacheUpdateJob::NotifyAllError(const std::string& error_message) { |
+ HostNotifier host_notifier; |
+ AddAllAssociatedHostsToNotifier(&host_notifier); |
+ host_notifier.SendErrorNotifications(error_message); |
+} |
+ |
void AppCacheUpdateJob::AddAllAssociatedHostsToNotifier( |
HostNotifier* host_notifier) { |
// Collect hosts so we only send one notification per frontend. |
@@ -958,10 +964,10 @@ |
DCHECK(it != url_file_list_.end()); |
AppCacheEntry& entry = it->second; |
if (ShouldSkipUrlFetch(entry)) { |
- NotifyProgress(url); |
+ NotifyAllProgress(url); |
++url_fetches_completed_; |
} else if (AlreadyFetchedEntry(url, entry.types())) { |
- NotifyProgress(url); |
+ NotifyAllProgress(url); |
++url_fetches_completed_; // saved a URL request |
} else if (!storage_checked && MaybeLoadFromNewestCache(url, entry)) { |
// Continues asynchronously after data is loaded from newest cache. |
@@ -1089,7 +1095,8 @@ |
} |
} |
-void AppCacheUpdateJob::CancelAllMasterEntryFetches() { |
+void AppCacheUpdateJob::CancelAllMasterEntryFetches( |
+ const std::string& error_message) { |
// For now, cancel all in-progress fetches for master entries and pretend |
// all master entries fetches have completed. |
// TODO(jennb): Delete this when update no longer fetches master entries |
@@ -1125,7 +1132,7 @@ |
master_entries_to_fetch_.erase(master_entries_to_fetch_.begin()); |
} |
- host_notifier.SendNotifications(ERROR_EVENT); |
+ host_notifier.SendErrorNotifications(error_message); |
} |
bool AppCacheUpdateJob::MaybeLoadFromNewestCache(const GURL& url, |
@@ -1174,6 +1181,7 @@ |
http_info->response_time, |
base::Time::Now()) || |
http_info->headers->EnumerateHeader(&iter, name, &value)) { |
+ // TODO(michaeln): Make a conditional request when we can in this case. |
LoadFromNewestCacheFailed(url); |
} else { |
DCHECK(group_->newest_complete_cache()); |
@@ -1187,7 +1195,7 @@ |
entry.set_response_id(response_id); |
entry.set_response_size(copy_me->response_size()); |
inprogress_cache_->AddOrModifyEntry(url, entry); |
- NotifyProgress(url); |
+ NotifyAllProgress(url); |
++url_fetches_completed_; |
} |
} |
@@ -1206,6 +1214,8 @@ |
} |
void AppCacheUpdateJob::MaybeCompleteUpdate() { |
+ DCHECK(internal_state_ != CACHE_FAILURE); |
+ |
// Must wait for any pending master entries or url fetches to complete. |
if (master_entries_completed_ != pending_master_entries_.size() || |
url_fetches_completed_ != url_file_list_.size()) { |
@@ -1237,7 +1247,7 @@ |
break; |
case REFETCH_MANIFEST: |
DCHECK(stored_state_ == STORED); |
- NotifyFinalProgress(); |
+ NotifyAllFinalProgress(); |
if (update_type_ == CACHE_ATTEMPT) |
NotifyAllAssociatedHosts(CACHED_EVENT); |
else |
@@ -1246,13 +1256,7 @@ |
internal_state_ = COMPLETED; |
break; |
case CACHE_FAILURE: |
- // 6.9.4 cache failure steps 2-8. |
- NotifyAllAssociatedHosts(ERROR_EVENT); |
- DiscardInprogressCache(); |
- // For a CACHE_ATTEMPT, group will be discarded when the host(s) that |
- // started this update removes its reference to the group. Nothing more |
- // to do here. |
- internal_state_ = COMPLETED; |
+ NOTREACHED(); // See HandleCacheFailure |
break; |
default: |
break; |