Skip to content

Commit

Permalink
Third-party appcache blocking.
Browse files Browse the repository at this point in the history
BUG=72586
TEST=AppCacheHostTest.SelectCacheAllowed, AppCacheHostTest.SelectCacheBlocked, AppCacheRequestHandlerTest.MainResource_Blocked


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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100131 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
marja@chromium.org committed Sep 8, 2011
1 parent b3d0768 commit 0a60884
Show file tree
Hide file tree
Showing 32 changed files with 316 additions and 326 deletions.
4 changes: 2 additions & 2 deletions chrome/browser/chrome_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -385,13 +385,13 @@ SkBitmap* ChromeContentBrowserClient::GetDefaultFavicon() {

bool ChromeContentBrowserClient::AllowAppCache(
const GURL& manifest_url,
const GURL& first_party,
const content::ResourceContext& context) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
ProfileIOData* io_data =
reinterpret_cast<ProfileIOData*>(context.GetUserData(NULL));
// FIXME(jochen): get the correct top-level origin.
ContentSetting setting = io_data->GetHostContentSettingsMap()->
GetCookieContentSetting(manifest_url, manifest_url, true);
GetCookieContentSetting(manifest_url, first_party, true);
DCHECK(setting != CONTENT_SETTING_DEFAULT);
return setting != CONTENT_SETTING_BLOCK;
}
Expand Down
1 change: 1 addition & 0 deletions chrome/browser/chrome_content_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class ChromeContentBrowserClient : public content::ContentBrowserClient {
virtual std::string GetAcceptLangs(const TabContents* tab) OVERRIDE;
virtual SkBitmap* GetDefaultFavicon() OVERRIDE;
virtual bool AllowAppCache(const GURL& manifest_url,
const GURL& first_party,
const content::ResourceContext& context) OVERRIDE;
virtual bool AllowGetCookie(const GURL& url,
const GURL& first_party,
Expand Down
3 changes: 2 additions & 1 deletion chrome/browser/renderer_host/offline_resource_handler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ bool OfflineResourceHandler::OnWillStart(int request_id,
new net::CancelableCompletionCallback<OfflineResourceHandler>(
this, &OfflineResourceHandler::OnCanHandleOfflineComplete);
appcache_service_->CanHandleMainResourceOffline(
url, appcache_completion_callback_);
url, request_->first_party_for_cookies(),
appcache_completion_callback_);

*defer = true;
return true;
Expand Down
11 changes: 6 additions & 5 deletions content/browser/appcache/chrome_appcache_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,19 @@ void ChromeAppCacheService::InitializeOnIOThread(
ChromeAppCacheService::~ChromeAppCacheService() {
}

bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url) {
bool ChromeAppCacheService::CanLoadAppCache(const GURL& manifest_url,
const GURL& first_party) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
// We don't prompt for read access.
return content::GetContentClient()->browser()->AllowAppCache(
manifest_url, *resource_context_);
manifest_url, first_party, *resource_context_);
}

int ChromeAppCacheService::CanCreateAppCache(
const GURL& manifest_url, net::CompletionCallback* callback) {
bool ChromeAppCacheService::CanCreateAppCache(
const GURL& manifest_url, const GURL& first_party) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
return content::GetContentClient()->browser()->AllowAppCache(
manifest_url, *resource_context_) ? net::OK : net::ERR_ACCESS_DENIED;
manifest_url, first_party, *resource_context_);
}

