summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/common/appcache/chrome_appcache_service.cc22
-rw-r--r--chrome/common/appcache/chrome_appcache_service.h7
-rw-r--r--webkit/appcache/appcache_policy.h38
-rw-r--r--webkit/appcache/appcache_service.cc2
-rw-r--r--webkit/appcache/appcache_service.h11
-rw-r--r--webkit/appcache/appcache_storage_impl.cc35
-rw-r--r--webkit/appcache/appcache_storage_impl.h5
-rw-r--r--webkit/appcache/appcache_storage_impl_unittest.cc72
-rw-r--r--webkit/appcache/appcache_update_job.cc51
-rw-r--r--webkit/appcache/appcache_update_job.h9
-rw-r--r--webkit/appcache/appcache_update_job_unittest.cc105
-rw-r--r--webkit/webkit.gyp1
12 files changed, 337 insertions, 21 deletions
diff --git a/chrome/common/appcache/chrome_appcache_service.cc b/chrome/common/appcache/chrome_appcache_service.cc
index 68e30c7..5fdb17f 100644
--- a/chrome/common/appcache/chrome_appcache_service.cc
+++ b/chrome/common/appcache/chrome_appcache_service.cc
@@ -10,6 +10,7 @@
#include "chrome/browser/net/chrome_url_request_context.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/notification_service.h"
+#include "net/base/net_errors.h"
#include "webkit/appcache/appcache_thread.h"
static bool has_initialized_thread_ids;
@@ -33,6 +34,7 @@ ChromeAppCacheService::ChromeAppCacheService(
Initialize(request_context->is_off_the_record() ?
FilePath() : profile_path.Append(chrome::kAppCacheDirname));
set_request_context(request_context);
+ set_appcache_policy(this);
}
ChromeAppCacheService::~ChromeAppCacheService() {
@@ -44,6 +46,26 @@ void ChromeAppCacheService::ClearLocalState(const FilePath& profile_path) {
file_util::Delete(profile_path.Append(chrome::kAppCacheDirname), true);
}
+bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url) {
+ ContentSetting setting = host_contents_settings_map_->GetContentSetting(
+ manifest_url, CONTENT_SETTINGS_TYPE_COOKIES);
+ DCHECK(setting != CONTENT_SETTING_DEFAULT);
+ return setting == CONTENT_SETTING_ALLOW ||
+ setting == CONTENT_SETTING_ASK; // we don't prompt for read access
+}
+
+int ChromeAppCacheService::CanCreateAppCache(
+ const GURL& manifest_url, net::CompletionCallback* callback) {
+ ContentSetting setting = host_contents_settings_map_->GetContentSetting(
+ manifest_url, CONTENT_SETTINGS_TYPE_COOKIES);
+ DCHECK(setting != CONTENT_SETTING_DEFAULT);
+ if (setting == CONTENT_SETTING_ASK) {
+ // TODO(michaeln): prompt the user, for now we block
+ setting = CONTENT_SETTING_BLOCK;
+ }
+ return (setting != CONTENT_SETTING_BLOCK) ? net::OK : net::ERR_ACCESS_DENIED;
+}
+
void ChromeAppCacheService::Observe(NotificationType type,
const NotificationSource& source,
const NotificationDetails& details) {
diff --git a/chrome/common/appcache/chrome_appcache_service.h b/chrome/common/appcache/chrome_appcache_service.h
index ec7b0bd..fd36a05 100644
--- a/chrome/common/appcache/chrome_appcache_service.h
+++ b/chrome/common/appcache/chrome_appcache_service.h
@@ -8,6 +8,7 @@
#include "base/ref_counted.h"
#include "chrome/browser/host_content_settings_map.h"
#include "chrome/common/notification_registrar.h"
+#include "webkit/appcache/appcache_policy.h"
#include "webkit/appcache/appcache_service.h"
class ChromeURLRequestContext;
@@ -24,6 +25,7 @@ class FilePath;
class ChromeAppCacheService
: public base::RefCounted<ChromeAppCacheService>,
public appcache::AppCacheService,
+ public appcache::AppCachePolicy,
public NotificationObserver {
public:
ChromeAppCacheService(const FilePath& profile_path,
@@ -35,6 +37,11 @@ class ChromeAppCacheService
friend class base::RefCounted<ChromeAppCacheService>;
virtual ~ChromeAppCacheService();
+ // AppCachePolicy overrides
+ virtual bool CanLoadAppCache(const GURL& manifest_url);
+ virtual int CanCreateAppCache(const GURL& manifest_url,
+ net::CompletionCallback* callback);
+
// NotificationObserver override
virtual void Observe(NotificationType type,
const NotificationSource& source,
diff --git a/webkit/appcache/appcache_policy.h b/webkit/appcache/appcache_policy.h
new file mode 100644
index 0000000..7d3e844
--- /dev/null
+++ b/webkit/appcache/appcache_policy.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef WEBKIT_APPCACHE_APPCACHE_POLICY_H_
+#define WEBKIT_APPCACHE_APPCACHE_POLICY_H_
+
+#include "net/base/completion_callback.h"
+
+class GURL;
+
+namespace appcache {
+
+class AppCachePolicy {
+ public:
+ AppCachePolicy() {}
+
+ // Called prior to loading a main resource from the appache.
+ // Returns true if allowed. This is expected to return immediately
+ // without any user prompt.
+ virtual bool CanLoadAppCache(const GURL& manifest_url) = 0;
+
+ // Called prior to creating a new appcache.
+ // Returns net::OK if allowed, net::ERR_ACCESS_DENIED if not allowed.
+ // May also return net::ERR_IO_PENDING to indicate
+ // that the completion callback will be notified (asynchronously and on
+ // the current thread) of the final result. Note: The completion callback
+ // must remain valid until notified.
+ virtual int CanCreateAppCache(const GURL& manifest_url,
+ net::CompletionCallback* callback) = 0;
+
+ protected:
+ ~AppCachePolicy() {}
+};
+
+} // namespace appcache
+
+#endif // WEBKIT_APPCACHE_APPCACHE_POLICY_H_
diff --git a/webkit/appcache/appcache_service.cc b/webkit/appcache/appcache_service.cc
index f0c8784..65cc457 100644
--- a/webkit/appcache/appcache_service.cc
+++ b/webkit/appcache/appcache_service.cc
@@ -11,7 +11,7 @@
namespace appcache {
AppCacheService::AppCacheService()
- : request_context_(NULL) {
+ : appcache_policy_(NULL), request_context_(NULL) {
}
AppCacheService::~AppCacheService() {
diff --git a/webkit/appcache/appcache_service.h b/webkit/appcache/appcache_service.h
index 986e620..70a0953 100644
--- a/webkit/appcache/appcache_service.h
+++ b/webkit/appcache/appcache_service.h
@@ -15,6 +15,7 @@ class URLRequestContext;
namespace appcache {
class AppCacheBackendImpl;
+class AppCachePolicy;
// Class that manages the application cache service. Sends notifications
// to many frontends. One instance per user-profile. Each instance has
@@ -40,6 +41,14 @@ class AppCacheService {
request_context_ = context;
}
+ // The appcache policy, may be null, in which case access is always allowed.
+ // The service does NOT assume ownership of the policy, it is the callers
+ // responsibility to ensure that the pointer remains valid while set.
+ AppCachePolicy* appcache_policy() const { return appcache_policy_; }
+ void set_appcache_policy(AppCachePolicy* policy) {
+ appcache_policy_ = policy;
+ }
+
// Track which processes are using this appcache service.
void RegisterBackend(AppCacheBackendImpl* backend_impl);
void UnregisterBackend(AppCacheBackendImpl* backend_impl);
@@ -51,6 +60,8 @@ class AppCacheService {
AppCacheStorage* storage() const { return storage_.get(); }
protected:
+ AppCachePolicy* appcache_policy_;
+
// Deals with persistence.
scoped_ptr<AppCacheStorage> storage_;
diff --git a/webkit/appcache/appcache_storage_impl.cc b/webkit/appcache/appcache_storage_impl.cc
index ed893c1..0d908aa 100644
--- a/webkit/appcache/appcache_storage_impl.cc
+++ b/webkit/appcache/appcache_storage_impl.cc
@@ -12,11 +12,14 @@
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "net/base/cache_type.h"
+#include "net/base/net_errors.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_database.h"
#include "webkit/appcache/appcache_entry.h"
#include "webkit/appcache/appcache_group.h"
+#include "webkit/appcache/appcache_policy.h"
#include "webkit/appcache/appcache_response.h"
+#include "webkit/appcache/appcache_service.h"
#include "webkit/appcache/appcache_thread.h"
namespace appcache {
@@ -562,9 +565,8 @@ void AppCacheStorageImpl::FindMainResponseTask::Run() {
}
void AppCacheStorageImpl::FindMainResponseTask::RunCompleted() {
- FOR_EACH_DELEGATE(delegates_,
- OnMainResponseFound(url_, entry_, fallback_entry_,
- cache_id_, manifest_url_));
+ storage_->CheckPolicyAndCallOnMainResponseFound(
+ &delegates_, url_, entry_, fallback_entry_, cache_id_, manifest_url_);
}
// MarkEntryAsForeignTask -------
@@ -902,13 +904,36 @@ void AppCacheStorageImpl::DeliverShortCircuitedFindMainResponse(
scoped_refptr<AppCacheGroup> group, scoped_refptr<AppCache> cache,
scoped_refptr<DelegateReference> delegate_ref) {
if (delegate_ref->delegate) {
- delegate_ref->delegate->OnMainResponseFound(
- url, found_entry, AppCacheEntry(),
+ DelegateReferenceVector delegates(1, delegate_ref);
+ CheckPolicyAndCallOnMainResponseFound(
+ &delegates, url, found_entry, AppCacheEntry(),
cache.get() ? cache->cache_id() : kNoCacheId,
group.get() ? group->manifest_url() : GURL());
}
}
+void AppCacheStorageImpl::CheckPolicyAndCallOnMainResponseFound(
+ DelegateReferenceVector* delegates, const GURL& url,
+ const AppCacheEntry& entry, const AppCacheEntry& fallback_entry,
+ int64 cache_id, const GURL& manifest_url) {
+ if (!manifest_url.is_empty()) {
+ // Check the policy prior to returning a main resource from the appcache.
+ AppCachePolicy* policy = service()->appcache_policy();
+ if (policy && !policy->CanLoadAppCache(manifest_url)) {
+ FOR_EACH_DELEGATE(
+ (*delegates),
+ OnMainResponseFound(url, AppCacheEntry(), AppCacheEntry(),
+ kNoCacheId, GURL()));
+ return;
+ }
+ }
+
+ FOR_EACH_DELEGATE(
+ (*delegates),
+ OnMainResponseFound(url, entry, fallback_entry,
+ cache_id, manifest_url));
+}
+
void AppCacheStorageImpl::FindResponseForSubRequest(
AppCache* cache, const GURL& url,
AppCacheEntry* found_entry, AppCacheEntry* found_fallback_entry,
diff --git a/webkit/appcache/appcache_storage_impl.h b/webkit/appcache/appcache_storage_impl.h
index 96fc876..93391e9 100644
--- a/webkit/appcache/appcache_storage_impl.h
+++ b/webkit/appcache/appcache_storage_impl.h
@@ -97,6 +97,11 @@ class AppCacheStorageImpl : public AppCacheStorage {
scoped_refptr<AppCacheGroup> group, scoped_refptr<AppCache> newest_cache,
scoped_refptr<DelegateReference> delegate_ref);
+ void CheckPolicyAndCallOnMainResponseFound(
+ DelegateReferenceVector* delegates, const GURL& url,
+ const AppCacheEntry& entry, const AppCacheEntry& fallback_entry,
+ int64 cache_id, const GURL& manifest_url);
+
disk_cache::Backend* disk_cache();
// The directory in which we place files in the file system.
diff --git a/webkit/appcache/appcache_storage_impl_unittest.cc b/webkit/appcache/appcache_storage_impl_unittest.cc
index 9e207f8..ad6a8310 100644
--- a/webkit/appcache/appcache_storage_impl_unittest.cc
+++ b/webkit/appcache/appcache_storage_impl_unittest.cc
@@ -7,11 +7,13 @@
#include "base/message_loop.h"
#include "base/thread.h"
#include "base/waitable_event.h"
+#include "net/base/net_errors.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_database.h"
#include "webkit/appcache/appcache_entry.h"
#include "webkit/appcache/appcache_group.h"
+#include "webkit/appcache/appcache_policy.h"
#include "webkit/appcache/appcache_service.h"
#include "webkit/appcache/appcache_storage_impl.h"
#include "webkit/tools/test_shell/simple_appcache_system.h"
@@ -130,6 +132,34 @@ class AppCacheStorageImplTest : public testing::Test {
AppCacheStorageImplTest* test_;
};
+ class MockAppCachePolicy : public AppCachePolicy {
+ public:
+ explicit MockAppCachePolicy(AppCacheStorageImplTest* test)
+ : can_load_return_value_(true), can_create_return_value_(0),
+ callback_(NULL), test_(test) {
+ }
+
+ virtual bool CanLoadAppCache(const GURL& manifest_url) {
+ requested_manifest_url_ = manifest_url;
+ return can_load_return_value_;
+ }
+
+ virtual int CanCreateAppCache(const GURL& manifest_url,
+ net::CompletionCallback* callback) {
+ requested_manifest_url_ = manifest_url;
+ callback_ = callback;
+ if (can_create_return_value_ == net::ERR_IO_PENDING)
+ test_->ScheduleNextTask();
+ return can_create_return_value_;
+ }
+
+ bool can_load_return_value_;
+ int can_create_return_value_;
+ GURL requested_manifest_url_;
+ net::CompletionCallback* callback_;
+ AppCacheStorageImplTest* test_;
+ };
+
// Helper class run a test on our io_thread. The io_thread
// is spun up once and reused for all tests.
template <class Method>
@@ -182,7 +212,8 @@ class AppCacheStorageImplTest : public testing::Test {
// Test harness --------------------------------------------------
AppCacheStorageImplTest()
- : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)) {
+ : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(policy_(this)) {
}
template <class Method>
@@ -664,17 +695,25 @@ class AppCacheStorageImplTest : public testing::Test {
// BasicFindMainResponse -------------------------------
void BasicFindMainResponseInDatabase() {
- BasicFindMainResponse(true);
+ BasicFindMainResponse(true, false);
}
void BasicFindMainResponseInWorkingSet() {
- BasicFindMainResponse(false);
+ BasicFindMainResponse(false, false);
+ }
+
+ void BlockFindMainResponseWithPolicyCheck() {
+ BasicFindMainResponse(true, true);
}
- void BasicFindMainResponse(bool drop_from_working_set) {
+ void BasicFindMainResponse(bool drop_from_working_set,
+ bool block_with_policy_check) {
PushNextTask(method_factory_.NewRunnableMethod(
&AppCacheStorageImplTest::Verify_BasicFindMainResponse));
+ policy_.can_load_return_value_ = !block_with_policy_check;
+ service()->set_appcache_policy(&policy_);
+
// Setup some preconditions. Create a complete cache with an entry
// in storage.
MakeCacheAndGroup(kManifestUrl, 1, 1, true);
@@ -700,13 +739,18 @@ class AppCacheStorageImplTest : public testing::Test {
}
void Verify_BasicFindMainResponse() {
- EXPECT_EQ(kEntryUrl, delegate()->found_url_);
- EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
- EXPECT_EQ(1, delegate()->found_cache_id_);
- EXPECT_EQ(1, delegate()->found_entry_.response_id());
- EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
- EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
- TestFinished();
+ EXPECT_EQ(kManifestUrl, policy_.requested_manifest_url_);
+ if (policy_.can_load_return_value_) {
+ EXPECT_EQ(kEntryUrl, delegate()->found_url_);
+ EXPECT_EQ(kManifestUrl, delegate()->found_manifest_url_);
+ EXPECT_EQ(1, delegate()->found_cache_id_);
+ EXPECT_EQ(1, delegate()->found_entry_.response_id());
+ EXPECT_TRUE(delegate()->found_entry_.IsExplicit());
+ EXPECT_FALSE(delegate()->found_fallback_entry_.has_response_id());
+ TestFinished();
+ } else {
+ Verify_FindNoMainResponse();
+ }
}
// BasicFindMainFallbackResponse -------------------------------
@@ -914,6 +958,7 @@ class AppCacheStorageImplTest : public testing::Test {
ScopedRunnableMethodFactory<AppCacheStorageImplTest> method_factory_;
scoped_ptr<base::WaitableEvent> test_finished_event_;
std::stack<Task*> task_stack_;
+ MockAppCachePolicy policy_;
scoped_ptr<AppCacheService> service_;
scoped_ptr<MockStorageDelegate> delegate_;
scoped_refptr<AppCacheGroup> group_;
@@ -981,6 +1026,11 @@ TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
&AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
}
+TEST_F(AppCacheStorageImplTest, BlockFindMainResponseWithPolicyCheck) {
+ RunTestOnIOThread(
+ &AppCacheStorageImplTest::BlockFindMainResponseWithPolicyCheck);
+}
+
TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
RunTestOnIOThread(
&AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
diff --git a/webkit/appcache/appcache_update_job.cc b/webkit/appcache/appcache_update_job.cc
index dcf77b0..a022ed3 100644
--- a/webkit/appcache/appcache_update_job.cc
+++ b/webkit/appcache/appcache_update_job.cc
@@ -9,7 +9,9 @@
#include "base/string_util.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
+#include "net/base/net_errors.h"
#include "webkit/appcache/appcache_group.h"
+#include "webkit/appcache/appcache_policy.h"
#include "webkit/appcache/appcache_response.h"
namespace appcache {
@@ -113,7 +115,10 @@ AppCacheUpdateJob::AppCacheUpdateJob(AppCacheService* service,
ALLOW_THIS_IN_INITIALIZER_LIST(manifest_data_write_callback_(
this, &AppCacheUpdateJob::OnManifestDataWriteComplete)),
ALLOW_THIS_IN_INITIALIZER_LIST(manifest_data_read_callback_(
- this, &AppCacheUpdateJob::OnManifestDataReadComplete)) {
+ this, &AppCacheUpdateJob::OnManifestDataReadComplete)),
+ ALLOW_THIS_IN_INITIALIZER_LIST(policy_callback_(
+ new net::CancelableCompletionCallback<AppCacheUpdateJob>(
+ this, &AppCacheUpdateJob::OnPolicyCheckComplete))) {
DCHECK(group_);
manifest_url_ = group_->manifest_url();
}
@@ -130,6 +135,8 @@ AppCacheUpdateJob::~AppCacheUpdateJob() {
if (group_)
group_->SetUpdateStatus(AppCacheGroup::IDLE);
+
+ policy_callback_->Cancel();
}
void AppCacheUpdateJob::StartUpdate(AppCacheHost* host,
@@ -191,7 +198,45 @@ void AppCacheUpdateJob::StartUpdate(AppCacheHost* host,
is_new_pending_master_entry);
}
- FetchManifest(true);
+ if (update_type_ == CACHE_ATTEMPT)
+ CheckPolicy();
+ else
+ FetchManifest(true);
+}
+
+void AppCacheUpdateJob::CheckPolicy() {
+ int rv = net::OK;
+ policy_callback_->AddRef(); // Balanced in OnPolicyCheckComplete.
+ AppCachePolicy* policy = service_->appcache_policy();
+ if (policy) {
+ rv = policy->CanCreateAppCache(manifest_url_, policy_callback_);
+ if (rv == net::ERR_IO_PENDING)
+ return;
+ }
+ OnPolicyCheckComplete(rv);
+}
+
+void AppCacheUpdateJob::OnPolicyCheckComplete(int rv) {
+ policy_callback_->Release(); // Balanced in CheckPolicy.
+ if (rv == net::OK) {
+ FetchManifest(true);
+ return;
+ }
+
+ MessageLoop::current()->PostTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &AppCacheUpdateJob::HandleCacheFailure));
+}
+
+void AppCacheUpdateJob::HandleCacheFailure() {
+ // TODO(michaeln): For now this is only invoked from one point
+ // of failure. Overtime, attempt the migrate the various places
+ // where we can detect a failure condition to use this same
+ // method to enter the cache_failure state.
+ internal_state_ = CACHE_FAILURE;
+ CancelAllUrlFetches();
+ CancelAllMasterEntryFetches();
+ MaybeCompleteUpdate();
}
void AppCacheUpdateJob::FetchManifest(bool is_first_fetch) {
@@ -1227,6 +1272,8 @@ void AppCacheUpdateJob::Cancel() {
manifest_response_writer_.reset();
service_->storage()->CancelDelegateCallbacks(this);
+
+ policy_callback_->Cancel();
}
void AppCacheUpdateJob::ClearPendingMasterEntries() {
diff --git a/webkit/appcache/appcache_update_job.h b/webkit/appcache/appcache_update_job.h
index 2580ff8..c50f202 100644
--- a/webkit/appcache/appcache_update_job.h
+++ b/webkit/appcache/appcache_update_job.h
@@ -14,6 +14,7 @@
#include "base/ref_counted.h"
#include "base/task.h"
#include "googleurl/src/gurl.h"
+#include "net/base/completion_callback.h"
#include "net/url_request/url_request.h"
#include "testing/gtest/include/gtest/gtest_prod.h"
#include "webkit/appcache/appcache.h"
@@ -99,6 +100,11 @@ class AppCacheUpdateJob : public URLRequest::Delegate,
void OnCacheSelectionComplete(AppCacheHost* host) {} // N/A
void OnDestructionImminent(AppCacheHost* host);
+ void CheckPolicy();
+ void OnPolicyCheckComplete(int rv);
+
+ void HandleCacheFailure();
+
void FetchManifest(bool is_first_fetch);
// Add extra HTTP headers to the request based on the response info and
@@ -260,6 +266,9 @@ class AppCacheUpdateJob : public URLRequest::Delegate,
net::CompletionCallbackImpl<AppCacheUpdateJob> manifest_data_write_callback_;
net::CompletionCallbackImpl<AppCacheUpdateJob> manifest_data_read_callback_;
+ scoped_refptr<net::CancelableCompletionCallback<AppCacheUpdateJob> >
+ policy_callback_;
+
FRIEND_TEST(AppCacheGroupTest, QueueUpdate);
DISALLOW_COPY_AND_ASSIGN(AppCacheUpdateJob);
};
diff --git a/webkit/appcache/appcache_update_job_unittest.cc b/webkit/appcache/appcache_update_job_unittest.cc
index d41e486..42efbff 100644
--- a/webkit/appcache/appcache_update_job_unittest.cc
+++ b/webkit/appcache/appcache_update_job_unittest.cc
@@ -7,10 +7,12 @@
#include "base/stl_util-inl.h"
#include "base/thread.h"
#include "base/waitable_event.h"
+#include "net/base/net_errors.h"
#include "net/url_request/url_request_test_job.h"
#include "net/url_request/url_request_unittest.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_host.h"
+#include "webkit/appcache/appcache_policy.h"
#include "webkit/appcache/appcache_response.h"
#include "webkit/appcache/appcache_update_job.h"
#include "webkit/appcache/mock_appcache_service.h"
@@ -276,6 +278,43 @@ bool HttpHeadersRequestTestJob::already_checked_ = false;
class AppCacheUpdateJobTest : public testing::Test,
public AppCacheGroup::UpdateObserver {
public:
+ class MockAppCachePolicy : public AppCachePolicy {
+ public:
+ MockAppCachePolicy()
+ : ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
+ can_create_return_value_(net::OK), return_immediately_(true),
+ callback_(NULL) {
+ }
+
+ virtual bool CanLoadAppCache(const GURL& manifest_url) {
+ return true;
+ }
+
+ virtual int CanCreateAppCache(const GURL& manifest_url,
+ net::CompletionCallback* callback) {
+ requested_manifest_url_ = manifest_url;
+ callback_ = callback;
+ if (return_immediately_)
+ return can_create_return_value_;
+
+ MessageLoop::current()->PostTask(FROM_HERE,
+ method_factory_.NewRunnableMethod(
+ &MockAppCachePolicy::CompleteCanCreateAppCache));
+ return net::ERR_IO_PENDING;
+ }
+
+ void CompleteCanCreateAppCache() {
+ callback_->Run(can_create_return_value_);
+ }
+
+ ScopedRunnableMethodFactory<MockAppCachePolicy> method_factory_;
+ int can_create_return_value_;
+ bool return_immediately_;
+ GURL requested_manifest_url_;
+ net::CompletionCallback* callback_;
+ };
+
+
AppCacheUpdateJobTest()
: ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
do_checks_after_update_finished_(false),
@@ -355,6 +394,52 @@ class AppCacheUpdateJobTest : public testing::Test,
UpdateFinished();
}
+ void ImmediatelyBlockCacheAttemptTest() {
+ BlockCacheAttemptTest(true);
+ }
+
+ void DelayedBlockCacheAttemptTest() {
+ BlockCacheAttemptTest(false);
+ }
+
+ void BlockCacheAttemptTest(bool immediately) {
+ ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type());
+
+ GURL manifest_url = GURL("http://failme");
+
+ // Setup to block the cache attempt immediately.
+ policy_.return_immediately_ = immediately;
+ policy_.can_create_return_value_ = net::ERR_ACCESS_DENIED;
+
+ MakeService();
+ group_ = new AppCacheGroup(service_.get(), manifest_url,
+ service_->storage()->NewGroupId());
+
+ AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
+ group_->update_job_ = update;
+
+ MockFrontend mock_frontend;
+ AppCacheHost host(1, &mock_frontend, service_.get());
+
+ update->StartUpdate(&host, GURL());
+ EXPECT_EQ(manifest_url, policy_.requested_manifest_url_);
+
+ // Verify state.
+ EXPECT_EQ(AppCacheUpdateJob::CACHE_ATTEMPT, update->update_type_);
+ EXPECT_EQ(AppCacheUpdateJob::FETCH_MANIFEST, update->internal_state_);
+ EXPECT_EQ(AppCacheGroup::CHECKING, group_->update_status());
+
+ // Verify notifications.
+ MockFrontend::RaisedEvents& events = mock_frontend.raised_events_;
+ size_t expected = 1;
+ EXPECT_EQ(expected, events.size());
+ EXPECT_EQ(1U, events[0].first.size());
+ EXPECT_EQ(host.host_id(), events[0].first[0]);
+ EXPECT_EQ(CHECKING_EVENT, events[0].second);
+
+ WaitForUpdateToFinish();
+ }
+
void StartUpgradeAttemptTest() {
ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type());
@@ -727,9 +812,15 @@ class AppCacheUpdateJobTest : public testing::Test,
void BasicCacheAttemptSuccessTest() {
ASSERT_EQ(MessageLoop::TYPE_IO, MessageLoop::current()->type());
+ GURL manifest_url = http_server_->TestServerPage("files/manifest1");
+
+ // We also test the async AppCachePolicy return path in this test case.
+ policy_.return_immediately_ = false;
+ policy_.can_create_return_value_ = net::OK;
+
MakeService();
group_ = new AppCacheGroup(
- service_.get(), http_server_->TestServerPage("files/manifest1"),
+ service_.get(), manifest_url,
service_->storage()->NewGroupId());
AppCacheUpdateJob* update = new AppCacheUpdateJob(service_.get(), group_);
group_->update_job_ = update;
@@ -737,7 +828,7 @@ class AppCacheUpdateJobTest : public testing::Test,
MockFrontend* frontend = MakeMockFrontend();
AppCacheHost* host = MakeHost(1, frontend);
update->StartUpdate(host, GURL());
- EXPECT_TRUE(update->manifest_url_request_ != NULL);
+ EXPECT_EQ(manifest_url, policy_.requested_manifest_url_);;
// Set up checks for when update job finishes.
do_checks_after_update_finished_ = true;
@@ -2485,6 +2576,7 @@ class AppCacheUpdateJobTest : public testing::Test,
void MakeService() {
service_.reset(new MockAppCacheService());
service_->set_request_context(request_context_);
+ service_->set_appcache_policy(&policy_);
}
AppCache* MakeCacheForGroup(int64 cache_id, int64 manifest_response_id) {
@@ -2777,6 +2869,7 @@ class AppCacheUpdateJobTest : public testing::Test,
scoped_refptr<AppCacheGroup> group_;
scoped_refptr<AppCache> protect_newest_cache_;
scoped_ptr<base::WaitableEvent> event_;
+ MockAppCachePolicy policy_;
scoped_ptr<AppCacheResponseWriter> response_writer_;
scoped_ptr<net::CompletionCallbackImpl<AppCacheUpdateJobTest> >
@@ -2873,6 +2966,14 @@ TEST_F(AppCacheUpdateJobTest, StartCacheAttempt) {
RunTestOnIOThread(&AppCacheUpdateJobTest::StartCacheAttemptTest);
}
+TEST_F(AppCacheUpdateJobTest, ImmediatelyBlockCacheAttemptTest) {
+ RunTestOnIOThread(&AppCacheUpdateJobTest::ImmediatelyBlockCacheAttemptTest);
+}
+
+TEST_F(AppCacheUpdateJobTest, DelayedBlockCacheAttemptTest) {
+ RunTestOnIOThread(&AppCacheUpdateJobTest::DelayedBlockCacheAttemptTest);
+}
+
TEST_F(AppCacheUpdateJobTest, StartUpgradeAttempt) {
RunTestOnIOThread(&AppCacheUpdateJobTest::StartUpgradeAttemptTest);
}
diff --git a/webkit/webkit.gyp b/webkit/webkit.gyp
index 4784106..483c1a6 100644
--- a/webkit/webkit.gyp
+++ b/webkit/webkit.gyp
@@ -145,6 +145,7 @@
'appcache/appcache_interceptor.h',
'appcache/appcache_interfaces.cc',
'appcache/appcache_interfaces.h',
+ 'appcache/appcache_policy.h',
'appcache/appcache_request_handler.cc',
'appcache/appcache_request_handler.h',
'appcache/appcache_response.cc',