Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(224)

Side by Side Diff: webkit/appcache/appcache_update_job.cc

Issue 2910007: Report an error message when an update job results in an error. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/appcache/appcache_update_job.h ('k') | webkit/appcache/appcache_update_job_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "webkit/appcache/appcache_update_job.h" 5 #include "webkit/appcache/appcache_update_job.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "net/base/io_buffer.h" 10 #include "net/base/io_buffer.h"
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 void SendProgressNotifications( 99 void SendProgressNotifications(
100 const GURL& url, int num_total, int num_complete) { 100 const GURL& url, int num_total, int num_complete) {
101 for (NotifyHostMap::iterator it = hosts_to_notify.begin(); 101 for (NotifyHostMap::iterator it = hosts_to_notify.begin();
102 it != hosts_to_notify.end(); ++it) { 102 it != hosts_to_notify.end(); ++it) {
103 AppCacheFrontend* frontend = it->first; 103 AppCacheFrontend* frontend = it->first;
104 frontend->OnProgressEventRaised(it->second, url, 104 frontend->OnProgressEventRaised(it->second, url,
105 num_total, num_complete); 105 num_total, num_complete);
106 } 106 }
107 } 107 }
108 108
109 void SendErrorNotifications(const std::string& error_message) {
110 DCHECK(!error_message.empty());
111 for (NotifyHostMap::iterator it = hosts_to_notify.begin();
112 it != hosts_to_notify.end(); ++it) {
113 AppCacheFrontend* frontend = it->first;
114 frontend->OnErrorEventRaised(it->second, error_message);
115 }
116 }
117
109 private: 118 private:
110 NotifyHostMap hosts_to_notify; 119 NotifyHostMap hosts_to_notify;
111 }; 120 };
112 121
113 AppCacheUpdateJob::AppCacheUpdateJob(AppCacheService* service, 122 AppCacheUpdateJob::AppCacheUpdateJob(AppCacheService* service,
114 AppCacheGroup* group) 123 AppCacheGroup* group)
115 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)), 124 : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
116 service_(service), 125 service_(service),
117 group_(group), 126 group_(group),
118 update_type_(UNKNOWN_TYPE), 127 update_type_(UNKNOWN_TYPE),
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 238
230 void AppCacheUpdateJob::OnPolicyCheckComplete(int rv) { 239 void AppCacheUpdateJob::OnPolicyCheckComplete(int rv) {
231 policy_callback_->Release(); // Balanced in CheckPolicy. 240 policy_callback_->Release(); // Balanced in CheckPolicy.
232 if (rv == net::OK) { 241 if (rv == net::OK) {
233 FetchManifest(true); 242 FetchManifest(true);
234 return; 243 return;
235 } 244 }
236 245
237 group_->NotifyContentBlocked(); 246 group_->NotifyContentBlocked();
238 247
248 const char* kErrorMessage =
249 "Cache creation was blocked by the content policy";
239 MessageLoop::current()->PostTask(FROM_HERE, 250 MessageLoop::current()->PostTask(FROM_HERE,
240 method_factory_.NewRunnableMethod( 251 method_factory_.NewRunnableMethod(
241 &AppCacheUpdateJob::HandleCacheFailure)); 252 &AppCacheUpdateJob::HandleCacheFailure,
253 kErrorMessage));
242 } 254 }
243 255
244 void AppCacheUpdateJob::HandleCacheFailure() { 256 void AppCacheUpdateJob::HandleCacheFailure(const std::string& error_message) {
245 // TODO(michaeln): For now this is only invoked from one point 257 // 6.9.4 cache failure steps 2-8.
246 // of failure. Overtime, attempt the migrate the various places 258 DCHECK(internal_state_ != CACHE_FAILURE);
247 // where we can detect a failure condition to use this same 259 DCHECK(!error_message.empty());
248 // method to enter the cache_failure state.
249 internal_state_ = CACHE_FAILURE; 260 internal_state_ = CACHE_FAILURE;
250 CancelAllUrlFetches(); 261 CancelAllUrlFetches();
251 CancelAllMasterEntryFetches(); 262 CancelAllMasterEntryFetches(error_message);
252 MaybeCompleteUpdate(); 263 NotifyAllError(error_message);
264 DiscardInprogressCache();
265 internal_state_ = COMPLETED;
266 DeleteSoon(); // To unwind the stack prior to deletion.
253 } 267 }
254 268
255 void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) { 269 void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) {
256 DCHECK(!manifest_url_request_); 270 DCHECK(!manifest_url_request_);
257 manifest_url_request_ = new URLRequest(manifest_url_, this); 271 manifest_url_request_ = new URLRequest(manifest_url_, this);
258 UpdateJobInfo::RequestType fetch_type = is_first_fetch ? 272 UpdateJobInfo::RequestType fetch_type = is_first_fetch ?
259 UpdateJobInfo::MANIFEST_FETCH : UpdateJobInfo::MANIFEST_REFETCH; 273 UpdateJobInfo::MANIFEST_FETCH : UpdateJobInfo::MANIFEST_REFETCH;
260 manifest_url_request_->SetUserData(this, new UpdateJobInfo(fetch_type)); 274 manifest_url_request_->SetUserData(this, new UpdateJobInfo(fetch_type));
261 manifest_url_request_->set_context(service_->request_context()); 275 manifest_url_request_->set_context(service_->request_context());
262 manifest_url_request_->set_load_flags( 276 manifest_url_request_->set_load_flags(
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
505 new net::HttpResponseInfo(request->response_info())); 519 new net::HttpResponseInfo(request->response_info()));
506 if (update_type_ == UPGRADE_ATTEMPT) 520 if (update_type_ == UPGRADE_ATTEMPT)
507 CheckIfManifestChanged(); // continues asynchronously 521 CheckIfManifestChanged(); // continues asynchronously
508 else 522 else
509 ContinueHandleManifestFetchCompleted(true); 523 ContinueHandleManifestFetchCompleted(true);
510 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) { 524 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) {
511 ContinueHandleManifestFetchCompleted(false); 525 ContinueHandleManifestFetchCompleted(false);
512 } else if (response_code == 404 || response_code == 410) { 526 } else if (response_code == 404 || response_code == 410) {
513 service_->storage()->MakeGroupObsolete(group_, this); // async 527 service_->storage()->MakeGroupObsolete(group_, this); // async
514 } else { 528 } else {
515 internal_state_ = CACHE_FAILURE; 529 const char* kFormatString = "Manifest fetch failed (%d) %s";
516 CancelAllMasterEntryFetches(); 530 const std::string message = StringPrintf(kFormatString, response_code,
517 MaybeCompleteUpdate(); // if not done, run async cache failure steps 531 manifest_url_.spec().c_str());
532 HandleCacheFailure(message);
518 } 533 }
519 } 534 }
520 535
521 void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group, 536 void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group,
522 bool success) { 537 bool success) {
523 DCHECK(master_entry_fetches_.empty()); 538 DCHECK(master_entry_fetches_.empty());
524 CancelAllMasterEntryFetches(); 539 CancelAllMasterEntryFetches("The group has been made obsolete");
525 if (success) { 540 if (success) {
526 DCHECK(group->is_obsolete()); 541 DCHECK(group->is_obsolete());
527 NotifyAllAssociatedHosts(OBSOLETE_EVENT); 542 NotifyAllAssociatedHosts(OBSOLETE_EVENT);
528 internal_state_ = COMPLETED; 543 internal_state_ = COMPLETED;
544 MaybeCompleteUpdate();
529 } else { 545 } else {
530 // Treat failure to mark group obsolete as a cache failure. 546 // Treat failure to mark group obsolete as a cache failure.
531 internal_state_ = CACHE_FAILURE; 547 HandleCacheFailure("Failed to make the group as obsolete");
532 } 548 }
533 MaybeCompleteUpdate();
534 } 549 }
535 550
536 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) { 551 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) {
537 DCHECK(internal_state_ == FETCH_MANIFEST); 552 DCHECK(internal_state_ == FETCH_MANIFEST);
538 553
539 if (!changed) { 554 if (!changed) {
540 DCHECK(update_type_ == UPGRADE_ATTEMPT); 555 DCHECK(update_type_ == UPGRADE_ATTEMPT);
541 internal_state_ = NO_UPDATE; 556 internal_state_ = NO_UPDATE;
542 557
543 // Wait for pending master entries to download. 558 // Wait for pending master entries to download.
544 FetchMasterEntries(); 559 FetchMasterEntries();
545 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps 560 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps
546 return; 561 return;
547 } 562 }
548 563
549 Manifest manifest; 564 Manifest manifest;
550 if (!ParseManifest(manifest_url_, manifest_data_.data(), 565 if (!ParseManifest(manifest_url_, manifest_data_.data(),
551 manifest_data_.length(), manifest)) { 566 manifest_data_.length(), manifest)) {
552 LOG(INFO) << "Failed to parse manifest: " << manifest_url_; 567 const char* kFormatString = "Failed to parse manifest %s";
553 internal_state_ = CACHE_FAILURE; 568 const std::string message = StringPrintf(kFormatString,
554 CancelAllMasterEntryFetches(); 569 manifest_url_.spec().c_str());
555 MaybeCompleteUpdate(); // if not done, run async cache failure steps 570 HandleCacheFailure(message);
571 LOG(INFO) << message;
556 return; 572 return;
557 } 573 }
558 574
559 // Proceed with update process. Section 6.9.4 steps 8-20. 575 // Proceed with update process. Section 6.9.4 steps 8-20.
560 internal_state_ = DOWNLOADING; 576 internal_state_ = DOWNLOADING;
561 inprogress_cache_ = new AppCache(service_, 577 inprogress_cache_ = new AppCache(service_,
562 service_->storage()->NewCacheId()); 578 service_->storage()->NewCacheId());
563 BuildUrlFileList(manifest); 579 BuildUrlFileList(manifest);
564 inprogress_cache_->InitializeWithManifest(&manifest); 580 inprogress_cache_->InitializeWithManifest(&manifest);
565 581
(...skipping 12 matching lines...) Expand all
578 FetchUrls(); 594 FetchUrls();
579 FetchMasterEntries(); 595 FetchMasterEntries();
580 MaybeCompleteUpdate(); // if not done, continues when async fetches complete 596 MaybeCompleteUpdate(); // if not done, continues when async fetches complete
581 } 597 }
582 598
583 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) { 599 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) {
584 DCHECK(internal_state_ == DOWNLOADING); 600 DCHECK(internal_state_ == DOWNLOADING);
585 601
586 const GURL& url = request->original_url(); 602 const GURL& url = request->original_url();
587 pending_url_fetches_.erase(url); 603 pending_url_fetches_.erase(url);
588 NotifyProgress(url); 604 NotifyAllProgress(url);
589 ++url_fetches_completed_; 605 ++url_fetches_completed_;
590 606
591 int response_code = request->status().is_success() 607 int response_code = request->status().is_success()
592 ? request->GetResponseCode() : -1; 608 ? request->GetResponseCode() : -1;
593 AppCacheEntry& entry = url_file_list_.find(url)->second; 609 AppCacheEntry& entry = url_file_list_.find(url)->second;
594 610
595 if (request->status().is_success() && (response_code / 100 == 2)) { 611 if (request->status().is_success() && (response_code / 100 == 2)) {
596 // Associate storage with the new entry. 612 // Associate storage with the new entry.
597 UpdateJobInfo* info = 613 UpdateJobInfo* info =
598 static_cast<UpdateJobInfo*>(request->GetUserData(this)); 614 static_cast<UpdateJobInfo*>(request->GetUserData(this));
599 DCHECK(info->response_writer_.get()); 615 DCHECK(info->response_writer_.get());
600 entry.set_response_id(info->response_writer_->response_id()); 616 entry.set_response_id(info->response_writer_->response_id());
601 entry.set_response_size(info->response_writer_->amount_written()); 617 entry.set_response_size(info->response_writer_->amount_written());
602 618
603 if (!inprogress_cache_->AddOrModifyEntry(url, entry)) 619 if (!inprogress_cache_->AddOrModifyEntry(url, entry))
604 duplicate_response_ids_.push_back(entry.response_id()); 620 duplicate_response_ids_.push_back(entry.response_id());
605 621
606 // Foreign entries will be detected during cache selection. 622 // Foreign entries will be detected during cache selection.
607 // Note: 6.9.4, step 17.9 possible optimization: if resource is HTML or XML 623 // Note: 6.9.4, step 17.9 possible optimization: if resource is HTML or XML
608 // file whose root element is an html element with a manifest attribute 624 // file whose root element is an html element with a manifest attribute
609 // whose value doesn't match the manifest url of the application cache 625 // whose value doesn't match the manifest url of the application cache
610 // being processed, mark the entry as being foreign. 626 // being processed, mark the entry as being foreign.
611 } else { 627 } else {
612 LOG(INFO) << "Request status: " << request->status().status() 628 LOG(INFO) << "Request status: " << request->status().status()
613 << " os_error: " << request->status().os_error() 629 << " os_error: " << request->status().os_error()
614 << " response code: " << response_code; 630 << " response code: " << response_code;
615 if (entry.IsExplicit() || entry.IsFallback()) { 631 if (entry.IsExplicit() || entry.IsFallback()) {
616 internal_state_ = CACHE_FAILURE; 632 const char* kFormatString = "Resource fetch failed (%d) %s";
617 CancelAllUrlFetches(); 633 const std::string message = StringPrintf(kFormatString, response_code,
618 CancelAllMasterEntryFetches(); 634 request->url().spec().c_str());
635 HandleCacheFailure(message);
636 return;
619 } else if (response_code == 404 || response_code == 410) { 637 } else if (response_code == 404 || response_code == 410) {
620 // Entry is skipped. They are dropped from the cache. 638 // Entry is skipped. They are dropped from the cache.
621 } else if (update_type_ == UPGRADE_ATTEMPT) { 639 } else if (update_type_ == UPGRADE_ATTEMPT) {
622 // Copy the response from the newest complete cache. 640 // Copy the response from the newest complete cache.
623 AppCache* cache = group_->newest_complete_cache(); 641 AppCache* cache = group_->newest_complete_cache();
624 AppCacheEntry* copy = cache->GetEntry(url); 642 AppCacheEntry* copy = cache->GetEntry(url);
625 if (copy) { 643 if (copy) {
626 entry.set_response_id(copy->response_id()); 644 entry.set_response_id(copy->response_id());
627 entry.set_response_size(copy->response_size()); 645 entry.set_response_size(copy->response_size());
628 inprogress_cache_->AddOrModifyEntry(url, entry); 646 inprogress_cache_->AddOrModifyEntry(url, entry);
629 } 647 }
630 } 648 }
631 } 649 }
632 650
633 // Fetch another URL now that one request has completed. 651 // Fetch another URL now that one request has completed.
634 if (internal_state_ != CACHE_FAILURE) 652 DCHECK(internal_state_ != CACHE_FAILURE);
635 FetchUrls(); 653 FetchUrls();
636
637 MaybeCompleteUpdate(); 654 MaybeCompleteUpdate();
638 } 655 }
639 656
640 void AppCacheUpdateJob::HandleMasterEntryFetchCompleted(URLRequest* request) { 657 void AppCacheUpdateJob::HandleMasterEntryFetchCompleted(URLRequest* request) {
641 DCHECK(internal_state_ == NO_UPDATE || internal_state_ == DOWNLOADING); 658 DCHECK(internal_state_ == NO_UPDATE || internal_state_ == DOWNLOADING);
642 659
643 // TODO(jennb): Handle downloads completing during cache failure when update 660 // TODO(jennb): Handle downloads completing during cache failure when update
644 // no longer fetches master entries directly. For now, we cancel all pending 661 // no longer fetches master entries directly. For now, we cancel all pending
645 // master entry fetches when entering cache failure state so this will never 662 // master entry fetches when entering cache failure state so this will never
646 // be called in CACHE_FAILURE state. 663 // be called in CACHE_FAILURE state.
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 AppCacheHost* host = *host_it; 703 AppCacheHost* host = *host_it;
687 host_notifier.AddHost(host); 704 host_notifier.AddHost(host);
688 705
689 // In downloading case, disassociate host from inprogress cache. 706 // In downloading case, disassociate host from inprogress cache.
690 if (inprogress_cache_) 707 if (inprogress_cache_)
691 host->AssociateCache(NULL); 708 host->AssociateCache(NULL);
692 709
693 host->RemoveObserver(this); 710 host->RemoveObserver(this);
694 } 711 }
695 hosts.clear(); 712 hosts.clear();
696 host_notifier.SendNotifications(ERROR_EVENT); 713
714 const char* kFormatString = "Master entry fetch failed (%d) %s";
715 const std::string message = StringPrintf(kFormatString, response_code,
716 request->url().spec().c_str());
717 host_notifier.SendErrorNotifications(message);
697 718
698 // In downloading case, update result is different if all master entries 719 // In downloading case, update result is different if all master entries
699 // failed vs. only some failing. 720 // failed vs. only some failing.
700 if (inprogress_cache_) { 721 if (inprogress_cache_) {
701 // Only count successful downloads to know if all master entries failed. 722 // Only count successful downloads to know if all master entries failed.
702 pending_master_entries_.erase(found); 723 pending_master_entries_.erase(found);
703 --master_entries_completed_; 724 --master_entries_completed_;
704 725
705 // Section 6.9.4, step 22.3. 726 // Section 6.9.4, step 22.3.
706 if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) { 727 if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) {
707 CancelAllUrlFetches(); 728 HandleCacheFailure(message);
708 internal_state_ = CACHE_FAILURE; 729 return;
709 } 730 }
710 } 731 }
711 } 732 }
712 733
713 if (internal_state_ != CACHE_FAILURE) 734 DCHECK(internal_state_ != CACHE_FAILURE);
714 FetchMasterEntries(); 735 FetchMasterEntries();
715
716 MaybeCompleteUpdate(); 736 MaybeCompleteUpdate();
717 } 737 }
718 738
719 void AppCacheUpdateJob::HandleManifestRefetchCompleted(URLRequest* request) { 739 void AppCacheUpdateJob::HandleManifestRefetchCompleted(URLRequest* request) {
720 DCHECK(internal_state_ == REFETCH_MANIFEST); 740 DCHECK(internal_state_ == REFETCH_MANIFEST);
721 manifest_url_request_ = NULL; 741 manifest_url_request_ = NULL;
722 742
723 int response_code = request->status().is_success() 743 int response_code = request->status().is_success()
724 ? request->GetResponseCode() : -1; 744 ? request->GetResponseCode() : -1;
725 if (response_code == 304 || manifest_data_ == manifest_refetch_data_) { 745 if (response_code == 304 || manifest_data_ == manifest_refetch_data_) {
(...skipping 10 matching lines...) Expand all
736 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer = 756 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
737 new HttpResponseInfoIOBuffer(manifest_response_info_.release()); 757 new HttpResponseInfoIOBuffer(manifest_response_info_.release());
738 manifest_response_writer_->WriteInfo(io_buffer, 758 manifest_response_writer_->WriteInfo(io_buffer,
739 &manifest_info_write_callback_); 759 &manifest_info_write_callback_);
740 } 760 }
741 } else { 761 } else {
742 LOG(INFO) << "Request status: " << request->status().status() 762 LOG(INFO) << "Request status: " << request->status().status()
743 << " os_error: " << request->status().os_error() 763 << " os_error: " << request->status().os_error()
744 << " response code: " << response_code; 764 << " response code: " << response_code;
745 ScheduleUpdateRetry(kRerunDelayMs); 765 ScheduleUpdateRetry(kRerunDelayMs);
746 internal_state_ = CACHE_FAILURE; 766 HandleCacheFailure("Manifest changed during update, scheduling retry");
747 MaybeCompleteUpdate(); // will definitely complete
748 } 767 }
749 } 768 }
750 769
751 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) { 770 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) {
752 if (result > 0) { 771 if (result > 0) {
753 scoped_refptr<net::StringIOBuffer> io_buffer = 772 scoped_refptr<net::StringIOBuffer> io_buffer =
754 new net::StringIOBuffer(manifest_data_); 773 new net::StringIOBuffer(manifest_data_);
755 manifest_response_writer_->WriteData(io_buffer, manifest_data_.length(), 774 manifest_response_writer_->WriteData(io_buffer, manifest_data_.length(),
756 &manifest_data_write_callback_); 775 &manifest_data_write_callback_);
757 } else { 776 } else {
758 internal_state_ = CACHE_FAILURE; 777 HandleCacheFailure("Failed to write the manifest headers to storage");
759 MaybeCompleteUpdate(); // will definitely complete
760 } 778 }
761 } 779 }
762 780
763 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { 781 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) {
764 if (result > 0) { 782 if (result > 0) {
765 AppCacheEntry entry(AppCacheEntry::MANIFEST, 783 AppCacheEntry entry(AppCacheEntry::MANIFEST,
766 manifest_response_writer_->response_id(), 784 manifest_response_writer_->response_id(),
767 manifest_response_writer_->amount_written()); 785 manifest_response_writer_->amount_written());
768 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry)) 786 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry))
769 duplicate_response_ids_.push_back(entry.response_id()); 787 duplicate_response_ids_.push_back(entry.response_id());
770 StoreGroupAndCache(); 788 StoreGroupAndCache();
771 } else { 789 } else {
772 internal_state_ = CACHE_FAILURE; 790 HandleCacheFailure("Failed to write the manifest data to storage");
773 MaybeCompleteUpdate(); // will definitely complete
774 } 791 }
775 } 792 }
776 793
777 void AppCacheUpdateJob::StoreGroupAndCache() { 794 void AppCacheUpdateJob::StoreGroupAndCache() {
778 DCHECK(stored_state_ == UNSTORED); 795 DCHECK(stored_state_ == UNSTORED);
779 stored_state_ = STORING; 796 stored_state_ = STORING;
780 scoped_refptr<AppCache> newest_cache; 797 scoped_refptr<AppCache> newest_cache;
781 if (inprogress_cache_) 798 if (inprogress_cache_)
782 newest_cache.swap(inprogress_cache_); 799 newest_cache.swap(inprogress_cache_);
783 else 800 else
784 newest_cache = group_->newest_complete_cache(); 801 newest_cache = group_->newest_complete_cache();
785 newest_cache->set_update_time(base::Time::Now()); 802 newest_cache->set_update_time(base::Time::Now());
786 service_->storage()->StoreGroupAndNewestCache(group_, newest_cache, 803 service_->storage()->StoreGroupAndNewestCache(group_, newest_cache,
787 this); // async 804 this); // async
788 } 805 }
789 806
790 void AppCacheUpdateJob::OnGroupAndNewestCacheStored(AppCacheGroup* group, 807 void AppCacheUpdateJob::OnGroupAndNewestCacheStored(AppCacheGroup* group,
791 AppCache* newest_cache, 808 AppCache* newest_cache,
792 bool success) { 809 bool success) {
793 DCHECK(stored_state_ == STORING); 810 DCHECK(stored_state_ == STORING);
794 if (success) { 811 if (success) {
795 stored_state_ = STORED; 812 stored_state_ = STORED;
813 MaybeCompleteUpdate(); // will definitely complete
796 } else { 814 } else {
797 internal_state_ = CACHE_FAILURE;
798
799 // Restore inprogress_cache_ to get the proper events delivered 815 // Restore inprogress_cache_ to get the proper events delivered
800 // and the proper cleanup to occur. 816 // and the proper cleanup to occur.
801 if (newest_cache != group->newest_complete_cache()) 817 if (newest_cache != group->newest_complete_cache())
802 inprogress_cache_ = newest_cache; 818 inprogress_cache_ = newest_cache;
819
820 HandleCacheFailure("Failed to commit new cache to storage");
803 } 821 }
804 MaybeCompleteUpdate(); // will definitely complete
805 } 822 }
806 823
807 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, 824 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host,
808 EventID event_id) { 825 EventID event_id) {
809 std::vector<int> ids(1, host->host_id()); 826 std::vector<int> ids(1, host->host_id());
810 host->frontend()->OnEventRaised(ids, event_id); 827 host->frontend()->OnEventRaised(ids, event_id);
811 } 828 }
812 829
813 void AppCacheUpdateJob::NotifyAllPendingMasterHosts(EventID event_id) {
814 // Collect hosts so we only send one notification per frontend.
815 // A host can only be associated with a single pending master entry
816 // so no need to worry about duplicate hosts being added to the notifier.
817 HostNotifier host_notifier;
818 for (PendingMasters::iterator it = pending_master_entries_.begin();
819 it != pending_master_entries_.end(); ++it) {
820 PendingHosts& hosts = it->second;
821 for (PendingHosts::iterator host_it = hosts.begin();
822 host_it != hosts.end(); ++host_it) {
823 host_notifier.AddHost(*host_it);
824 }
825 }
826
827 host_notifier.SendNotifications(event_id);
828 }
829
830 void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) { 830 void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) {
831 HostNotifier host_notifier; 831 HostNotifier host_notifier;
832 AddAllAssociatedHostsToNotifier(&host_notifier); 832 AddAllAssociatedHostsToNotifier(&host_notifier);
833 host_notifier.SendNotifications(event_id); 833 host_notifier.SendNotifications(event_id);
834 } 834 }
835 835
836 void AppCacheUpdateJob::NotifyProgress(const GURL& url) { 836 void AppCacheUpdateJob::NotifyAllProgress(const GURL& url) {
837 HostNotifier host_notifier; 837 HostNotifier host_notifier;
838 AddAllAssociatedHostsToNotifier(&host_notifier); 838 AddAllAssociatedHostsToNotifier(&host_notifier);
839 host_notifier.SendProgressNotifications( 839 host_notifier.SendProgressNotifications(
840 url, url_file_list_.size(), url_fetches_completed_); 840 url, url_file_list_.size(), url_fetches_completed_);
841 } 841 }
842 842
843 void AppCacheUpdateJob::NotifyFinalProgress() { 843 void AppCacheUpdateJob::NotifyAllFinalProgress() {
844 DCHECK(url_file_list_.size() == url_fetches_completed_); 844 DCHECK(url_file_list_.size() == url_fetches_completed_);
845 NotifyProgress(GURL()); 845 NotifyAllProgress(GURL());
846 }
847
848 void AppCacheUpdateJob::NotifyAllError(const std::string& error_message) {
849 HostNotifier host_notifier;
850 AddAllAssociatedHostsToNotifier(&host_notifier);
851 host_notifier.SendErrorNotifications(error_message);
846 } 852 }
847 853
848 void AppCacheUpdateJob::AddAllAssociatedHostsToNotifier( 854 void AppCacheUpdateJob::AddAllAssociatedHostsToNotifier(
849 HostNotifier* host_notifier) { 855 HostNotifier* host_notifier) {
850 // Collect hosts so we only send one notification per frontend. 856 // Collect hosts so we only send one notification per frontend.
851 // A host can only be associated with a single cache so no need to worry 857 // A host can only be associated with a single cache so no need to worry
852 // about duplicate hosts being added to the notifier. 858 // about duplicate hosts being added to the notifier.
853 if (inprogress_cache_) { 859 if (inprogress_cache_) {
854 DCHECK(internal_state_ == DOWNLOADING || internal_state_ == CACHE_FAILURE); 860 DCHECK(internal_state_ == DOWNLOADING || internal_state_ == CACHE_FAILURE);
855 host_notifier->AddHosts(inprogress_cache_->associated_hosts()); 861 host_notifier->AddHosts(inprogress_cache_->associated_hosts());
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 while (pending_url_fetches_.size() < kMaxConcurrentUrlFetches && 957 while (pending_url_fetches_.size() < kMaxConcurrentUrlFetches &&
952 !urls_to_fetch_.empty()) { 958 !urls_to_fetch_.empty()) {
953 const GURL url = urls_to_fetch_.front().first; 959 const GURL url = urls_to_fetch_.front().first;
954 bool storage_checked = urls_to_fetch_.front().second; 960 bool storage_checked = urls_to_fetch_.front().second;
955 urls_to_fetch_.pop_front(); 961 urls_to_fetch_.pop_front();
956 962
957 AppCache::EntryMap::iterator it = url_file_list_.find(url); 963 AppCache::EntryMap::iterator it = url_file_list_.find(url);
958 DCHECK(it != url_file_list_.end()); 964 DCHECK(it != url_file_list_.end());
959 AppCacheEntry& entry = it->second; 965 AppCacheEntry& entry = it->second;
960 if (ShouldSkipUrlFetch(entry)) { 966 if (ShouldSkipUrlFetch(entry)) {
961 NotifyProgress(url); 967 NotifyAllProgress(url);
962 ++url_fetches_completed_; 968 ++url_fetches_completed_;
963 } else if (AlreadyFetchedEntry(url, entry.types())) { 969 } else if (AlreadyFetchedEntry(url, entry.types())) {
964 NotifyProgress(url); 970 NotifyAllProgress(url);
965 ++url_fetches_completed_; // saved a URL request 971 ++url_fetches_completed_; // saved a URL request
966 } else if (!storage_checked && MaybeLoadFromNewestCache(url, entry)) { 972 } else if (!storage_checked && MaybeLoadFromNewestCache(url, entry)) {
967 // Continues asynchronously after data is loaded from newest cache. 973 // Continues asynchronously after data is loaded from newest cache.
968 } else { 974 } else {
969 // Send URL request for the resource. 975 // Send URL request for the resource.
970 URLRequest* request = new URLRequest(url, this); 976 URLRequest* request = new URLRequest(url, this);
971 request->SetUserData(this, new UpdateJobInfo(UpdateJobInfo::URL_FETCH)); 977 request->SetUserData(this, new UpdateJobInfo(UpdateJobInfo::URL_FETCH));
972 request->set_context(service_->request_context()); 978 request->set_context(service_->request_context());
973 request->set_load_flags( 979 request->set_load_flags(
974 request->load_flags() | net::LOAD_DISABLE_INTERCEPT); 980 request->load_flags() | net::LOAD_DISABLE_INTERCEPT);
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after
1082 request->set_load_flags( 1088 request->set_load_flags(
1083 request->load_flags() | net::LOAD_DISABLE_INTERCEPT); 1089 request->load_flags() | net::LOAD_DISABLE_INTERCEPT);
1084 request->Start(); 1090 request->Start();
1085 master_entry_fetches_.insert(PendingUrlFetches::value_type(url, request)); 1091 master_entry_fetches_.insert(PendingUrlFetches::value_type(url, request));
1086 } 1092 }
1087 1093
1088 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin()); 1094 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin());
1089 } 1095 }
1090 } 1096 }
1091 1097
1092 void AppCacheUpdateJob::CancelAllMasterEntryFetches() { 1098 void AppCacheUpdateJob::CancelAllMasterEntryFetches(
1099 const std::string& error_message) {
1093 // For now, cancel all in-progress fetches for master entries and pretend 1100 // For now, cancel all in-progress fetches for master entries and pretend
1094 // all master entries fetches have completed. 1101 // all master entries fetches have completed.
1095 // TODO(jennb): Delete this when update no longer fetches master entries 1102 // TODO(jennb): Delete this when update no longer fetches master entries
1096 // directly. 1103 // directly.
1097 1104
1098 // Cancel all in-progress fetches. 1105 // Cancel all in-progress fetches.
1099 for (PendingUrlFetches::iterator it = master_entry_fetches_.begin(); 1106 for (PendingUrlFetches::iterator it = master_entry_fetches_.begin();
1100 it != master_entry_fetches_.end(); ++it) { 1107 it != master_entry_fetches_.end(); ++it) {
1101 delete it->second; 1108 delete it->second;
1102 master_entries_to_fetch_.insert(it->first); // back in unfetched list 1109 master_entries_to_fetch_.insert(it->first); // back in unfetched list
(...skipping 15 matching lines...) Expand all
1118 host_it != hosts.end(); ++host_it) { 1125 host_it != hosts.end(); ++host_it) {
1119 AppCacheHost* host = *host_it; 1126 AppCacheHost* host = *host_it;
1120 host->AssociateCache(NULL); 1127 host->AssociateCache(NULL);
1121 host_notifier.AddHost(host); 1128 host_notifier.AddHost(host);
1122 host->RemoveObserver(this); 1129 host->RemoveObserver(this);
1123 } 1130 }
1124 hosts.clear(); 1131 hosts.clear();
1125 1132
1126 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin()); 1133 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin());
1127 } 1134 }
1128 host_notifier.SendNotifications(ERROR_EVENT); 1135 host_notifier.SendErrorNotifications(error_message);
1129 } 1136 }
1130 1137
1131 bool AppCacheUpdateJob::MaybeLoadFromNewestCache(const GURL& url, 1138 bool AppCacheUpdateJob::MaybeLoadFromNewestCache(const GURL& url,
1132 AppCacheEntry& entry) { 1139 AppCacheEntry& entry) {
1133 if (update_type_ != UPGRADE_ATTEMPT) 1140 if (update_type_ != UPGRADE_ATTEMPT)
1134 return false; 1141 return false;
1135 1142
1136 AppCache* newest = group_->newest_complete_cache(); 1143 AppCache* newest = group_->newest_complete_cache();
1137 AppCacheEntry* copy_me = newest->GetEntry(url); 1144 AppCacheEntry* copy_me = newest->GetEntry(url);
1138 if (!copy_me || !copy_me->has_response_id()) 1145 if (!copy_me || !copy_me->has_response_id())
(...skipping 28 matching lines...) Expand all
1167 } else { 1174 } else {
1168 // Check if response can be re-used according to HTTP caching semantics. 1175 // Check if response can be re-used according to HTTP caching semantics.
1169 // Responses with a "vary" header get treated as expired. 1176 // Responses with a "vary" header get treated as expired.
1170 const std::string name = "vary"; 1177 const std::string name = "vary";
1171 std::string value; 1178 std::string value;
1172 void* iter = NULL; 1179 void* iter = NULL;
1173 if (http_info->headers->RequiresValidation(http_info->request_time, 1180 if (http_info->headers->RequiresValidation(http_info->request_time,
1174 http_info->response_time, 1181 http_info->response_time,
1175 base::Time::Now()) || 1182 base::Time::Now()) ||
1176 http_info->headers->EnumerateHeader(&iter, name, &value)) { 1183 http_info->headers->EnumerateHeader(&iter, name, &value)) {
1184 // TODO(michaeln): Make a conditional request when we can in this case.
1177 LoadFromNewestCacheFailed(url); 1185 LoadFromNewestCacheFailed(url);
1178 } else { 1186 } else {
1179 DCHECK(group_->newest_complete_cache()); 1187 DCHECK(group_->newest_complete_cache());
1180 AppCacheEntry* copy_me = group_->newest_complete_cache()->GetEntry(url); 1188 AppCacheEntry* copy_me = group_->newest_complete_cache()->GetEntry(url);
1181 DCHECK(copy_me); 1189 DCHECK(copy_me);
1182 DCHECK(copy_me->response_id() == response_id); 1190 DCHECK(copy_me->response_id() == response_id);
1183 1191
1184 AppCache::EntryMap::iterator it = url_file_list_.find(url); 1192 AppCache::EntryMap::iterator it = url_file_list_.find(url);
1185 DCHECK(it != url_file_list_.end()); 1193 DCHECK(it != url_file_list_.end());
1186 AppCacheEntry& entry = it->second; 1194 AppCacheEntry& entry = it->second;
1187 entry.set_response_id(response_id); 1195 entry.set_response_id(response_id);
1188 entry.set_response_size(copy_me->response_size()); 1196 entry.set_response_size(copy_me->response_size());
1189 inprogress_cache_->AddOrModifyEntry(url, entry); 1197 inprogress_cache_->AddOrModifyEntry(url, entry);
1190 NotifyProgress(url); 1198 NotifyAllProgress(url);
1191 ++url_fetches_completed_; 1199 ++url_fetches_completed_;
1192 } 1200 }
1193 } 1201 }
1194 loading_responses_.erase(found); 1202 loading_responses_.erase(found);
1195 1203
1196 MaybeCompleteUpdate(); 1204 MaybeCompleteUpdate();
1197 } 1205 }
1198 1206
1199 void AppCacheUpdateJob::LoadFromNewestCacheFailed(const GURL& url) { 1207 void AppCacheUpdateJob::LoadFromNewestCacheFailed(const GURL& url) {
1200 if (internal_state_ == CACHE_FAILURE) 1208 if (internal_state_ == CACHE_FAILURE)
1201 return; 1209 return;
1202 1210
1203 // Re-insert url at front of fetch list. Indicate storage has been checked. 1211 // Re-insert url at front of fetch list. Indicate storage has been checked.
1204 urls_to_fetch_.push_front(AppCacheUpdateJob::UrlsToFetch(url, true)); 1212 urls_to_fetch_.push_front(AppCacheUpdateJob::UrlsToFetch(url, true));
1205 FetchUrls(); 1213 FetchUrls();
1206 } 1214 }
1207 1215
1208 void AppCacheUpdateJob::MaybeCompleteUpdate() { 1216 void AppCacheUpdateJob::MaybeCompleteUpdate() {
1217 DCHECK(internal_state_ != CACHE_FAILURE);
1218
1209 // Must wait for any pending master entries or url fetches to complete. 1219 // Must wait for any pending master entries or url fetches to complete.
1210 if (master_entries_completed_ != pending_master_entries_.size() || 1220 if (master_entries_completed_ != pending_master_entries_.size() ||
1211 url_fetches_completed_ != url_file_list_.size()) { 1221 url_fetches_completed_ != url_file_list_.size()) {
1212 DCHECK(internal_state_ != COMPLETED); 1222 DCHECK(internal_state_ != COMPLETED);
1213 return; 1223 return;
1214 } 1224 }
1215 1225
1216 switch (internal_state_) { 1226 switch (internal_state_) {
1217 case NO_UPDATE: 1227 case NO_UPDATE:
1218 if (master_entries_completed_ > 0) { 1228 if (master_entries_completed_ > 0) {
(...skipping 11 matching lines...) Expand all
1230 NotifyAllAssociatedHosts(NO_UPDATE_EVENT); 1240 NotifyAllAssociatedHosts(NO_UPDATE_EVENT);
1231 DiscardDuplicateResponses(); 1241 DiscardDuplicateResponses();
1232 internal_state_ = COMPLETED; 1242 internal_state_ = COMPLETED;
1233 break; 1243 break;
1234 case DOWNLOADING: 1244 case DOWNLOADING:
1235 internal_state_ = REFETCH_MANIFEST; 1245 internal_state_ = REFETCH_MANIFEST;
1236 FetchManifest(false); 1246 FetchManifest(false);
1237 break; 1247 break;
1238 case REFETCH_MANIFEST: 1248 case REFETCH_MANIFEST:
1239 DCHECK(stored_state_ == STORED); 1249 DCHECK(stored_state_ == STORED);
1240 NotifyFinalProgress(); 1250 NotifyAllFinalProgress();
1241 if (update_type_ == CACHE_ATTEMPT) 1251 if (update_type_ == CACHE_ATTEMPT)
1242 NotifyAllAssociatedHosts(CACHED_EVENT); 1252 NotifyAllAssociatedHosts(CACHED_EVENT);
1243 else 1253 else
1244 NotifyAllAssociatedHosts(UPDATE_READY_EVENT); 1254 NotifyAllAssociatedHosts(UPDATE_READY_EVENT);
1245 DiscardDuplicateResponses(); 1255 DiscardDuplicateResponses();
1246 internal_state_ = COMPLETED; 1256 internal_state_ = COMPLETED;
1247 break; 1257 break;
1248 case CACHE_FAILURE: 1258 case CACHE_FAILURE:
1249 // 6.9.4 cache failure steps 2-8. 1259 NOTREACHED(); // See HandleCacheFailure
1250 NotifyAllAssociatedHosts(ERROR_EVENT);
1251 DiscardInprogressCache();
1252 // For a CACHE_ATTEMPT, group will be discarded when the host(s) that
1253 // started this update removes its reference to the group. Nothing more
1254 // to do here.
1255 internal_state_ = COMPLETED;
1256 break; 1260 break;
1257 default: 1261 default:
1258 break; 1262 break;
1259 } 1263 }
1260 1264
1261 // Let the stack unwind before deletion to make it less risky as this 1265 // Let the stack unwind before deletion to make it less risky as this
1262 // method is called from multiple places in this file. 1266 // method is called from multiple places in this file.
1263 if (internal_state_ == COMPLETED) 1267 if (internal_state_ == COMPLETED)
1264 DeleteSoon(); 1268 DeleteSoon();
1265 } 1269 }
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
1339 1343
1340 // Break the connection with the group so the group cannot call delete 1344 // Break the connection with the group so the group cannot call delete
1341 // on this object after we've posted a task to delete ourselves. 1345 // on this object after we've posted a task to delete ourselves.
1342 group_->SetUpdateStatus(AppCacheGroup::IDLE); 1346 group_->SetUpdateStatus(AppCacheGroup::IDLE);
1343 group_ = NULL; 1347 group_ = NULL;
1344 1348
1345 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 1349 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
1346 } 1350 }
1347 1351
1348 } // namespace appcache 1352 } // namespace appcache
OLDNEW
« no previous file with comments | « webkit/appcache/appcache_update_job.h ('k') | webkit/appcache/appcache_update_job_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698