| 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 |