| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/browser/appcache/appcache_update_job.h" | 5 #include "webkit/browser/appcache/appcache_update_job.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
| 9 #include "base/compiler_specific.h" | 9 #include "base/compiler_specific.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 void SendProgressNotifications( | 69 void SendProgressNotifications( |
| 70 const GURL& url, int num_total, int num_complete) { | 70 const GURL& url, int num_total, int num_complete) { |
| 71 for (NotifyHostMap::iterator it = hosts_to_notify.begin(); | 71 for (NotifyHostMap::iterator it = hosts_to_notify.begin(); |
| 72 it != hosts_to_notify.end(); ++it) { | 72 it != hosts_to_notify.end(); ++it) { |
| 73 AppCacheFrontend* frontend = it->first; | 73 AppCacheFrontend* frontend = it->first; |
| 74 frontend->OnProgressEventRaised(it->second, url, | 74 frontend->OnProgressEventRaised(it->second, url, |
| 75 num_total, num_complete); | 75 num_total, num_complete); |
| 76 } | 76 } |
| 77 } | 77 } |
| 78 | 78 |
| 79 void SendErrorNotifications(const std::string& error_message) { | 79 void SendErrorNotifications(const ErrorDetails& details) { |
| 80 DCHECK(!error_message.empty()); | 80 DCHECK(!details.message.empty()); |
| 81 for (NotifyHostMap::iterator it = hosts_to_notify.begin(); | 81 for (NotifyHostMap::iterator it = hosts_to_notify.begin(); |
| 82 it != hosts_to_notify.end(); ++it) { | 82 it != hosts_to_notify.end(); ++it) { |
| 83 AppCacheFrontend* frontend = it->first; | 83 AppCacheFrontend* frontend = it->first; |
| 84 frontend->OnErrorEventRaised(it->second, error_message); | 84 frontend->OnErrorEventRaised(it->second, details); |
| 85 } | 85 } |
| 86 } | 86 } |
| 87 | 87 |
| 88 private: | 88 private: |
| 89 NotifyHostMap hosts_to_notify; | 89 NotifyHostMap hosts_to_notify; |
| 90 }; | 90 }; |
| 91 | 91 |
| 92 AppCacheUpdateJob::UrlToFetch::UrlToFetch(const GURL& url, | 92 AppCacheUpdateJob::UrlToFetch::UrlToFetch(const GURL& url, |
| 93 bool checked, | 93 bool checked, |
| 94 AppCacheResponseInfo* info) | 94 AppCacheResponseInfo* info) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 105 // data out to the disk cache. | 105 // data out to the disk cache. |
| 106 AppCacheUpdateJob::URLFetcher::URLFetcher(const GURL& url, | 106 AppCacheUpdateJob::URLFetcher::URLFetcher(const GURL& url, |
| 107 FetchType fetch_type, | 107 FetchType fetch_type, |
| 108 AppCacheUpdateJob* job) | 108 AppCacheUpdateJob* job) |
| 109 : url_(url), | 109 : url_(url), |
| 110 job_(job), | 110 job_(job), |
| 111 fetch_type_(fetch_type), | 111 fetch_type_(fetch_type), |
| 112 retry_503_attempts_(0), | 112 retry_503_attempts_(0), |
| 113 buffer_(new net::IOBuffer(kBufferSize)), | 113 buffer_(new net::IOBuffer(kBufferSize)), |
| 114 request_(job->service_->request_context() | 114 request_(job->service_->request_context() |
| 115 ->CreateRequest(url, net::DEFAULT_PRIORITY, this, NULL)), | 115 ->CreateRequest(url, net::DEFAULT_PRIORITY, this, NULL)), |
| 116 result_(UPDATE_OK) {} | 116 result_(UPDATE_OK), |
| 117 redirect_response_code_(-1) {} |
| 117 | 118 |
| 118 AppCacheUpdateJob::URLFetcher::~URLFetcher() { | 119 AppCacheUpdateJob::URLFetcher::~URLFetcher() { |
| 119 } | 120 } |
| 120 | 121 |
| 121 void AppCacheUpdateJob::URLFetcher::Start() { | 122 void AppCacheUpdateJob::URLFetcher::Start() { |
| 122 request_->set_first_party_for_cookies(job_->manifest_url_); | 123 request_->set_first_party_for_cookies(job_->manifest_url_); |
| 123 request_->SetLoadFlags(request_->load_flags() | | 124 request_->SetLoadFlags(request_->load_flags() | |
| 124 net::LOAD_DISABLE_INTERCEPT); | 125 net::LOAD_DISABLE_INTERCEPT); |
| 125 if (existing_response_headers_.get()) | 126 if (existing_response_headers_.get()) |
| 126 AddConditionalHeaders(existing_response_headers_.get()); | 127 AddConditionalHeaders(existing_response_headers_.get()); |
| 127 request_->Start(); | 128 request_->Start(); |
| 128 } | 129 } |
| 129 | 130 |
| 130 void AppCacheUpdateJob::URLFetcher::OnReceivedRedirect( | 131 void AppCacheUpdateJob::URLFetcher::OnReceivedRedirect( |
| 131 net::URLRequest* request, const GURL& new_url, bool* defer_redirect) { | 132 net::URLRequest* request, const GURL& new_url, bool* defer_redirect) { |
| 132 DCHECK(request_ == request); | 133 DCHECK(request_ == request); |
| 133 // Redirect is not allowed by the update process. | 134 // Redirect is not allowed by the update process. |
| 134 job_->MadeProgress(); | |
| 135 request->Cancel(); | 135 request->Cancel(); |
| 136 result_ = REDIRECT_ERROR; | 136 result_ = REDIRECT_ERROR; |
| 137 OnResponseCompleted(); | 137 OnResponseCompleted(); |
| 138 } | 138 } |
| 139 | 139 |
| 140 void AppCacheUpdateJob::URLFetcher::OnResponseStarted( | 140 void AppCacheUpdateJob::URLFetcher::OnResponseStarted( |
| 141 net::URLRequest *request) { | 141 net::URLRequest *request) { |
| 142 DCHECK(request == request_); | 142 DCHECK(request == request_); |
| 143 int response_code = -1; | 143 int response_code = -1; |
| 144 if (request->status().is_success()) { | 144 if (request->status().is_success()) { |
| 145 response_code = request->GetResponseCode(); | 145 response_code = request->GetResponseCode(); |
| 146 job_->MadeProgress(); | 146 job_->MadeProgress(); |
| 147 } | 147 } |
| 148 if ((response_code / 100) == 2) { | 148 if ((response_code / 100) == 2) { |
| 149 | 149 |
| 150 // See http://code.google.com/p/chromium/issues/detail?id=69594 | 150 // See http://code.google.com/p/chromium/issues/detail?id=69594 |
| 151 // We willfully violate the HTML5 spec at this point in order | 151 // We willfully violate the HTML5 spec at this point in order |
| 152 // to support the appcaching of cross-origin HTTPS resources. | 152 // to support the appcaching of cross-origin HTTPS resources. |
| 153 // We've opted for a milder constraint and allow caching unless | 153 // We've opted for a milder constraint and allow caching unless |
| 154 // the resource has a "no-store" header. A spec change has been | 154 // the resource has a "no-store" header. A spec change has been |
| 155 // requested on the whatwg list. | 155 // requested on the whatwg list. |
| 156 // TODO(michaeln): Consider doing this for cross-origin HTTP resources too. | 156 // TODO(michaeln): Consider doing this for cross-origin HTTP resources too. |
| 157 if (url_.SchemeIsSecure() && | 157 if (url_.SchemeIsSecure() && |
| 158 url_.GetOrigin() != job_->manifest_url_.GetOrigin()) { | 158 url_.GetOrigin() != job_->manifest_url_.GetOrigin()) { |
| 159 if (request->response_headers()-> | 159 if (request->response_headers()-> |
| 160 HasHeaderValue("cache-control", "no-store")) { | 160 HasHeaderValue("cache-control", "no-store")) { |
| 161 DCHECK_EQ(-1, redirect_response_code_); |
| 161 request->Cancel(); | 162 request->Cancel(); |
| 162 result_ = SERVER_ERROR; // Not the best match? | 163 result_ = SERVER_ERROR; // Not the best match? |
| 163 OnResponseCompleted(); | 164 OnResponseCompleted(); |
| 164 return; | 165 return; |
| 165 } | 166 } |
| 166 } | 167 } |
| 167 | 168 |
| 168 // Write response info to storage for URL fetches. Wait for async write | 169 // Write response info to storage for URL fetches. Wait for async write |
| 169 // completion before reading any response data. | 170 // completion before reading any response data. |
| 170 if (fetch_type_ == URL_FETCH || fetch_type_ == MASTER_ENTRY_FETCH) { | 171 if (fetch_type_ == URL_FETCH || fetch_type_ == MASTER_ENTRY_FETCH) { |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 } | 422 } |
| 422 | 423 |
| 423 AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() { | 424 AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() { |
| 424 AppCacheResponseWriter* writer = | 425 AppCacheResponseWriter* writer = |
| 425 storage_->CreateResponseWriter(manifest_url_, | 426 storage_->CreateResponseWriter(manifest_url_, |
| 426 group_->group_id()); | 427 group_->group_id()); |
| 427 stored_response_ids_.push_back(writer->response_id()); | 428 stored_response_ids_.push_back(writer->response_id()); |
| 428 return writer; | 429 return writer; |
| 429 } | 430 } |
| 430 | 431 |
| 431 void AppCacheUpdateJob::HandleCacheFailure( | 432 void AppCacheUpdateJob::HandleCacheFailure(const ErrorDetails& error_details, |
| 432 const std::string& error_message, | 433 ResultType result, |
| 433 ResultType result, | 434 const GURL& failed_resource_url) { |
| 434 const GURL& failed_resource_url) { | |
| 435 // 6.9.4 cache failure steps 2-8. | 435 // 6.9.4 cache failure steps 2-8. |
| 436 DCHECK(internal_state_ != CACHE_FAILURE); | 436 DCHECK(internal_state_ != CACHE_FAILURE); |
| 437 DCHECK(!error_message.empty()); | 437 DCHECK(!error_details.message.empty()); |
| 438 DCHECK(result != UPDATE_OK); | 438 DCHECK(result != UPDATE_OK); |
| 439 internal_state_ = CACHE_FAILURE; | 439 internal_state_ = CACHE_FAILURE; |
| 440 LogHistogramStats(result, failed_resource_url); | 440 LogHistogramStats(result, failed_resource_url); |
| 441 CancelAllUrlFetches(); | 441 CancelAllUrlFetches(); |
| 442 CancelAllMasterEntryFetches(error_message); | 442 CancelAllMasterEntryFetches(error_details); |
| 443 NotifyAllError(error_message); | 443 NotifyAllError(error_details); |
| 444 DiscardInprogressCache(); | 444 DiscardInprogressCache(); |
| 445 internal_state_ = COMPLETED; | 445 internal_state_ = COMPLETED; |
| 446 DeleteSoon(); // To unwind the stack prior to deletion. | 446 DeleteSoon(); // To unwind the stack prior to deletion. |
| 447 } | 447 } |
| 448 | 448 |
| 449 void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) { | 449 void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) { |
| 450 DCHECK(!manifest_fetcher_); | 450 DCHECK(!manifest_fetcher_); |
| 451 manifest_fetcher_ = new URLFetcher( | 451 manifest_fetcher_ = new URLFetcher( |
| 452 manifest_url_, | 452 manifest_url_, |
| 453 is_first_fetch ? URLFetcher::MANIFEST_FETCH : | 453 is_first_fetch ? URLFetcher::MANIFEST_FETCH : |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 494 manifest_response_info_.reset( | 494 manifest_response_info_.reset( |
| 495 new net::HttpResponseInfo(request->response_info())); | 495 new net::HttpResponseInfo(request->response_info())); |
| 496 if (update_type_ == UPGRADE_ATTEMPT) | 496 if (update_type_ == UPGRADE_ATTEMPT) |
| 497 CheckIfManifestChanged(); // continues asynchronously | 497 CheckIfManifestChanged(); // continues asynchronously |
| 498 else | 498 else |
| 499 ContinueHandleManifestFetchCompleted(true); | 499 ContinueHandleManifestFetchCompleted(true); |
| 500 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) { | 500 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) { |
| 501 ContinueHandleManifestFetchCompleted(false); | 501 ContinueHandleManifestFetchCompleted(false); |
| 502 } else if ((response_code == 404 || response_code == 410) && | 502 } else if ((response_code == 404 || response_code == 410) && |
| 503 update_type_ == UPGRADE_ATTEMPT) { | 503 update_type_ == UPGRADE_ATTEMPT) { |
| 504 storage_->MakeGroupObsolete(group_, this); // async | 504 storage_->MakeGroupObsolete(group_, this, response_code); // async |
| 505 } else { | 505 } else { |
| 506 const char* kFormatString = "Manifest fetch failed (%d) %s"; | 506 const char* kFormatString = "Manifest fetch failed (%d) %s"; |
| 507 std::string message = FormatUrlErrorMessage( | 507 std::string message = FormatUrlErrorMessage( |
| 508 kFormatString, manifest_url_, fetcher->result(), response_code); | 508 kFormatString, manifest_url_, fetcher->result(), response_code); |
| 509 HandleCacheFailure(message, fetcher->result(), GURL()); | 509 HandleCacheFailure(ErrorDetails(message, |
| 510 appcache::MANIFEST_ERROR, |
| 511 manifest_url_, |
| 512 response_code, |
| 513 false /*is_cross_origin*/), |
| 514 fetcher->result(), |
| 515 GURL()); |
| 510 } | 516 } |
| 511 } | 517 } |
| 512 | 518 |
| 513 void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group, | 519 void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group, |
| 514 bool success) { | 520 bool success, |
| 521 int response_code) { |
| 515 DCHECK(master_entry_fetches_.empty()); | 522 DCHECK(master_entry_fetches_.empty()); |
| 516 CancelAllMasterEntryFetches("The cache has been made obsolete, " | 523 CancelAllMasterEntryFetches(ErrorDetails( |
| 517 "the manifest file returned 404 or 410"); | 524 "The cache has been made obsolete, " |
| 525 "the manifest file returned 404 or 410", |
| 526 appcache::MANIFEST_ERROR, |
| 527 GURL(), |
| 528 response_code, |
| 529 false /*is_cross_origin*/)); |
| 518 if (success) { | 530 if (success) { |
| 519 DCHECK(group->is_obsolete()); | 531 DCHECK(group->is_obsolete()); |
| 520 NotifyAllAssociatedHosts(OBSOLETE_EVENT); | 532 NotifyAllAssociatedHosts(OBSOLETE_EVENT); |
| 521 internal_state_ = COMPLETED; | 533 internal_state_ = COMPLETED; |
| 522 MaybeCompleteUpdate(); | 534 MaybeCompleteUpdate(); |
| 523 } else { | 535 } else { |
| 524 // Treat failure to mark group obsolete as a cache failure. | 536 // Treat failure to mark group obsolete as a cache failure. |
| 525 HandleCacheFailure("Failed to mark the cache as obsolete", | 537 HandleCacheFailure(ErrorDetails("Failed to mark the cache as obsolete", |
| 526 DB_ERROR, GURL()); | 538 UNKNOWN_ERROR, |
| 539 GURL(), |
| 540 0, |
| 541 false /*is_cross_origin*/), |
| 542 DB_ERROR, |
| 543 GURL()); |
| 527 } | 544 } |
| 528 } | 545 } |
| 529 | 546 |
| 530 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) { | 547 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) { |
| 531 DCHECK(internal_state_ == FETCH_MANIFEST); | 548 DCHECK(internal_state_ == FETCH_MANIFEST); |
| 532 | 549 |
| 533 if (!changed) { | 550 if (!changed) { |
| 534 DCHECK(update_type_ == UPGRADE_ATTEMPT); | 551 DCHECK(update_type_ == UPGRADE_ATTEMPT); |
| 535 internal_state_ = NO_UPDATE; | 552 internal_state_ = NO_UPDATE; |
| 536 | 553 |
| 537 // Wait for pending master entries to download. | 554 // Wait for pending master entries to download. |
| 538 FetchMasterEntries(); | 555 FetchMasterEntries(); |
| 539 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps | 556 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps |
| 540 return; | 557 return; |
| 541 } | 558 } |
| 542 | 559 |
| 543 Manifest manifest; | 560 Manifest manifest; |
| 544 if (!ParseManifest(manifest_url_, manifest_data_.data(), | 561 if (!ParseManifest(manifest_url_, manifest_data_.data(), |
| 545 manifest_data_.length(), manifest)) { | 562 manifest_data_.length(), manifest)) { |
| 546 const char* kFormatString = "Failed to parse manifest %s"; | 563 const char* kFormatString = "Failed to parse manifest %s"; |
| 547 const std::string message = base::StringPrintf(kFormatString, | 564 const std::string message = base::StringPrintf(kFormatString, |
| 548 manifest_url_.spec().c_str()); | 565 manifest_url_.spec().c_str()); |
| 549 HandleCacheFailure(message, MANIFEST_ERROR, GURL()); | 566 HandleCacheFailure( |
| 567 ErrorDetails( |
| 568 message, SIGNATURE_ERROR, GURL(), 0, false /*is_cross_origin*/), |
| 569 MANIFEST_ERROR, |
| 570 GURL()); |
| 550 VLOG(1) << message; | 571 VLOG(1) << message; |
| 551 return; | 572 return; |
| 552 } | 573 } |
| 553 | 574 |
| 554 // Proceed with update process. Section 6.9.4 steps 8-20. | 575 // Proceed with update process. Section 6.9.4 steps 8-20. |
| 555 internal_state_ = DOWNLOADING; | 576 internal_state_ = DOWNLOADING; |
| 556 inprogress_cache_ = new AppCache(storage_, storage_->NewCacheId()); | 577 inprogress_cache_ = new AppCache(storage_, storage_->NewCacheId()); |
| 557 BuildUrlFileList(manifest); | 578 BuildUrlFileList(manifest); |
| 558 inprogress_cache_->InitializeWithManifest(&manifest); | 579 inprogress_cache_->InitializeWithManifest(&manifest); |
| 559 | 580 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 578 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLFetcher* fetcher) { | 599 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLFetcher* fetcher) { |
| 579 DCHECK(internal_state_ == DOWNLOADING); | 600 DCHECK(internal_state_ == DOWNLOADING); |
| 580 | 601 |
| 581 net::URLRequest* request = fetcher->request(); | 602 net::URLRequest* request = fetcher->request(); |
| 582 const GURL& url = request->original_url(); | 603 const GURL& url = request->original_url(); |
| 583 pending_url_fetches_.erase(url); | 604 pending_url_fetches_.erase(url); |
| 584 NotifyAllProgress(url); | 605 NotifyAllProgress(url); |
| 585 ++url_fetches_completed_; | 606 ++url_fetches_completed_; |
| 586 | 607 |
| 587 int response_code = request->status().is_success() | 608 int response_code = request->status().is_success() |
| 588 ? request->GetResponseCode() : -1; | 609 ? request->GetResponseCode() |
| 610 : fetcher->canceled_response_code(); |
| 589 AppCacheEntry& entry = url_file_list_.find(url)->second; | 611 AppCacheEntry& entry = url_file_list_.find(url)->second; |
| 590 | 612 |
| 591 if (response_code / 100 == 2) { | 613 if (response_code / 100 == 2) { |
| 592 // Associate storage with the new entry. | 614 // Associate storage with the new entry. |
| 593 DCHECK(fetcher->response_writer()); | 615 DCHECK(fetcher->response_writer()); |
| 594 entry.set_response_id(fetcher->response_writer()->response_id()); | 616 entry.set_response_id(fetcher->response_writer()->response_id()); |
| 595 entry.set_response_size(fetcher->response_writer()->amount_written()); | 617 entry.set_response_size(fetcher->response_writer()->amount_written()); |
| 596 if (!inprogress_cache_->AddOrModifyEntry(url, entry)) | 618 if (!inprogress_cache_->AddOrModifyEntry(url, entry)) |
| 597 duplicate_response_ids_.push_back(entry.response_id()); | 619 duplicate_response_ids_.push_back(entry.response_id()); |
| 598 | 620 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 613 if (entry.IsExplicit() || entry.IsFallback() || entry.IsIntercept()) { | 635 if (entry.IsExplicit() || entry.IsFallback() || entry.IsIntercept()) { |
| 614 if (response_code == 304 && fetcher->existing_entry().has_response_id()) { | 636 if (response_code == 304 && fetcher->existing_entry().has_response_id()) { |
| 615 // Keep the existing response. | 637 // Keep the existing response. |
| 616 entry.set_response_id(fetcher->existing_entry().response_id()); | 638 entry.set_response_id(fetcher->existing_entry().response_id()); |
| 617 entry.set_response_size(fetcher->existing_entry().response_size()); | 639 entry.set_response_size(fetcher->existing_entry().response_size()); |
| 618 inprogress_cache_->AddOrModifyEntry(url, entry); | 640 inprogress_cache_->AddOrModifyEntry(url, entry); |
| 619 } else { | 641 } else { |
| 620 const char* kFormatString = "Resource fetch failed (%d) %s"; | 642 const char* kFormatString = "Resource fetch failed (%d) %s"; |
| 621 std::string message = FormatUrlErrorMessage( | 643 std::string message = FormatUrlErrorMessage( |
| 622 kFormatString, url, fetcher->result(), response_code); | 644 kFormatString, url, fetcher->result(), response_code); |
| 623 HandleCacheFailure(message, fetcher->result(), url); | 645 ResultType result = fetcher->result(); |
| 646 bool is_cross_origin = url.GetOrigin() != manifest_url_.GetOrigin(); |
| 647 switch (result) { |
| 648 case DISKCACHE_ERROR: |
| 649 HandleCacheFailure( |
| 650 ErrorDetails( |
| 651 message, UNKNOWN_ERROR, GURL(), 0, is_cross_origin), |
| 652 result, |
| 653 url); |
| 654 break; |
| 655 case NETWORK_ERROR: |
| 656 HandleCacheFailure( |
| 657 ErrorDetails(message, RESOURCE_ERROR, url, 0, is_cross_origin), |
| 658 result, |
| 659 url); |
| 660 break; |
| 661 default: |
| 662 HandleCacheFailure(ErrorDetails(message, |
| 663 RESOURCE_ERROR, |
| 664 url, |
| 665 response_code, |
| 666 is_cross_origin), |
| 667 result, |
| 668 url); |
| 669 break; |
| 670 } |
| 624 return; | 671 return; |
| 625 } | 672 } |
| 626 } else if (response_code == 404 || response_code == 410) { | 673 } else if (response_code == 404 || response_code == 410) { |
| 627 // Entry is skipped. They are dropped from the cache. | 674 // Entry is skipped. They are dropped from the cache. |
| 628 } else if (update_type_ == UPGRADE_ATTEMPT && | 675 } else if (update_type_ == UPGRADE_ATTEMPT && |
| 629 fetcher->existing_entry().has_response_id()) { | 676 fetcher->existing_entry().has_response_id()) { |
| 630 // Keep the existing response. | 677 // Keep the existing response. |
| 631 // TODO(michaeln): Not sure this is a good idea. This is spec compliant | 678 // TODO(michaeln): Not sure this is a good idea. This is spec compliant |
| 632 // but the old resource may or may not be compatible with the new contents | 679 // but the old resource may or may not be compatible with the new contents |
| 633 // of the cache. Impossible to know one way or the other. | 680 // of the cache. Impossible to know one way or the other. |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 698 if (inprogress_cache_.get()) | 745 if (inprogress_cache_.get()) |
| 699 host->AssociateNoCache(GURL()); | 746 host->AssociateNoCache(GURL()); |
| 700 | 747 |
| 701 host->RemoveObserver(this); | 748 host->RemoveObserver(this); |
| 702 } | 749 } |
| 703 hosts.clear(); | 750 hosts.clear(); |
| 704 | 751 |
| 705 const char* kFormatString = "Manifest fetch failed (%d) %s"; | 752 const char* kFormatString = "Manifest fetch failed (%d) %s"; |
| 706 std::string message = FormatUrlErrorMessage( | 753 std::string message = FormatUrlErrorMessage( |
| 707 kFormatString, request->url(), fetcher->result(), response_code); | 754 kFormatString, request->url(), fetcher->result(), response_code); |
| 708 host_notifier.SendErrorNotifications(message); | 755 host_notifier.SendErrorNotifications( |
| 756 ErrorDetails(message, |
| 757 appcache::MANIFEST_ERROR, |
| 758 request->url(), |
| 759 response_code, |
| 760 false /*is_cross_origin*/)); |
| 709 | 761 |
| 710 // In downloading case, update result is different if all master entries | 762 // In downloading case, update result is different if all master entries |
| 711 // failed vs. only some failing. | 763 // failed vs. only some failing. |
| 712 if (inprogress_cache_.get()) { | 764 if (inprogress_cache_.get()) { |
| 713 // Only count successful downloads to know if all master entries failed. | 765 // Only count successful downloads to know if all master entries failed. |
| 714 pending_master_entries_.erase(found); | 766 pending_master_entries_.erase(found); |
| 715 --master_entries_completed_; | 767 --master_entries_completed_; |
| 716 | 768 |
| 717 // Section 6.9.4, step 22.3. | 769 // Section 6.9.4, step 22.3. |
| 718 if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) { | 770 if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) { |
| 719 HandleCacheFailure(message, fetcher->result(), GURL()); | 771 HandleCacheFailure(ErrorDetails(message, |
| 772 appcache::MANIFEST_ERROR, |
| 773 request->url(), |
| 774 response_code, |
| 775 false /*is_cross_origin*/), |
| 776 fetcher->result(), |
| 777 GURL()); |
| 720 return; | 778 return; |
| 721 } | 779 } |
| 722 } | 780 } |
| 723 } | 781 } |
| 724 | 782 |
| 725 DCHECK(internal_state_ != CACHE_FAILURE); | 783 DCHECK(internal_state_ != CACHE_FAILURE); |
| 726 FetchMasterEntries(); | 784 FetchMasterEntries(); |
| 727 MaybeCompleteUpdate(); | 785 MaybeCompleteUpdate(); |
| 728 } | 786 } |
| 729 | 787 |
| (...skipping 21 matching lines...) Expand all Loading... |
| 751 io_buffer.get(), | 809 io_buffer.get(), |
| 752 base::Bind(&AppCacheUpdateJob::OnManifestInfoWriteComplete, | 810 base::Bind(&AppCacheUpdateJob::OnManifestInfoWriteComplete, |
| 753 base::Unretained(this))); | 811 base::Unretained(this))); |
| 754 } | 812 } |
| 755 } else { | 813 } else { |
| 756 VLOG(1) << "Request status: " << request->status().status() | 814 VLOG(1) << "Request status: " << request->status().status() |
| 757 << " error: " << request->status().error() | 815 << " error: " << request->status().error() |
| 758 << " response code: " << response_code; | 816 << " response code: " << response_code; |
| 759 ScheduleUpdateRetry(kRerunDelayMs); | 817 ScheduleUpdateRetry(kRerunDelayMs); |
| 760 if (response_code == 200) { | 818 if (response_code == 200) { |
| 761 HandleCacheFailure( | 819 HandleCacheFailure(ErrorDetails("Manifest changed during update", |
| 762 "Manifest changed during update", MANIFEST_ERROR, GURL()); | 820 CHANGED_ERROR, |
| 821 GURL(), |
| 822 0, |
| 823 false /*is_cross_origin*/), |
| 824 MANIFEST_ERROR, |
| 825 GURL()); |
| 763 } else { | 826 } else { |
| 764 const char* kFormatString = "Manifest re-fetch failed (%d) %s"; | 827 const char* kFormatString = "Manifest re-fetch failed (%d) %s"; |
| 765 std::string message = FormatUrlErrorMessage( | 828 std::string message = FormatUrlErrorMessage( |
| 766 kFormatString, manifest_url_, fetcher->result(), response_code); | 829 kFormatString, manifest_url_, fetcher->result(), response_code); |
| 767 HandleCacheFailure(message, fetcher->result(), GURL()); | 830 HandleCacheFailure(ErrorDetails(message, |
| 831 appcache::MANIFEST_ERROR, |
| 832 GURL(), |
| 833 response_code, |
| 834 false /*is_cross_origin*/), |
| 835 fetcher->result(), |
| 836 GURL()); |
| 768 } | 837 } |
| 769 } | 838 } |
| 770 } | 839 } |
| 771 | 840 |
| 772 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) { | 841 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) { |
| 773 if (result > 0) { | 842 if (result > 0) { |
| 774 scoped_refptr<net::StringIOBuffer> io_buffer( | 843 scoped_refptr<net::StringIOBuffer> io_buffer( |
| 775 new net::StringIOBuffer(manifest_data_)); | 844 new net::StringIOBuffer(manifest_data_)); |
| 776 manifest_response_writer_->WriteData( | 845 manifest_response_writer_->WriteData( |
| 777 io_buffer.get(), | 846 io_buffer.get(), |
| 778 manifest_data_.length(), | 847 manifest_data_.length(), |
| 779 base::Bind(&AppCacheUpdateJob::OnManifestDataWriteComplete, | 848 base::Bind(&AppCacheUpdateJob::OnManifestDataWriteComplete, |
| 780 base::Unretained(this))); | 849 base::Unretained(this))); |
| 781 } else { | 850 } else { |
| 782 HandleCacheFailure("Failed to write the manifest headers to storage", | 851 HandleCacheFailure( |
| 783 DISKCACHE_ERROR, GURL()); | 852 ErrorDetails("Failed to write the manifest headers to storage", |
| 853 UNKNOWN_ERROR, |
| 854 GURL(), |
| 855 0, |
| 856 false /*is_cross_origin*/), |
| 857 DISKCACHE_ERROR, |
| 858 GURL()); |
| 784 } | 859 } |
| 785 } | 860 } |
| 786 | 861 |
| 787 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { | 862 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { |
| 788 if (result > 0) { | 863 if (result > 0) { |
| 789 AppCacheEntry entry(AppCacheEntry::MANIFEST, | 864 AppCacheEntry entry(AppCacheEntry::MANIFEST, |
| 790 manifest_response_writer_->response_id(), | 865 manifest_response_writer_->response_id(), |
| 791 manifest_response_writer_->amount_written()); | 866 manifest_response_writer_->amount_written()); |
| 792 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry)) | 867 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry)) |
| 793 duplicate_response_ids_.push_back(entry.response_id()); | 868 duplicate_response_ids_.push_back(entry.response_id()); |
| 794 StoreGroupAndCache(); | 869 StoreGroupAndCache(); |
| 795 } else { | 870 } else { |
| 796 HandleCacheFailure("Failed to write the manifest data to storage", | 871 HandleCacheFailure( |
| 797 DISKCACHE_ERROR, GURL()); | 872 ErrorDetails("Failed to write the manifest data to storage", |
| 873 UNKNOWN_ERROR, |
| 874 GURL(), |
| 875 0, |
| 876 false /*is_cross_origin*/), |
| 877 DISKCACHE_ERROR, |
| 878 GURL()); |
| 798 } | 879 } |
| 799 } | 880 } |
| 800 | 881 |
| 801 void AppCacheUpdateJob::StoreGroupAndCache() { | 882 void AppCacheUpdateJob::StoreGroupAndCache() { |
| 802 DCHECK(stored_state_ == UNSTORED); | 883 DCHECK(stored_state_ == UNSTORED); |
| 803 stored_state_ = STORING; | 884 stored_state_ = STORING; |
| 804 scoped_refptr<AppCache> newest_cache; | 885 scoped_refptr<AppCache> newest_cache; |
| 805 if (inprogress_cache_.get()) | 886 if (inprogress_cache_.get()) |
| 806 newest_cache.swap(inprogress_cache_); | 887 newest_cache.swap(inprogress_cache_); |
| 807 else | 888 else |
| (...skipping 15 matching lines...) Expand all Loading... |
| 823 MaybeCompleteUpdate(); // will definitely complete | 904 MaybeCompleteUpdate(); // will definitely complete |
| 824 } else { | 905 } else { |
| 825 stored_state_ = UNSTORED; | 906 stored_state_ = UNSTORED; |
| 826 | 907 |
| 827 // Restore inprogress_cache_ to get the proper events delivered | 908 // Restore inprogress_cache_ to get the proper events delivered |
| 828 // and the proper cleanup to occur. | 909 // and the proper cleanup to occur. |
| 829 if (newest_cache != group->newest_complete_cache()) | 910 if (newest_cache != group->newest_complete_cache()) |
| 830 inprogress_cache_ = newest_cache; | 911 inprogress_cache_ = newest_cache; |
| 831 | 912 |
| 832 ResultType result = DB_ERROR; | 913 ResultType result = DB_ERROR; |
| 914 ErrorReason reason = UNKNOWN_ERROR; |
| 833 std::string message("Failed to commit new cache to storage"); | 915 std::string message("Failed to commit new cache to storage"); |
| 834 if (would_exceed_quota) { | 916 if (would_exceed_quota) { |
| 835 message.append(", would exceed quota"); | 917 message.append(", would exceed quota"); |
| 836 result = QUOTA_ERROR; | 918 result = QUOTA_ERROR; |
| 919 reason = appcache::QUOTA_ERROR; |
| 837 } | 920 } |
| 838 HandleCacheFailure(message, result, GURL()); | 921 HandleCacheFailure( |
| 922 ErrorDetails(message, reason, GURL(), 0, false /*is_cross_origin*/), |
| 923 result, |
| 924 GURL()); |
| 839 } | 925 } |
| 840 } | 926 } |
| 841 | 927 |
| 842 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, | 928 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, |
| 843 EventID event_id) { | 929 EventID event_id) { |
| 844 std::vector<int> ids(1, host->host_id()); | 930 std::vector<int> ids(1, host->host_id()); |
| 845 host->frontend()->OnEventRaised(ids, event_id); | 931 host->frontend()->OnEventRaised(ids, event_id); |
| 846 } | 932 } |
| 847 | 933 |
| 848 void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) { | 934 void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) { |
| 849 HostNotifier host_notifier; | 935 HostNotifier host_notifier; |
| 850 AddAllAssociatedHostsToNotifier(&host_notifier); | 936 AddAllAssociatedHostsToNotifier(&host_notifier); |
| 851 host_notifier.SendNotifications(event_id); | 937 host_notifier.SendNotifications(event_id); |
| 852 } | 938 } |
| 853 | 939 |
| 854 void AppCacheUpdateJob::NotifyAllProgress(const GURL& url) { | 940 void AppCacheUpdateJob::NotifyAllProgress(const GURL& url) { |
| 855 HostNotifier host_notifier; | 941 HostNotifier host_notifier; |
| 856 AddAllAssociatedHostsToNotifier(&host_notifier); | 942 AddAllAssociatedHostsToNotifier(&host_notifier); |
| 857 host_notifier.SendProgressNotifications( | 943 host_notifier.SendProgressNotifications( |
| 858 url, url_file_list_.size(), url_fetches_completed_); | 944 url, url_file_list_.size(), url_fetches_completed_); |
| 859 } | 945 } |
| 860 | 946 |
| 861 void AppCacheUpdateJob::NotifyAllFinalProgress() { | 947 void AppCacheUpdateJob::NotifyAllFinalProgress() { |
| 862 DCHECK(url_file_list_.size() == url_fetches_completed_); | 948 DCHECK(url_file_list_.size() == url_fetches_completed_); |
| 863 NotifyAllProgress(GURL()); | 949 NotifyAllProgress(GURL()); |
| 864 } | 950 } |
| 865 | 951 |
| 866 void AppCacheUpdateJob::NotifyAllError(const std::string& error_message) { | 952 void AppCacheUpdateJob::NotifyAllError(const ErrorDetails& details) { |
| 867 HostNotifier host_notifier; | 953 HostNotifier host_notifier; |
| 868 AddAllAssociatedHostsToNotifier(&host_notifier); | 954 AddAllAssociatedHostsToNotifier(&host_notifier); |
| 869 host_notifier.SendErrorNotifications(error_message); | 955 host_notifier.SendErrorNotifications(details); |
| 870 } | 956 } |
| 871 | 957 |
| 872 void AppCacheUpdateJob::AddAllAssociatedHostsToNotifier( | 958 void AppCacheUpdateJob::AddAllAssociatedHostsToNotifier( |
| 873 HostNotifier* host_notifier) { | 959 HostNotifier* host_notifier) { |
| 874 // Collect hosts so we only send one notification per frontend. | 960 // Collect hosts so we only send one notification per frontend. |
| 875 // A host can only be associated with a single cache so no need to worry | 961 // A host can only be associated with a single cache so no need to worry |
| 876 // about duplicate hosts being added to the notifier. | 962 // about duplicate hosts being added to the notifier. |
| 877 if (inprogress_cache_.get()) { | 963 if (inprogress_cache_.get()) { |
| 878 DCHECK(internal_state_ == DOWNLOADING || internal_state_ == CACHE_FAILURE); | 964 DCHECK(internal_state_ == DOWNLOADING || internal_state_ == CACHE_FAILURE); |
| 879 host_notifier->AddHosts(inprogress_cache_->associated_hosts()); | 965 host_notifier->AddHosts(inprogress_cache_->associated_hosts()); |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 DCHECK(update_type_ == UPGRADE_ATTEMPT); | 999 DCHECK(update_type_ == UPGRADE_ATTEMPT); |
| 914 AppCacheEntry* entry = NULL; | 1000 AppCacheEntry* entry = NULL; |
| 915 if (group_->newest_complete_cache()) | 1001 if (group_->newest_complete_cache()) |
| 916 entry = group_->newest_complete_cache()->GetEntry(manifest_url_); | 1002 entry = group_->newest_complete_cache()->GetEntry(manifest_url_); |
| 917 if (!entry) { | 1003 if (!entry) { |
| 918 // TODO(michaeln): This is just a bandaid to avoid a crash. | 1004 // TODO(michaeln): This is just a bandaid to avoid a crash. |
| 919 // http://code.google.com/p/chromium/issues/detail?id=95101 | 1005 // http://code.google.com/p/chromium/issues/detail?id=95101 |
| 920 if (service_->storage() == storage_) { | 1006 if (service_->storage() == storage_) { |
| 921 // Use a local variable because service_ is reset in HandleCacheFailure. | 1007 // Use a local variable because service_ is reset in HandleCacheFailure. |
| 922 AppCacheService* service = service_; | 1008 AppCacheService* service = service_; |
| 923 HandleCacheFailure("Manifest entry not found in existing cache", | 1009 HandleCacheFailure( |
| 924 DB_ERROR, GURL()); | 1010 ErrorDetails("Manifest entry not found in existing cache", |
| 1011 UNKNOWN_ERROR, |
| 1012 GURL(), |
| 1013 0, |
| 1014 false /*is_cross_origin*/), |
| 1015 DB_ERROR, |
| 1016 GURL()); |
| 925 AppCacheHistograms::AddMissingManifestEntrySample(); | 1017 AppCacheHistograms::AddMissingManifestEntrySample(); |
| 926 service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback()); | 1018 service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback()); |
| 927 } | 1019 } |
| 928 return; | 1020 return; |
| 929 } | 1021 } |
| 930 | 1022 |
| 931 // Load manifest data from storage to compare against fetched manifest. | 1023 // Load manifest data from storage to compare against fetched manifest. |
| 932 manifest_response_reader_.reset( | 1024 manifest_response_reader_.reset( |
| 933 storage_->CreateResponseReader(manifest_url_, | 1025 storage_->CreateResponseReader(manifest_url_, |
| 934 group_->group_id(), | 1026 group_->group_id(), |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1155 url, URLFetcher::MASTER_ENTRY_FETCH, this); | 1247 url, URLFetcher::MASTER_ENTRY_FETCH, this); |
| 1156 fetcher->Start(); | 1248 fetcher->Start(); |
| 1157 master_entry_fetches_.insert(PendingUrlFetches::value_type(url, fetcher)); | 1249 master_entry_fetches_.insert(PendingUrlFetches::value_type(url, fetcher)); |
| 1158 } | 1250 } |
| 1159 | 1251 |
| 1160 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin()); | 1252 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin()); |
| 1161 } | 1253 } |
| 1162 } | 1254 } |
| 1163 | 1255 |
| 1164 void AppCacheUpdateJob::CancelAllMasterEntryFetches( | 1256 void AppCacheUpdateJob::CancelAllMasterEntryFetches( |
| 1165 const std::string& error_message) { | 1257 const ErrorDetails& error_details) { |
| 1166 // For now, cancel all in-progress fetches for master entries and pretend | 1258 // For now, cancel all in-progress fetches for master entries and pretend |
| 1167 // all master entries fetches have completed. | 1259 // all master entries fetches have completed. |
| 1168 // TODO(jennb): Delete this when update no longer fetches master entries | 1260 // TODO(jennb): Delete this when update no longer fetches master entries |
| 1169 // directly. | 1261 // directly. |
| 1170 | 1262 |
| 1171 // Cancel all in-progress fetches. | 1263 // Cancel all in-progress fetches. |
| 1172 for (PendingUrlFetches::iterator it = master_entry_fetches_.begin(); | 1264 for (PendingUrlFetches::iterator it = master_entry_fetches_.begin(); |
| 1173 it != master_entry_fetches_.end(); ++it) { | 1265 it != master_entry_fetches_.end(); ++it) { |
| 1174 delete it->second; | 1266 delete it->second; |
| 1175 master_entries_to_fetch_.insert(it->first); // back in unfetched list | 1267 master_entries_to_fetch_.insert(it->first); // back in unfetched list |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1191 host_it != hosts.end(); ++host_it) { | 1283 host_it != hosts.end(); ++host_it) { |
| 1192 AppCacheHost* host = *host_it; | 1284 AppCacheHost* host = *host_it; |
| 1193 host->AssociateNoCache(GURL()); | 1285 host->AssociateNoCache(GURL()); |
| 1194 host_notifier.AddHost(host); | 1286 host_notifier.AddHost(host); |
| 1195 host->RemoveObserver(this); | 1287 host->RemoveObserver(this); |
| 1196 } | 1288 } |
| 1197 hosts.clear(); | 1289 hosts.clear(); |
| 1198 | 1290 |
| 1199 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin()); | 1291 master_entries_to_fetch_.erase(master_entries_to_fetch_.begin()); |
| 1200 } | 1292 } |
| 1201 host_notifier.SendErrorNotifications(error_message); | 1293 host_notifier.SendErrorNotifications(error_details); |
| 1202 } | 1294 } |
| 1203 | 1295 |
| 1204 bool AppCacheUpdateJob::MaybeLoadFromNewestCache(const GURL& url, | 1296 bool AppCacheUpdateJob::MaybeLoadFromNewestCache(const GURL& url, |
| 1205 AppCacheEntry& entry) { | 1297 AppCacheEntry& entry) { |
| 1206 if (update_type_ != UPGRADE_ATTEMPT) | 1298 if (update_type_ != UPGRADE_ATTEMPT) |
| 1207 return false; | 1299 return false; |
| 1208 | 1300 |
| 1209 AppCache* newest = group_->newest_complete_cache(); | 1301 AppCache* newest = group_->newest_complete_cache(); |
| 1210 AppCacheEntry* copy_me = newest->GetEntry(url); | 1302 AppCacheEntry* copy_me = newest->GetEntry(url); |
| 1211 if (!copy_me || !copy_me->has_response_id()) | 1303 if (!copy_me || !copy_me->has_response_id()) |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1467 | 1559 |
| 1468 // Break the connection with the group so the group cannot call delete | 1560 // Break the connection with the group so the group cannot call delete |
| 1469 // on this object after we've posted a task to delete ourselves. | 1561 // on this object after we've posted a task to delete ourselves. |
| 1470 group_->SetUpdateStatus(AppCacheGroup::IDLE); | 1562 group_->SetUpdateStatus(AppCacheGroup::IDLE); |
| 1471 group_ = NULL; | 1563 group_ = NULL; |
| 1472 | 1564 |
| 1473 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 1565 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
| 1474 } | 1566 } |
| 1475 | 1567 |
| 1476 } // namespace appcache | 1568 } // namespace appcache |
| OLD | NEW |