283 lines
8.7 KiB
C++
283 lines
8.7 KiB
C++
|
// Copyright (c) 2012 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 "libcef/cookie_manager_impl.h"
|
||
|
|
||
|
#include <string>
|
||
|
|
||
|
#include "libcef/cef_context.h"
|
||
|
#include "libcef/cef_thread.h"
|
||
|
#include "libcef/cef_time_util.h"
|
||
|
|
||
|
#include "base/bind.h"
|
||
|
#include "base/logging.h"
|
||
|
#include "chrome/browser/net/sqlite_persistent_cookie_store.h"
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
// Callback class for visiting cookies.
|
||
|
class VisitCookiesCallback : public base::RefCounted<VisitCookiesCallback> {
|
||
|
public:
|
||
|
explicit VisitCookiesCallback(net::CookieMonster* cookie_monster,
|
||
|
CefRefPtr<CefCookieVisitor> visitor)
|
||
|
: cookie_monster_(cookie_monster),
|
||
|
visitor_(visitor) {
|
||
|
}
|
||
|
|
||
|
void Run(const net::CookieList& list) {
|
||
|
REQUIRE_IOT();
|
||
|
|
||
|
int total = list.size(), count = 0;
|
||
|
|
||
|
net::CookieList::const_iterator it = list.begin();
|
||
|
for (; it != list.end(); ++it, ++count) {
|
||
|
CefCookie cookie;
|
||
|
const net::CanonicalCookie& cc = *(it);
|
||
|
|
||
|
CefString(&cookie.name).FromString(cc.Name());
|
||
|
CefString(&cookie.value).FromString(cc.Value());
|
||
|
CefString(&cookie.domain).FromString(cc.Domain());
|
||
|
CefString(&cookie.path).FromString(cc.Path());
|
||
|
cookie.secure = cc.IsSecure();
|
||
|
cookie.httponly = cc.IsHttpOnly();
|
||
|
cef_time_from_basetime(cc.CreationDate(), cookie.creation);
|
||
|
cef_time_from_basetime(cc.LastAccessDate(), cookie.last_access);
|
||
|
cookie.has_expires = cc.IsPersistent();
|
||
|
if (cookie.has_expires)
|
||
|
cef_time_from_basetime(cc.ExpiryDate(), cookie.expires);
|
||
|
|
||
|
bool deleteCookie = false;
|
||
|
bool keepLooping = visitor_->Visit(cookie, count, total, deleteCookie);
|
||
|
if (deleteCookie) {
|
||
|
cookie_monster_->DeleteCanonicalCookieAsync(cc,
|
||
|
net::CookieMonster::DeleteCookieCallback());
|
||
|
}
|
||
|
if (!keepLooping)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
scoped_refptr<net::CookieMonster> cookie_monster_;
|
||
|
CefRefPtr<CefCookieVisitor> visitor_;
|
||
|
};
|
||
|
|
||
|
} // namespace
|
||
|
|
||
|
|
||
|
CefCookieManagerImpl::CefCookieManagerImpl(bool is_global)
|
||
|
: is_global_(is_global) {
|
||
|
if (is_global) {
|
||
|
cookie_monster_ =
|
||
|
static_cast<net::CookieMonster*>(
|
||
|
_Context->request_context()->cookie_store());
|
||
|
DCHECK(cookie_monster_);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CefCookieManagerImpl::~CefCookieManagerImpl() {
|
||
|
}
|
||
|
|
||
|
void CefCookieManagerImpl::SetSupportedSchemes(
|
||
|
const std::vector<CefString>& schemes) {
|
||
|
if (CefThread::CurrentlyOn(CefThread::IO)) {
|
||
|
if (schemes.empty())
|
||
|
return;
|
||
|
|
||
|
std::set<std::string> scheme_set;
|
||
|
std::vector<CefString>::const_iterator it = schemes.begin();
|
||
|
for (; it != schemes.end(); ++it)
|
||
|
scheme_set.insert(*it);
|
||
|
|
||
|
const char** arr = new const char*[scheme_set.size()];
|
||
|
std::set<std::string>::const_iterator it2 = scheme_set.begin();
|
||
|
for (int i = 0; it2 != scheme_set.end(); ++it2, ++i)
|
||
|
arr[i] = it2->c_str();
|
||
|
|
||
|
cookie_monster_->SetCookieableSchemes(arr, scheme_set.size());
|
||
|
|
||
|
delete [] arr;
|
||
|
} else {
|
||
|
// Execute on the IO thread.
|
||
|
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||
|
base::Bind(&CefCookieManagerImpl::SetSupportedSchemes,
|
||
|
this, schemes));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool CefCookieManagerImpl::VisitAllCookies(
|
||
|
CefRefPtr<CefCookieVisitor> visitor) {
|
||
|
if (CefThread::CurrentlyOn(CefThread::IO)) {
|
||
|
scoped_refptr<VisitCookiesCallback> callback(
|
||
|
new VisitCookiesCallback(cookie_monster_, visitor));
|
||
|
|
||
|
cookie_monster_->GetAllCookiesAsync(
|
||
|
base::Bind(&VisitCookiesCallback::Run, callback.get()));
|
||
|
} else {
|
||
|
// Execute on the IO thread.
|
||
|
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||
|
base::Bind(base::IgnoreResult(&CefCookieManagerImpl::VisitAllCookies),
|
||
|
this, visitor));
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool CefCookieManagerImpl::VisitUrlCookies(
|
||
|
const CefString& url, bool includeHttpOnly,
|
||
|
CefRefPtr<CefCookieVisitor> visitor) {
|
||
|
if (CefThread::CurrentlyOn(CefThread::IO)) {
|
||
|
net::CookieOptions options;
|
||
|
if (includeHttpOnly)
|
||
|
options.set_include_httponly();
|
||
|
|
||
|
scoped_refptr<VisitCookiesCallback> callback(
|
||
|
new VisitCookiesCallback(cookie_monster_, visitor));
|
||
|
|
||
|
GURL gurl = GURL(url.ToString());
|
||
|
cookie_monster_->GetAllCookiesForURLWithOptionsAsync(gurl, options,
|
||
|
base::Bind(&VisitCookiesCallback::Run, callback.get()));
|
||
|
} else {
|
||
|
// Execute on the IO thread.
|
||
|
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||
|
base::Bind(base::IgnoreResult(&CefCookieManagerImpl::VisitUrlCookies),
|
||
|
this, url, includeHttpOnly, visitor));
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool CefCookieManagerImpl::SetCookie(const CefString& url,
|
||
|
const CefCookie& cookie) {
|
||
|
// Verify that this function is being called on the IO thread.
|
||
|
if (!CefThread::CurrentlyOn(CefThread::IO)) {
|
||
|
NOTREACHED() << "called on invalid thread";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
GURL gurl = GURL(url.ToString());
|
||
|
if (!gurl.is_valid())
|
||
|
return false;
|
||
|
|
||
|
std::string name = CefString(&cookie.name).ToString();
|
||
|
std::string value = CefString(&cookie.value).ToString();
|
||
|
std::string domain = CefString(&cookie.domain).ToString();
|
||
|
std::string path = CefString(&cookie.path).ToString();
|
||
|
|
||
|
base::Time expiration_time;
|
||
|
if (cookie.has_expires)
|
||
|
cef_time_to_basetime(cookie.expires, expiration_time);
|
||
|
|
||
|
cookie_monster_->SetCookieWithDetailsAsync(gurl, name, value, domain, path,
|
||
|
expiration_time, cookie.secure, cookie.httponly,
|
||
|
net::CookieStore::SetCookiesCallback());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool CefCookieManagerImpl::DeleteCookies(const CefString& url,
|
||
|
const CefString& cookie_name) {
|
||
|
// Verify that this function is being called on the IO thread.
|
||
|
if (!CefThread::CurrentlyOn(CefThread::IO)) {
|
||
|
NOTREACHED() << "called on invalid thread";
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (url.empty()) {
|
||
|
// Delete all cookies.
|
||
|
cookie_monster_->DeleteAllAsync(net::CookieMonster::DeleteCallback());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
GURL gurl = GURL(url.ToString());
|
||
|
if (!gurl.is_valid())
|
||
|
return false;
|
||
|
|
||
|
if (cookie_name.empty()) {
|
||
|
// Delete all matching host cookies.
|
||
|
cookie_monster_->DeleteAllForHostAsync(gurl,
|
||
|
net::CookieMonster::DeleteCallback());
|
||
|
} else {
|
||
|
// Delete all matching host and domain cookies.
|
||
|
cookie_monster_->DeleteCookieAsync(gurl, cookie_name, base::Closure());
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool CefCookieManagerImpl::SetStoragePath(const CefString& path) {
|
||
|
if (CefThread::CurrentlyOn(CefThread::IO)) {
|
||
|
FilePath new_path;
|
||
|
if (!path.empty())
|
||
|
new_path = FilePath(path);
|
||
|
|
||
|
if (is_global_) {
|
||
|
// Global path changes are handled by the request context.
|
||
|
_Context->request_context()->SetCookieStoragePath(new_path);
|
||
|
cookie_monster_ =
|
||
|
static_cast<net::CookieMonster*>(
|
||
|
_Context->request_context()->cookie_store());
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
if (cookie_monster_ && ((storage_path_.empty() && path.empty()) ||
|
||
|
storage_path_ == new_path)) {
|
||
|
// The path has not changed so don't do anything.
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
scoped_refptr<SQLitePersistentCookieStore> persistent_store;
|
||
|
if (!new_path.empty()) {
|
||
|
if (!file_util::PathExists(new_path) &&
|
||
|
!file_util::CreateDirectory(new_path)) {
|
||
|
NOTREACHED() << "Failed to create cookie storage directory";
|
||
|
new_path.clear();
|
||
|
} else {
|
||
|
FilePath cookie_path = new_path.Append(FILE_PATH_LITERAL("Cookies"));
|
||
|
persistent_store =
|
||
|
new SQLitePersistentCookieStore(cookie_path, false, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Set the new cookie store that will be used for all new requests. The old
|
||
|
// cookie store, if any, will be automatically flushed and closed when no
|
||
|
// longer referenced.
|
||
|
cookie_monster_ = new net::CookieMonster(persistent_store.get(), NULL);
|
||
|
storage_path_ = new_path;
|
||
|
} else {
|
||
|
// Execute on the IO thread.
|
||
|
CefThread::PostTask(CefThread::IO, FROM_HERE,
|
||
|
base::Bind(base::IgnoreResult(&CefCookieManagerImpl::SetStoragePath),
|
||
|
this, path));
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
// CefCookieManager methods ----------------------------------------------------
|
||
|
|
||
|
// static
|
||
|
CefRefPtr<CefCookieManager> CefCookieManager::GetGlobalManager() {
|
||
|
// Verify that the context is in a valid state.
|
||
|
if (!CONTEXT_STATE_VALID()) {
|
||
|
NOTREACHED() << "context not valid";
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return new CefCookieManagerImpl(true);
|
||
|
}
|
||
|
|
||
|
// static
|
||
|
CefRefPtr<CefCookieManager> CefCookieManager::CreateManager(
|
||
|
const CefString& path) {
|
||
|
// Verify that the context is in a valid state.
|
||
|
if (!CONTEXT_STATE_VALID()) {
|
||
|
NOTREACHED() << "context not valid";
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
CefRefPtr<CefCookieManager> manager(new CefCookieManagerImpl(false));
|
||
|
manager->SetStoragePath(path);
|
||
|
return manager;
|
||
|
}
|