Skip to content

Commit

Permalink
Introduce an AppCachePolicy interface that allows the containing brow…
Browse files Browse the repository at this point in the history
…ser to determine appcache permissions. The policy can allow or deny loading existing manifests or the creation of new manifests. The policy check for creating new manifests can be async to allow for a user prompt.

BUG=none
TEST=new unit tests added

Review URL: http://codereview.chromium.org/565042

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@39280 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
michaeln@chromium.org committed Feb 17, 2010
1 parent a3d3a7c commit ea776d0
Show file tree
Hide file tree
Showing 12 changed files with 337 additions and 21 deletions.
22 changes: 22 additions & 0 deletions chrome/common/appcache/chrome_appcache_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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() {
Expand All @@ -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) {
Expand Down
7 changes: 7 additions & 0 deletions chrome/common/appcache/chrome_appcache_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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,
Expand Down
38 changes: 38 additions & 0 deletions webkit/appcache/appcache_policy.h
Original file line number Diff line number Diff line change
@@ -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_
2 changes: 1 addition & 1 deletion webkit/appcache/appcache_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
namespace appcache {

AppCacheService::AppCacheService()
: request_context_(NULL) {
: appcache_policy_(NULL), request_context_(NULL) {
}

AppCacheService::~AppCacheService() {
Expand Down
11 changes: 11 additions & 0 deletions webkit/appcache/appcache_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand All @@ -51,6 +60,8 @@ class AppCacheService {
AppCacheStorage* storage() const { return storage_.get(); }

protected:
AppCachePolicy* appcache_policy_;

// Deals with persistence.
scoped_ptr<AppCacheStorage> storage_;

Expand Down
35 changes: 30 additions & 5 deletions webkit/appcache/appcache_storage_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 -------
Expand Down Expand Up @@ -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,
Expand Down
5 changes: 5 additions & 0 deletions webkit/appcache/appcache_storage_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
72 changes: 61 additions & 11 deletions webkit/appcache/appcache_storage_impl_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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);
Expand All @@ -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 -------------------------------
Expand Down Expand Up @@ -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_;
Expand Down Expand Up @@ -981,6 +1026,11 @@ TEST_F(AppCacheStorageImplTest, BasicFindMainResponseInWorkingSet) {
&AppCacheStorageImplTest::BasicFindMainResponseInWorkingSet);
}

TEST_F(AppCacheStorageImplTest, BlockFindMainResponseWithPolicyCheck) {
RunTestOnIOThread(
&AppCacheStorageImplTest::BlockFindMainResponseWithPolicyCheck);
}

TEST_F(AppCacheStorageImplTest, BasicFindMainFallbackResponseInDatabase) {
RunTestOnIOThread(
&AppCacheStorageImplTest::BasicFindMainFallbackResponseInDatabase);
Expand Down
Loading

0 comments on commit ea776d0

Please sign in to comment.