Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(225)

Side by Side Diff: webkit/appcache/appcache_update_job.cc

Issue 3033003: Make conditional requests when updating the appcache.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/appcache/appcache_update_job.h ('k') | webkit/appcache/appcache_update_job_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 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/appcache/appcache_update_job.h" 5 #include "webkit/appcache/appcache_update_job.h"
6 6
7 #include "base/compiler_specific.h" 7 #include "base/compiler_specific.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "net/base/io_buffer.h" 10 #include "net/base/io_buffer.h"
11 #include "net/base/load_flags.h" 11 #include "net/base/load_flags.h"
12 #include "net/base/net_errors.h" 12 #include "net/base/net_errors.h"
13 #include "net/http/http_request_headers.h" 13 #include "net/http/http_request_headers.h"
14 #include "webkit/appcache/appcache_group.h" 14 #include "webkit/appcache/appcache_group.h"
15 #include "webkit/appcache/appcache_policy.h" 15 #include "webkit/appcache/appcache_policy.h"
16 #include "webkit/appcache/appcache_response.h"
17 16
18 namespace appcache { 17 namespace appcache {
19 18
20 static const int kBufferSize = 32768; 19 static const int kBufferSize = 32768;
21 static const size_t kMaxConcurrentUrlFetches = 2; 20 static const size_t kMaxConcurrentUrlFetches = 2;
22 static const int kMax503Retries = 3; 21 static const int kMax503Retries = 3;
23 22
24 // Extra info associated with requests for use during response processing. 23 // Extra info associated with requests for use during response processing.
25 // This info is deleted when the URLRequest is deleted. 24 // This info is deleted when the URLRequest is deleted.
26 class UpdateJobInfo : public URLRequest::UserData { 25 class UpdateJobInfo : public URLRequest::UserData {
27 public: 26 public:
28 enum RequestType { 27 enum RequestType {
29 MANIFEST_FETCH, 28 MANIFEST_FETCH,
30 URL_FETCH, 29 URL_FETCH,
31 MASTER_ENTRY_FETCH, 30 MASTER_ENTRY_FETCH,
32 MANIFEST_REFETCH, 31 MANIFEST_REFETCH,
33 }; 32 };
34 33
35 explicit UpdateJobInfo(RequestType request_type) 34 explicit UpdateJobInfo(RequestType request_type)
36 : type_(request_type), 35 : type_(request_type),
37 buffer_(new net::IOBuffer(kBufferSize)), 36 buffer_(new net::IOBuffer(kBufferSize)),
38 retry_503_attempts_(0), 37 retry_503_attempts_(0),
39 update_job_(NULL), 38 update_job_(NULL),
40 request_(NULL), 39 request_(NULL),
41 ALLOW_THIS_IN_INITIALIZER_LIST(write_callback_( 40 ALLOW_THIS_IN_INITIALIZER_LIST(write_callback_(
42 this, &UpdateJobInfo::OnWriteComplete)) { 41 this, &UpdateJobInfo::OnWriteComplete)) {
43 } 42 }
44 43
45 void SetUpResponseWriter(AppCacheResponseWriter* writer, 44 void SetUpResponseWriter(AppCacheResponseWriter* writer,
46 AppCacheUpdateJob* update, 45 AppCacheUpdateJob* update,
47 URLRequest* request) { 46 URLRequest* request) {
48 DCHECK(!response_writer_.get()); 47 DCHECK(!response_writer_.get());
49 response_writer_.reset(writer); 48 response_writer_.reset(writer);
50 update_job_ = update; 49 update_job_ = update;
51 request_ = request; 50 request_ = request;
52 } 51 }
53 52
54 void OnWriteComplete(int result) { 53 void OnWriteComplete(int result) {
55 // A completed write may delete the URL request and this object. 54 // A completed write may delete the URL request and this object.
56 update_job_->OnWriteResponseComplete(result, request_, this); 55 update_job_->OnWriteResponseComplete(result, request_, this);
57 } 56 }
58 57
59 RequestType type_; 58 RequestType type_;
60 scoped_refptr<net::IOBuffer> buffer_; 59 scoped_refptr<net::IOBuffer> buffer_;
61 int retry_503_attempts_; 60 int retry_503_attempts_;
62 61
62 // The entry from the newest cache for this url, used for 304 responses.
63 AppCacheEntry existing_entry_;
64
63 // Info needed to write responses to storage and process callbacks. 65 // Info needed to write responses to storage and process callbacks.
64 scoped_ptr<AppCacheResponseWriter> response_writer_; 66 scoped_ptr<AppCacheResponseWriter> response_writer_;
65 AppCacheUpdateJob* update_job_; 67 AppCacheUpdateJob* update_job_;
66 URLRequest* request_; 68 URLRequest* request_;
67 net::CompletionCallbackImpl<UpdateJobInfo> write_callback_; 69 net::CompletionCallbackImpl<UpdateJobInfo> write_callback_;
68 }; 70 };
69 71
70 // Helper class for collecting hosts per frontend when sending notifications 72 // Helper class for collecting hosts per frontend when sending notifications
71 // so that only one notification is sent for all hosts using the same frontend. 73 // so that only one notification is sent for all hosts using the same frontend.
72 class HostNotifier { 74 class HostNotifier {
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 DCHECK(!inprogress_cache_); 154 DCHECK(!inprogress_cache_);
153 DCHECK(pending_master_entries_.empty()); 155 DCHECK(pending_master_entries_.empty());
154 DCHECK(master_entry_fetches_.empty()); 156 DCHECK(master_entry_fetches_.empty());
155 157
156 if (group_) 158 if (group_)
157 group_->SetUpdateStatus(AppCacheGroup::IDLE); 159 group_->SetUpdateStatus(AppCacheGroup::IDLE);
158 160
159 policy_callback_->Cancel(); 161 policy_callback_->Cancel();
160 } 162 }
161 163
164 UpdateJobInfo* AppCacheUpdateJob::GetUpdateJobInfo(URLRequest* request) {
165 return static_cast<UpdateJobInfo*>(request->GetUserData(this));
166 }
167
162 void AppCacheUpdateJob::StartUpdate(AppCacheHost* host, 168 void AppCacheUpdateJob::StartUpdate(AppCacheHost* host,
163 const GURL& new_master_resource) { 169 const GURL& new_master_resource) {
164 DCHECK(group_->update_job() == this); 170 DCHECK(group_->update_job() == this);
165 DCHECK(!group_->is_obsolete()); 171 DCHECK(!group_->is_obsolete());
166 172
167 bool is_new_pending_master_entry = false; 173 bool is_new_pending_master_entry = false;
168 if (!new_master_resource.is_empty()) { 174 if (!new_master_resource.is_empty()) {
169 DCHECK(new_master_resource == host->pending_master_entry_url()); 175 DCHECK(new_master_resource == host->pending_master_entry_url());
170 DCHECK(!new_master_resource.has_ref()); 176 DCHECK(!new_master_resource.has_ref());
171 DCHECK(new_master_resource.GetOrigin() == manifest_url_.GetOrigin()); 177 DCHECK(new_master_resource.GetOrigin() == manifest_url_.GetOrigin());
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 284
279 // Add any necessary Http headers before sending fetch request. 285 // Add any necessary Http headers before sending fetch request.
280 if (is_first_fetch) { 286 if (is_first_fetch) {
281 AppCacheEntry* entry = (update_type_ == UPGRADE_ATTEMPT) ? 287 AppCacheEntry* entry = (update_type_ == UPGRADE_ATTEMPT) ?
282 group_->newest_complete_cache()->GetEntry(manifest_url_) : NULL; 288 group_->newest_complete_cache()->GetEntry(manifest_url_) : NULL;
283 if (entry) { 289 if (entry) {
284 // Asynchronously load response info for manifest from newest cache. 290 // Asynchronously load response info for manifest from newest cache.
285 service_->storage()->LoadResponseInfo(manifest_url_, 291 service_->storage()->LoadResponseInfo(manifest_url_,
286 entry->response_id(), this); 292 entry->response_id(), this);
287 } else { 293 } else {
288 AddHttpHeadersAndFetch(manifest_url_request_, NULL); 294 manifest_url_request_->Start();
289 } 295 }
290 } else { 296 } else {
291 DCHECK(internal_state_ == REFETCH_MANIFEST); 297 DCHECK(internal_state_ == REFETCH_MANIFEST);
292 DCHECK(manifest_response_info_.get()); 298 DCHECK(manifest_response_info_.get());
293 AddHttpHeadersAndFetch(manifest_url_request_, 299 AddConditionalHeaders(manifest_url_request_,
294 manifest_response_info_.get()); 300 manifest_response_info_.get());
301 manifest_url_request_->Start();
295 } 302 }
296 } 303 }
297 304
298 void AppCacheUpdateJob::AddHttpHeadersAndFetch( 305 void AppCacheUpdateJob::AddConditionalHeaders(
299 URLRequest* request, const net::HttpResponseInfo* info) { 306 URLRequest* request, const net::HttpResponseInfo* info) {
300 DCHECK(request); 307 DCHECK(request && info);
301 if (info) { 308 net::HttpRequestHeaders extra_headers;
302 net::HttpRequestHeaders extra_headers;
303 309
304 // Add If-Modified-Since header if response info has Last-Modified header. 310 // Add If-Modified-Since header if response info has Last-Modified header.
305 const std::string last_modified = "Last-Modified"; 311 const std::string last_modified = "Last-Modified";
306 std::string last_modified_value; 312 std::string last_modified_value;
307 info->headers->EnumerateHeader(NULL, last_modified, &last_modified_value); 313 info->headers->EnumerateHeader(NULL, last_modified, &last_modified_value);
308 if (!last_modified_value.empty()) { 314 if (!last_modified_value.empty()) {
309 extra_headers.SetHeader(net::HttpRequestHeaders::kIfModifiedSince, 315 extra_headers.SetHeader(net::HttpRequestHeaders::kIfModifiedSince,
310 last_modified_value); 316 last_modified_value);
311 } 317 }
312 318
313 // Add If-None-Match header if resposne info has ETag header. 319 // Add If-None-Match header if resposne info has ETag header.
314 const std::string etag = "ETag"; 320 const std::string etag = "ETag";
315 std::string etag_value; 321 std::string etag_value;
316 info->headers->EnumerateHeader(NULL, etag, &etag_value); 322 info->headers->EnumerateHeader(NULL, etag, &etag_value);
317 if (!etag_value.empty()) { 323 if (!etag_value.empty()) {
318 extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch, 324 extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch,
319 etag_value); 325 etag_value);
320 }
321
322 if (!extra_headers.IsEmpty())
323 request->SetExtraRequestHeaders(extra_headers);
324 } 326 }
325 request->Start(); 327 if (!extra_headers.IsEmpty())
328 request->SetExtraRequestHeaders(extra_headers);
326 } 329 }
327 330
328 void AppCacheUpdateJob::OnResponseStarted(URLRequest *request) { 331 void AppCacheUpdateJob::OnResponseStarted(URLRequest *request) {
329 if (request->status().is_success() && 332 if (request->status().is_success() &&
330 (request->GetResponseCode() / 100) == 2) { 333 (request->GetResponseCode() / 100) == 2) {
331 // Write response info to storage for URL fetches. Wait for async write 334 // Write response info to storage for URL fetches. Wait for async write
332 // completion before reading any response data. 335 // completion before reading any response data.
333 UpdateJobInfo* info = 336 UpdateJobInfo* info = GetUpdateJobInfo(request);
334 static_cast<UpdateJobInfo*>(request->GetUserData(this));
335 if (info->type_ == UpdateJobInfo::URL_FETCH || 337 if (info->type_ == UpdateJobInfo::URL_FETCH ||
336 info->type_ == UpdateJobInfo::MASTER_ENTRY_FETCH) { 338 info->type_ == UpdateJobInfo::MASTER_ENTRY_FETCH) {
337 info->SetUpResponseWriter( 339 info->SetUpResponseWriter(
338 service_->storage()->CreateResponseWriter(manifest_url_), 340 service_->storage()->CreateResponseWriter(manifest_url_),
339 this, request); 341 this, request);
340 stored_response_ids_.push_back(info->response_writer_->response_id()); 342 stored_response_ids_.push_back(info->response_writer_->response_id());
341 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer = 343 scoped_refptr<HttpResponseInfoIOBuffer> io_buffer =
342 new HttpResponseInfoIOBuffer( 344 new HttpResponseInfoIOBuffer(
343 new net::HttpResponseInfo(request->response_info())); 345 new net::HttpResponseInfo(request->response_info()));
344 info->response_writer_->WriteInfo(io_buffer, &info->write_callback_); 346 info->response_writer_->WriteInfo(io_buffer, &info->write_callback_);
345 } else { 347 } else {
346 ReadResponseData(request); 348 ReadResponseData(request);
347 } 349 }
348 } else { 350 } else {
349 OnResponseCompleted(request); 351 OnResponseCompleted(request);
350 } 352 }
351 } 353 }
352 354
353 void AppCacheUpdateJob::ReadResponseData(URLRequest* request) { 355 void AppCacheUpdateJob::ReadResponseData(URLRequest* request) {
354 if (internal_state_ == CACHE_FAILURE || internal_state_ == CANCELLED || 356 if (internal_state_ == CACHE_FAILURE || internal_state_ == CANCELLED ||
355 internal_state_ == COMPLETED) { 357 internal_state_ == COMPLETED) {
356 return; 358 return;
357 } 359 }
358 360
359 int bytes_read = 0; 361 int bytes_read = 0;
360 UpdateJobInfo* info = 362 UpdateJobInfo* info = GetUpdateJobInfo(request);
361 static_cast<UpdateJobInfo*>(request->GetUserData(this));
362 request->Read(info->buffer_, kBufferSize, &bytes_read); 363 request->Read(info->buffer_, kBufferSize, &bytes_read);
363 OnReadCompleted(request, bytes_read); 364 OnReadCompleted(request, bytes_read);
364 } 365 }
365 366
366 void AppCacheUpdateJob::OnReadCompleted(URLRequest* request, int bytes_read) { 367 void AppCacheUpdateJob::OnReadCompleted(URLRequest* request, int bytes_read) {
367 bool data_consumed = true; 368 bool data_consumed = true;
368 if (request->status().is_success() && bytes_read > 0) { 369 if (request->status().is_success() && bytes_read > 0) {
369 UpdateJobInfo* info = 370 UpdateJobInfo* info = GetUpdateJobInfo(request);
370 static_cast<UpdateJobInfo*>(request->GetUserData(this));
371
372 data_consumed = ConsumeResponseData(request, info, bytes_read); 371 data_consumed = ConsumeResponseData(request, info, bytes_read);
373 if (data_consumed) { 372 if (data_consumed) {
374 bytes_read = 0; 373 bytes_read = 0;
375 while (request->Read(info->buffer_, kBufferSize, &bytes_read)) { 374 while (request->Read(info->buffer_, kBufferSize, &bytes_read)) {
376 if (bytes_read > 0) { 375 if (bytes_read > 0) {
377 data_consumed = ConsumeResponseData(request, info, bytes_read); 376 data_consumed = ConsumeResponseData(request, info, bytes_read);
378 if (!data_consumed) 377 if (!data_consumed)
379 break; // wait for async data processing, then read more 378 break; // wait for async data processing, then read more
380 } else { 379 } else {
381 break; 380 break;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
432 } 431 }
433 432
434 void AppCacheUpdateJob::OnResponseCompleted(URLRequest* request) { 433 void AppCacheUpdateJob::OnResponseCompleted(URLRequest* request) {
435 // Retry for 503s where retry-after is 0. 434 // Retry for 503s where retry-after is 0.
436 if (request->status().is_success() && 435 if (request->status().is_success() &&
437 request->GetResponseCode() == 503 && 436 request->GetResponseCode() == 503 &&
438 RetryRequest(request)) { 437 RetryRequest(request)) {
439 return; 438 return;
440 } 439 }
441 440
442 UpdateJobInfo* info = 441 UpdateJobInfo* info = GetUpdateJobInfo(request);
443 static_cast<UpdateJobInfo*>(request->GetUserData(this));
444 switch (info->type_) { 442 switch (info->type_) {
445 case UpdateJobInfo::MANIFEST_FETCH: 443 case UpdateJobInfo::MANIFEST_FETCH:
446 HandleManifestFetchCompleted(request); 444 HandleManifestFetchCompleted(request);
447 break; 445 break;
448 case UpdateJobInfo::URL_FETCH: 446 case UpdateJobInfo::URL_FETCH:
449 HandleUrlFetchCompleted(request); 447 HandleUrlFetchCompleted(request);
450 break; 448 break;
451 case UpdateJobInfo::MASTER_ENTRY_FETCH: 449 case UpdateJobInfo::MASTER_ENTRY_FETCH:
452 HandleMasterEntryFetchCompleted(request); 450 HandleMasterEntryFetchCompleted(request);
453 break; 451 break;
454 case UpdateJobInfo::MANIFEST_REFETCH: 452 case UpdateJobInfo::MANIFEST_REFETCH:
455 HandleManifestRefetchCompleted(request); 453 HandleManifestRefetchCompleted(request);
456 break; 454 break;
457 default: 455 default:
458 NOTREACHED(); 456 NOTREACHED();
459 } 457 }
460 458
461 delete request; 459 delete request;
462 } 460 }
463 461
464 bool AppCacheUpdateJob::RetryRequest(URLRequest* request) { 462 bool AppCacheUpdateJob::RetryRequest(URLRequest* request) {
465 UpdateJobInfo* info = 463 UpdateJobInfo* info = GetUpdateJobInfo(request);
466 static_cast<UpdateJobInfo*>(request->GetUserData(this));
467 if (info->retry_503_attempts_ >= kMax503Retries) { 464 if (info->retry_503_attempts_ >= kMax503Retries) {
468 return false; 465 return false;
469 } 466 }
470 467
471 if (!request->response_headers()->HasHeaderValue("retry-after", "0")) 468 if (!request->response_headers()->HasHeaderValue("retry-after", "0"))
472 return false; 469 return false;
473 470
474 const GURL& url = request->original_url(); 471 const GURL& url = request->original_url();
475 URLRequest* retry = new URLRequest(url, this); 472 URLRequest* retry = new URLRequest(url, this);
476 UpdateJobInfo* retry_info = new UpdateJobInfo(info->type_); 473 UpdateJobInfo* retry_info = new UpdateJobInfo(info->type_);
477 retry_info->retry_503_attempts_ = info->retry_503_attempts_ + 1; 474 retry_info->retry_503_attempts_ = info->retry_503_attempts_ + 1;
475 retry_info->existing_entry_ = info->existing_entry_;
478 retry->SetUserData(this, retry_info); 476 retry->SetUserData(this, retry_info);
479 retry->set_context(request->context()); 477 retry->set_context(request->context());
480 retry->set_load_flags(request->load_flags()); 478 retry->set_load_flags(request->load_flags());
481 479
482 switch (info->type_) { 480 switch (info->type_) {
483 case UpdateJobInfo::MANIFEST_FETCH: 481 case UpdateJobInfo::MANIFEST_FETCH:
484 case UpdateJobInfo::MANIFEST_REFETCH: 482 case UpdateJobInfo::MANIFEST_REFETCH:
485 manifest_url_request_ = retry; 483 manifest_url_request_ = retry;
486 manifest_data_.clear(); 484 manifest_data_.clear();
487 break; 485 break;
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after
591 589
592 group_->SetUpdateStatus(AppCacheGroup::DOWNLOADING); 590 group_->SetUpdateStatus(AppCacheGroup::DOWNLOADING);
593 NotifyAllAssociatedHosts(DOWNLOADING_EVENT); 591 NotifyAllAssociatedHosts(DOWNLOADING_EVENT);
594 FetchUrls(); 592 FetchUrls();
595 FetchMasterEntries(); 593 FetchMasterEntries();
596 MaybeCompleteUpdate(); // if not done, continues when async fetches complete 594 MaybeCompleteUpdate(); // if not done, continues when async fetches complete
597 } 595 }
598 596
599 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) { 597 void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) {
600 DCHECK(internal_state_ == DOWNLOADING); 598 DCHECK(internal_state_ == DOWNLOADING);
599 UpdateJobInfo* info = GetUpdateJobInfo(request);
601 600
602 const GURL& url = request->original_url(); 601 const GURL& url = request->original_url();
603 pending_url_fetches_.erase(url); 602 pending_url_fetches_.erase(url);
604 NotifyAllProgress(url); 603 NotifyAllProgress(url);
605 ++url_fetches_completed_; 604 ++url_fetches_completed_;
606 605
607 int response_code = request->status().is_success() 606 int response_code = request->status().is_success()
608 ? request->GetResponseCode() : -1; 607 ? request->GetResponseCode() : -1;
609 AppCacheEntry& entry = url_file_list_.find(url)->second; 608 AppCacheEntry& entry = url_file_list_.find(url)->second;
610 609
611 if (request->status().is_success() && (response_code / 100 == 2)) { 610 if (response_code / 100 == 2) {
612 // Associate storage with the new entry. 611 // Associate storage with the new entry.
613 UpdateJobInfo* info =
614 static_cast<UpdateJobInfo*>(request->GetUserData(this));
615 DCHECK(info->response_writer_.get()); 612 DCHECK(info->response_writer_.get());
616 entry.set_response_id(info->response_writer_->response_id()); 613 entry.set_response_id(info->response_writer_->response_id());
617 entry.set_response_size(info->response_writer_->amount_written()); 614 entry.set_response_size(info->response_writer_->amount_written());
618
619 if (!inprogress_cache_->AddOrModifyEntry(url, entry)) 615 if (!inprogress_cache_->AddOrModifyEntry(url, entry))
620 duplicate_response_ids_.push_back(entry.response_id()); 616 duplicate_response_ids_.push_back(entry.response_id());
621 617
622 // Foreign entries will be detected during cache selection. 618 // Foreign entries will be detected during cache selection.
623 // Note: 6.9.4, step 17.9 possible optimization: if resource is HTML or XML 619 // Note: 6.9.4, step 17.9 possible optimization: if resource is HTML or XML
624 // file whose root element is an html element with a manifest attribute 620 // file whose root element is an html element with a manifest attribute
625 // whose value doesn't match the manifest url of the application cache 621 // whose value doesn't match the manifest url of the application cache
626 // being processed, mark the entry as being foreign. 622 // being processed, mark the entry as being foreign.
627 } else { 623 } else {
628 LOG(INFO) << "Request status: " << request->status().status() 624 LOG(INFO) << "Request status: " << request->status().status()
629 << " os_error: " << request->status().os_error() 625 << " os_error: " << request->status().os_error()
630 << " response code: " << response_code; 626 << " response code: " << response_code;
631 if (entry.IsExplicit() || entry.IsFallback()) { 627 if (entry.IsExplicit() || entry.IsFallback()) {
632 const char* kFormatString = "Resource fetch failed (%d) %s"; 628 if (response_code == 304 && info->existing_entry_.has_response_id()) {
633 const std::string message = StringPrintf(kFormatString, response_code, 629 // Copy the response from the newest complete cache.
rvargas (doing something else) 2010/07/20 19:17:18 maybe change from the newest complete cache -> fro
634 request->url().spec().c_str()); 630 entry.set_response_id(info->existing_entry_.response_id());
635 HandleCacheFailure(message); 631 entry.set_response_size(info->existing_entry_.response_size());
636 return; 632 inprogress_cache_->AddOrModifyEntry(url, entry);
633 } else {
634 const char* kFormatString = "Resource fetch failed (%d) %s";
635 const std::string message = StringPrintf(kFormatString, response_code,
636 request->url().spec().c_str());
637 HandleCacheFailure(message);
638 return;
639 }
637 } else if (response_code == 404 || response_code == 410) { 640 } else if (response_code == 404 || response_code == 410) {
638 // Entry is skipped. They are dropped from the cache. 641 // Entry is skipped. They are dropped from the cache.
639 } else if (update_type_ == UPGRADE_ATTEMPT) { 642 } else if (update_type_ == UPGRADE_ATTEMPT &&
643 info->existing_entry_.has_response_id()) {
640 // Copy the response from the newest complete cache. 644 // Copy the response from the newest complete cache.
641 AppCache* cache = group_->newest_complete_cache(); 645 // TODO(michaeln): Not sure this is a good idea. This is spec compliant
642 AppCacheEntry* copy = cache->GetEntry(url); 646 // but the old resource may or may not be compatible with the new contents
643 if (copy) { 647 // of the cache. Impossible to know one way or the other.
644 entry.set_response_id(copy->response_id()); 648 entry.set_response_id(info->existing_entry_.response_id());
645 entry.set_response_size(copy->response_size()); 649 entry.set_response_size(info->existing_entry_.response_size());
646 inprogress_cache_->AddOrModifyEntry(url, entry); 650 inprogress_cache_->AddOrModifyEntry(url, entry);
647 }
648 } 651 }
649 } 652 }
650 653
651 // Fetch another URL now that one request has completed. 654 // Fetch another URL now that one request has completed.
652 DCHECK(internal_state_ != CACHE_FAILURE); 655 DCHECK(internal_state_ != CACHE_FAILURE);
653 FetchUrls(); 656 FetchUrls();
654 MaybeCompleteUpdate(); 657 MaybeCompleteUpdate();
655 } 658 }
656 659
657 void AppCacheUpdateJob::HandleMasterEntryFetchCompleted(URLRequest* request) { 660 void AppCacheUpdateJob::HandleMasterEntryFetchCompleted(URLRequest* request) {
(...skipping 11 matching lines...) Expand all
669 int response_code = request->status().is_success() 672 int response_code = request->status().is_success()
670 ? request->GetResponseCode() : -1; 673 ? request->GetResponseCode() : -1;
671 674
672 PendingMasters::iterator found = pending_master_entries_.find(url); 675 PendingMasters::iterator found = pending_master_entries_.find(url);
673 DCHECK(found != pending_master_entries_.end()); 676 DCHECK(found != pending_master_entries_.end());
674 PendingHosts& hosts = found->second; 677 PendingHosts& hosts = found->second;
675 678
676 // Section 6.9.4. No update case: step 7.3, else step 22. 679 // Section 6.9.4. No update case: step 7.3, else step 22.
677 if (response_code / 100 == 2) { 680 if (response_code / 100 == 2) {
678 // Add fetched master entry to the appropriate cache. 681 // Add fetched master entry to the appropriate cache.
679 UpdateJobInfo* info = 682 UpdateJobInfo* info = GetUpdateJobInfo(request);
680 static_cast<UpdateJobInfo*>(request->GetUserData(this));
681 AppCache* cache = inprogress_cache_ ? inprogress_cache_.get() : 683 AppCache* cache = inprogress_cache_ ? inprogress_cache_.get() :
682 group_->newest_complete_cache(); 684 group_->newest_complete_cache();
683 DCHECK(info->response_writer_.get()); 685 DCHECK(info->response_writer_.get());
684 AppCacheEntry master_entry(AppCacheEntry::MASTER, 686 AppCacheEntry master_entry(AppCacheEntry::MASTER,
685 info->response_writer_->response_id(), 687 info->response_writer_->response_id(),
686 info->response_writer_->amount_written()); 688 info->response_writer_->amount_written());
687 if (!cache->AddOrModifyEntry(url, master_entry)) 689 if (!cache->AddOrModifyEntry(url, master_entry))
688 duplicate_response_ids_.push_back(master_entry.response_id()); 690 duplicate_response_ids_.push_back(master_entry.response_id());
689 691
690 // In no-update case, associate host with the newest cache. 692 // In no-update case, associate host with the newest cache.
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
936 AddUrlToFileList(it->first, AppCacheEntry::MASTER); 938 AddUrlToFileList(it->first, AppCacheEntry::MASTER);
937 } 939 }
938 } 940 }
939 } 941 }
940 942
941 void AppCacheUpdateJob::AddUrlToFileList(const GURL& url, int type) { 943 void AppCacheUpdateJob::AddUrlToFileList(const GURL& url, int type) {
942 std::pair<AppCache::EntryMap::iterator, bool> ret = url_file_list_.insert( 944 std::pair<AppCache::EntryMap::iterator, bool> ret = url_file_list_.insert(
943 AppCache::EntryMap::value_type(url, AppCacheEntry(type))); 945 AppCache::EntryMap::value_type(url, AppCacheEntry(type)));
944 946
945 if (ret.second) 947 if (ret.second)
946 urls_to_fetch_.push_back(UrlsToFetch(url, false)); 948 urls_to_fetch_.push_back(UrlToFetch(url, false, NULL));
947 else 949 else
948 ret.first->second.add_types(type); // URL already exists. Merge types. 950 ret.first->second.add_types(type); // URL already exists. Merge types.
949 } 951 }
950 952
951 void AppCacheUpdateJob::FetchUrls() { 953 void AppCacheUpdateJob::FetchUrls() {
952 DCHECK(internal_state_ == DOWNLOADING); 954 DCHECK(internal_state_ == DOWNLOADING);
953 955
954 // Fetch each URL in the list according to section 6.9.4 step 17.1-17.3. 956 // Fetch each URL in the list according to section 6.9.4 step 17.1-17.3.
955 // Fetch up to the concurrent limit. Other fetches will be triggered as each 957 // Fetch up to the concurrent limit. Other fetches will be triggered as each
956 // each fetch completes. 958 // each fetch completes.
957 while (pending_url_fetches_.size() < kMaxConcurrentUrlFetches && 959 while (pending_url_fetches_.size() < kMaxConcurrentUrlFetches &&
958 !urls_to_fetch_.empty()) { 960 !urls_to_fetch_.empty()) {
959 const GURL url = urls_to_fetch_.front().first; 961 UrlToFetch url_to_fetch = urls_to_fetch_.front();
960 bool storage_checked = urls_to_fetch_.front().second;
961 urls_to_fetch_.pop_front(); 962 urls_to_fetch_.pop_front();
962 963
963 AppCache::EntryMap::iterator it = url_file_list_.find(url); 964 AppCache::EntryMap::iterator it = url_file_list_.find(url_to_fetch.url);
964 DCHECK(it != url_file_list_.end()); 965 DCHECK(it != url_file_list_.end());
965 AppCacheEntry& entry = it->second; 966 AppCacheEntry& entry = it->second;
966 if (ShouldSkipUrlFetch(entry)) { 967 if (ShouldSkipUrlFetch(entry)) {
967 NotifyAllProgress(url); 968 NotifyAllProgress(url_to_fetch.url);
968 ++url_fetches_completed_; 969 ++url_fetches_completed_;
969 } else if (AlreadyFetchedEntry(url, entry.types())) { 970 } else if (AlreadyFetchedEntry(url_to_fetch.url, entry.types())) {
970 NotifyAllProgress(url); 971 NotifyAllProgress(url_to_fetch.url);
971 ++url_fetches_completed_; // saved a URL request 972 ++url_fetches_completed_; // saved a URL request
972 } else if (!storage_checked && MaybeLoadFromNewestCache(url, entry)) { 973 } else if (!url_to_fetch.storage_checked &&
974 MaybeLoadFromNewestCache(url_to_fetch.url, entry)) {
973 // Continues asynchronously after data is loaded from newest cache. 975 // Continues asynchronously after data is loaded from newest cache.
974 } else { 976 } else {
977 UpdateJobInfo* info = new UpdateJobInfo(UpdateJobInfo::URL_FETCH);
978 const net::HttpResponseInfo* http_info = NULL;
979 if (url_to_fetch.existing_response_info.get()) {
980 DCHECK(group_->newest_complete_cache());
981 AppCacheEntry* existing_entry =
982 group_->newest_complete_cache()->GetEntry(url_to_fetch.url);
983 DCHECK(existing_entry);
984 DCHECK(existing_entry->response_id() ==
985 url_to_fetch.existing_response_info->response_id());
986 info->existing_entry_ = *existing_entry;
987 http_info = url_to_fetch.existing_response_info->http_response_info();
988 }
989
975 // Send URL request for the resource. 990 // Send URL request for the resource.
976 URLRequest* request = new URLRequest(url, this); 991 URLRequest* request = new URLRequest(url_to_fetch.url, this);
977 request->SetUserData(this, new UpdateJobInfo(UpdateJobInfo::URL_FETCH)); 992 request->SetUserData(this, info);
978 request->set_context(service_->request_context()); 993 request->set_context(service_->request_context());
979 request->set_load_flags( 994 request->set_load_flags(
980 request->load_flags() | net::LOAD_DISABLE_INTERCEPT); 995 request->load_flags() | net::LOAD_DISABLE_INTERCEPT);
996 if (http_info)
997 AddConditionalHeaders(request, http_info);
981 request->Start(); 998 request->Start();
982 pending_url_fetches_.insert(PendingUrlFetches::value_type(url, request)); 999 pending_url_fetches_.insert(
1000 PendingUrlFetches::value_type(url_to_fetch.url, request));
983 } 1001 }
984 } 1002 }
985 } 1003 }
986 1004
987 void AppCacheUpdateJob::CancelAllUrlFetches() { 1005 void AppCacheUpdateJob::CancelAllUrlFetches() {
988 // Cancel any pending URL requests. 1006 // Cancel any pending URL requests.
989 for (PendingUrlFetches::iterator it = pending_url_fetches_.begin(); 1007 for (PendingUrlFetches::iterator it = pending_url_fetches_.begin();
990 it != pending_url_fetches_.end(); ++it) { 1008 it != pending_url_fetches_.end(); ++it) {
991 delete it->second; 1009 delete it->second;
992 } 1010 }
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after
1154 return true; 1172 return true;
1155 } 1173 }
1156 1174
1157 void AppCacheUpdateJob::OnResponseInfoLoaded( 1175 void AppCacheUpdateJob::OnResponseInfoLoaded(
1158 AppCacheResponseInfo* response_info, int64 response_id) { 1176 AppCacheResponseInfo* response_info, int64 response_id) {
1159 const net::HttpResponseInfo* http_info = response_info ? 1177 const net::HttpResponseInfo* http_info = response_info ?
1160 response_info->http_response_info() : NULL; 1178 response_info->http_response_info() : NULL;
1161 1179
1162 // Needed response info for a manifest fetch request. 1180 // Needed response info for a manifest fetch request.
1163 if (internal_state_ == FETCH_MANIFEST) { 1181 if (internal_state_ == FETCH_MANIFEST) {
1164 AddHttpHeadersAndFetch(manifest_url_request_, http_info); 1182 if (http_info)
1183 AddConditionalHeaders(manifest_url_request_, http_info);
1184 manifest_url_request_->Start();
1165 return; 1185 return;
1166 } 1186 }
1167 1187
1168 LoadingResponses::iterator found = loading_responses_.find(response_id); 1188 LoadingResponses::iterator found = loading_responses_.find(response_id);
1169 DCHECK(found != loading_responses_.end()); 1189 DCHECK(found != loading_responses_.end());
1170 const GURL& url = found->second; 1190 const GURL& url = found->second;
1171 1191
1172 if (!http_info) { 1192 if (!http_info) {
1173 LoadFromNewestCacheFailed(url); // no response found 1193 LoadFromNewestCacheFailed(url, NULL); // no response found
1174 } else { 1194 } else {
1175 // Check if response can be re-used according to HTTP caching semantics. 1195 // Check if response can be re-used according to HTTP caching semantics.
1176 // Responses with a "vary" header get treated as expired. 1196 // Responses with a "vary" header get treated as expired.
1177 const std::string name = "vary"; 1197 const std::string name = "vary";
1178 std::string value; 1198 std::string value;
1179 void* iter = NULL; 1199 void* iter = NULL;
1180 if (http_info->headers->RequiresValidation(http_info->request_time, 1200 if (http_info->headers->RequiresValidation(http_info->request_time,
1181 http_info->response_time, 1201 http_info->response_time,
1182 base::Time::Now()) || 1202 base::Time::Now()) ||
1183 http_info->headers->EnumerateHeader(&iter, name, &value)) { 1203 http_info->headers->EnumerateHeader(&iter, name, &value)) {
1184 // TODO(michaeln): Make a conditional request when we can in this case. 1204 // TODO(michaeln): Make a conditional request when we can in this case.
1185 LoadFromNewestCacheFailed(url); 1205 LoadFromNewestCacheFailed(url, response_info);
1186 } else { 1206 } else {
1187 DCHECK(group_->newest_complete_cache()); 1207 DCHECK(group_->newest_complete_cache());
1188 AppCacheEntry* copy_me = group_->newest_complete_cache()->GetEntry(url); 1208 AppCacheEntry* copy_me = group_->newest_complete_cache()->GetEntry(url);
1189 DCHECK(copy_me); 1209 DCHECK(copy_me);
1190 DCHECK(copy_me->response_id() == response_id); 1210 DCHECK(copy_me->response_id() == response_id);
1191 1211
1192 AppCache::EntryMap::iterator it = url_file_list_.find(url); 1212 AppCache::EntryMap::iterator it = url_file_list_.find(url);
1193 DCHECK(it != url_file_list_.end()); 1213 DCHECK(it != url_file_list_.end());
1194 AppCacheEntry& entry = it->second; 1214 AppCacheEntry& entry = it->second;
1195 entry.set_response_id(response_id); 1215 entry.set_response_id(response_id);
1196 entry.set_response_size(copy_me->response_size()); 1216 entry.set_response_size(copy_me->response_size());
1197 inprogress_cache_->AddOrModifyEntry(url, entry); 1217 inprogress_cache_->AddOrModifyEntry(url, entry);
1198 NotifyAllProgress(url); 1218 NotifyAllProgress(url);
1199 ++url_fetches_completed_; 1219 ++url_fetches_completed_;
1200 } 1220 }
1201 } 1221 }
1202 loading_responses_.erase(found); 1222 loading_responses_.erase(found);
1203 1223
1204 MaybeCompleteUpdate(); 1224 MaybeCompleteUpdate();
1205 } 1225 }
1206 1226
1207 void AppCacheUpdateJob::LoadFromNewestCacheFailed(const GURL& url) { 1227 void AppCacheUpdateJob::LoadFromNewestCacheFailed(
1228 const GURL& url, AppCacheResponseInfo* response_info) {
1208 if (internal_state_ == CACHE_FAILURE) 1229 if (internal_state_ == CACHE_FAILURE)
1209 return; 1230 return;
1210 1231
1211 // Re-insert url at front of fetch list. Indicate storage has been checked. 1232 // Re-insert url at front of fetch list. Indicate storage has been checked.
1212 urls_to_fetch_.push_front(AppCacheUpdateJob::UrlsToFetch(url, true)); 1233 urls_to_fetch_.push_front(UrlToFetch(url, true, response_info));
1213 FetchUrls(); 1234 FetchUrls();
1214 } 1235 }
1215 1236
1216 void AppCacheUpdateJob::MaybeCompleteUpdate() { 1237 void AppCacheUpdateJob::MaybeCompleteUpdate() {
1217 DCHECK(internal_state_ != CACHE_FAILURE); 1238 DCHECK(internal_state_ != CACHE_FAILURE);
1218 1239
1219 // Must wait for any pending master entries or url fetches to complete. 1240 // Must wait for any pending master entries or url fetches to complete.
1220 if (master_entries_completed_ != pending_master_entries_.size() || 1241 if (master_entries_completed_ != pending_master_entries_.size() ||
1221 url_fetches_completed_ != url_file_list_.size()) { 1242 url_fetches_completed_ != url_file_list_.size()) {
1222 DCHECK(internal_state_ != COMPLETED); 1243 DCHECK(internal_state_ != COMPLETED);
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
1343 1364
1344 // Break the connection with the group so the group cannot call delete 1365 // Break the connection with the group so the group cannot call delete
1345 // on this object after we've posted a task to delete ourselves. 1366 // on this object after we've posted a task to delete ourselves.
1346 group_->SetUpdateStatus(AppCacheGroup::IDLE); 1367 group_->SetUpdateStatus(AppCacheGroup::IDLE);
1347 group_ = NULL; 1368 group_ = NULL;
1348 1369
1349 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 1370 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
1350 } 1371 }
1351 1372
1352 } // namespace appcache 1373 } // namespace appcache
OLDNEW
« no previous file with comments | « webkit/appcache/appcache_update_job.h ('k') | webkit/appcache/appcache_update_job_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698