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 |