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