- Add CefSettings.local_storage_quota and session_storage_quota options for setting localStorage and sessionStorage quota limits respectively (issue #348).

- Add Cef*Storage() functions and CefStorageVisitor interface for accessing localStorage and sessionStorage data via the native API (issue #361).
- Add a "cache_path" command-line flag option to cef_unittests for running the unit tests with a cache path value (issue #368).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@302 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2011-10-06 13:34:47 +00:00
parent 50b909a417
commit 6b134b4def
29 changed files with 1209 additions and 127 deletions

View File

@ -238,7 +238,9 @@
'tests/unittests/scheme_handler_unittest.cc',
'tests/unittests/stream_unittest.cc',
'tests/unittests/string_unittest.cc',
'tests/unittests/storage_unittest.cc',
'tests/unittests/test_handler.h',
'tests/unittests/test_suite.cc',
'tests/unittests/test_suite.h',
'tests/unittests/url_unittest.cc',
'tests/unittests/v8_unittest.cc',
@ -390,6 +392,8 @@
'libcef_dll/ctocpp/scheme_handler_ctocpp.h',
'libcef_dll/ctocpp/scheme_handler_factory_ctocpp.cc',
'libcef_dll/ctocpp/scheme_handler_factory_ctocpp.h',
'libcef_dll/ctocpp/storage_visitor_ctocpp.cc',
'libcef_dll/ctocpp/storage_visitor_ctocpp.h',
'libcef_dll/ctocpp/task_ctocpp.cc',
'libcef_dll/ctocpp/task_ctocpp.h',
'libcef_dll/ctocpp/v8accessor_ctocpp.cc',

View File

@ -158,6 +158,8 @@
'libcef_dll/cpptoc/scheme_handler_cpptoc.h',
'libcef_dll/cpptoc/scheme_handler_factory_cpptoc.cc',
'libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h',
'libcef_dll/cpptoc/storage_visitor_cpptoc.cc',
'libcef_dll/cpptoc/storage_visitor_cpptoc.h',
'libcef_dll/cpptoc/task_cpptoc.cc',
'libcef_dll/cpptoc/task_cpptoc.h',
'libcef_dll/cpptoc/v8accessor_cpptoc.cc',

View File

@ -73,6 +73,7 @@ class CefRequest;
class CefResponse;
class CefSchemeHandler;
class CefSchemeHandlerFactory;
class CefStorageVisitor;
class CefStreamReader;
class CefStreamWriter;
class CefTask;
@ -389,6 +390,40 @@ bool CefSetCookie(const CefString& url, const CefCookie& cookie);
bool CefDeleteCookies(const CefString& url, const CefString& cookie_name);
typedef cef_storage_type_t CefStorageType;
///
// Visit storage of the specified type. If |origin| is non-empty only data
// matching that origin will be visited. If |key| is non-empty only data
// matching that key will be visited. Otherwise, all data for the storage
// type will be visited. Returns false if the storage cannot be accessed.
// Origin should be of the form scheme://domain.
///
/*--cef()--*/
bool CefVisitStorage(CefStorageType type, const CefString& origin,
const CefString& key,
CefRefPtr<CefStorageVisitor> visitor);
///
// Sets storage of the specified type, origin, key and value. Returns false if
// storage cannot be accessed. This method must be called on the UI thread.
///
/*--cef()--*/
bool CefSetStorage(CefStorageType type, const CefString& origin,
const CefString& key, const CefString& value);
///
// Deletes all storage of the specified type. If |origin| is non-empty only data
// matching that origin will be cleared. If |key| is non-empty only data
// matching that key will be cleared. Otherwise, all data for the storage type
// will be cleared. Returns false if storage cannot be accessed. This method
// must be called on the UI thread.
///
/*--cef()--*/
bool CefDeleteStorage(CefStorageType type, const CefString& origin,
const CefString& key);
///
// Interface defining the reference count implementation methods. All framework
// classes must extend the CefBase class.
@ -528,6 +563,28 @@ public:
};
///
// Interface to implement for visiting storage. The methods of this class will
// always be called on the UI thread.
///
/*--cef(source=client)--*/
class CefStorageVisitor : public virtual CefBase
{
public:
///
// Method that will be called once for each key/value data pair in storage.
// |count| is the 0-based index for the current pair. |total| is the total
// number of pairs. Set |deleteData| to true to delete the pair currently
// being visited. Return false to stop visiting pairs. This method may never
// be called if no data is found.
///
/*--cef()--*/
virtual bool Visit(CefStorageType type, const CefString& origin,
const CefString& key, const CefString& value, int count,
int total, bool& deleteData) =0;
};
///
// Class used to represent a browser window. The methods of this class may be
// called on any thread unless otherwise indicated in the comments.

View File

@ -325,6 +325,35 @@ CEF_EXPORT int cef_set_cookie(const cef_string_t* url,
CEF_EXPORT int cef_delete_cookies(const cef_string_t* url,
const cef_string_t* cookie_name);
///
// Visit storage of the specified type. If |origin| is non-NULL only data
// matching that origin will be visited. If |key| is non-NULL only data matching
// that key will be visited. Otherwise, all data for the storage type will be
// visited. Returns false (0) if the storage cannot be accessed. Origin should
// be of the form scheme://domain.
///
CEF_EXPORT int cef_visit_storage(enum cef_storage_type_t type,
const cef_string_t* origin, const cef_string_t* key,
struct _cef_storage_visitor_t* visitor);
///
// Sets storage of the specified type, origin, key and value. Returns false (0)
// if storage cannot be accessed. This function must be called on the UI thread.
///
CEF_EXPORT int cef_set_storage(enum cef_storage_type_t type,
const cef_string_t* origin, const cef_string_t* key,
const cef_string_t* value);
///
// Deletes all storage of the specified type. If |origin| is non-NULL only data
// matching that origin will be cleared. If |key| is non-NULL only data matching
// that key will be cleared. Otherwise, all data for the storage type will be
// cleared. Returns false (0) if storage cannot be accessed. This function must
// be called on the UI thread.
///
CEF_EXPORT int cef_delete_storage(enum cef_storage_type_t type,
const cef_string_t* origin, const cef_string_t* key);
typedef struct _cef_base_t
{
// Size of the data structure.
@ -390,6 +419,30 @@ typedef struct _cef_cookie_visitor_t
} cef_cookie_visitor_t;
///
// Structure to implement for visiting storage. The functions of this structure
// will always be called on the UI thread.
///
typedef struct _cef_storage_visitor_t
{
// Base structure.
cef_base_t base;
///
// Method that will be called once for each key/value data pair in storage.
// |count| is the 0-based index for the current pair. |total| is the total
// number of pairs. Set |deleteData| to true (1) to delete the pair currently
// being visited. Return false (0) to stop visiting pairs. This function may
// never be called if no data is found.
///
int (CEF_CALLBACK *visit)(struct _cef_storage_visitor_t* self,
enum cef_storage_type_t type, const cef_string_t* origin,
const cef_string_t* key, const cef_string_t* value, int count, int total,
int* deleteData);
} cef_storage_visitor_t;
///
// Structure used to represent a browser window. The functions of this structure
// may be called on any thread unless otherwise indicated in the comments.

View File

@ -141,6 +141,16 @@ typedef struct _cef_settings_t
// content like WebGL, accelerated layers and 3D CSS.
///
cef_graphics_implementation_t graphics_implementation;
///
// Quota limit for localStorage data across all origins. Default size is 5MB.
///
unsigned int local_storage_quota;
///
// Quota limit for sessionStorage data per namespace. Default size is 5MB.
///
unsigned int session_storage_quota;
} cef_settings_t;
///
@ -469,6 +479,15 @@ typedef struct _cef_cookie_t
cef_time_t expires;
} cef_cookie_t;
///
// Storage types.
///
enum cef_storage_type_t
{
ST_LOCALSTORAGE = 0,
ST_SESSIONSTORAGE,
};
///
// Mouse button types.
///

View File

@ -175,14 +175,7 @@ WebKit::WebString BrowserWebKitInit::defaultLocale() {
WebKit::WebStorageNamespace* BrowserWebKitInit::createLocalStorageNamespace(
const WebKit::WebString& path, unsigned quota) {
if (BrowserWebStorageNamespaceImpl::IsStorageActive()) {
// Use the localStorage implementation that writes data to disk.
return new BrowserWebStorageNamespaceImpl(DOM_STORAGE_LOCAL);
}
// Use the default localStorage implementation.
return WebKit::WebStorageNamespace::createLocalStorageNamespace(path,
WebKit::WebStorageNamespace::m_localStorageQuota);
return new BrowserWebStorageNamespaceImpl(DOM_STORAGE_LOCAL);
}
void BrowserWebKitInit::dispatchStorageEvent(const WebKit::WebString& key,

View File

@ -18,8 +18,8 @@ using WebKit::WebView;
BrowserWebStorageAreaImpl::BrowserWebStorageAreaImpl(
int64 namespace_id, const WebString& origin) {
area_ = _Context->storage_context()->GetStorageNamespace(namespace_id, true)->
GetStorageArea(origin);
area_ =
_Context->storage_context()->GetStorageArea(namespace_id, origin, true);
DCHECK(area_ != NULL);
}

View File

@ -16,14 +16,12 @@ BrowserWebStorageNamespaceImpl::BrowserWebStorageNamespaceImpl(
DOMStorageType storage_type)
: storage_type_(storage_type),
namespace_id_(kLocalStorageNamespaceId) {
DCHECK(storage_type == DOM_STORAGE_LOCAL);
}
BrowserWebStorageNamespaceImpl::BrowserWebStorageNamespaceImpl(
DOMStorageType storage_type, int64 namespace_id)
: storage_type_(storage_type),
namespace_id_(namespace_id) {
DCHECK(storage_type == DOM_STORAGE_SESSION);
}
BrowserWebStorageNamespaceImpl::~BrowserWebStorageNamespaceImpl() {
@ -50,8 +48,3 @@ void BrowserWebStorageNamespaceImpl::close() {
// This is called only on LocalStorage namespaces when WebKit thinks its
// shutting down. This has no impact on Chromium.
}
//static
bool BrowserWebStorageNamespaceImpl::IsStorageActive() {
return (_Context->storage_context() != NULL);
}

View File

@ -23,9 +23,6 @@ class BrowserWebStorageNamespaceImpl : public WebKit::WebStorageNamespace {
virtual WebKit::WebStorageNamespace* copy();
virtual void close();
// Returns true if storage data is being cached to disk.
static bool IsStorageActive();
private:
// Used during lazy initialization of namespace_id_.
const DOMStorageType storage_type_;

View File

@ -14,6 +14,7 @@
#include "browser_navigation_controller.h"
#include "browser_web_worker.h"
#include "browser_webkit_glue.h"
#include "browser_webstoragenamespace_impl.h"
#include "browser_zoom_map.h"
#include "cef_context.h"
#include "request_impl.h"
@ -180,11 +181,9 @@ WebWidget* BrowserWebViewDelegate::createPopupMenu(WebPopupType popup_type) {
WebStorageNamespace* BrowserWebViewDelegate::createSessionStorageNamespace(
unsigned quota) {
// Enforce quota, ignoring the parameter from WebCore as in Chrome. We could
// potentially use DOMStorageContext to manage session storage but there's
// currently no need since session storage data is not written to disk.
return WebKit::WebStorageNamespace::createSessionStorageNamespace(
WebStorageNamespace::m_sessionStorageQuota);
// Ignore the quota parameter from WebCore as in Chrome.
return new BrowserWebStorageNamespaceImpl(DOM_STORAGE_SESSION,
kLocalStorageNamespaceId + 1);
}
void BrowserWebViewDelegate::didAddMessageToConsole(

View File

@ -2,14 +2,15 @@
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.
#include "cef_context.h"
#include "include/cef_nplugin.h"
#include "browser_devtools_scheme_handler.h"
#include "browser_impl.h"
#include "browser_webkit_glue.h"
#include "cef_thread.h"
#include "cef_context.h"
#include "cef_time_util.h"
#include "cef_process.h"
#include "../include/cef_nplugin.h"
#include "dom_storage_common.h"
#include "dom_storage_namespace.h"
#include "dom_storage_area.h"
#include "base/bind.h"
#include "base/file_util.h"
@ -169,6 +170,124 @@ private:
base::WaitableEvent *event_;
};
void UIT_VisitStorage(int64 namespace_id, const CefString& origin,
const CefString& key,
CefRefPtr<CefStorageVisitor> visitor)
{
REQUIRE_UIT();
DOMStorageContext* context = _Context->storage_context();
DOMStorageNamespace* ns =
context->GetStorageNamespace(namespace_id, false);
if (!ns)
return;
typedef std::vector<DOMStorageArea*> AreaList;
AreaList areas;
if (!origin.empty()) {
// Visit only the area with the specified origin.
DOMStorageArea* area = ns->GetStorageArea(origin, false);
if (area)
areas.push_back(area);
} else {
// Visit all areas.
ns->GetStorageAreas(areas, true);
}
if (areas.empty())
return;
// Count the total number of matching keys.
unsigned int total = 0;
{
NullableString16 value;
AreaList::iterator it = areas.begin();
for (; it != areas.end(); ) {
DOMStorageArea* area = (*it);
if (!key.empty()) {
value = area->GetItem(key);
if (value.is_null()) {
it = areas.erase(it);
// Don't increment the iterator.
continue;
} else {
total++;
}
} else {
total += area->Length();
}
++it;
}
}
if (total == 0)
return;
DOMStorageArea* area;
bool stop = false, deleteData;
unsigned int count = 0, i, len;
NullableString16 keyVal, valueVal;
string16 keyStr, valueStr;
typedef std::vector<string16> String16List;
String16List delete_keys;
// Visit all matching pairs.
AreaList::iterator it = areas.begin();
for (; it != areas.end() && !stop; ++it) {
// Each area.
area = *(it);
if (!key.empty()) {
// Visit only the matching key.
valueVal = area->GetItem(key);
if (valueVal.is_null())
valueStr.clear();
else
valueStr = valueVal.string();
deleteData = false;
stop = !visitor->Visit(static_cast<CefStorageType>(namespace_id),
area->origin(), key, valueStr, count, total, deleteData);
if (deleteData)
area->RemoveItem(key);
count++;
} else {
// Visit all keys.
len = area->Length();
for(i = 0; i < len && !stop; ++i) {
keyVal = area->Key(i);
if (keyVal.is_null()) {
keyStr.clear();
valueStr.clear();
} else {
keyStr = keyVal.string();
valueVal = area->GetItem(keyStr);
if (valueVal.is_null())
valueStr.clear();
else
valueStr = valueVal.string();
}
deleteData = false;
stop = !visitor->Visit(static_cast<CefStorageType>(namespace_id),
area->origin(), keyStr, valueStr, count, total, deleteData);
if (deleteData)
delete_keys.push_back(keyStr);
count++;
}
// Delete the requested keys.
if (!delete_keys.empty()) {
String16List::const_iterator it = delete_keys.begin();
for (; it != delete_keys.end(); ++it)
area->RemoveItem(*it);
delete_keys.clear();
}
}
}
}
} // anonymous
bool CefInitialize(const CefSettings& settings)
@ -178,7 +297,7 @@ bool CefInitialize(const CefSettings& settings)
return true;
if(settings.size != sizeof(cef_settings_t)) {
NOTREACHED();
NOTREACHED() << "invalid CefSettings structure size";
return false;
}
@ -193,13 +312,13 @@ void CefShutdown()
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return;
}
// Must always be called on the same thread as Initialize.
if(!_Context->process()->CalledOnValidThread()) {
NOTREACHED();
NOTREACHED() << "called on invalid thread";
return;
}
@ -214,13 +333,13 @@ void CefDoMessageLoopWork()
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return;
}
// Must always be called on the same thread as Initialize.
if(!_Context->process()->CalledOnValidThread()) {
NOTREACHED();
NOTREACHED() << "called on invalid thread";
return;
}
@ -231,13 +350,13 @@ void CefRunMessageLoop()
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return;
}
// Must always be called on the same thread as Initialize.
if(!_Context->process()->CalledOnValidThread()) {
NOTREACHED();
NOTREACHED() << "called on invalid thread";
return;
}
@ -248,7 +367,7 @@ bool CefRegisterPlugin(const CefPluginInfo& plugin_info)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return false;
}
@ -367,7 +486,7 @@ bool CefVisitAllCookies(CefRefPtr<CefCookieVisitor> visitor)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return false;
}
@ -380,7 +499,7 @@ bool CefVisitUrlCookies(const CefString& url, bool includeHttpOnly,
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return false;
}
@ -397,13 +516,13 @@ bool CefSetCookie(const CefString& url, const CefCookie& cookie)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return false;
}
// Verify that this function is being called on the IO thread.
if (!CefThread::CurrentlyOn(CefThread::IO)) {
NOTREACHED();
NOTREACHED() << "called on invalid thread";
return false;
}
@ -436,13 +555,13 @@ bool CefDeleteCookies(const CefString& url, const CefString& cookie_name)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED();
NOTREACHED() << "context not valid";
return false;
}
// Verify that this function is being called on the IO thread.
if (!CefThread::CurrentlyOn(CefThread::IO)) {
NOTREACHED();
NOTREACHED() << "called on invalid thread";
return false;
}
@ -473,6 +592,132 @@ bool CefDeleteCookies(const CefString& url, const CefString& cookie_name)
return true;
}
bool CefVisitStorage(CefStorageType type, const CefString& origin,
const CefString& key,
CefRefPtr<CefStorageVisitor> visitor)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED() << "context not valid";
return false;
}
int64 namespace_id;
if (type == ST_LOCALSTORAGE) {
namespace_id = kLocalStorageNamespaceId;
} else if(type == ST_SESSIONSTORAGE) {
namespace_id = kLocalStorageNamespaceId + 1;
} else {
NOTREACHED() << "invalid type";
return false;
}
if (CefThread::CurrentlyOn(CefThread::UI)) {
UIT_VisitStorage(namespace_id, origin, key, visitor);
} else {
CefThread::PostTask(CefThread::UI, FROM_HERE,
base::Bind(&UIT_VisitStorage, namespace_id, origin, key, visitor));
}
return true;
}
bool CefSetStorage(CefStorageType type, const CefString& origin,
const CefString& key, const CefString& value)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED() << "context not valid";
return false;
}
// Verify that this function is being called on the UI thread.
if (!CefThread::CurrentlyOn(CefThread::UI)) {
NOTREACHED() << "called on invalid thread";
return false;
}
int64 namespace_id;
if (type == ST_LOCALSTORAGE) {
namespace_id = kLocalStorageNamespaceId;
} else if(type == ST_SESSIONSTORAGE) {
namespace_id = kLocalStorageNamespaceId + 1;
} else {
NOTREACHED() << "invalid type";
return false;
}
if (origin.empty()) {
NOTREACHED() << "invalid origin";
return false;
}
DOMStorageArea* area =
_Context->storage_context()->GetStorageArea(namespace_id, origin, true);
if (!area)
return false;
WebKit::WebStorageArea::Result result;
area->SetItem(key, value, &result);
return (result == WebKit::WebStorageArea::ResultOK);
}
bool CefDeleteStorage(CefStorageType type, const CefString& origin,
const CefString& key)
{
// Verify that the context is in a valid state.
if (!CONTEXT_STATE_VALID()) {
NOTREACHED() << "context not valid";
return false;
}
// Verify that this function is being called on the UI thread.
if (!CefThread::CurrentlyOn(CefThread::UI)) {
NOTREACHED() << "called on invalid thread";
return false;
}
int64 namespace_id;
if (type == ST_LOCALSTORAGE) {
namespace_id = kLocalStorageNamespaceId;
} else if(type == ST_SESSIONSTORAGE) {
namespace_id = kLocalStorageNamespaceId + 1;
} else {
NOTREACHED() << "invalid type";
return false;
}
DOMStorageContext* context = _Context->storage_context();
if (origin.empty()) {
// Delete all storage for the namespace.
if (namespace_id == kLocalStorageNamespaceId)
context->DeleteAllLocalStorageFiles();
else
context->PurgeMemory(namespace_id);
} else if(key.empty()) {
// Clear the storage area for the specified origin.
if (namespace_id == kLocalStorageNamespaceId) {
context->DeleteLocalStorageForOrigin(origin);
} else {
DOMStorageArea* area =
context->GetStorageArea(namespace_id, origin, false);
if (area) {
// Calling Clear() is necessary to remove the data from the namespace.
area->Clear();
area->PurgeMemory();
}
}
} else {
// Delete the specified key.
DOMStorageArea* area = context->GetStorageArea(namespace_id, origin, false);
if (area)
area->RemoveItem(key);
}
return true;
}
// CefContext

