Chromium Code Reviews| 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; // ?? | |
| 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); |
| 173 if (data_consumed) { | 193 if (data_consumed) { |
| 174 bytes_read = 0; | 194 bytes_read = 0; |
| 175 while (request->Read(buffer_.get(), kBufferSize, &bytes_read)) { | 195 while (request->Read(buffer_.get(), kBufferSize, &bytes_read)) { |
| 176 if (bytes_read > 0) { | 196 if (bytes_read > 0) { |
| 177 data_consumed = ConsumeResponseData(bytes_read); | 197 data_consumed = ConsumeResponseData(bytes_read); |
| 178 if (!data_consumed) | 198 if (!data_consumed) |
| 179 break; // wait for async data processing, then read more | 199 break; // wait for async data processing, then read more |
| 180 } else { | 200 } else { |
| 181 break; | 201 break; |
| 182 } | 202 } |
| 183 } | 203 } |
| 184 } | 204 } |
| 185 } | 205 } |
| 186 if (data_consumed && !request->status().is_io_pending()) | 206 if (data_consumed && !request->status().is_io_pending()) { |
| 207 DCHECK_EQ(UPDATE_OK, result_); | |
| 187 OnResponseCompleted(); | 208 OnResponseCompleted(); |
| 209 } | |
| 188 } | 210 } |
| 189 | 211 |
| 190 void AppCacheUpdateJob::URLFetcher::AddConditionalHeaders( | 212 void AppCacheUpdateJob::URLFetcher::AddConditionalHeaders( |
| 191 const net::HttpResponseHeaders* headers) { | 213 const net::HttpResponseHeaders* headers) { |
| 192 DCHECK(request_.get() && headers); | 214 DCHECK(request_.get() && headers); |
| 193 net::HttpRequestHeaders extra_headers; | 215 net::HttpRequestHeaders extra_headers; |
| 194 | 216 |
| 195 // Add If-Modified-Since header if response info has Last-Modified header. | 217 // Add If-Modified-Since header if response info has Last-Modified header. |
| 196 const std::string last_modified = "Last-Modified"; | 218 const std::string last_modified = "Last-Modified"; |
| 197 std::string last_modified_value; | 219 std::string last_modified_value; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 209 extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch, | 231 extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch, |
| 210 etag_value); | 232 etag_value); |
| 211 } | 233 } |
| 212 if (!extra_headers.IsEmpty()) | 234 if (!extra_headers.IsEmpty()) |
| 213 request_->SetExtraRequestHeaders(extra_headers); | 235 request_->SetExtraRequestHeaders(extra_headers); |
| 214 } | 236 } |
| 215 | 237 |
| 216 void AppCacheUpdateJob::URLFetcher::OnWriteComplete(int result) { | 238 void AppCacheUpdateJob::URLFetcher::OnWriteComplete(int result) { |
| 217 if (result < 0) { | 239 if (result < 0) { |
| 218 request_->Cancel(); | 240 request_->Cancel(); |
| 241 result_ = DISKCACHE_ERROR; | |
| 219 OnResponseCompleted(); | 242 OnResponseCompleted(); |
| 220 return; | 243 return; |
| 221 } | 244 } |
| 222 ReadResponseData(); | 245 ReadResponseData(); |
| 223 } | 246 } |
| 224 | 247 |
| 225 void AppCacheUpdateJob::URLFetcher::ReadResponseData() { | 248 void AppCacheUpdateJob::URLFetcher::ReadResponseData() { |
| 226 InternalUpdateState state = job_->internal_state_; | 249 InternalUpdateState state = job_->internal_state_; |
| 227 if (state == CACHE_FAILURE || state == CANCELLED || state == COMPLETED) | 250 if (state == CACHE_FAILURE || state == CANCELLED || state == COMPLETED) |
| 228 return; | 251 return; |
| (...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 389 } | 412 } |
| 390 | 413 |
| 391 AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() { | 414 AppCacheResponseWriter* AppCacheUpdateJob::CreateResponseWriter() { |
| 392 AppCacheResponseWriter* writer = | 415 AppCacheResponseWriter* writer = |
| 393 storage_->CreateResponseWriter(manifest_url_, | 416 storage_->CreateResponseWriter(manifest_url_, |
| 394 group_->group_id()); | 417 group_->group_id()); |
| 395 stored_response_ids_.push_back(writer->response_id()); | 418 stored_response_ids_.push_back(writer->response_id()); |
| 396 return writer; | 419 return writer; |
| 397 } | 420 } |
| 398 | 421 |
| 399 void AppCacheUpdateJob::HandleCacheFailure(const std::string& error_message) { | 422 void AppCacheUpdateJob::HandleCacheFailure( |
| 423 const std::string& error_message, | |
| 424 ResultType result) { | |
| 400 // 6.9.4 cache failure steps 2-8. | 425 // 6.9.4 cache failure steps 2-8. |
| 401 DCHECK(internal_state_ != CACHE_FAILURE); | 426 DCHECK(internal_state_ != CACHE_FAILURE); |
| 402 DCHECK(!error_message.empty()); | 427 DCHECK(!error_message.empty()); |
| 403 internal_state_ = CACHE_FAILURE; | 428 internal_state_ = CACHE_FAILURE; |
| 404 CancelAllUrlFetches(); | 429 CancelAllUrlFetches(); |
| 405 CancelAllMasterEntryFetches(error_message); | 430 CancelAllMasterEntryFetches(error_message); |
| 406 NotifyAllError(error_message); | 431 NotifyAllError(error_message); |
| 407 DiscardInprogressCache(); | 432 DiscardInprogressCache(); |
| 408 internal_state_ = COMPLETED; | 433 internal_state_ = COMPLETED; |
| 434 AppCacheHistograms::CountUpdateJobResult(result); | |
| 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 DCHECK(fetcher->result() != UPDATE_OK); |
|
michaeln
2014/02/14 23:42:06
i'll put this dcheck in HandleCacheFailure()
| |
| 708 HandleCacheFailure(message, fetcher->result()); | |
| 682 return; | 709 return; |
| 683 } | 710 } |
| 684 } | 711 } |
| 685 } | 712 } |
| 686 | 713 |
| 687 DCHECK(internal_state_ != CACHE_FAILURE); | 714 DCHECK(internal_state_ != CACHE_FAILURE); |
| 688 FetchMasterEntries(); | 715 FetchMasterEntries(); |
| 689 MaybeCompleteUpdate(); | 716 MaybeCompleteUpdate(); |
| 690 } | 717 } |
| 691 | 718 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 712 manifest_response_writer_->WriteInfo( | 739 manifest_response_writer_->WriteInfo( |
| 713 io_buffer.get(), | 740 io_buffer.get(), |
| 714 base::Bind(&AppCacheUpdateJob::OnManifestInfoWriteComplete, | 741 base::Bind(&AppCacheUpdateJob::OnManifestInfoWriteComplete, |
| 715 base::Unretained(this))); | 742 base::Unretained(this))); |
| 716 } | 743 } |
| 717 } else { | 744 } else { |
| 718 VLOG(1) << "Request status: " << request->status().status() | 745 VLOG(1) << "Request status: " << request->status().status() |
| 719 << " error: " << request->status().error() | 746 << " error: " << request->status().error() |
| 720 << " response code: " << response_code; | 747 << " response code: " << response_code; |
| 721 ScheduleUpdateRetry(kRerunDelayMs); | 748 ScheduleUpdateRetry(kRerunDelayMs); |
| 722 HandleCacheFailure("Manifest changed during update, scheduling retry"); | 749 if (response_code == 200) { |
| 750 HandleCacheFailure("Manifest changed during update", MANIFEST_ERROR); | |
| 751 } else { | |
| 752 const char* kFormatString = "Manifest re-fetch failed (%d) %s"; | |
| 753 std::string message = FormatUrlErrorMessage( | |
| 754 kFormatString, manifest_url_, fetcher->result(), response_code); | |
| 755 HandleCacheFailure(message, fetcher->result()); | |
| 756 } | |
| 723 } | 757 } |
| 724 } | 758 } |
| 725 | 759 |
| 726 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) { | 760 void AppCacheUpdateJob::OnManifestInfoWriteComplete(int result) { |
| 727 if (result > 0) { | 761 if (result > 0) { |
| 728 scoped_refptr<net::StringIOBuffer> io_buffer( | 762 scoped_refptr<net::StringIOBuffer> io_buffer( |
| 729 new net::StringIOBuffer(manifest_data_)); | 763 new net::StringIOBuffer(manifest_data_)); |
| 730 manifest_response_writer_->WriteData( | 764 manifest_response_writer_->WriteData( |
| 731 io_buffer.get(), | 765 io_buffer.get(), |
| 732 manifest_data_.length(), | 766 manifest_data_.length(), |
| 733 base::Bind(&AppCacheUpdateJob::OnManifestDataWriteComplete, | 767 base::Bind(&AppCacheUpdateJob::OnManifestDataWriteComplete, |
| 734 base::Unretained(this))); | 768 base::Unretained(this))); |
| 735 } else { | 769 } else { |
| 736 HandleCacheFailure("Failed to write the manifest headers to storage"); | 770 HandleCacheFailure("Failed to write the manifest headers to storage", |
| 771 DISKCACHE_ERROR); | |
| 737 } | 772 } |
| 738 } | 773 } |
| 739 | 774 |
| 740 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { | 775 void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { |
| 741 if (result > 0) { | 776 if (result > 0) { |
| 742 AppCacheEntry entry(AppCacheEntry::MANIFEST, | 777 AppCacheEntry entry(AppCacheEntry::MANIFEST, |
| 743 manifest_response_writer_->response_id(), | 778 manifest_response_writer_->response_id(), |
| 744 manifest_response_writer_->amount_written()); | 779 manifest_response_writer_->amount_written()); |
| 745 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry)) | 780 if (!inprogress_cache_->AddOrModifyEntry(manifest_url_, entry)) |
| 746 duplicate_response_ids_.push_back(entry.response_id()); | 781 duplicate_response_ids_.push_back(entry.response_id()); |
| 747 StoreGroupAndCache(); | 782 StoreGroupAndCache(); |
| 748 } else { | 783 } else { |
| 749 HandleCacheFailure("Failed to write the manifest data to storage"); | 784 HandleCacheFailure("Failed to write the manifest data to storage", |
| 785 DISKCACHE_ERROR); | |
| 750 } | 786 } |
| 751 } | 787 } |
| 752 | 788 |
| 753 void AppCacheUpdateJob::StoreGroupAndCache() { | 789 void AppCacheUpdateJob::StoreGroupAndCache() { |
| 754 DCHECK(stored_state_ == UNSTORED); | 790 DCHECK(stored_state_ == UNSTORED); |
| 755 stored_state_ = STORING; | 791 stored_state_ = STORING; |
| 756 scoped_refptr<AppCache> newest_cache; | 792 scoped_refptr<AppCache> newest_cache; |
| 757 if (inprogress_cache_.get()) | 793 if (inprogress_cache_.get()) |
| 758 newest_cache.swap(inprogress_cache_); | 794 newest_cache.swap(inprogress_cache_); |
| 759 else | 795 else |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 772 DCHECK(stored_state_ == STORING); | 808 DCHECK(stored_state_ == STORING); |
| 773 if (success) { | 809 if (success) { |
| 774 stored_state_ = STORED; | 810 stored_state_ = STORED; |
| 775 MaybeCompleteUpdate(); // will definitely complete | 811 MaybeCompleteUpdate(); // will definitely complete |
| 776 } else { | 812 } else { |
| 777 // Restore inprogress_cache_ to get the proper events delivered | 813 // Restore inprogress_cache_ to get the proper events delivered |
| 778 // and the proper cleanup to occur. | 814 // and the proper cleanup to occur. |
| 779 if (newest_cache != group->newest_complete_cache()) | 815 if (newest_cache != group->newest_complete_cache()) |
| 780 inprogress_cache_ = newest_cache; | 816 inprogress_cache_ = newest_cache; |
| 781 | 817 |
| 818 ResultType result = DB_ERROR; | |
| 782 std::string message("Failed to commit new cache to storage"); | 819 std::string message("Failed to commit new cache to storage"); |
| 783 if (would_exceed_quota) | 820 if (would_exceed_quota) { |
| 784 message.append(", would exceed quota"); | 821 message.append(", would exceed quota"); |
| 785 HandleCacheFailure(message); | 822 result = QUOTA_ERROR; |
| 823 } | |
| 824 HandleCacheFailure(message, result); | |
| 786 } | 825 } |
| 787 } | 826 } |
| 788 | 827 |
| 789 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, | 828 void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, |
| 790 EventID event_id) { | 829 EventID event_id) { |
| 791 std::vector<int> ids(1, host->host_id()); | 830 std::vector<int> ids(1, host->host_id()); |
| 792 host->frontend()->OnEventRaised(ids, event_id); | 831 host->frontend()->OnEventRaised(ids, event_id); |
| 793 } | 832 } |
| 794 | 833 |
| 795 void AppCacheUpdateJob::NotifyAllAssociatedHosts(EventID event_id) { | 834 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); | 899 DCHECK(update_type_ == UPGRADE_ATTEMPT); |
| 861 AppCacheEntry* entry = NULL; | 900 AppCacheEntry* entry = NULL; |
| 862 if (group_->newest_complete_cache()) | 901 if (group_->newest_complete_cache()) |
| 863 entry = group_->newest_complete_cache()->GetEntry(manifest_url_); | 902 entry = group_->newest_complete_cache()->GetEntry(manifest_url_); |
| 864 if (!entry) { | 903 if (!entry) { |
| 865 // TODO(michaeln): This is just a bandaid to avoid a crash. | 904 // TODO(michaeln): This is just a bandaid to avoid a crash. |
| 866 // http://code.google.com/p/chromium/issues/detail?id=95101 | 905 // http://code.google.com/p/chromium/issues/detail?id=95101 |
| 867 if (service_->storage() == storage_) { | 906 if (service_->storage() == storage_) { |
| 868 // Use a local variable because service_ is reset in HandleCacheFailure. | 907 // Use a local variable because service_ is reset in HandleCacheFailure. |
| 869 AppCacheService* service = service_; | 908 AppCacheService* service = service_; |
| 870 HandleCacheFailure("Manifest entry not found in existing cache"); | 909 HandleCacheFailure("Manifest entry not found in existing cache", |
| 910 DB_ERROR); | |
| 871 AppCacheHistograms::AddMissingManifestEntrySample(); | 911 AppCacheHistograms::AddMissingManifestEntrySample(); |
| 872 service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback()); | 912 service->DeleteAppCacheGroup(manifest_url_, net::CompletionCallback()); |
| 873 } | 913 } |
| 874 return; | 914 return; |
| 875 } | 915 } |
| 876 | 916 |
| 877 // Load manifest data from storage to compare against fetched manifest. | 917 // Load manifest data from storage to compare against fetched manifest. |
| 878 manifest_response_reader_.reset( | 918 manifest_response_reader_.reset( |
| 879 storage_->CreateResponseReader(manifest_url_, | 919 storage_->CreateResponseReader(manifest_url_, |
| 880 group_->group_id(), | 920 group_->group_id(), |
| (...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1264 break; | 1304 break; |
| 1265 case REFETCH_MANIFEST: | 1305 case REFETCH_MANIFEST: |
| 1266 DCHECK(stored_state_ == STORED); | 1306 DCHECK(stored_state_ == STORED); |
| 1267 NotifyAllFinalProgress(); | 1307 NotifyAllFinalProgress(); |
| 1268 if (update_type_ == CACHE_ATTEMPT) | 1308 if (update_type_ == CACHE_ATTEMPT) |
| 1269 NotifyAllAssociatedHosts(CACHED_EVENT); | 1309 NotifyAllAssociatedHosts(CACHED_EVENT); |
| 1270 else | 1310 else |
| 1271 NotifyAllAssociatedHosts(UPDATE_READY_EVENT); | 1311 NotifyAllAssociatedHosts(UPDATE_READY_EVENT); |
| 1272 DiscardDuplicateResponses(); | 1312 DiscardDuplicateResponses(); |
| 1273 internal_state_ = COMPLETED; | 1313 internal_state_ = COMPLETED; |
| 1314 AppCacheHistograms::CountUpdateJobResult(UPDATE_OK); | |
| 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 |