| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |