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" |
11 #include "base/strings/string_util.h" | 11 #include "base/strings/string_util.h" |
12 #include "base/strings/stringprintf.h" | 12 #include "base/strings/stringprintf.h" |
13 #include "net/base/io_buffer.h" | 13 #include "net/base/io_buffer.h" |
14 #include "net/base/load_flags.h" | 14 #include "net/base/load_flags.h" |
15 #include "net/base/net_errors.h" | 15 #include "net/base/net_errors.h" |
16 #include "net/base/request_priority.h" | 16 #include "net/base/request_priority.h" |
17 #include "net/http/http_request_headers.h" | 17 #include "net/http/http_request_headers.h" |
18 #include "net/http/http_response_headers.h" | 18 #include "net/http/http_response_headers.h" |
19 #include "net/url_request/url_request_context.h" | 19 #include "net/url_request/url_request_context.h" |
20 #include "webkit/browser/appcache/appcache_group.h" | 20 #include "webkit/browser/appcache/appcache_group.h" |
21 #include "webkit/browser/appcache/appcache_histograms.h" | 21 #include "webkit/browser/appcache/appcache_histograms.h" |
22 | 22 |
23 namespace appcache { | 23 namespace appcache { |
24 | 24 |
25 static const int kBufferSize = 32768; | 25 static const int kBufferSize = 32768; |
26 static const size_t kMaxConcurrentUrlFetches = 2; | 26 static const size_t kMaxConcurrentUrlFetches = 2; |
27 static const int kMax503Retries = 3; | 27 static const int kMax503Retries = 3; |
28 | 28 |
| 29 static std::string FormatUrlErrorMessage( |
| 30 const char* format, const GURL& url, |
| 31 AppCacheUpdateJob::ResultType error, |
| 32 int response_code) { |
| 33 // Show the net response code if we have one. |
| 34 int code = response_code; |
| 35 if (error != AppCacheUpdateJob::SERVER_ERROR) |
| 36 code = static_cast<int>(error); |
| 37 return base::StringPrintf(format, code, url.spec().c_str()); |
| 38 } |
| 39 |
29 // Helper class for collecting hosts per frontend when sending notifications | 40 // Helper class for collecting hosts per frontend when sending notifications |
30 // so that only one notification is sent for all hosts using the same frontend. | 41 // so that only one notification is sent for all hosts using the same frontend. |
31 class HostNotifier { | 42 class HostNotifier { |
32 public: | 43 public: |
33 typedef std::vector<int> HostIds; | 44 typedef std::vector<int> HostIds; |
34 typedef std::map<AppCacheFrontend*, HostIds> NotifyHostMap; | 45 typedef std::map<AppCacheFrontend*, HostIds> NotifyHostMap; |
35 | 46 |
36 // Caller is responsible for ensuring there will be no duplicate hosts. | 47 // Caller is responsible for ensuring there will be no duplicate hosts. |
37 void AddHost(AppCacheHost* host) { | 48 void AddHost(AppCacheHost* host) { |
38 std::pair<NotifyHostMap::iterator , bool> ret = hosts_to_notify.insert( | 49 std::pair<NotifyHostMap::iterator , bool> ret = hosts_to_notify.insert( |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 // data out to the disk cache. | 105 // data out to the disk cache. |
95 AppCacheUpdateJob::URLFetcher::URLFetcher(const GURL& url, | 106 AppCacheUpdateJob::URLFetcher::URLFetcher(const GURL& url, |
96 FetchType fetch_type, | 107 FetchType fetch_type, |
97 AppCacheUpdateJob* job) | 108 AppCacheUpdateJob* job) |
98 : url_(url), | 109 : url_(url), |
99 job_(job), | 110 job_(job), |
100 fetch_type_(fetch_type), | 111 fetch_type_(fetch_type), |
101 retry_503_attempts_(0), | 112 retry_503_attempts_(0), |
102 buffer_(new net::IOBuffer(kBufferSize)), | 113 buffer_(new net::IOBuffer(kBufferSize)), |
103 request_(job->service_->request_context() | 114 request_(job->service_->request_context() |
104 ->CreateRequest(url, net::DEFAULT_PRIORITY, this)) {} | 115 ->CreateRequest(url, net::DEFAULT_PRIORITY, this)), |
| 116 result_(UPDATE_OK) {} |
105 | 117 |
106 AppCacheUpdateJob::URLFetcher::~URLFetcher() { | 118 AppCacheUpdateJob::URLFetcher::~URLFetcher() { |
107 } | 119 } |
108 | 120 |
109 void AppCacheUpdateJob::URLFetcher::Start() { | 121 void AppCacheUpdateJob::URLFetcher::Start() { |
110 request_->set_first_party_for_cookies(job_->manifest_url_); | 122 request_->set_first_party_for_cookies(job_->manifest_url_); |
111 request_->SetLoadFlags(request_->load_flags() | | 123 request_->SetLoadFlags(request_->load_flags() | |
112 net::LOAD_DISABLE_INTERCEPT); | 124 net::LOAD_DISABLE_INTERCEPT); |
113 if (existing_response_headers_.get()) | 125 if (existing_response_headers_.get()) |
114 AddConditionalHeaders(existing_response_headers_.get()); | 126 AddConditionalHeaders(existing_response_headers_.get()); |
115 request_->Start(); | 127 request_->Start(); |
116 } | 128 } |
117 | 129 |
118 void AppCacheUpdateJob::URLFetcher::OnReceivedRedirect( | 130 void AppCacheUpdateJob::URLFetcher::OnReceivedRedirect( |
119 net::URLRequest* request, const GURL& new_url, bool* defer_redirect) { | 131 net::URLRequest* request, const GURL& new_url, bool* defer_redirect) { |
120 DCHECK(request_ == request); | 132 DCHECK(request_ == request); |
121 // Redirect is not allowed by the update process. | 133 // Redirect is not allowed by the update process. |
122 request->Cancel(); | 134 request->Cancel(); |
| 135 result_ = REDIRECT_ERROR; |
123 OnResponseCompleted(); | 136 OnResponseCompleted(); |
124 } | 137 } |
125 | 138 |
126 void AppCacheUpdateJob::URLFetcher::OnResponseStarted( | 139 void AppCacheUpdateJob::URLFetcher::OnResponseStarted( |
127 net::URLRequest *request) { | 140 net::URLRequest *request) { |
128 DCHECK(request == request_); | 141 DCHECK(request == request_); |
129 if (request->status().is_success() && | 142 int response_code = -1; |
130 (request->GetResponseCode() / 100) == 2) { | 143 if (request->status().is_success()) |
| 144 response_code = request->GetResponseCode(); |
| 145 if ((response_code / 100) == 2) { |
131 | 146 |
132 // See http://code.google.com/p/chromium/issues/detail?id=69594 | 147 // See http://code.google.com/p/chromium/issues/detail?id=69594 |
133 // We willfully violate the HTML5 spec at this point in order | 148 // We willfully violate the HTML5 spec at this point in order |
134 // to support the appcaching of cross-origin HTTPS resources. | 149 // to support the appcaching of cross-origin HTTPS resources. |
135 // We've opted for a milder constraint and allow caching unless | 150 // We've opted for a milder constraint and allow caching unless |
136 // the resource has a "no-store" header. A spec change has been | 151 // the resource has a "no-store" header. A spec change has been |
137 // requested on the whatwg list. | 152 // requested on the whatwg list. |
138 // TODO(michaeln): Consider doing this for cross-origin HTTP resources too. | 153 // TODO(michaeln): Consider doing this for cross-origin HTTP resources too. |
139 if (url_.SchemeIsSecure() && | 154 if (url_.SchemeIsSecure() && |
140 url_.GetOrigin() != job_->manifest_url_.GetOrigin()) { | 155 url_.GetOrigin() != job_->manifest_url_.GetOrigin()) { |
141 if (request->response_headers()-> | 156 if (request->response_headers()-> |
142 HasHeaderValue("cache-control", "no-store")) { | 157 HasHeaderValue("cache-control", "no-store")) { |
143 request->Cancel(); | 158 request->Cancel(); |
| 159 result_ = SERVER_ERROR; // Not the best match? |
144 OnResponseCompleted(); | 160 OnResponseCompleted(); |
145 return; | 161 return; |
146 } | 162 } |
147 } | 163 } |
148 | 164 |
149 // Write response info to storage for URL fetches. Wait for async write | 165 // Write response info to storage for URL fetches. Wait for async write |
150 // completion before reading any response data. | 166 // completion before reading any response data. |
151 if (fetch_type_ == URL_FETCH || fetch_type_ == MASTER_ENTRY_FETCH) { | 167 if (fetch_type_ == URL_FETCH || fetch_type_ == MASTER_ENTRY_FETCH) { |
152 response_writer_.reset(job_->CreateResponseWriter()); | 168 response_writer_.reset(job_->CreateResponseWriter()); |
153 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer( | 169 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer( |
154 new HttpResponseInfoIOBuffer( | 170 new HttpResponseInfoIOBuffer( |
155 new net::HttpResponseInfo(request->response_info()))); | 171 new net::HttpResponseInfo(request->response_info()))); |
156 response_writer_->WriteInfo( | 172 response_writer_->WriteInfo( |
157 io_buffer.get(), | 173 io_buffer.get(), |
158 base::Bind(&URLFetcher::OnWriteComplete, base::Unretained(this))); | 174 base::Bind(&URLFetcher::OnWriteComplete, base::Unretained(this))); |
159 } else { | 175 } else { |
160 ReadResponseData(); | 176 ReadResponseData(); |
161 } | 177 } |
162 } else { | 178 } else { |
| 179 if (response_code > 0) |
| 180 result_ = SERVER_ERROR; |
| 181 else |
| 182 result_ = NETWORK_ERROR; |
163 OnResponseCompleted(); | 183 OnResponseCompleted(); |
164 } | 184 } |
165 } | 185 } |
166 | 186 |
167 void AppCacheUpdateJob::URLFetcher::OnReadCompleted( | 187 void AppCacheUpdateJob::URLFetcher::OnReadCompleted( |
168 net::URLRequest* request, int bytes_read) { | 188 net::URLRequest* request, int bytes_read) { |
169 DCHECK(request_ == request); | 189 DCHECK(request_ == request); |
170 bool data_consumed = true; | 190 bool data_consumed = true; |
171 if (request->status().is_success() && bytes_read > 0) { | 191 if (request->status().is_success() && bytes_read > 0) { |
172 data_consumed = ConsumeResponseData(bytes_read); | 192 data_consumed = ConsumeResponseData(bytes_read); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
209 extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch, | 229 extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch, |
210 etag_value); | 230 etag_value); |
211 } | 231 } |
212 if (!extra_headers.IsEmpty()) | 232 if (!extra_headers.IsEmpty()) |
213 request_->SetExtraRequestHeaders(extra_headers); | 233 request_->SetExtraRequestHeaders(extra_headers); |
214 } | 234 } |
215 | 235 |
216 void AppCacheUpdateJob::URLFetcher::OnWriteComplete(int result) { | 236 void AppCacheUpdateJob::URLFetcher::OnWriteComplete(int result) { |
217 if (result < 0) { | 237 if (result < 0) { |
218 request_->Cancel(); | 238 request_->Cancel(); |
| 239 result_ = DISKCACHE_ERROR; |
219 OnResponseCompleted(); | 240 OnResponseCompleted(); |
220 return; | 241 return; |
221 } | 242 } |
222 ReadResponseData(); | 243 ReadResponseData(); |
223 } | 244 } |
224 | 245 |
225 void AppCacheUpdateJob::URLFetcher::ReadResponseData() { | 246 void AppCacheUpdateJob::URLFetcher::ReadResponseData() { |
226 InternalUpdateState state = job_->internal_state_; | 247 InternalUpdateState state = job_->internal_state_; |
227 if (state == CACHE_FAILURE || state == CANCELLED || state == COMPLETED) | 248 if (state == CACHE_FAILURE || state == CANCELLED || state == COMPLETED) |
228 return; | 249 return; |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
389 } | 410 } |
390 | 411 |
391 AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() { | 412 AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() { |
392 AppCacheResponseWriter* writer = | 413 AppCacheResponseWriter* writer = |
393 storage_->CreateResponseWriter(manifest_url_, | 414 storage_->CreateResponseWriter(manifest_url_, |
394 group_->group_id()); | 415 group_->group_id()); |
395 stored_response_ids_.push_back(writer->response_id()); | 416 stored_response_ids_.push_back(writer->response_id()); |
396 return writer; | 417 return writer; |
397 } | 418 } |
398 | 419 |
399 void AppCacheUpdateJob::HandleCacheFailure(const std::string& error_message) { | 420 void AppCacheUpdateJob::HandleCacheFailure( |
| 421 const std::string& error_message, |
| 422 ResultType result) { |
400 // 6.9.4 cache failure steps 2-8. | 423 // 6.9.4 cache failure steps 2-8. |
401 DCHECK(internal_state_ != CACHE_FAILURE); | 424 DCHECK(internal_state_ != CACHE_FAILURE); |
402 DCHECK(!error_message.empty()); | 425 DCHECK(!error_message.empty()); |
| 426 DCHECK(result != UPDATE_OK); |
403 internal_state_ = CACHE_FAILURE; | 427 internal_state_ = CACHE_FAILURE; |
404 CancelAllUrlFetches(); | 428 CancelAllUrlFetches(); |
405 CancelAllMasterEntryFetches(error_message); | 429 CancelAllMasterEntryFetches(error_message); |
406 NotifyAllError(error_message); | 430 NotifyAllError(error_message); |
407 DiscardInprogressCache(); | 431 DiscardInprogressCache(); |
408 internal_state_ = COMPLETED; | 432 internal_state_ = COMPLETED; |
| 433 AppCacheHistograms::CountUpdateJobResult( |
| 434 result, manifest_url_.GetOrigin()); |
409 DeleteSoon(); // To unwind the stack prior to deletion. | 435 DeleteSoon(); // To unwind the stack prior to deletion. |
410 } | 436 } |
411 | 437 |
412 void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) { | 438 void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) { |
413 DCHECK(!manifest_fetcher_); | 439 DCHECK(!manifest_fetcher_); |
414 manifest_fetcher_ = new URLFetcher( | 440 manifest_fetcher_ = new URLFetcher( |
415 manifest_url_, | 441 manifest_url_, |
416 is_first_fetch ? URLFetcher::MANIFEST_FETCH : | 442 is_first_fetch ? URLFetcher::MANIFEST_FETCH : |
417 URLFetcher::MANIFEST_REFETCH, | 443 URLFetcher::MANIFEST_REFETCH, |
418 this); | 444 this); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
460 CheckIfManifestChanged(); // continues asynchronously | 486 CheckIfManifestChanged(); // continues asynchronously |
461 else | 487 else |
462 ContinueHandleManifestFetchCompleted(true); | 488 ContinueHandleManifestFetchCompleted(true); |
463 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) { | 489 } else if (response_code == 304 && update_type_ == UPGRADE_ATTEMPT) { |
464 ContinueHandleManifestFetchCompleted(false); | 490 ContinueHandleManifestFetchCompleted(false); |
465 } else if ((response_code == 404 || response_code == 410) && | 491 } else if ((response_code == 404 || response_code == 410) && |
466 update_type_ == UPGRADE_ATTEMPT) { | 492 update_type_ == UPGRADE_ATTEMPT) { |
467 storage_->MakeGroupObsolete(group_, this); // async | 493 storage_->MakeGroupObsolete(group_, this); // async |
468 } else { | 494 } else { |
469 const char* kFormatString = "Manifest fetch failed (%d) %s"; | 495 const char* kFormatString = "Manifest fetch failed (%d) %s"; |
470 std::string message = base::StringPrintf(kFormatString, response_code, | 496 std::string message = FormatUrlErrorMessage( |
471 manifest_url_.spec().c_str()); | 497 kFormatString, manifest_url_, fetcher->result(), response_code); |
472 HandleCacheFailure(message); | 498 HandleCacheFailure(message, fetcher->result()); |
473 } | 499 } |
474 } | 500 } |
475 | 501 |
476 void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group, | 502 void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group, |
477 bool success) { | 503 bool success) { |
478 DCHECK(master_entry_fetches_.empty()); | 504 DCHECK(master_entry_fetches_.empty()); |
479 CancelAllMasterEntryFetches("The cache has been made obsolete, " | 505 CancelAllMasterEntryFetches("The cache has been made obsolete, " |
480 "the manifest file returned 404 or 410"); | 506 "the manifest file returned 404 or 410"); |
481 if (success) { | 507 if (success) { |
482 DCHECK(group->is_obsolete()); | 508 DCHECK(group->is_obsolete()); |
483 NotifyAllAssociatedHosts(OBSOLETE_EVENT); | 509 NotifyAllAssociatedHosts(OBSOLETE_EVENT); |
484 internal_state_ = COMPLETED; | 510 internal_state_ = COMPLETED; |
485 MaybeCompleteUpdate(); | 511 MaybeCompleteUpdate(); |
486 } else { | 512 } else { |
487 // Treat failure to mark group obsolete as a cache failure. | 513 // Treat failure to mark group obsolete as a cache failure. |
488 HandleCacheFailure("Failed to mark the cache as obsolete"); | 514 HandleCacheFailure("Failed to mark the cache as obsolete", DB_ERROR); |
489 } | 515 } |
490 } | 516 } |
491 | 517 |
492 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) { | 518 void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) { |
493 DCHECK(internal_state_ == FETCH_MANIFEST); | 519 DCHECK(internal_state_ == FETCH_MANIFEST); |
494 | 520 |
495 if (!changed) { | 521 if (!changed) { |
496 DCHECK(update_type_ == UPGRADE_ATTEMPT); | 522 DCHECK(update_type_ == UPGRADE_ATTEMPT); |
497 internal_state_ = NO_UPDATE; | 523 internal_state_ = NO_UPDATE; |
498 | 524 |
499 // Wait for pending master entries to download. | 525 // Wait for pending master entries to download. |
500 FetchMasterEntries(); | 526 FetchMasterEntries(); |
501 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps | 527 MaybeCompleteUpdate(); // if not done, run async 6.9.4 step 7 substeps |
502 return; | 528 return; |
503 } | 529 } |
504 | 530 |
505 Manifest manifest; | 531 Manifest manifest; |
506 if (!ParseManifest(manifest_url_, manifest_data_.data(), | 532 if (!ParseManifest(manifest_url_, manifest_data_.data(), |
507 manifest_data_.length(), manifest)) { | 533 manifest_data_.length(), manifest)) { |
508 const char* kFormatString = "Failed to parse manifest %s"; | 534 const char* kFormatString = "Failed to parse manifest %s"; |
509 const std::string message = base::StringPrintf(kFormatString, | 535 const std::string message = base::StringPrintf(kFormatString, |
510 manifest_url_.spec().c_str()); | 536 manifest_url_.spec().c_str()); |
511 HandleCacheFailure(message); | 537 HandleCacheFailure(message, MANIFEST_ERROR); |
512 VLOG(1) << message; | 538 VLOG(1) << message; |
513 return; | 539 return; |
514 } | 540 } |
515 | 541 |
516 // Proceed with update process. Section 6.9.4 steps 8-20. | 542 // Proceed with update process. Section 6.9.4 steps 8-20. |
517 internal_state_ = DOWNLOADING; | 543 internal_state_ = DOWNLOADING; |
518 inprogress_cache_ = new AppCache(storage_, storage_->NewCacheId()); | 544 inprogress_cache_ = new AppCache(storage_, storage_->NewCacheId()); |
519 BuildUrlFileList(manifest); | 545 BuildUrlFileList(manifest); |
520 inprogress_cache_->InitializeWithManifest(&manifest); | 546 inprogress_cache_->InitializeWithManifest(&manifest); |
521 | 547 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
573 << " error: " << request->status().error() | 599 << " error: " << request->status().error() |
574 << " response code: " << response_code; | 600 << " response code: " << response_code; |
575 if (entry.IsExplicit() || entry.IsFallback() || entry.IsIntercept()) { | 601 if (entry.IsExplicit() || entry.IsFallback() || entry.IsIntercept()) { |
576 if (response_code == 304 && fetcher->existing_entry().has_response_id()) { | 602 if (response_code == 304 && fetcher->existing_entry().has_response_id()) { |
577 // Keep the existing response. | 603 // Keep the existing response. |
578 entry.set_response_id(fetcher->existing_entry().response_id()); | 604 entry.set_response_id(fetcher->existing_entry().response_id()); |
579 entry.set_response_size(fetcher->existing_entry().response_size()); | 605 entry.set_response_size(fetcher->existing_entry().response_size()); |
580 inprogress_cache_->AddOrModifyEntry(url, entry); | 606 inprogress_cache_->AddOrModifyEntry(url, entry); |
581 } else { | 607 } else { |
582 const char* kFormatString = "Resource fetch failed (%d) %s"; | 608 const char* kFormatString = "Resource fetch failed (%d) %s"; |
583 const std::string message = base::StringPrintf(kFormatString, | 609 std::string message = FormatUrlErrorMessage( |
584 response_code, url.spec().c_str()); | 610 kFormatString, url, fetcher->result(), response_code); |
585 HandleCacheFailure(message); | 611 HandleCacheFailure(message, fetcher->result()); |
586 return; | 612 return; |
587 } | 613 } |
588 } else if (response_code == 404 || response_code == 410) { | 614 } else if (response_code == 404 || response_code == 410) { |
589 // Entry is skipped. They are dropped from the cache. | 615 // Entry is skipped. They are dropped from the cache. |
590 } else if (update_type_ == UPGRADE_ATTEMPT && | 616 } else if (update_type_ == UPGRADE_ATTEMPT && |
591 fetcher->existing_entry().has_response_id()) { | 617 fetcher->existing_entry().has_response_id()) { |
592 // Keep the existing response. | 618 // Keep the existing response. |
593 // TODO(michaeln): Not sure this is a good idea. This is spec compliant | 619 // TODO(michaeln): Not sure this is a good idea. This is spec compliant |
594 // but the old resource may or may not be compatible with the new contents | 620 // but the old resource may or may not be compatible with the new contents |
595 // of the cache. Impossible to know one way or the other. | 621 // of the cache. Impossible to know one way or the other. |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
657 host_notifier.AddHost(host); | 683 host_notifier.AddHost(host); |
658 | 684 |
659 // In downloading case, disassociate host from inprogress cache. | 685 // In downloading case, disassociate host from inprogress cache. |
660 if (inprogress_cache_.get()) | 686 if (inprogress_cache_.get()) |
661 host->AssociateNoCache(GURL()); | 687 host->AssociateNoCache(GURL()); |
662 | 688 |
663 host->RemoveObserver(this); | 689 host->RemoveObserver(this); |
664 } | 690 } |
665 hosts.clear(); | 691 hosts.clear(); |
666 | 692 |
667 const char* kFormatString = "Master entry fetch failed (%d) %s"; | 693 const char* kFormatString = "Manifest fetch failed (%d) %s"; |
668 const std::string message = base::StringPrintf(kFormatString, | 694 std::string message = FormatUrlErrorMessage( |
669 response_code, request->url().spec().c_str()); | 695 kFormatString, request->url(), fetcher->result(), response_code); |
670 host_notifier.SendErrorNotifications(message); | 696 host_notifier.SendErrorNotifications(message); |
671 | 697 |
672 // In downloading case, update result is different if all master entries | 698 // In downloading case, update result is different if all master entries |
673 // failed vs. only some failing. | 699 // failed vs. only some failing. |
674 if (inprogress_cache_.get()) { | 700 if (inprogress_cache_.get()) { |
675 // Only count successful downloads to know if all master entries failed. | 701 // Only count successful downloads to know if all master entries failed. |
676 pending_master_entries_.erase(found); | 702 pending_master_entries_.erase(found); |
677 --master_entries_completed_; | 703 --master_entries_completed_; |
678 | 704 |
679 // Section 6.9.4, step 22.3. | 705 // Section 6.9.4, step 22.3. |
680 if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) { | 706 if (update_type_ == CACHE_ATTEMPT && pending_master_entries_.empty()) { |
681 HandleCacheFailure(message); | 707 HandleCacheFailure(message, fetcher->result()); |
682 return; | 708 return; |
683 } | 709 } |
684 } | 710 } |
685 } | 711 } |
686 | 712 |
687 DCHECK(internal_state_ != CACHE_FAILURE); | 713 DCHECK(internal_state_ != CACHE_FAILURE); |
688 FetchMasterEntries(); | 714 FetchMasterEntries(); |
689 MaybeCompleteUpdate(); | 715 MaybeCompleteUpdate(); |
690 } | 716 } |
691 | 717 |
(...skipping 20 matching lines...) Expand all Loading... |
712 manifest_response_writer_->WriteInfo( | 738 manifest_response_writer_->WriteInfo( |
713 io_buffer.get(), | 739 io_buffer.get(), |
714 base::Bind(&AppCacheUpdateJob::OnManifestInfoWriteComplete, | 740 base::Bind(&AppCacheUpdateJob::OnManifestInfoWriteComplete, |
715 base::Unretained(this))); | 741 base::Unretained(this))); |
716 } | 742 } |
717 } else { | 743 } else { |
718 VLOG(1) << "Request status: " << request->status().status() | 744 VLOG(1) << "Request status: " << request->status().status() |
719 << " error: " << request->status().error() | 745 << " error: " << request->status().error() |
720 << " response code: " << response_code; | 746 << " response code: " << response_code; |
721 ScheduleUpdateRetry(kRerunDelayMs); | 747 ScheduleUpdateRetry(kRerunDelayMs); |
722 HandleCacheFailure("Manifest changed during update, scheduling retry"); | 748 if (response_code == 200) { |
| 749 HandleCacheFailure("Manifest changed during update", MANIFEST_ERROR); |
| 750 } else { |
| 751 const char* kFormatString = "Manifest re-fetch failed (%d) %s"; |
| 752 std::string message = FormatUrlErrorMessage( |
| 753 kFormatString, manifest_url_, fetcher->result(), response_code); |
| 754 HandleCacheFailure(message, fetcher->result()); |
| 755 } |
723 } | 756 } |
724 } | 757 } |
725 | 758 |
726 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) { | 759 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) { |
727 if (result > 0) { | 760 if (result > 0) { |
728 scoped_refptr<net::StringIOBuffer> io_buffer( | 761 scoped_refptr<net::StringIOBuffer> io_buffer( |
729 new net::StringIOBuffer(manifest_data_)); | 762 new net::StringIOBuffer(manifest_data_)); |
730 manifest_response_writer_->WriteData( | 763 manifest_response_writer_->WriteData( |
731 io_buffer.get(), | 764 io_buffer.get(), |
732 manifest_data_.length(), | 765 manifest_data_.length(), |
733 base::Bind(&AppCacheUpdateJob::OnManifestDataWriteComplete, | 766 base::Bind(&AppCacheUpdateJob::OnManifestDataWriteComplete, |
734 base::Unretained(this))); | 767 base::Unretained(this))); |
735 } else { | 768 } else { |
736 HandleCacheFailure("Failed to write the manifest headers to storage"); | 769 HandleCacheFailure("Failed to write the manifest headers to storage", |
| 770 DISKCACHE_ERROR); |
737 } | 771 } |
738 } | 772 } |
739 | 773 |
740 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { | 774 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { |
741 if (result > 0) { | 775 if (result > 0) { |
742 AppCacheEntry entry(AppCacheEntry::MANIFEST, | 776 AppCacheEntry entry(AppCacheEntry::MANIFEST, |
743 manifest_response_writer_->response_id(), | 777 manifest_response_writer_->response_id(), |
744 manifest_response_writer_->amount_written()); | 778 manifest_response_writer_->amount_written()); |
745 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry)) | 779 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry)) |
746 duplicate_response_ids_.push_back(entry.response_id()); | 780 duplicate_response_ids_.push_back(entry.response_id()); |
747 StoreGroupAndCache(); | 781 StoreGroupAndCache(); |
748 } else { | 782 } else { |
749 HandleCacheFailure("Failed to write the manifest data to storage"); | 783 HandleCacheFailure("Failed to write the manifest data to storage", |
| 784 DISKCACHE_ERROR); |
750 } | 785 } |
751 } | 786 } |
752 | 787 |
753 void AppCacheUpdateJob::StoreGroupAndCache() { | 788 void AppCacheUpdateJob::StoreGroupAndCache() { |
754 DCHECK(stored_state_ == UNSTORED); | 789 DCHECK(stored_state_ == UNSTORED); |
755 stored_state_ = STORING; | 790 stored_state_ = STORING; |
756 scoped_refptr<AppCache> newest_cache; | 791 scoped_refptr<AppCache> newest_cache; |
757 if (inprogress_cache_.get()) | 792 if (inprogress_cache_.get()) |
758 newest_cache.swap(inprogress_cache_); | 793 newest_cache.swap(inprogress_cache_); |
759 else | 794 else |
(...skipping 12 matching lines...) Expand all Loading... |
772 DCHECK(stored_state_ == STORING); | 807 DCHECK(stored_state_ == STORING); |
773 if (success) { | 808 if (success) { |
774 stored_state_ = STORED; | 809 stored_state_ = STORED; |
775 MaybeCompleteUpdate(); // will definitely complete | 810 MaybeCompleteUpdate(); // will definitely complete |
776 } else { | 811 } else { |
777 // Restore inprogress_cache_ to get the proper events delivered | 812 // Restore inprogress_cache_ to get the proper events delivered |
778 // and the proper cleanup to occur. | 813 // and the proper cleanup to occur. |
779 if (newest_cache != group->newest_complete_cache()) | 814 if (newest_cache != group->newest_complete_cache()) |
780 inprogress_cache_ = newest_cache; | 815 inprogress_cache_ = newest_cache; |
781 | 816 |
| 817 ResultType result = DB_ERROR; |
782 std::string message("Failed to commit new cache to storage"); | 818 std::string message("Failed to commit new cache to storage"); |
783 if (would_exceed_quota) | 819 if (would_exceed_quota) { |
784 message.append(", would exceed quota"); | 820 message.append(", would exceed quota"); |
785 HandleCacheFailure(message); | 821 result = QUOTA_ERROR; |
| 822 } |
| 823 HandleCacheFailure(message, result); |
786 } | 824 } |
787 } | 825 } |
788 | 826 |
789 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, | 827 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, |
790 EventID event_id) { | 828 EventID event_id) { |
791 std::vector<int> ids(1, host->host_id()); | 829 std::vector<int> ids(1, host->host_id()); |
792 host->frontend()->OnEventRaised(ids, event_id); | 830 host->frontend()->OnEventRaised(ids, event_id); |
793 } | 831 } |
794 | 832 |
795 void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) { | 833 void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
860 DCHECK(update_type_ == UPGRADE_ATTEMPT); | 898 DCHECK(update_type_ == UPGRADE_ATTEMPT); |
861 AppCacheEntry* entry = NULL; | 899 AppCacheEntry* entry = NULL; |
862 if (group_->newest_complete_cache()) | 900 if (group_->newest_complete_cache()) |
863 entry = group_->newest_complete_cache()->GetEntry(manifest_url_); | 901 entry = group_->newest_complete_cache()->GetEntry(manifest_url_); |
864 if (!entry) { | 902 if (!entry) { |
865 // TODO(michaeln): This is just a bandaid to avoid a crash. | 903 // TODO(michaeln): This is just a bandaid to avoid a crash. |
866 // http://code.google.com/p/chromium/issues/detail?id=95101 | 904 // http://code.google.com/p/chromium/issues/detail?id=95101 |
867 if (service_->storage() == storage_) { | 905 if (service_->storage() == storage_) { |
868 // Use a local variable because service_ is reset in HandleCacheFailure. | 906 // Use a local variable because service_ is reset in HandleCacheFailure. |
869 AppCacheService* service = service_; | 907 AppCacheService* service = service_; |
870 HandleCacheFailure("Manifest entry not found in existing cache"); | 908 HandleCacheFailure("Manifest entry not found in existing cache", |
| 909 DB_ERROR); |
871 AppCacheHistograms::AddMissingManifestEntrySample(); | 910 AppCacheHistograms::AddMissingManifestEntrySample(); |
872 service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback()); | 911 service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback()); |
873 } | 912 } |
874 return; | 913 return; |
875 } | 914 } |
876 | 915 |
877 // Load manifest data from storage to compare against fetched manifest. | 916 // Load manifest data from storage to compare against fetched manifest. |
878 manifest_response_reader_.reset( | 917 manifest_response_reader_.reset( |
879 storage_->CreateResponseReader(manifest_url_, | 918 storage_->CreateResponseReader(manifest_url_, |
880 group_->group_id(), | 919 group_->group_id(), |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1264 break; | 1303 break; |
1265 case REFETCH_MANIFEST: | 1304 case REFETCH_MANIFEST: |
1266 DCHECK(stored_state_ == STORED); | 1305 DCHECK(stored_state_ == STORED); |
1267 NotifyAllFinalProgress(); | 1306 NotifyAllFinalProgress(); |
1268 if (update_type_ == CACHE_ATTEMPT) | 1307 if (update_type_ == CACHE_ATTEMPT) |
1269 NotifyAllAssociatedHosts(CACHED_EVENT); | 1308 NotifyAllAssociatedHosts(CACHED_EVENT); |
1270 else | 1309 else |
1271 NotifyAllAssociatedHosts(UPDATE_READY_EVENT); | 1310 NotifyAllAssociatedHosts(UPDATE_READY_EVENT); |
1272 DiscardDuplicateResponses(); | 1311 DiscardDuplicateResponses(); |
1273 internal_state_ = COMPLETED; | 1312 internal_state_ = COMPLETED; |
| 1313 AppCacheHistograms::CountUpdateJobResult( |
| 1314 UPDATE_OK, manifest_url_.GetOrigin()); |
1274 break; | 1315 break; |
1275 case CACHE_FAILURE: | 1316 case CACHE_FAILURE: |
1276 NOTREACHED(); // See HandleCacheFailure | 1317 NOTREACHED(); // See HandleCacheFailure |
1277 break; | 1318 break; |
1278 default: | 1319 default: |
1279 break; | 1320 break; |
1280 } | 1321 } |
1281 | 1322 |
1282 // Let the stack unwind before deletion to make it less risky as this | 1323 // Let the stack unwind before deletion to make it less risky as this |
1283 // method is called from multiple places in this file. | 1324 // method is called from multiple places in this file. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1367 | 1408 |
1368 // Break the connection with the group so the group cannot call delete | 1409 // Break the connection with the group so the group cannot call delete |
1369 // on this object after we've posted a task to delete ourselves. | 1410 // on this object after we've posted a task to delete ourselves. |
1370 group_->SetUpdateStatus(AppCacheGroup::IDLE); | 1411 group_->SetUpdateStatus(AppCacheGroup::IDLE); |
1371 group_ = NULL; | 1412 group_ = NULL; |
1372 | 1413 |
1373 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); | 1414 base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
1374 } | 1415 } |
1375 | 1416 |
1376 } // namespace appcache | 1417 } // namespace appcache |
OLD | NEW |