summaryrefslogtreecommitdiffstats
path: root/webkit/appcache
diff options
context:
space:
mode:
authormichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-21 19:28:04 +0000
committermichaeln@chromium.org <michaeln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-07-21 19:28:04 +0000
commit348b9bc12d4e2ccd03a7fbcb327a3975207a5fec (patch)
treed3c81fa677e6bd2b5f179e4ef113a0cbcdcc80bf /webkit/appcache
parent248a52e7965033a65b8d12b623739ac727e54e89 (diff)
downloadchromium_src-348b9bc12d4e2ccd03a7fbcb327a3975207a5fec.zip
chromium_src-348b9bc12d4e2ccd03a7fbcb327a3975207a5fec.tar.gz
chromium_src-348b9bc12d4e2ccd03a7fbcb327a3975207a5fec.tar.bz2
Make conditional requests when updating the appcache.
TEST=altered existing tests to also cover this case BUG=49548 Review URL: http://codereview.chromium.org/3033003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@53230 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/appcache')
-rw-r--r--webkit/appcache/appcache_update_job.cc177
-rw-r--r--webkit/appcache/appcache_update_job.h25
-rw-r--r--webkit/appcache/appcache_update_job_unittest.cc58
3 files changed, 172 insertions, 88 deletions
diff --git a/webkit/appcache/appcache_update_job.cc b/webkit/appcache/appcache_update_job.cc
index 9a2d729..a112310 100644
--- a/webkit/appcache/appcache_update_job.cc
+++ b/webkit/appcache/appcache_update_job.cc
@@ -13,7 +13,6 @@
#include "net/http/http_request_headers.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_policy.h"
-#include "webkit/appcache/appcache_response.h"
namespace appcache {
@@ -43,8 +42,8 @@ class UpdateJobInfo : public URLRequest::UserData {
}
void SetUpResponseWriter(AppCacheResponseWriter* writer,
- AppCacheUpdateJob* update,
- URLRequest* request) {
+ AppCacheUpdateJob* update,
+ URLRequest* request) {
DCHECK(!response_writer_.get());
response_writer_.reset(writer);
update_job_ = update;
@@ -60,6 +59,9 @@ class UpdateJobInfo : public URLRequest::UserData {
scoped_refptr<net::IOBuffer> buffer_;
int retry_503_attempts_;
+ // The entry from the newest cache for this url, used for 304 responses.
+ AppCacheEntry existing_entry_;
+
// Info needed to write responses to storage and process callbacks.
scoped_ptr<AppCacheResponseWriter> response_writer_;
AppCacheUpdateJob* update_job_;
@@ -159,6 +161,10 @@ AppCacheUpdateJob::~AppCacheUpdateJob() {
policy_callback_->Cancel();
}
+UpdateJobInfo* AppCacheUpdateJob::GetUpdateJobInfo(URLRequest* request) {
+ return static_cast<UpdateJobInfo*>(request->GetUserData(this));
+}
+
void AppCacheUpdateJob::StartUpdate(AppCacheHost* host,
const GURL& new_master_resource) {
DCHECK(group_->update_job() == this);
@@ -285,44 +291,41 @@ void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) {
service_->storage()->LoadResponseInfo(manifest_url_,
entry->response_id(), this);
} else {
- AddHttpHeadersAndFetch(manifest_url_request_, NULL);
+ manifest_url_request_->Start();
}
} else {
DCHECK(internal_state_ == REFETCH_MANIFEST);
DCHECK(manifest_response_info_.get());
- AddHttpHeadersAndFetch(manifest_url_request_,
- manifest_response_info_.get());
+ AddConditionalHeaders(manifest_url_request_,
+ manifest_response_info_.get());
+ manifest_url_request_->Start();
}
}
-void AppCacheUpdateJob::AddHttpHeadersAndFetch(
+void AppCacheUpdateJob::AddConditionalHeaders(
URLRequest* request, const net::HttpResponseInfo* info) {
- DCHECK(request);
- if (info) {
- net::HttpRequestHeaders extra_headers;
-
- // Add If-Modified-Since header if response info has Last-Modified header.
- const std::string last_modified = "Last-Modified";
- std::string last_modified_value;
- info->headers->EnumerateHeader(NULL, last_modified, &last_modified_value);
- if (!last_modified_value.empty()) {
- extra_headers.SetHeader(net::HttpRequestHeaders::kIfModifiedSince,
- last_modified_value);
- }
-
- // Add If-None-Match header if resposne info has ETag header.
- const std::string etag = "ETag";
- std::string etag_value;
- info->headers->EnumerateHeader(NULL, etag, &etag_value);
- if (!etag_value.empty()) {
- extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch,
- etag_value);
- }
+ DCHECK(request && info);
+ net::HttpRequestHeaders extra_headers;
+
+ // Add If-Modified-Since header if response info has Last-Modified header.
+ const std::string last_modified = "Last-Modified";
+ std::string last_modified_value;
+ info->headers->EnumerateHeader(NULL, last_modified, &last_modified_value);
+ if (!last_modified_value.empty()) {
+ extra_headers.SetHeader(net::HttpRequestHeaders::kIfModifiedSince,
+ last_modified_value);
+ }
- if (!extra_headers.IsEmpty())
- request->SetExtraRequestHeaders(extra_headers);
+ // Add If-None-Match header if resposne info has ETag header.
+ const std::string etag = "ETag";
+ std::string etag_value;
+ info->headers->EnumerateHeader(NULL, etag, &etag_value);
+ if (!etag_value.empty()) {
+ extra_headers.SetHeader(net::HttpRequestHeaders::kIfNoneMatch,
+ etag_value);
}
- request->Start();
+ if (!extra_headers.IsEmpty())
+ request->SetExtraRequestHeaders(extra_headers);
}
void AppCacheUpdateJob::OnResponseStarted(URLRequest *request) {
@@ -330,8 +333,7 @@ void AppCacheUpdateJob::OnResponseStarted(URLRequest *request) {
(request->GetResponseCode() / 100) == 2) {
// Write response info to storage for URL fetches. Wait for async write
// completion before reading any response data.
- UpdateJobInfo* info =
- static_cast<UpdateJobInfo*>(request->GetUserData(this));
+ UpdateJobInfo* info = GetUpdateJobInfo(request);
if (info->type_ == UpdateJobInfo::URL_FETCH ||
info->type_ == UpdateJobInfo::MASTER_ENTRY_FETCH) {
info->SetUpResponseWriter(
@@ -357,8 +359,7 @@ void AppCacheUpdateJob::ReadResponseData(URLRequest* request) {
}
int bytes_read = 0;
- UpdateJobInfo* info =
- static_cast<UpdateJobInfo*>(request->GetUserData(this));
+ UpdateJobInfo* info = GetUpdateJobInfo(request);
request->Read(info->buffer_, kBufferSize, &bytes_read);
OnReadCompleted(request, bytes_read);
}
@@ -366,9 +367,7 @@ void AppCacheUpdateJob::ReadResponseData(URLRequest* request) {
void AppCacheUpdateJob::OnReadCompleted(URLRequest* request, int bytes_read) {
bool data_consumed = true;
if (request->status().is_success() && bytes_read > 0) {
- UpdateJobInfo* info =
- static_cast<UpdateJobInfo*>(request->GetUserData(this));
-
+ UpdateJobInfo* info = GetUpdateJobInfo(request);
data_consumed = ConsumeResponseData(request, info, bytes_read);
if (data_consumed) {
bytes_read = 0;
@@ -439,8 +438,7 @@ void AppCacheUpdateJob::OnResponseCompleted(URLRequest* request) {
return;
}
- UpdateJobInfo* info =
- static_cast<UpdateJobInfo*>(request->GetUserData(this));
+ UpdateJobInfo* info = GetUpdateJobInfo(request);
switch (info->type_) {
case UpdateJobInfo::MANIFEST_FETCH:
HandleManifestFetchCompleted(request);
@@ -462,8 +460,7 @@ void AppCacheUpdateJob::OnResponseCompleted(URLRequest* request) {
}
bool AppCacheUpdateJob::RetryRequest(URLRequest* request) {
- UpdateJobInfo* info =
- static_cast<UpdateJobInfo*>(request->GetUserData(this));
+ UpdateJobInfo* info = GetUpdateJobInfo(request);
if (info->retry_503_attempts_ >= kMax503Retries) {
return false;
}
@@ -475,6 +472,7 @@ bool AppCacheUpdateJob::RetryRequest(URLRequest* request) {
URLRequest* retry = new URLRequest(url, this);
UpdateJobInfo* retry_info = new UpdateJobInfo(info->type_);
retry_info->retry_503_attempts_ = info->retry_503_attempts_ + 1;
+ retry_info->existing_entry_ = info->existing_entry_;
retry->SetUserData(this, retry_info);
retry->set_context(request->context());
retry->set_load_flags(request->load_flags());
@@ -598,6 +596,7 @@ void AppCacheUpdateJob::ContinueHandleManifestFetchCompleted(bool changed) {
void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) {
DCHECK(internal_state_ == DOWNLOADING);
+ UpdateJobInfo* info = GetUpdateJobInfo(request);
const GURL& url = request->original_url();
pending_url_fetches_.erase(url);
@@ -608,14 +607,11 @@ void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) {
? request->GetResponseCode() : -1;
AppCacheEntry& entry = url_file_list_.find(url)->second;
- if (request->status().is_success() && (response_code / 100 == 2)) {
+ if (response_code / 100 == 2) {
// Associate storage with the new entry.
- UpdateJobInfo* info =
- static_cast<UpdateJobInfo*>(request->GetUserData(this));
DCHECK(info->response_writer_.get());
entry.set_response_id(info->response_writer_->response_id());
entry.set_response_size(info->response_writer_->amount_written());
-
if (!inprogress_cache_->AddOrModifyEntry(url, entry))
duplicate_response_ids_.push_back(entry.response_id());
@@ -629,22 +625,29 @@ void AppCacheUpdateJob::HandleUrlFetchCompleted(URLRequest* request) {
<< " os_error: " << request->status().os_error()
<< " response code: " << response_code;
if (entry.IsExplicit() || entry.IsFallback()) {
- const char* kFormatString = "Resource fetch failed (%d) %s";
- const std::string message = StringPrintf(kFormatString, response_code,
- request->url().spec().c_str());
- HandleCacheFailure(message);
- return;
- } else if (response_code == 404 || response_code == 410) {
- // Entry is skipped. They are dropped from the cache.
- } else if (update_type_ == UPGRADE_ATTEMPT) {
- // Copy the response from the newest complete cache.
- AppCache* cache = group_->newest_complete_cache();
- AppCacheEntry* copy = cache->GetEntry(url);
- if (copy) {
- entry.set_response_id(copy->response_id());
- entry.set_response_size(copy->response_size());
+ if (response_code == 304 && info->existing_entry_.has_response_id()) {
+ // Keep the existing response.
+ entry.set_response_id(info->existing_entry_.response_id());
+ entry.set_response_size(info->existing_entry_.response_size());
inprogress_cache_->AddOrModifyEntry(url, entry);
+ } else {
+ const char* kFormatString = "Resource fetch failed (%d) %s";
+ const std::string message = StringPrintf(kFormatString, response_code,
+ request->url().spec().c_str());
+ HandleCacheFailure(message);
+ return;
}
+ } else if (response_code == 404 || response_code == 410) {
+ // Entry is skipped. They are dropped from the cache.
+ } else if (update_type_ == UPGRADE_ATTEMPT &&
+ info->existing_entry_.has_response_id()) {
+ // Keep the existing response.
+ // TODO(michaeln): Not sure this is a good idea. This is spec compliant
+ // but the old resource may or may not be compatible with the new contents
+ // of the cache. Impossible to know one way or the other.
+ entry.set_response_id(info->existing_entry_.response_id());
+ entry.set_response_size(info->existing_entry_.response_size());
+ inprogress_cache_->AddOrModifyEntry(url, entry);
}
}
@@ -676,8 +679,7 @@ void AppCacheUpdateJob::HandleMasterEntryFetchCompleted(URLRequest* request) {
// Section 6.9.4. No update case: step 7.3, else step 22.
if (response_code / 100 == 2) {
// Add fetched master entry to the appropriate cache.
- UpdateJobInfo* info =
- static_cast<UpdateJobInfo*>(request->GetUserData(this));
+ UpdateJobInfo* info = GetUpdateJobInfo(request);
AppCache* cache = inprogress_cache_ ? inprogress_cache_.get() :
group_->newest_complete_cache();
DCHECK(info->response_writer_.get());
@@ -943,7 +945,7 @@ void AppCacheUpdateJob::AddUrlToFileList(const GURL& url, int type) {
AppCache::EntryMap::value_type(url, AppCacheEntry(type)));
if (ret.second)
- urls_to_fetch_.push_back(UrlsToFetch(url, false));
+ urls_to_fetch_.push_back(UrlToFetch(url, false, NULL));
else
ret.first->second.add_types(type); // URL already exists. Merge types.
}
@@ -956,30 +958,46 @@ void AppCacheUpdateJob::FetchUrls() {
// each fetch completes.
while (pending_url_fetches_.size() < kMaxConcurrentUrlFetches &&
!urls_to_fetch_.empty()) {
- const GURL url = urls_to_fetch_.front().first;
- bool storage_checked = urls_to_fetch_.front().second;
+ UrlToFetch url_to_fetch = urls_to_fetch_.front();
urls_to_fetch_.pop_front();
- AppCache::EntryMap::iterator it = url_file_list_.find(url);
+ AppCache::EntryMap::iterator it = url_file_list_.find(url_to_fetch.url);
DCHECK(it != url_file_list_.end());
AppCacheEntry& entry = it->second;
if (ShouldSkipUrlFetch(entry)) {
- NotifyAllProgress(url);
+ NotifyAllProgress(url_to_fetch.url);
++url_fetches_completed_;
- } else if (AlreadyFetchedEntry(url, entry.types())) {
- NotifyAllProgress(url);
+ } else if (AlreadyFetchedEntry(url_to_fetch.url, entry.types())) {
+ NotifyAllProgress(url_to_fetch.url);
++url_fetches_completed_; // saved a URL request
- } else if (!storage_checked && MaybeLoadFromNewestCache(url, entry)) {
+ } else if (!url_to_fetch.storage_checked &&
+ MaybeLoadFromNewestCache(url_to_fetch.url, entry)) {
// Continues asynchronously after data is loaded from newest cache.
} else {
+ UpdateJobInfo* info = new UpdateJobInfo(UpdateJobInfo::URL_FETCH);
+ const net::HttpResponseInfo* http_info = NULL;
+ if (url_to_fetch.existing_response_info.get()) {
+ DCHECK(group_->newest_complete_cache());
+ AppCacheEntry* existing_entry =
+ group_->newest_complete_cache()->GetEntry(url_to_fetch.url);
+ DCHECK(existing_entry);
+ DCHECK(existing_entry->response_id() ==
+ url_to_fetch.existing_response_info->response_id());
+ info->existing_entry_ = *existing_entry;
+ http_info = url_to_fetch.existing_response_info->http_response_info();
+ }
+
// Send URL request for the resource.
- URLRequest* request = new URLRequest(url, this);
- request->SetUserData(this, new UpdateJobInfo(UpdateJobInfo::URL_FETCH));
+ URLRequest* request = new URLRequest(url_to_fetch.url, this);
+ request->SetUserData(this, info);
request->set_context(service_->request_context());
request->set_load_flags(
request->load_flags() | net::LOAD_DISABLE_INTERCEPT);
+ if (http_info)
+ AddConditionalHeaders(request, http_info);
request->Start();
- pending_url_fetches_.insert(PendingUrlFetches::value_type(url, request));
+ pending_url_fetches_.insert(
+ PendingUrlFetches::value_type(url_to_fetch.url, request));
}
}
}
@@ -1161,7 +1179,9 @@ void AppCacheUpdateJob::OnResponseInfoLoaded(
// Needed response info for a manifest fetch request.
if (internal_state_ == FETCH_MANIFEST) {
- AddHttpHeadersAndFetch(manifest_url_request_, http_info);
+ if (http_info)
+ AddConditionalHeaders(manifest_url_request_, http_info);
+ manifest_url_request_->Start();
return;
}
@@ -1170,7 +1190,7 @@ void AppCacheUpdateJob::OnResponseInfoLoaded(
const GURL& url = found->second;
if (!http_info) {
- LoadFromNewestCacheFailed(url); // no response found
+ LoadFromNewestCacheFailed(url, NULL); // no response found
} else {
// Check if response can be re-used according to HTTP caching semantics.
// Responses with a "vary" header get treated as expired.
@@ -1182,7 +1202,7 @@ void AppCacheUpdateJob::OnResponseInfoLoaded(
base::Time::Now()) ||
http_info->headers->EnumerateHeader(&iter, name, &value)) {
// TODO(michaeln): Make a conditional request when we can in this case.
- LoadFromNewestCacheFailed(url);
+ LoadFromNewestCacheFailed(url, response_info);
} else {
DCHECK(group_->newest_complete_cache());
AppCacheEntry* copy_me = group_->newest_complete_cache()->GetEntry(url);
@@ -1204,12 +1224,13 @@ void AppCacheUpdateJob::OnResponseInfoLoaded(
MaybeCompleteUpdate();
}
-void AppCacheUpdateJob::LoadFromNewestCacheFailed(const GURL& url) {
+void AppCacheUpdateJob::LoadFromNewestCacheFailed(
+ const GURL& url, AppCacheResponseInfo* response_info) {
if (internal_state_ == CACHE_FAILURE)
return;
// Re-insert url at front of fetch list. Indicate storage has been checked.
- urls_to_fetch_.push_front(AppCacheUpdateJob::UrlsToFetch(url, true));
+ urls_to_fetch_.push_front(UrlToFetch(url, true, response_info));
FetchUrls();
}
diff --git a/webkit/appcache/appcache_update_job.h b/webkit/appcache/appcache_update_job.h
index d9c1669..ff6452c 100644
--- a/webkit/appcache/appcache_update_job.h
+++ b/webkit/appcache/appcache_update_job.h
@@ -20,6 +20,7 @@
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/appcache_interfaces.h"
+#include "webkit/appcache/appcache_response.h"
#include "webkit/appcache/appcache_storage.h"
namespace appcache {
@@ -49,7 +50,6 @@ class AppCacheUpdateJob : public URLRequest::Delegate,
typedef std::vector<AppCacheHost*> PendingHosts;
typedef std::map<GURL, PendingHosts> PendingMasters;
typedef std::map<GURL, URLRequest*> PendingUrlFetches;
- typedef std::pair<GURL, bool> UrlsToFetch; // flag TRUE if storage checked
typedef std::map<int64, GURL> LoadingResponses;
static const int kRerunDelayMs = 1000;
@@ -82,6 +82,16 @@ class AppCacheUpdateJob : public URLRequest::Delegate,
STORED,
};
+ struct UrlToFetch {
+ GURL url;
+ bool storage_checked;
+ scoped_refptr<AppCacheResponseInfo> existing_response_info;
+ UrlToFetch(const GURL& url, bool checked, AppCacheResponseInfo* info)
+ : url(url), storage_checked(checked), existing_response_info(info) {}
+ };
+
+ UpdateJobInfo* GetUpdateJobInfo(URLRequest* request);
+
// Methods for URLRequest::Delegate.
void OnResponseStarted(URLRequest* request);
void OnReadCompleted(URLRequest* request, int bytes_read);
@@ -108,10 +118,10 @@ class AppCacheUpdateJob : public URLRequest::Delegate,
void FetchManifest(bool is_first_fetch);
- // Add extra HTTP headers to the request based on the response info and
- // start the URL request.
- void AddHttpHeadersAndFetch(URLRequest* request,
- const net::HttpResponseInfo* info);
+ // Add extra conditional HTTP headers to the request based on the
+ // currently cached response headers.
+ void AddConditionalHeaders(URLRequest* request,
+ const net::HttpResponseInfo* info);
void OnResponseCompleted(URLRequest* request);
@@ -180,7 +190,8 @@ class AppCacheUpdateJob : public URLRequest::Delegate,
// Returns false if immediately obvious that data cannot be loaded from
// newest complete cache.
bool MaybeLoadFromNewestCache(const GURL& url, AppCacheEntry& entry);
- void LoadFromNewestCacheFailed(const GURL& url);
+ void LoadFromNewestCacheFailed(const GURL& url,
+ AppCacheResponseInfo* newest_response_info);
// Does nothing if update process is still waiting for pending master
// entries or URL fetches to complete downloading. Otherwise, completes
@@ -233,7 +244,7 @@ class AppCacheUpdateJob : public URLRequest::Delegate,
// Helper container to track which urls have not been fetched yet. URLs are
// removed when the fetch is initiated. Flag indicates whether an attempt
// to load the URL from storage has already been tried and failed.
- std::deque<UrlsToFetch> urls_to_fetch_;
+ std::deque<UrlToFetch> urls_to_fetch_;
// Helper container to track which urls are being loaded from response
// storage.
diff --git a/webkit/appcache/appcache_update_job_unittest.cc b/webkit/appcache/appcache_update_job_unittest.cc
index f90eb87..0bcda2c 100644
--- a/webkit/appcache/appcache_update_job_unittest.cc
+++ b/webkit/appcache/appcache_update_job_unittest.cc
@@ -105,6 +105,11 @@ class MockHttpServer {
} else if (path == "/files/manifest1") {
(*headers) = std::string(manifest_headers, arraysize(manifest_headers));
(*body) = kManifest1Contents;
+ } else if (path == "/files/manifest1-with-notmodified") {
+ (*headers) = std::string(manifest_headers, arraysize(manifest_headers));
+ (*body) = kManifest1Contents;
+ (*body).append("CACHE:\n"
+ "notmodified\n");
} else if (path == "/files/manifest-fb-404") {
(*headers) = std::string(manifest_headers, arraysize(manifest_headers));
(*body) = "CACHE MANIFEST\n"
@@ -529,6 +534,7 @@ class AppCacheUpdateJobTest : public testing::Test,
expect_newest_cache_(NULL),
expect_non_null_update_time_(false),
tested_manifest_(NONE),
+ tested_manifest1_path_override_(NULL),
registered_factory_(false),
old_factory_(NULL) {
}
@@ -1396,9 +1402,13 @@ class AppCacheUpdateJobTest : public testing::Test,
void UpgradeFailMasterUrlFetchTest() {
ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type());
+ tested_manifest1_path_override_ = "files/manifest1-with-notmodified";
+
MakeService();
+ const GURL kManifestUrl =
+ MockHttpServer::GetMockUrl(tested_manifest1_path_override_);
group_ = new AppCacheGroup(
- service_.get(), MockHttpServer::GetMockUrl("files/manifest1"),
+ service_.get(), kManifestUrl,
service_->storage()->NewGroupId());
AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
group_->update_job_ = update;
@@ -1411,7 +1421,7 @@ class AppCacheUpdateJobTest : public testing::Test,
host1->AssociateCache(cache);
host2->AssociateCache(cache);
- // Give the newest cache some master entries; one will fail with a 404.
+ // Give the newest cache some existing entries; one will fail with a 404.
cache->AddEntry(
MockHttpServer::GetMockUrl("files/notfound"),
AppCacheEntry(AppCacheEntry::MASTER, 222));
@@ -1421,6 +1431,20 @@ class AppCacheUpdateJobTest : public testing::Test,
cache->AddEntry(
MockHttpServer::GetMockUrl("files/servererror"),
AppCacheEntry(AppCacheEntry::MASTER, 444));
+ cache->AddEntry(
+ MockHttpServer::GetMockUrl("files/notmodified"),
+ AppCacheEntry(AppCacheEntry::EXPLICIT, 555));
+
+ // Seed the response_info working set with canned data for
+ // files/servererror and for files/notmodified to test that the
+ // existing entries for those resource are reused by the update job.
+ const char kData[] =
+ "HTTP/1.1 200 OK\0"
+ "Last-Modified: Sat, 29 Oct 1994 19:43:31 GMT\0"
+ "\0";
+ const std::string kRawHeaders(kData, arraysize(kData));
+ MakeAppCacheResponseInfo(kManifestUrl, 444, kRawHeaders);
+ MakeAppCacheResponseInfo(kManifestUrl, 555, kRawHeaders);
update->StartUpdate(NULL, GURL());
EXPECT_TRUE(update->manifest_url_request_ != NULL);
@@ -1437,8 +1461,13 @@ class AppCacheUpdateJobTest : public testing::Test,
expect_extra_entries_.insert(AppCache::EntryMap::value_type(
MockHttpServer::GetMockUrl("files/servererror"),
AppCacheEntry(AppCacheEntry::MASTER)));
+ expect_extra_entries_.insert(AppCache::EntryMap::value_type(
+ MockHttpServer::GetMockUrl("files/notmodified"),
+ AppCacheEntry(AppCacheEntry::EXPLICIT)));
expect_response_ids_.insert(std::map<GURL, int64>::value_type(
MockHttpServer::GetMockUrl("files/servererror"), 444)); // copied
+ expect_response_ids_.insert(std::map<GURL, int64>::value_type(
+ MockHttpServer::GetMockUrl("files/notmodified"), 555)); // copied
MockFrontend::HostIds ids1(1, host1->host_id());
frontend1->AddExpectedEvent(ids1, CHECKING_EVENT);
frontend1->AddExpectedEvent(ids1, DOWNLOADING_EVENT);
@@ -1447,6 +1476,7 @@ class AppCacheUpdateJobTest : public testing::Test,
frontend1->AddExpectedEvent(ids1, PROGRESS_EVENT); // notfound
frontend1->AddExpectedEvent(ids1, PROGRESS_EVENT); // explicit2
frontend1->AddExpectedEvent(ids1, PROGRESS_EVENT); // servererror
+ frontend1->AddExpectedEvent(ids1, PROGRESS_EVENT); // notmodified
frontend1->AddExpectedEvent(ids1, PROGRESS_EVENT); // final
frontend1->AddExpectedEvent(ids1, UPDATE_READY_EVENT);
MockFrontend::HostIds ids2(1, host2->host_id());
@@ -1457,6 +1487,7 @@ class AppCacheUpdateJobTest : public testing::Test,
frontend2->AddExpectedEvent(ids2, PROGRESS_EVENT); // notfound
frontend2->AddExpectedEvent(ids2, PROGRESS_EVENT); // explicit2
frontend2->AddExpectedEvent(ids2, PROGRESS_EVENT); // servererror
+ frontend2->AddExpectedEvent(ids2, PROGRESS_EVENT); // notmodified
frontend2->AddExpectedEvent(ids2, PROGRESS_EVENT); // final
frontend2->AddExpectedEvent(ids2, UPDATE_READY_EVENT);
@@ -2773,6 +2804,7 @@ class AppCacheUpdateJobTest : public testing::Test,
group_ = NULL;
STLDeleteContainerPointers(hosts_.begin(), hosts_.end());
STLDeleteContainerPointers(frontends_.begin(), frontends_.end());
+ response_infos_.clear();
service_.reset(NULL);
if (registered_factory_)
URLRequest::RegisterProtocolFactory("http", old_factory_);
@@ -2805,6 +2837,18 @@ class AppCacheUpdateJobTest : public testing::Test,
return host;
}
+ AppCacheResponseInfo* MakeAppCacheResponseInfo(
+ const GURL& manifest_url, int64 response_id,
+ const std::string& raw_headers) {
+ net::HttpResponseInfo* http_info = new net::HttpResponseInfo();
+ http_info->headers = new net::HttpResponseHeaders(raw_headers);
+ scoped_refptr<AppCacheResponseInfo> info =
+ new AppCacheResponseInfo(service_.get(), manifest_url,
+ response_id, http_info, 0);
+ response_infos_.push_back(info);
+ return info;
+ }
+
MockFrontend* MakeMockFrontend() {
MockFrontend* frontend = new MockFrontend();
frontends_.push_back(frontend);
@@ -2929,8 +2973,11 @@ class AppCacheUpdateJobTest : public testing::Test,
void VerifyManifest1(AppCache* cache) {
size_t expected = 3 + expect_extra_entries_.size();
EXPECT_EQ(expected, cache->entries().size());
+ const char* kManifestPath = tested_manifest1_path_override_ ?
+ tested_manifest1_path_override_ :
+ "files/manifest1";
AppCacheEntry* entry =
- cache->GetEntry(MockHttpServer::GetMockUrl("files/manifest1"));
+ cache->GetEntry(MockHttpServer::GetMockUrl(kManifestPath));
ASSERT_TRUE(entry);
EXPECT_EQ(AppCacheEntry::MANIFEST, entry->types());
entry = cache->GetEntry(MockHttpServer::GetMockUrl("files/explicit1"));
@@ -3083,6 +3130,10 @@ class AppCacheUpdateJobTest : public testing::Test,
// Otherwise, test can put host on the stack instead of here.
std::vector<AppCacheHost*> hosts_;
+ // Response infos used by an async test that need to live until update job
+ // finishes.
+ std::vector<scoped_refptr<AppCacheResponseInfo> > response_infos_;
+
// Flag indicating if test cares to verify the update after update finishes.
bool do_checks_after_update_finished_;
bool expect_group_obsolete_;
@@ -3092,6 +3143,7 @@ class AppCacheUpdateJobTest : public testing::Test,
bool expect_non_null_update_time_;
std::vector<MockFrontend*> frontends_; // to check expected events
TestedManifest tested_manifest_;
+ const char* tested_manifest1_path_override_;
AppCache::EntryMap expect_extra_entries_;
std::map<GURL, int64> expect_response_ids_;