Index: content/browser/appcache/appcache_update_job.cc |
diff --git a/content/browser/appcache/appcache_update_job.cc b/content/browser/appcache/appcache_update_job.cc |
index 708b42c32a2996f93fc988ec50bccec5c13d9b80..bcf620860a978180fa78477cb05c7f54b3caee66 100644 |
--- a/content/browser/appcache/appcache_update_job.cc |
+++ b/content/browser/appcache/appcache_update_job.cc |
@@ -23,11 +23,13 @@ |
namespace content { |
-static const int kBufferSize = 32768; |
-static const size_t kMaxConcurrentUrlFetches = 2; |
-static const int kMax503Retries = 3; |
+namespace { |
-static std::string FormatUrlErrorMessage( |
+const int kBufferSize = 32768; |
+const size_t kMaxConcurrentUrlFetches = 2; |
+const int kMax503Retries = 3; |
+ |
+std::string FormatUrlErrorMessage( |
const char* format, const GURL& url, |
AppCacheUpdateJob::ResultType error, |
int response_code) { |
@@ -38,6 +40,34 @@ static std::string FormatUrlErrorMessage( |
return base::StringPrintf(format, code, url.spec().c_str()); |
} |
+bool IsEvictableError(AppCacheUpdateJob::ResultType result, |
+ const AppCacheErrorDetails& details) { |
+ switch (result) { |
+ case AppCacheUpdateJob::DB_ERROR: |
+ case AppCacheUpdateJob::DISKCACHE_ERROR: |
+ case AppCacheUpdateJob::QUOTA_ERROR: |
+ case AppCacheUpdateJob::NETWORK_ERROR: |
+ case AppCacheUpdateJob::CANCELLED_ERROR: |
+ return false; |
+ |
+ case AppCacheUpdateJob::REDIRECT_ERROR: |
+ case AppCacheUpdateJob::SERVER_ERROR: |
+ case AppCacheUpdateJob::SECURITY_ERROR: |
+ return true; |
+ |
+ case AppCacheUpdateJob::MANIFEST_ERROR: |
+ return details.reason == APPCACHE_SIGNATURE_ERROR; |
+ |
+ default: |
+ NOTREACHED(); |
+ return true; |
+ } |
+} |
+ |
+void EmptyCompletionCallback(int result) {} |
+ |
+} // namespace |
+ |
// Helper class for collecting hosts per frontend when sending notifications |
// so that only one notification is sent for all hosts using the same frontend. |
class HostNotifier { |
@@ -133,7 +163,9 @@ AppCacheUpdateJob::URLFetcher::~URLFetcher() { |
void AppCacheUpdateJob::URLFetcher::Start() { |
request_->set_first_party_for_cookies(job_->manifest_url_); |
- if (existing_response_headers_.get()) |
+ if (fetch_type_ == MANIFEST_FETCH && job_->doing_full_update_check_) |
+ request_->SetLoadFlags(request_->load_flags() | net::LOAD_BYPASS_CACHE); |
+ else if (existing_response_headers_.get()) |
AddConditionalHeaders(existing_response_headers_.get()); |
request_->Start(); |
} |
@@ -356,6 +388,7 @@ AppCacheUpdateJob::AppCacheUpdateJob(AppCacheServiceImpl* service, |
group_(group), |
update_type_(UNKNOWN_TYPE), |
internal_state_(FETCH_MANIFEST), |
+ doing_full_update_check_(false), |
master_entries_completed_(0), |
url_fetches_completed_(0), |
manifest_fetcher_(NULL), |
@@ -430,9 +463,14 @@ void AppCacheUpdateJob::StartUpdate(AppCacheHost* host, |
group_->SetUpdateAppCacheStatus(AppCacheGroup::CHECKING); |
if (group_->HasCache()) { |
update_type_ = UPGRADE_ATTEMPT; |
+ base::TimeDelta time_since_last_check = |
+ base::Time::Now() - group_->last_full_update_check_time(); |
+ doing_full_update_check_ = |
+ time_since_last_check > base::TimeDelta::FromHours(24); |
NotifyAllAssociatedHosts(APPCACHE_CHECKING_EVENT); |
} else { |
update_type_ = CACHE_ATTEMPT; |
+ doing_full_update_check_ = true; |
DCHECK(host); |
NotifySingleHost(host, APPCACHE_CHECKING_EVENT); |
} |
@@ -471,6 +509,34 @@ void AppCacheUpdateJob::HandleCacheFailure( |
NotifyAllError(error_details); |
DiscardInprogressCache(); |
internal_state_ = COMPLETED; |
+ |
+ if (update_type_ == CACHE_ATTEMPT || |
+ !IsEvictableError(result, error_details) || |
+ service_->storage() != storage_) { |
+ DeleteSoon(); |
+ return; |
+ } |
+ |
+ if (group_->first_evictable_error_time().is_null()) { |
+ group_->set_first_evictable_error_time(base::Time::Now()); |
+ storage_->StoreEvictionTimes(group_); |
+ DeleteSoon(); |
+ return; |
+ } |
+ |
+ base::TimeDelta error_duration = |
+ base::Time::Now() - group_->first_evictable_error_time(); |
+ base::TimeDelta kMaxPersistentErrorDuration = base::TimeDelta::FromDays(4); |
+ if (error_duration > kMaxPersistentErrorDuration) { |
+ // Break the connection with the group prior to calling |
+ // DeleteAppCacheGroup, otherwise that method would delete |this| |
+ // and we need the stack to unwind prior to deletion. |
+ group_->SetUpdateAppCacheStatus(AppCacheGroup::IDLE); |
+ group_ = NULL; |
+ service_->DeleteAppCacheGroup(manifest_url_, |
+ base::Bind(EmptyCompletionCallback)); |
+ } |
+ |
DeleteSoon(); // To unwind the stack prior to deletion. |
} |
@@ -482,24 +548,25 @@ void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) { |
URLFetcher::MANIFEST_REFETCH, |
this); |
- // Add any necessary Http headers before sending fetch request. |
if (is_first_fetch) { |
+ // Maybe load the cached headers to make a condiditional request. |
AppCacheEntry* entry = (update_type_ == UPGRADE_ATTEMPT) ? |
group_->newest_complete_cache()->GetEntry(manifest_url_) : NULL; |
- if (entry) { |
+ if (entry && !doing_full_update_check_) { |
// Asynchronously load response info for manifest from newest cache. |
storage_->LoadResponseInfo(manifest_url_, group_->group_id(), |
entry->response_id(), this); |
- } else { |
- manifest_fetcher_->Start(); |
+ return; |
jsbell
2015/05/27 22:38:18
Much nicer code flow here!
michaeln
2015/05/27 23:21:51
yup, i put in some early returns elsewhere too for
|
} |
- } else { |
- DCHECK(internal_state_ == REFETCH_MANIFEST); |
- DCHECK(manifest_response_info_.get()); |
- manifest_fetcher_->set_existing_response_headers( |
- manifest_response_info_->headers.get()); |
manifest_fetcher_->Start(); |
+ return; |
} |
+ |
+ DCHECK(internal_state_ == REFETCH_MANIFEST); |
+ DCHECK(manifest_response_info_.get()); |
+ manifest_fetcher_->set_existing_response_headers( |
+ manifest_response_info_->headers.get()); |
+ manifest_fetcher_->Start(); |
} |
@@ -567,11 +634,9 @@ void AppCacheUpdateJob::OnGroupMadeObsolete(AppCacheGroup* group, |
} else { |
// Treat failure to mark group obsolete as a cache failure. |
HandleCacheFailure(AppCacheErrorDetails( |
- "Failed to mark the cache as obsolete", |
- APPCACHE_UNKNOWN_ERROR, |
- GURL(), |
- 0, |
- false /*is_cross_origin*/), |
+ "Failed to mark the cache as obsolete", |
+ APPCACHE_UNKNOWN_ERROR, GURL(), 0, |
+ false /*is_cross_origin*/), |
DB_ERROR, |
GURL()); |
} |
@@ -931,6 +996,7 @@ void AppCacheUpdateJob::OnManifestDataWriteComplete(int result) { |
void AppCacheUpdateJob::StoreGroupAndCache() { |
DCHECK(stored_state_ == UNSTORED); |
stored_state_ = STORING; |
+ |
scoped_refptr<AppCache> newest_cache; |
if (inprogress_cache_.get()) |
newest_cache.swap(inprogress_cache_); |
@@ -938,8 +1004,10 @@ void AppCacheUpdateJob::StoreGroupAndCache() { |
newest_cache = group_->newest_complete_cache(); |
newest_cache->set_update_time(base::Time::Now()); |
- // TODO(michaeln): dcheck is fishing for clues to crbug/95101 |
- DCHECK_EQ(manifest_url_, group_->manifest_url()); |
+ group_->set_first_evictable_error_time(base::Time()); |
+ if (doing_full_update_check_) |
+ group_->set_last_full_update_check_time(base::Time::Now()); |
+ |
storage_->StoreGroupAndNewestCache(group_, newest_cache.get(), this); |
} |
@@ -951,8 +1019,10 @@ void AppCacheUpdateJob::OnGroupAndNewestCacheStored(AppCacheGroup* group, |
if (success) { |
stored_state_ = STORED; |
MaybeCompleteUpdate(); // will definitely complete |
- } else { |
- stored_state_ = UNSTORED; |
+ return; |
+ } |
+ |
+ stored_state_ = UNSTORED; |
// Restore inprogress_cache_ to get the proper events delivered |
// and the proper cleanup to occur. |
@@ -972,7 +1042,6 @@ void AppCacheUpdateJob::OnGroupAndNewestCacheStored(AppCacheGroup* group, |
false /*is_cross_origin*/), |
result, |
GURL()); |
- } |
} |
void AppCacheUpdateJob::NotifySingleHost(AppCacheHost* host, |
@@ -1454,6 +1523,18 @@ void AppCacheUpdateJob::MaybeCompleteUpdate() { |
case STORED: |
break; |
} |
+ } else { |
+ bool times_changed = false; |
+ if (!group_->first_evictable_error_time().is_null()) { |
+ group_->set_first_evictable_error_time(base::Time()); |
+ times_changed = true; |
+ } |
+ if (doing_full_update_check_) { |
+ group_->set_last_full_update_check_time(base::Time::Now()); |
+ times_changed = true; |
+ } |
+ if (times_changed) |
+ storage_->StoreEvictionTimes(group_); |
} |
// 6.9.4 steps 7.3-7.7. |
NotifyAllAssociatedHosts(APPCACHE_NO_UPDATE_EVENT); |
@@ -1615,8 +1696,10 @@ void AppCacheUpdateJob::DeleteSoon() { |
// Break the connection with the group so the group cannot call delete |
// on this object after we've posted a task to delete ourselves. |
- group_->SetUpdateAppCacheStatus(AppCacheGroup::IDLE); |
- group_ = NULL; |
+ if (group_) { |
+ group_->SetUpdateAppCacheStatus(AppCacheGroup::IDLE); |
+ group_ = NULL; |
+ } |
base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); |
} |