View File

@ -5,22 +5,23 @@
#ifndef _CEF_CONTEXT_H
#define _CEF_CONTEXT_H
#include "../include/cef.h"
#include "include/cef.h"
#include "browser_request_context.h"
#include "cef_process.h"
#include "cef_thread.h"
#include "dom_storage_context.h"
#include "base/at_exit.h"
#include "base/file_path.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop.h"
#include <map>
class BrowserRequestContext;
class CefBrowserImpl;
class WebViewHost;
namespace base {
class WaitableEvent;
}
class CefContext : public CefBase
{
public:

View File

@ -124,10 +124,14 @@ void CefProcessUIThread::Init() {
gfx::InitializeGLBindings(gfx::kGLImplementationDesktopGL);
#endif
if (!_Context->cache_path().empty()) {
// Create the storage context object.
_Context->set_storage_context(new DOMStorageContext());
}
// Set storage quota limits.
if (settings.local_storage_quota != 0)
DOMStorageContext::set_local_storage_quota(settings.local_storage_quota);
if (settings.session_storage_quota != 0)
DOMStorageContext::set_session_storage_quota(settings.session_storage_quota);
// Create the storage context object.
_Context->set_storage_context(new DOMStorageContext(_Context->cache_path()));
if (settings.user_agent.length > 0)
webkit_glue::SetUserAgent(CefString(&settings.user_agent));

View File

@ -37,6 +37,7 @@ class DOMStorageArea {
int64 id() const { return id_; }
DOMStorageNamespace* owner() const { return owner_; }
const string16& origin() const { return origin_; }
private:
// Creates the underlying WebStorageArea on demand.

View File

@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "dom_storage_context.h"
#include "cef_context.h"
#include "cef_thread.h"
#include "dom_storage_namespace.h"
@ -14,7 +13,9 @@
#include "base/string_util.h"
#include "dom_storage_area.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityOrigin.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebStorageNamespace.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"
#include "webkit/database/database_util.h"
#include "webkit/glue/webkit_glue.h"
const FilePath::CharType DOMStorageContext::kLocalStorageDirectory[] =
@ -23,8 +24,15 @@ const FilePath::CharType DOMStorageContext::kLocalStorageDirectory[] =
const FilePath::CharType DOMStorageContext::kLocalStorageExtension[] =
FILE_PATH_LITERAL(".localstorage");
DOMStorageContext::DOMStorageContext()
: last_storage_area_id_(0),
// Use WebStorageNamespace quota sizes as the default.
unsigned int DOMStorageContext::local_storage_quota_ =
WebKit::WebStorageNamespace::m_localStorageQuota;
unsigned int DOMStorageContext::session_storage_quota_ =
WebKit::WebStorageNamespace::m_sessionStorageQuota;
DOMStorageContext::DOMStorageContext(const FilePath& local_storage_path)
: local_storage_path_(local_storage_path),
last_storage_area_id_(0),
last_session_storage_namespace_id_on_ui_thread_(kLocalStorageNamespaceId),
last_session_storage_namespace_id_on_io_thread_(kLocalStorageNamespaceId){
}
@ -103,15 +111,20 @@ DOMStorageNamespace* DOMStorageContext::GetStorageNamespace(
return CreateSessionStorage(id);
}
void DOMStorageContext::PurgeMemory() {
// It is only safe to purge the memory from the LocalStorage namespace,
// because it is backed by disk and can be reloaded later. If we purge a
// SessionStorage namespace, its data will be gone forever, because it isn't
// currently backed by disk.
DOMStorageNamespace* local_storage =
GetStorageNamespace(kLocalStorageNamespaceId, false);
if (local_storage)
local_storage->PurgeMemory();
DOMStorageArea* DOMStorageContext::GetStorageArea(int64 namespace_id,
const string16& origin, bool allocation_allowed) {
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
DOMStorageNamespace* ns =
GetStorageNamespace(namespace_id, allocation_allowed);
if (ns)
return ns->GetStorageArea(origin, allocation_allowed);
return NULL;
}
void DOMStorageContext::PurgeMemory(int64 namespace_id) {
DOMStorageNamespace* ns = GetStorageNamespace(namespace_id, false);
if (ns)
ns->PurgeMemory();
}
void DOMStorageContext::DeleteDataModifiedSince(
@ -120,11 +133,13 @@ void DOMStorageContext::DeleteDataModifiedSince(
const std::vector<string16>& protected_origins) {
// Make sure that we don't delete a database that's currently being accessed
// by unloading all of the databases temporarily.
PurgeMemory();
PurgeMemory(kLocalStorageNamespaceId);
if (local_storage_path_.empty())
return;
FilePath data_path(_Context->cache_path());
file_util::FileEnumerator file_enumerator(
data_path.Append(kLocalStorageDirectory), false,
local_storage_path_.Append(kLocalStorageDirectory), false,
file_util::FileEnumerator::FILES);
for (FilePath path = file_enumerator.Next(); !path.value().empty();
path = file_enumerator.Next()) {
@ -147,21 +162,24 @@ void DOMStorageContext::DeleteDataModifiedSince(
}
}
void DOMStorageContext::DeleteLocalStorageFile(const FilePath& file_path) {
void DOMStorageContext::DeleteLocalStorageForOrigin(const string16& origin) {
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
DOMStorageArea* area =
GetStorageArea(kLocalStorageNamespaceId, origin, false);
if (!area)
return;
// Make sure that we don't delete a database that's currently being accessed
// by unloading all of the databases temporarily.
// TODO(bulach): both this method and DeleteDataModifiedSince could purge
// only the memory used by the specific file instead of all memory at once.
// See http://crbug.com/32000
PurgeMemory();
file_util::Delete(file_path, false);
}
// Calling Clear() is necessary to remove the data from the namespace.
area->Clear();
area->PurgeMemory();
void DOMStorageContext::DeleteLocalStorageForOrigin(const string16& origin_id) {
DCHECK(CefThread::CurrentlyOn(CefThread::UI));
DeleteLocalStorageFile(GetLocalStorageFilePath(origin_id));
if (local_storage_path_.empty())
return;
FilePath file_path = GetLocalStorageFilePath(origin);
if (!file_path.empty())
file_util::Delete(file_path, false);
}
void DOMStorageContext::DeleteAllLocalStorageFiles() {
@ -169,11 +187,13 @@ void DOMStorageContext::DeleteAllLocalStorageFiles() {
// Make sure that we don't delete a database that's currently being accessed
// by unloading all of the databases temporarily.
PurgeMemory();
PurgeMemory(kLocalStorageNamespaceId);
if (local_storage_path_.empty())
return;
FilePath data_path(_Context->cache_path());
file_util::FileEnumerator file_enumerator(
data_path.Append(kLocalStorageDirectory), false,
local_storage_path_.Append(kLocalStorageDirectory), false,
file_util::FileEnumerator::FILES);
for (FilePath file_path = file_enumerator.Next(); !file_path.empty();
file_path = file_enumerator.Next()) {
@ -183,11 +203,9 @@ void DOMStorageContext::DeleteAllLocalStorageFiles() {
}
DOMStorageNamespace* DOMStorageContext::CreateLocalStorage() {
FilePath data_path(_Context->cache_path());
FilePath dir_path;
if (!data_path.empty())
dir_path = data_path.Append(kLocalStorageDirectory);
if (!local_storage_path_.empty())
dir_path = local_storage_path_.Append(kLocalStorageDirectory);
DOMStorageNamespace* new_namespace =
DOMStorageNamespace::CreateLocalStorageNamespace(this, dir_path);
RegisterStorageNamespace(new_namespace);
@ -240,9 +258,13 @@ void DOMStorageContext::ClearLocalState(const FilePath& profile_path,
}
FilePath DOMStorageContext::GetLocalStorageFilePath(
const string16& origin_id) const {
FilePath data_path(_Context->cache_path());
FilePath storageDir = data_path.Append(
const string16& origin) const {
DCHECK(!local_storage_path_.empty());
string16 origin_id =
webkit_database::DatabaseUtil::GetOriginIdentifier(GURL(origin));
FilePath storageDir = local_storage_path_.Append(
DOMStorageContext::kLocalStorageDirectory);
FilePath::StringType id =
webkit_glue::WebStringToFilePathString(origin_id);

View File

@ -24,7 +24,7 @@ class DOMStorageNamespace;
// NOTE: Virtual methods facilitate mocking functions for testing.
class DOMStorageContext {
public:
DOMStorageContext();
DOMStorageContext(const FilePath& local_storage_path);
virtual ~DOMStorageContext();
// Allocate a new storage area id. Only call on the WebKit thread.
@ -51,8 +51,14 @@ class DOMStorageContext {
// namespace if it hasn't been already.
DOMStorageNamespace* GetStorageNamespace(int64 id, bool allocation_allowed);
// Get a storage area with the specified namespace_id and origin. If
// allocation_allowed is true this function will create a new namespace and/or
// storage area if it doesn't already exist.
DOMStorageArea* GetStorageArea(int64 namespace_id, const string16& origin,
bool allocation_allowed);
// Tells storage namespaces to purge any memory they do not need.
virtual void PurgeMemory();
virtual void PurgeMemory(int64 namespace_id);
// Delete any local storage files that have been touched since the cutoff
// date that's supplied.
@ -60,11 +66,8 @@ class DOMStorageContext {
const char* url_scheme_to_be_skipped,
const std::vector<string16>& protected_origins);
// Deletes a single local storage file.
void DeleteLocalStorageFile(const FilePath& file_path);
// Deletes the local storage file for the given origin.
void DeleteLocalStorageForOrigin(const string16& origin_id);
void DeleteLocalStorageForOrigin(const string16& origin);
// Deletes all local storage files.
void DeleteAllLocalStorageFiles();
@ -80,7 +83,16 @@ class DOMStorageContext {
const char* url_scheme_to_be_skipped);
// Get the file name of the local storage file for the given origin.
FilePath GetLocalStorageFilePath(const string16& origin_id) const;
FilePath GetLocalStorageFilePath(const string16& origin) const;
// Set the quota limits for localStorage and sessionStorage respectively.
// Changes will only take affect if made before creation of the namespaces.
static void set_local_storage_quota(unsigned int quota)
{ local_storage_quota_ = quota; }
static void set_session_storage_quota(unsigned int quota)
{ session_storage_quota_ = quota; }
static unsigned int local_storage_quota() { return local_storage_quota_; }
static unsigned int session_storage_quota() { return session_storage_quota_; }
private:
// Get the local storage instance. The object is owned by this class.
@ -99,6 +111,10 @@ class DOMStorageContext {
static void CompleteCloningSessionStorage(DOMStorageContext* context,
int64 existing_id, int64 clone_id);
// Location where localStorage files will be stored on disk. This may be empty
// in which case localStorage data will be stored in-memory only.
FilePath local_storage_path_;
// The last used storage_area_id and storage_namespace_id's. For the storage
// namespaces, IDs allocated on the UI thread are positive and count up while
// IDs allocated on the IO thread are negative and count down. This allows us
@ -116,6 +132,10 @@ class DOMStorageContext {
// Maps ids to StorageNamespaces. We own these objects.
typedef std::map<int64, DOMStorageNamespace*> StorageNamespaceMap;
StorageNamespaceMap storage_namespace_map_;
// Quota limits for localStorage and sessionStorage respectively.
static unsigned int local_storage_quota_;
static unsigned int session_storage_quota_;
};
#endif // _DOM_STORAGE_CONTEXT_H

View File

@ -21,8 +21,11 @@ DOMStorageNamespace* DOMStorageNamespace::CreateLocalStorageNamespace(
DOMStorageContext* dom_storage_context, const FilePath& data_dir_path) {
int64 id = kLocalStorageNamespaceId;
DCHECK(!dom_storage_context->GetStorageNamespace(id, false));
return new DOMStorageNamespace(dom_storage_context, id,
webkit_glue::FilePathToWebString(data_dir_path), DOM_STORAGE_LOCAL);
WebString path;
if (!data_dir_path.empty())
path = webkit_glue::FilePathToWebString(data_dir_path);
return new DOMStorageNamespace(dom_storage_context, id, path,
DOM_STORAGE_LOCAL);
}
/* static */
@ -55,12 +58,15 @@ DOMStorageNamespace::~DOMStorageNamespace() {
}
DOMStorageArea* DOMStorageNamespace::GetStorageArea(
const string16& origin) {
const string16& origin, bool allocation_allowed) {
// We may have already created it for another dispatcher host.
OriginToStorageAreaMap::iterator iter = origin_to_storage_area_.find(origin);
if (iter != origin_to_storage_area_.end())
return iter->second;
if (!allocation_allowed)
return NULL;
// We need to create a new one.
int64 id = dom_storage_context_->AllocateStorageAreaId();
DCHECK(!dom_storage_context_->GetStorageArea(id));
@ -81,8 +87,16 @@ DOMStorageNamespace* DOMStorageNamespace::Copy(int64 id) {
return new_storage_namespace;
}
void DOMStorageNamespace::GetStorageAreas(std::vector<DOMStorageArea*>& areas,
bool skip_empty) const {
OriginToStorageAreaMap::const_iterator iter = origin_to_storage_area_.begin();
for (; iter != origin_to_storage_area_.end(); ++iter) {
if (!skip_empty || iter->second->Length() > 0)
areas.push_back(iter->second);
}
}
void DOMStorageNamespace::PurgeMemory() {
DCHECK(dom_storage_type_ == DOM_STORAGE_LOCAL);
for (OriginToStorageAreaMap::iterator iter(origin_to_storage_area_.begin());
iter != origin_to_storage_area_.end(); ++iter)
iter->second->PurgeMemory();
@ -102,9 +116,9 @@ void DOMStorageNamespace::CreateWebStorageNamespaceIfNecessary() {
if (dom_storage_type_ == DOM_STORAGE_LOCAL) {
storage_namespace_.reset(
WebStorageNamespace::createLocalStorageNamespace(data_dir_path_,
WebStorageNamespace::m_localStorageQuota));
DOMStorageContext::local_storage_quota()));
} else {
storage_namespace_.reset(WebStorageNamespace::createSessionStorageNamespace(
WebStorageNamespace::m_sessionStorageQuota));
DOMStorageContext::session_storage_quota()));
}
}

View File

@ -31,9 +31,13 @@ class DOMStorageNamespace {
~DOMStorageNamespace();
DOMStorageArea* GetStorageArea(const string16& origin);
DOMStorageArea* GetStorageArea(const string16& origin,
bool allocation_allowed);
DOMStorageNamespace* Copy(int64 clone_namespace_id);
void GetStorageAreas(std::vector<DOMStorageArea*>& areas,
bool skip_empty) const;
void PurgeMemory();
const DOMStorageContext* dom_storage_context() const {

View File

@ -4,6 +4,7 @@
#include "include/cef.h"
#include "cef_context.h"
#include "cef_thread.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebString.h"

View File

@ -5,6 +5,7 @@
#include "include/cef.h"
#include "cef_context.h"
#include "cef_thread.h"
#include "request_impl.h"
#include "response_impl.h"

View File

@ -0,0 +1,51 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing function
// implementations. See the translator.README.txt file in the tools directory
// for more information.
//
#include "libcef_dll/cpptoc/storage_visitor_cpptoc.h"
// MEMBER FUNCTIONS - Body may be edited by hand.
int CEF_CALLBACK storage_visitor_visit(struct _cef_storage_visitor_t* self,
enum cef_storage_type_t type, const cef_string_t* origin,
const cef_string_t* key, const cef_string_t* value, int count, int total,
int* deleteData)
{
DCHECK(self);
DCHECK(origin);
DCHECK(deleteData);
if (!self || !origin || !deleteData)
return false;
bool delVal = (*deleteData)?true:false;
bool retVal = CefStorageVisitorCppToC::Get(self)->Visit(type, origin, key,
value, count, total, delVal);
*deleteData = delVal;
return retVal;
}
// CONSTRUCTOR - Do not edit by hand.
CefStorageVisitorCppToC::CefStorageVisitorCppToC(CefStorageVisitor* cls)
: CefCppToC<CefStorageVisitorCppToC, CefStorageVisitor,
cef_storage_visitor_t>(cls)
{
struct_.struct_.visit = storage_visitor_visit;
}
#ifndef NDEBUG
template<> long CefCppToC<CefStorageVisitorCppToC, CefStorageVisitor,
cef_storage_visitor_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,35 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// ---------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _STORAGEVISITOR_CPPTOC_H
#define _STORAGEVISITOR_CPPTOC_H
#ifndef USING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed wrapper-side only")
#else // USING_CEF_SHARED
#include "include/cef.h"
#include "include/cef_capi.h"
#include "libcef_dll/cpptoc/cpptoc.h"
// Wrap a C++ class with a C structure.
// This class may be instantiated and accessed wrapper-side only.
class CefStorageVisitorCppToC
: public CefCppToC<CefStorageVisitorCppToC, CefStorageVisitor,
cef_storage_visitor_t>
{
public:
CefStorageVisitorCppToC(CefStorageVisitor* cls);
virtual ~CefStorageVisitorCppToC() {}
};
#endif // USING_CEF_SHARED
#endif // _STORAGEVISITOR_CPPTOC_H

View File

@ -0,0 +1,39 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// ---------------------------------------------------------------------------
//
// A portion of this file was generated by the CEF translator tool. When
// making changes by hand only do so within the body of existing static and
// virtual method implementations. See the translator.README.txt file in the
// tools directory for more information.
//
#include "libcef_dll/ctocpp/storage_visitor_ctocpp.h"
// VIRTUAL METHODS - Body may be edited by hand.
bool CefStorageVisitorCToCpp::Visit(CefStorageType type,
const CefString& origin, const CefString& key, const CefString& value,
int count, int total, bool& deleteData)
{
if (CEF_MEMBER_MISSING(struct_, visit))
return false;
int delVal = deleteData;
bool retVal = struct_->visit(struct_, type, origin.GetStruct(),
key.GetStruct(), value.GetStruct(), count, total, &delVal) ?
true : false;
deleteData = delVal?true:false;
return retVal;
}
#ifndef NDEBUG
template<> long CefCToCpp<CefStorageVisitorCToCpp, CefStorageVisitor,
cef_storage_visitor_t>::DebugObjCt = 0;
#endif

View File

@ -0,0 +1,43 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
//
// -------------------------------------------------------------------------
//
// This file was generated by the CEF translator tool and should not edited
// by hand. See the translator.README.txt file in the tools directory for
// more information.
//
#ifndef _STORAGEVISITOR_CTOCPP_H
#define _STORAGEVISITOR_CTOCPP_H
#ifndef BUILDING_CEF_SHARED
#pragma message("Warning: "__FILE__" may be accessed DLL-side only")
#else // BUILDING_CEF_SHARED
#include "include/cef.h"
#include "include/cef_capi.h"
#include "libcef_dll/ctocpp/ctocpp.h"
// Wrap a C structure with a C++ class.
// This class may be instantiated and accessed DLL-side only.
class CefStorageVisitorCToCpp
: public CefCToCpp<CefStorageVisitorCToCpp, CefStorageVisitor,
cef_storage_visitor_t>
{
public:
CefStorageVisitorCToCpp(cef_storage_visitor_t* str)
: CefCToCpp<CefStorageVisitorCToCpp, CefStorageVisitor,
cef_storage_visitor_t>(str) {}
virtual ~CefStorageVisitorCToCpp() {}
// CefStorageVisitor methods
virtual bool Visit(CefStorageType type, const CefString& origin,
const CefString& key, const CefString& value, int count, int total,
bool& deleteData) OVERRIDE;
};
#endif // BUILDING_CEF_SHARED
#endif // _STORAGEVISITOR_CTOCPP_H

View File

@ -29,6 +29,7 @@
#include "ctocpp/read_handler_ctocpp.h"
#include "ctocpp/scheme_handler_ctocpp.h"
#include "ctocpp/scheme_handler_factory_ctocpp.h"
#include "ctocpp/storage_visitor_ctocpp.h"
#include "ctocpp/task_ctocpp.h"
#include "ctocpp/v8accessor_ctocpp.h"
#include "ctocpp/v8handler_ctocpp.h"
@ -78,6 +79,7 @@ CEF_EXPORT void cef_shutdown()
DCHECK(CefReadHandlerCToCpp::DebugObjCt == 0);
DCHECK(CefSchemeHandlerCToCpp::DebugObjCt == 0);
DCHECK(CefSchemeHandlerFactoryCToCpp::DebugObjCt == 0);
DCHECK(CefStorageVisitorCToCpp::DebugObjCt == 0);
DCHECK(CefV8AccessorCToCpp::DebugObjCt == 0);
DCHECK(CefV8HandlerCToCpp::DebugObjCt == 0);
DCHECK(CefWebURLRequestClientCToCpp::DebugObjCt == 0);
@ -288,3 +290,47 @@ CEF_EXPORT int cef_delete_cookies(const cef_string_t* url,
return CefDeleteCookies(urlStr, cookieNameStr);
}
CEF_EXPORT int cef_visit_storage(enum cef_storage_type_t type,
const cef_string_t* origin, const cef_string_t* key,
struct _cef_storage_visitor_t* visitor)
{
CefString originStr, keyStr;
if (origin)
originStr = origin;
if (key)
keyStr = key;
return CefVisitStorage(type, originStr, keyStr,
CefStorageVisitorCToCpp::Wrap(visitor));
}
CEF_EXPORT int cef_set_storage(enum cef_storage_type_t type,
const cef_string_t* origin, const cef_string_t* key,
const cef_string_t* value)
{
CefString originStr, keyStr, valueStr;
if (origin)
originStr = origin;
if (key)
keyStr = key;
if (value)
valueStr = value;
return CefSetStorage(type, originStr, keyStr, valueStr);
}
CEF_EXPORT int cef_delete_storage(enum cef_storage_type_t type,
const cef_string_t* origin, const cef_string_t* key)
{
CefString originStr, keyStr;
if (origin)
originStr = origin;
if (key)
keyStr = key;
return CefDeleteStorage(type, origin, key);
}

View File

@ -14,6 +14,7 @@
#include "libcef_dll/cpptoc/read_handler_cpptoc.h"
#include "libcef_dll/cpptoc/scheme_handler_cpptoc.h"
#include "libcef_dll/cpptoc/scheme_handler_factory_cpptoc.h"
#include "libcef_dll/cpptoc/storage_visitor_cpptoc.h"
#include "libcef_dll/cpptoc/task_cpptoc.h"
#include "libcef_dll/cpptoc/v8accessor_cpptoc.h"
#include "libcef_dll/cpptoc/v8handler_cpptoc.h"
@ -54,6 +55,7 @@ void CefShutdown()
DCHECK(CefReadHandlerCppToC::DebugObjCt == 0);
DCHECK(CefSchemeHandlerCppToC::DebugObjCt == 0);
DCHECK(CefSchemeHandlerFactoryCppToC::DebugObjCt == 0);
DCHECK(CefStorageVisitorCppToC::DebugObjCt == 0);
DCHECK(CefV8AccessorCppToC::DebugObjCt == 0);
DCHECK(CefV8HandlerCppToC::DebugObjCt == 0);
DCHECK(CefWebURLRequestClientCppToC::DebugObjCt == 0);
@ -202,3 +204,25 @@ bool CefDeleteCookies(const CefString& url, const CefString& cookie_name)
return cef_delete_cookies(url.GetStruct(), cookie_name.GetStruct()) ?
true : false;
}
bool CefVisitStorage(CefStorageType type, const CefString& origin,
const CefString& key,
CefRefPtr<CefStorageVisitor> visitor)
{
return cef_visit_storage(type, origin.GetStruct(), key.GetStruct(),
CefStorageVisitorCppToC::Wrap(visitor)) ? true : false;
}
bool CefSetStorage(CefStorageType type, const CefString& origin,
const CefString& key, const CefString& value)
{
return cef_set_storage(type, origin.GetStruct(), key.GetStruct(),
value.GetStruct()) ? true : false;
}
bool CefDeleteStorage(CefStorageType type, const CefString& origin,
const CefString& key)
{
return cef_delete_storage(type, origin.GetStruct(), key.GetStruct()) ?
true : false;
}

View File

@ -0,0 +1,394 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "include/cef.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "test_handler.h"
namespace {
static const char* kOrigin = "http://tests";
static const char* kNav1 = "http://tests/nav1.html";
static const char* kNav2 = "http://tests/nav2.html";
static const char* kKey1 = "foo";
static const char* kVal1 = "bar";
static const char* kKey2 = "choo";
static const char* kVal2 = "whatzit";
class StorageTestHandler : public TestHandler
{
public:
class V8Handler : public CefV8Handler
{
public:
V8Handler(CefRefPtr<StorageTestHandler> tester)
: tester_(tester) {}
virtual bool Execute(const CefString& name,
CefRefPtr<CefV8Value> object,
const CefV8ValueList& arguments,
CefRefPtr<CefV8Value>& retval,
CefString& exception) OVERRIDE
{
if (arguments.size() != 2)
return false;
std::string key = arguments[0]->GetStringValue();
std::string val = arguments[1]->GetStringValue();
if (key == kKey1 && val == kVal1)
tester_->got_js_read1_.yes();
else if (key == kKey2 && val == kVal2)
tester_->got_js_read2_.yes();
return true;
}
CefRefPtr<StorageTestHandler> tester_;
IMPLEMENT_REFCOUNTING(V8Handler);
};
class StorageVisitor : public CefStorageVisitor
{
public:
enum Mode {
VisitKey,
DeleteKey1,
DeleteKey2
};
StorageVisitor(CefRefPtr<StorageTestHandler> tester,
const std::string& description, Mode mode,
TrackCallback* callback1, TrackCallback* callback2,
int expected_total)
: tester_(tester), description_(description), mode_(mode),
callback1_(callback1), callback2_(callback2),
expected_total_(expected_total), actual_total_(0)
{
}
virtual ~StorageVisitor()
{
EXPECT_EQ(expected_total_, actual_total_) << "test = "<< description_;
}
virtual bool Visit(CefStorageType type, const CefString& origin,
const CefString& key, const CefString& value, int count,
int total, bool& deleteData) OVERRIDE
{
EXPECT_EQ(type, tester_->type_);
std::string originStr = origin;
EXPECT_EQ(originStr, kOrigin);
std::string keyStr = key;
std::string valueStr = value;
if (keyStr == kKey1 && valueStr == kVal1)
callback1_->yes();
else if(keyStr == kKey2 && valueStr == kVal2)
callback2_->yes();
EXPECT_EQ(expected_total_, total) << "test = "<< description_;
if((mode_ == DeleteKey1 && keyStr == kKey1) ||
(mode_ == DeleteKey2 && keyStr == kKey2))
deleteData = true;
actual_total_++;
return true;
}
CefRefPtr<StorageTestHandler> tester_;
std::string description_;
Mode mode_;
TrackCallback* callback1_;
TrackCallback* callback2_;
int expected_total_;
int actual_total_;
IMPLEMENT_REFCOUNTING(StorageVisitor);
};
StorageTestHandler(CefStorageType type)
: type_(type), nav_(0) {}
virtual void RunTest() OVERRIDE
{
std::stringstream ss;
std::string func = (type_==ST_LOCALSTORAGE?"localStorage":"sessionStorage");
// Values will be set vis JS on page load.
ss << "<html><head><script language=\"JavaScript\">" <<
func << ".setItem('" << std::string(kKey1) << "', '" <<
std::string(kVal1) << "');" <<
func << ".setItem('" << std::string(kKey2) << "', '" <<
std::string(kVal2) << "');"
"</script></head><body>Nav1</body></html>";
AddResource(kNav1, ss.str(), "text/html");
ss.str("");
// Values will be verified vis JS on page load.
ss << "<html><head><script language=\"JavaScript\">"
"window.test.result('" << std::string(kKey1) << "', " <<
func << ".getItem('" << std::string(kKey1) << "'));"
"window.test.result('" << std::string(kKey2) << "', " <<
func << ".getItem('" << std::string(kKey2) << "'));"
"</script></head><body>Nav2</body></html>";
AddResource(kNav2, ss.str(), "text/html");
ss.str("");
// Create the browser.
CreateBrowser(kNav1);
}
virtual void OnLoadEnd(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
int httpStatusCode) OVERRIDE
{
if (nav_ == 0) {
// Verify read all.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "all_read",
StorageVisitor::VisitKey,
&got_cpp_all_read1_,
&got_cpp_all_read2_, 2));
// Verify read origin.
CefVisitStorage(type_, kOrigin, "",
new StorageVisitor(this, "origin_read",
StorageVisitor::VisitKey,
&got_cpp_origin_read1_,
&got_cpp_origin_read2_, 2));
// Verify read key1.
CefVisitStorage(type_, kOrigin, kKey1,
new StorageVisitor(this, "key1_read",
StorageVisitor::VisitKey,
&got_cpp_key_read1_,
&got_cpp_key_read1_fail_, 1));
// Verify read key2.
CefVisitStorage(type_, kOrigin, kKey2,
new StorageVisitor(this, "key2_read",
StorageVisitor::VisitKey,
&got_cpp_key_read2_fail_,
&got_cpp_key_read2_, 1));
// Delete key1. Verify that key2 still gets read.
CefVisitStorage(type_, kOrigin, "",
new StorageVisitor(this, "key1_delete",
StorageVisitor::DeleteKey1,
&got_cpp_key_delete1_delete_,
&got_cpp_key_delete1_, 2));
// Verify that key1 was deleted.
CefVisitStorage(type_, kOrigin, "",
new StorageVisitor(this, "key1_delete_verify",
StorageVisitor::VisitKey,
&got_cpp_afterdeletevisit1_fail_,
&got_cpp_afterdeletevisit1_, 1));
// Delete key2.
CefVisitStorage(type_, kOrigin, "",
new StorageVisitor(this, "key2_delete",
StorageVisitor::DeleteKey2,
&got_cpp_key_delete2_fail_,
&got_cpp_key_delete2_delete_, 1));
// Verify that all keys have been deleted.
CefVisitStorage(type_, kOrigin, "",
new StorageVisitor(this, "key2_delete_verify",
StorageVisitor::VisitKey,
&got_cpp_afterdeletevisit2_fail_,
&got_cpp_afterdeletevisit2_fail_, 0));
// Reset the values.
CefSetStorage(type_, kOrigin, kKey1, kVal1);
CefSetStorage(type_, kOrigin, kKey2, kVal2);
// Verify that all values have been reset.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "reset1a_verify",
StorageVisitor::VisitKey,
&got_cpp_all_reset1a_,
&got_cpp_all_reset2a_, 2));
// Delete all values.
CefDeleteStorage(type_, "", "");
// Verify that all values have been deleted.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "delete_all_verify",
StorageVisitor::VisitKey,
&got_cpp_afterdeleteall_fail_,
&got_cpp_afterdeleteall_fail_, 0));
// Reset all values.
CefSetStorage(type_, kOrigin, kKey1, kVal1);
CefSetStorage(type_, kOrigin, kKey2, kVal2);
// Verify that all values have been reset.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "reset1b_verify",
StorageVisitor::VisitKey,
&got_cpp_all_reset1b_,
&got_cpp_all_reset2b_, 2));
// Delete all values by origin.
CefDeleteStorage(type_, kOrigin, "");
// Verify that all values have been deleted.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "delete_origin_verify",
StorageVisitor::VisitKey,
&got_cpp_afterdeleteorigin_fail_,
&got_cpp_afterdeleteorigin_fail_, 0));
// Reset the values.
CefSetStorage(type_, kOrigin, kKey1, kVal1);
CefSetStorage(type_, kOrigin, kKey2, kVal2);
// Verify that all values have been reset.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "reset1c_verify",
StorageVisitor::VisitKey,
&got_cpp_all_reset1c_,
&got_cpp_all_reset2c_, 2));
// Delete key1.
CefDeleteStorage(type_, kOrigin, kKey1);
// Verify that key1 has been deleted.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "direct_key1_delete_verify",
StorageVisitor::VisitKey,
&got_cpp_afterdeletekey1_fail_,
&got_cpp_afterdeletekey1_, 1));
// Delete key2.
CefDeleteStorage(type_, kOrigin, kKey2);
// Verify that all values have been deleted.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "direct_key2_delete_verify",
StorageVisitor::VisitKey,
&got_cpp_afterdeletekey2_fail_,
&got_cpp_afterdeletekey2_fail_, 0));
// Reset all values.
CefSetStorage(type_, kOrigin, kKey1, kVal1);
CefSetStorage(type_, kOrigin, kKey2, kVal2);
// Verify that all values have been reset.
CefVisitStorage(type_, "", "",
new StorageVisitor(this, "reset1d_verify",
StorageVisitor::VisitKey,
&got_cpp_all_reset1d_,
&got_cpp_all_reset2d_, 2));
nav_++;
// Verify JS read after navigation.
frame->LoadURL(kNav2);
} else {
DestroyTest();
}
}
virtual void OnJSBinding(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefFrame> frame,
CefRefPtr<CefV8Value> object) OVERRIDE
{
CefRefPtr<CefV8Handler> handler = new V8Handler(this);
CefRefPtr<CefV8Value> testObj = CefV8Value::CreateObject(NULL, NULL);
testObj->SetValue("result", CefV8Value::CreateFunction("result", handler));
object->SetValue("test", testObj);
}
CefStorageType type_;
int nav_;
TrackCallback got_cpp_all_read1_;
TrackCallback got_cpp_all_read2_;
TrackCallback got_cpp_origin_read1_;
TrackCallback got_cpp_origin_read2_;
TrackCallback got_cpp_key_read1_;
TrackCallback got_cpp_key_read1_fail_;
TrackCallback got_cpp_key_read2_;
TrackCallback got_cpp_key_read2_fail_;
TrackCallback got_cpp_key_delete1_;
TrackCallback got_cpp_key_delete1_delete_;
TrackCallback got_cpp_key_delete2_delete_;
TrackCallback got_cpp_key_delete2_fail_;
TrackCallback got_cpp_afterdeletevisit1_;
TrackCallback got_cpp_afterdeletevisit1_fail_;
TrackCallback got_cpp_afterdeletevisit2_fail_;
TrackCallback got_cpp_all_reset1a_;
TrackCallback got_cpp_all_reset2a_;
TrackCallback got_cpp_afterdeleteall_fail_;
TrackCallback got_cpp_all_reset1b_;
TrackCallback got_cpp_all_reset2b_;
TrackCallback got_cpp_afterdeleteorigin_fail_;
TrackCallback got_cpp_all_reset1c_;
TrackCallback got_cpp_all_reset2c_;
TrackCallback got_cpp_afterdeletekey1_;
TrackCallback got_cpp_afterdeletekey1_fail_;
TrackCallback got_cpp_afterdeletekey2_fail_;
TrackCallback got_cpp_all_reset1d_;
TrackCallback got_cpp_all_reset2d_;
TrackCallback got_js_read1_;
TrackCallback got_js_read2_;
};
void StorageTest(CefStorageType type)
{
CefRefPtr<StorageTestHandler> handler = new StorageTestHandler(type);
handler->ExecuteTest();
EXPECT_TRUE(handler->got_cpp_all_read1_);
EXPECT_TRUE(handler->got_cpp_all_read2_);
EXPECT_TRUE(handler->got_cpp_origin_read1_);
EXPECT_TRUE(handler->got_cpp_origin_read2_);
EXPECT_TRUE(handler->got_cpp_key_read1_);
EXPECT_FALSE(handler->got_cpp_key_read1_fail_);
EXPECT_TRUE(handler->got_cpp_key_read2_);
EXPECT_FALSE(handler->got_cpp_key_read2_fail_);
EXPECT_TRUE(handler->got_cpp_key_delete1_);
EXPECT_TRUE(handler->got_cpp_key_delete1_delete_);
EXPECT_TRUE(handler->got_cpp_key_delete2_delete_);
EXPECT_FALSE(handler->got_cpp_key_delete2_fail_);
EXPECT_TRUE(handler->got_cpp_afterdeletevisit1_);
EXPECT_FALSE(handler->got_cpp_afterdeletevisit1_fail_);
EXPECT_FALSE(handler->got_cpp_afterdeletevisit2_fail_);
EXPECT_TRUE(handler->got_cpp_all_reset1a_);
EXPECT_TRUE(handler->got_cpp_all_reset2a_);
EXPECT_FALSE(handler->got_cpp_afterdeleteall_fail_);
EXPECT_TRUE(handler->got_cpp_all_reset1b_);
EXPECT_TRUE(handler->got_cpp_all_reset2b_);
EXPECT_FALSE(handler->got_cpp_afterdeleteorigin_fail_);
EXPECT_TRUE(handler->got_cpp_all_reset1c_);
EXPECT_TRUE(handler->got_cpp_all_reset2c_);
EXPECT_TRUE(handler->got_cpp_afterdeletekey1_);
EXPECT_FALSE(handler->got_cpp_afterdeletekey1_fail_);
EXPECT_FALSE(handler->got_cpp_afterdeletekey2_fail_);
EXPECT_TRUE(handler->got_cpp_all_reset1d_);
EXPECT_TRUE(handler->got_cpp_all_reset2d_);
EXPECT_TRUE(handler->got_js_read1_);
EXPECT_TRUE(handler->got_js_read2_);
}
} // namespace
// Test localStorage.
TEST(StorageTest, Local)
{
StorageTest(ST_LOCALSTORAGE);
}
// Test sessionStorage.
TEST(StorageTest, Session)
{
StorageTest(ST_SESSIONSTORAGE);
}