void ChromeAppCacheService::Observe(int type,
Expand Down
7 changes: 4 additions & 3 deletions content/browser/appcache/chrome_appcache_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ class ChromeAppCacheService
virtual ~ChromeAppCacheService();

// AppCachePolicy overrides
virtual bool CanLoadAppCache(const GURL& manifest_url);
virtual int CanCreateAppCache(const GURL& manifest_url,
net::CompletionCallback* callback);
virtual bool CanLoadAppCache(const GURL& manifest_url,
const GURL& first_party);
virtual bool CanCreateAppCache(const GURL& manifest_url,
const GURL& first_party);

// NotificationObserver override
virtual void Observe(int type,
Expand Down
1 change: 1 addition & 0 deletions content/browser/content_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ class ContentBrowserClient {
// Allow the embedder to control if an AppCache can be used for the given url.
// This is called on the IO thread.
virtual bool AllowAppCache(const GURL& manifest_url,
const GURL& first_party,
const content::ResourceContext& context) = 0;

// Allow the embedder to control if the given cookie can be read.
Expand Down
3 changes: 2 additions & 1 deletion content/browser/mock_content_browser_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ SkBitmap* MockContentBrowserClient::GetDefaultFavicon() {
}

bool MockContentBrowserClient::AllowAppCache(
const GURL& manifest_url, const content::ResourceContext& context) {
const GURL& manifest_url, const GURL& first_party,
const content::ResourceContext& context) {
return true;
}

Expand Down
1 change: 1 addition & 0 deletions content/browser/mock_content_browser_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class MockContentBrowserClient : public ContentBrowserClient {
virtual std::string GetAcceptLangs(const TabContents* tab) OVERRIDE;
virtual SkBitmap* GetDefaultFavicon() OVERRIDE;
virtual bool AllowAppCache(const GURL& manifest_url,
const GURL& first_party,
const content::ResourceContext& context) OVERRIDE;
virtual bool AllowGetCookie(const GURL& url,
const GURL& first_party,
Expand Down
7 changes: 1 addition & 6 deletions webkit/appcache/appcache_group.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Copyright (c) 2011 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.

Expand Down Expand Up @@ -264,9 +264,4 @@ void AppCacheGroup::SetUpdateStatus(UpdateStatus status) {
}
}

void AppCacheGroup::NotifyContentBlocked() {
FOR_EACH_OBSERVER(
UpdateObserver, observers_, OnContentBlocked(this));
}

} // namespace appcache
3 changes: 0 additions & 3 deletions webkit/appcache/appcache_group.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ class AppCacheGroup : public base::RefCounted<AppCacheGroup> {

class UpdateObserver {
public:
// Called if access to the appcache was blocked by a policy.
virtual void OnContentBlocked(AppCacheGroup* group) = 0;

// Called just after an appcache update has completed.
virtual void OnUpdateComplete(AppCacheGroup* group) = 0;
virtual ~UpdateObserver() {}
Expand Down
24 changes: 19 additions & 5 deletions webkit/appcache/appcache_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "base/stringprintf.h"
#include "webkit/appcache/appcache.h"
#include "webkit/appcache/appcache_backend_impl.h"
#include "webkit/appcache/appcache_policy.h"
#include "webkit/appcache/appcache_request_handler.h"
#include "webkit/quota/quota_manager.h"

Expand Down Expand Up @@ -95,6 +96,19 @@ void AppCacheHost::SelectCache(const GURL& document_url,

if (!manifest_url.is_empty() &&
(manifest_url.GetOrigin() == document_url.GetOrigin())) {
DCHECK(!first_party_url_.is_empty());
AppCachePolicy* policy = service()->appcache_policy();
if (policy &&
!policy->CanCreateAppCache(manifest_url, first_party_url_)) {
FinishCacheSelection(NULL, NULL);
std::vector<int> host_ids(1, host_id_);
frontend_->OnEventRaised(host_ids, CHECKING_EVENT);
frontend_->OnErrorEventRaised(
host_ids, "Cache creation was blocked by the content policy");
frontend_->OnContentBlocked(host_id_, manifest_url);
return;
}

// Note: The client detects if the document was not loaded using HTTP GET
// and invokes SelectCache without a manifest url, so that detection step
// is also skipped here. See WebApplicationCacheHostImpl.cc
Expand Down Expand Up @@ -267,8 +281,12 @@ AppCacheRequestHandler* AppCacheHost::CreateRequestHandler(
return NULL;
}

if (AppCacheRequestHandler::IsMainResourceType(resource_type))
if (AppCacheRequestHandler::IsMainResourceType(resource_type)) {
// Store the first party origin so that it can be used later in SelectCache
// for checking whether the creation of the appcache is allowed.
first_party_url_ = request->first_party_for_cookies();
return new AppCacheRequestHandler(this, resource_type);
}

if ((associated_cache() && associated_cache()->is_complete()) ||
is_selection_pending()) {
Expand Down Expand Up @@ -421,10 +439,6 @@ void AppCacheHost::OnUpdateComplete(AppCacheGroup* group) {
}
}

void AppCacheHost::OnContentBlocked(AppCacheGroup* group) {
frontend_->OnContentBlocked(host_id_, group->manifest_url());
}

void AppCacheHost::SetSwappableCache(AppCacheGroup* group) {
if (!group) {
swappable_cache_ = NULL;
Expand Down
8 changes: 7 additions & 1 deletion webkit/appcache/appcache_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ class AppCacheHost : public AppCacheStorage::Delegate,
!pending_selected_manifest_url_.is_empty();
}

const GURL& first_party_url() const { return first_party_url_; }

private:
Status GetStatus();
void LoadSelectedCache(int64 cache_id);
Expand All @@ -150,7 +152,6 @@ class AppCacheHost : public AppCacheStorage::Delegate,
void ObserveGroupBeingUpdated(AppCacheGroup* group);

// AppCacheGroup::UpdateObserver methods.
virtual void OnContentBlocked(AppCacheGroup* group);
virtual void OnUpdateComplete(AppCacheGroup* group);

// Returns true if this host is for a dedicated worker context.
Expand Down Expand Up @@ -245,6 +246,9 @@ class AppCacheHost : public AppCacheStorage::Delegate,
// Used to inform the QuotaManager of what origins are currently in use.
GURL origin_in_use_;

// First party url to be used in policy checks.
GURL first_party_url_;

friend class AppCacheRequestHandlerTest;
friend class AppCacheUpdateJobTest;
FRIEND_TEST_ALL_PREFIXES(AppCacheTest, CleanupUnusedCache);
Expand All @@ -256,6 +260,8 @@ class AppCacheHost : public AppCacheStorage::Delegate,
FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, FailedGroupLoad);
FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, SetSwappableCache);
FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, ForDedicatedWorker);
FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, SelectCacheAllowed);
FRIEND_TEST_ALL_PREFIXES(AppCacheHostTest, SelectCacheBlocked);
FRIEND_TEST_ALL_PREFIXES(AppCacheGroupTest, QueueUpdate);

DISALLOW_COPY_AND_ASSIGN(AppCacheHost);
Expand Down
89 changes: 87 additions & 2 deletions webkit/appcache/appcache_host_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "webkit/appcache/appcache_backend_impl.h"
#include "webkit/appcache/appcache_group.h"
#include "webkit/appcache/appcache_host.h"
#include "webkit/appcache/mock_appcache_policy.h"
#include "webkit/appcache/mock_appcache_service.h"
#include "webkit/quota/quota_manager.h"

Expand All @@ -32,7 +33,8 @@ class AppCacheHostTest : public testing::Test {
: last_host_id_(-222), last_cache_id_(-222),
last_status_(appcache::OBSOLETE),
last_status_changed_(appcache::OBSOLETE),
last_event_id_(appcache::OBSOLETE_EVENT) {
last_event_id_(appcache::OBSOLETE_EVENT),
content_blocked_(false) {
}

virtual void OnCacheSelected(
Expand Down Expand Up @@ -68,13 +70,15 @@ class AppCacheHostTest : public testing::Test {
}

virtual void OnContentBlocked(int host_id, const GURL& manifest_url) {
content_blocked_ = true;
}

int last_host_id_;
int64 last_cache_id_;
appcache::Status last_status_;
appcache::Status last_status_changed_;
appcache::EventID last_event_id_;
bool content_blocked_;
};

class MockQuotaManagerProxy : public quota::QuotaManagerProxy {
Expand Down Expand Up @@ -432,5 +436,86 @@ TEST_F(AppCacheHostTest, ForDedicatedWorker) {
EXPECT_EQ(NULL, worker_host->GetParentAppCacheHost());
}

} // namespace appcache
TEST_F(AppCacheHostTest, SelectCacheAllowed) {
scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy(
new MockQuotaManagerProxy);
MockAppCachePolicy mock_appcache_policy;
mock_appcache_policy.can_create_return_value_ = true;
service_.set_quota_manager_proxy(mock_quota_proxy);
service_.set_appcache_policy(&mock_appcache_policy);

// Reset our mock frontend
mock_frontend_.last_cache_id_ = -333;
mock_frontend_.last_host_id_ = -333;
mock_frontend_.last_status_ = OBSOLETE;
mock_frontend_.last_event_id_ = OBSOLETE_EVENT;
mock_frontend_.content_blocked_ = false;

const GURL kDocAndOriginUrl(GURL("http://whatever/").GetOrigin());
const GURL kManifestUrl(GURL("http://whatever/cache.manifest"));
{
AppCacheHost host(1, &mock_frontend_, &service_);
host.first_party_url_ = kDocAndOriginUrl;
host.SelectCache(kDocAndOriginUrl, kNoCacheId, kManifestUrl);
EXPECT_EQ(1, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl));

// MockAppCacheService::LoadOrCreateGroup is asynchronous, so we shouldn't
// have received an OnCacheSelected msg yet.
EXPECT_EQ(-333, mock_frontend_.last_host_id_);
EXPECT_EQ(-333, mock_frontend_.last_cache_id_);
EXPECT_EQ(OBSOLETE, mock_frontend_.last_status_);
// No error events either
EXPECT_EQ(OBSOLETE_EVENT, mock_frontend_.last_event_id_);
EXPECT_FALSE(mock_frontend_.content_blocked_);

EXPECT_TRUE(host.is_selection_pending());
}
EXPECT_EQ(0, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl));
service_.set_quota_manager_proxy(NULL);
}

TEST_F(AppCacheHostTest, SelectCacheBlocked) {
scoped_refptr<MockQuotaManagerProxy> mock_quota_proxy(
new MockQuotaManagerProxy);
MockAppCachePolicy mock_appcache_policy;
mock_appcache_policy.can_create_return_value_ = false;
service_.set_quota_manager_proxy(mock_quota_proxy);
service_.set_appcache_policy(&mock_appcache_policy);

// Reset our mock frontend
mock_frontend_.last_cache_id_ = -333;
mock_frontend_.last_host_id_ = -333;
mock_frontend_.last_status_ = OBSOLETE;
mock_frontend_.last_event_id_ = OBSOLETE_EVENT;
mock_frontend_.content_blocked_ = false;

const GURL kDocAndOriginUrl(GURL("http://whatever/").GetOrigin());
const GURL kManifestUrl(GURL("http://whatever/cache.manifest"));
{
AppCacheHost host(1, &mock_frontend_, &service_);
host.first_party_url_ = kDocAndOriginUrl;
host.SelectCache(kDocAndOriginUrl, kNoCacheId, kManifestUrl);
EXPECT_EQ(1, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl));

// We should have received an OnCacheSelected msg
EXPECT_EQ(1, mock_frontend_.last_host_id_);
EXPECT_EQ(kNoCacheId, mock_frontend_.last_cache_id_);
EXPECT_EQ(UNCACHED, mock_frontend_.last_status_);

// Also, an error event was raised
EXPECT_EQ(ERROR_EVENT, mock_frontend_.last_event_id_);
EXPECT_TRUE(mock_frontend_.content_blocked_);

// Otherwise, see that it respond as if there is no cache selected.
EXPECT_EQ(1, host.host_id());
EXPECT_EQ(&service_, host.service());
EXPECT_EQ(&mock_frontend_, host.frontend());
EXPECT_EQ(NULL, host.associated_cache());
EXPECT_FALSE(host.is_selection_pending());
EXPECT_TRUE(host.preferred_manifest_url().is_empty());
}
EXPECT_EQ(0, mock_quota_proxy->GetInUseCount(kDocAndOriginUrl));
service_.set_quota_manager_proxy(NULL);
}

} // namespace appcache
20 changes: 7 additions & 13 deletions webkit/appcache/appcache_policy.h
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Copyright (c) 2011 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 {
Expand All @@ -18,16 +16,12 @@ class 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;
virtual bool CanLoadAppCache(const GURL& manifest_url,
const GURL& first_party) = 0;

// Called prior to creating a new appcache. Returns true if allowed.
virtual bool CanCreateAppCache(const GURL& manifest_url,
const GURL& first_party) = 0;

protected:
~AppCachePolicy() {}
Expand Down
Loading

0 comments on commit 0a60884

Please sign in to comment.