| 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;
|
|
|