View File

@ -0,0 +1,39 @@
// Copyright (c) 2011 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that
// can be found in the LICENSE file.
#include "include/cef.h"
#include "test_suite.h"
#include "base/command_line.h"
#include "build/build_config.h"
#include "base/threading/platform_thread.h"
#include "base/test/test_suite.h"
CefTestSuite::CefTestSuite(int argc, char** argv) : TestSuite(argc, argv) {
}
void CefTestSuite::Initialize() {
TestSuite::Initialize();
CefSettings settings;
settings.multi_threaded_message_loop = true;
CommandLine* command_line = CommandLine::ForCurrentProcess();
if (command_line->HasSwitch("cache_path")) {
// Set the cache_path value.
std::string cache_path = command_line->GetSwitchValueASCII("cache_path");
CefString(&settings.cache_path).FromASCII(cache_path.c_str());
}
CefInitialize(settings);
}
void CefTestSuite::Shutdown() {
// Delay a bit so that the system has a chance to finish destroying windows
// before CefShutdown() checks for memory leaks.
base::PlatformThread::Sleep(500);
CefShutdown();
TestSuite::Shutdown();
}

View File

@ -1,38 +1,19 @@
// Copyright (c) 2009 The Chromium Embedded Framework Authors. All rights
// Copyright (c) 2011 The Chromium Embedded Framework 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 _CEF_TEST_SUITE_H
#define _CEF_TEST_SUITE_H
#include "build/build_config.h"
#include "base/threading/platform_thread.h"
#include "base/test/test_suite.h"
#include "include/cef.h"
class CefTestSuite : public TestSuite {
public:
CefTestSuite(int argc, char** argv) : TestSuite(argc, argv) {
}
public:
CefTestSuite(int argc, char** argv);
protected:
virtual void Initialize() {
TestSuite::Initialize();
CefSettings settings;
settings.multi_threaded_message_loop = true;
CefInitialize(settings);
}
virtual void Shutdown() {
// Delay a bit so that the system has a chance to finish destroying windows
// before CefShutdown() checks for memory leaks.
base::PlatformThread::Sleep(500);
CefShutdown();
TestSuite::Shutdown();
}
protected:
virtual void Initialize();
virtual void Shutdown();
};
#endif // _CEF_TEST_SUITE_H