Fix crash using CefCookieManager::SetStoragePath (issue #2522)

This commit is contained in:
Marshall Greenblatt 2018-10-08 18:57:14 +03:00
parent b472a8d9ea
commit 00188c7052
10 changed files with 230 additions and 141 deletions

View File

@ -403,6 +403,8 @@ static_library("libcef_static") {
"libcef/browser/net/chrome_scheme_handler.h",
"libcef/browser/net/cookie_store_proxy.cc",
"libcef/browser/net/cookie_store_proxy.h",
"libcef/browser/net/cookie_store_source.cc",
"libcef/browser/net/cookie_store_source.h",
"libcef/browser/net/crlset_file_util_impl.cc",
"libcef/browser/net/devtools_scheme_handler.cc",
"libcef/browser/net/devtools_scheme_handler.h",

View File

@ -10,19 +10,18 @@
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/context.h"
#include "libcef/browser/net/cookie_store_source.h"
#include "libcef/browser/net/network_delegate.h"
#include "libcef/common/task_runner_impl.h"
#include "libcef/common/time_util.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "base/format_macros.h"
#include "base/logging.h"
#include "base/threading/thread_restrictions.h"
#include "content/browser/storage_partition_impl.h"
#include "net/cookies/cookie_util.h"
#include "net/cookies/parsed_cookie.h"
#include "net/extras/sqlite/sqlite_persistent_cookie_store.h"
#include "net/url_request/url_request_context.h"
#include "url/gurl.h"
@ -162,7 +161,7 @@ void CefCookieManagerImpl::GetCookieStore(
return;
}
DCHECK(is_blocking_ || cookie_store_.get());
DCHECK(is_blocking_ || cookie_source_);
// Binding ref-counted |this| to CookieStoreGetter may result in
// heap-use-after-free if (a) the CookieStoreGetter contains the last
@ -185,8 +184,8 @@ void CefCookieManagerImpl::GetCookieStore(
net::CookieStore* CefCookieManagerImpl::GetExistingCookieStore() {
CEF_REQUIRE_IOT();
if (cookie_store_.get()) {
return cookie_store_.get();
if (cookie_source_) {
return cookie_source_->GetCookieStore();
} else if (request_context_impl_.get()) {
net::CookieStore* cookie_store =
request_context_impl_->GetExistingCookieStore();
@ -287,44 +286,13 @@ bool CefCookieManagerImpl::SetStoragePath(
if (!path.empty())
new_path = base::FilePath(path);
if (cookie_store_.get() &&
((storage_path_.empty() && path.empty()) || storage_path_ == new_path)) {
// The path has not changed so don't do anything.
RunAsyncCompletionOnIOThread(callback);
return true;
if (!cookie_source_) {
cookie_source_.reset(new CefCookieStoreOwnerSource());
}
scoped_refptr<net::SQLitePersistentCookieStore> persistent_store;
if (!new_path.empty()) {
// TODO(cef): Move directory creation to the blocking pool instead of
// allowing file IO on this thread.
base::ThreadRestrictions::ScopedAllowIO allow_io;
if (base::DirectoryExists(new_path) || base::CreateDirectory(new_path)) {
const base::FilePath& cookie_path = new_path.AppendASCII("Cookies");
persistent_store = new net::SQLitePersistentCookieStore(
cookie_path, BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
// Intentionally using the background task runner exposed by CEF to
// facilitate unit test expectations. This task runner MUST be
// configured with BLOCK_SHUTDOWN.
CefContentBrowserClient::Get()->background_task_runner(),
persist_session_cookies, NULL);
} else {
NOTREACHED() << "The cookie storage directory could not be created";
storage_path_.clear();
}
}
// 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_store_.reset(new net::CookieMonster(persistent_store.get(), NULL));
if (persistent_store.get() && persist_session_cookies)
cookie_store_->SetPersistSessionCookies(true);
storage_path_ = new_path;
// Restore the previously supported schemes.
SetSupportedSchemesInternal(supported_schemes_, callback);
cookie_source_->SetCookieStoragePath(new_path, persist_session_cookies);
RunAsyncCompletionOnIOThread(callback);
return true;
}
@ -502,10 +470,9 @@ void CefCookieManagerImpl::SetSupportedSchemesInternal(
return;
}
DCHECK(is_blocking_ || cookie_store_.get());
if (cookie_store_) {
supported_schemes_ = schemes;
SetCookieMonsterSchemes(cookie_store_.get(), supported_schemes_);
DCHECK(is_blocking_ || cookie_source_);
if (cookie_source_) {
cookie_source_->SetCookieSupportedSchemes(schemes);
}
RunAsyncCompletionOnIOThread(callback);

View File

@ -15,6 +15,8 @@
#include "base/memory/weak_ptr.h"
#include "net/cookies/cookie_monster.h"
class CefCookieStoreOwnerSource;
// Implementation of the CefCookieManager interface.
class CefCookieManagerImpl : public CefCookieManager {
public:
@ -122,9 +124,7 @@ class CefCookieManagerImpl : public CefCookieManager {
scoped_refptr<CefURLRequestContextGetterImpl> request_context_impl_;
// Used for cookie monsters owned by this object.
base::FilePath storage_path_;
std::vector<std::string> supported_schemes_;
std::unique_ptr<net::CookieMonster> cookie_store_;
std::unique_ptr<CefCookieStoreOwnerSource> cookie_source_;
// Must be the last member.
base::WeakPtrFactory<CefCookieManagerImpl> weak_ptr_factory_;

View File

@ -4,12 +4,12 @@
#include "libcef/browser/net/cookie_store_proxy.h"
#include "libcef/browser/cookie_manager_impl.h"
#include "libcef/browser/net/url_request_context_impl.h"
#include "include/cef_request_context.h"
#include "libcef/browser/net/cookie_store_source.h"
#include "libcef/browser/thread_util.h"
#include "base/logging.h"
#include "net/url_request/url_request_context.h"
#include "net/cookies/cookie_change_dispatcher.h"
namespace {
@ -44,12 +44,10 @@ class NullCookieChangeDispatcher : public net::CookieChangeDispatcher {
} // namespace
CefCookieStoreProxy::CefCookieStoreProxy(
CefURLRequestContextImpl* parent,
CefRefPtr<CefRequestContextHandler> handler)
: parent_(parent), handler_(handler) {
std::unique_ptr<CefCookieStoreSource> source)
: source_(std::move(source)) {
CEF_REQUIRE_IOT();
DCHECK(parent_);
DCHECK(handler_.get());
DCHECK(source_);
}
CefCookieStoreProxy::~CefCookieStoreProxy() {
@ -189,24 +187,5 @@ bool CefCookieStoreProxy::IsEphemeral() {
net::CookieStore* CefCookieStoreProxy::GetCookieStore() {
CEF_REQUIRE_IOT();
CefRefPtr<CefCookieManager> manager = handler_->GetCookieManager();
if (manager.get()) {
// Use the cookie store provided by the manager. May be nullptr if the
// cookie manager is blocking.
return reinterpret_cast<CefCookieManagerImpl*>(manager.get())
->GetExistingCookieStore();
}
DCHECK(parent_);
if (parent_) {
// Use the cookie store from the parent.
net::CookieStore* cookie_store = parent_->cookie_store();
DCHECK(cookie_store);
if (!cookie_store)
LOG(ERROR) << "Cookie store does not exist";
return cookie_store;
}
return nullptr;
return source_->GetCookieStore();
}

View File

@ -6,19 +6,15 @@
#define CEF_LIBCEF_BROWSER_COOKIE_STORE_PROXY_H_
#pragma once
#include "include/cef_request_context_handler.h"
#include "net/cookies/cookie_store.h"
class CefURLRequestContextImpl;
class CefCookieStoreSource;
// Proxies cookie requests to the CefRequestContextHandler or global cookie
// store. Life span is controlled by CefURLRequestContextProxy. Only accessed on
// the IO thread. See browser_context.h for an object relationship diagram.
// Proxies cookie requests to a CefCookieStoreSource (see comments on the
// implementation classes for details). Only accessed on the IO thread.
class CefCookieStoreProxy : public net::CookieStore {
public:
CefCookieStoreProxy(CefURLRequestContextImpl* parent,
CefRefPtr<CefRequestContextHandler> handler);
explicit CefCookieStoreProxy(std::unique_ptr<CefCookieStoreSource> source);
~CefCookieStoreProxy() override;
// net::CookieStore methods.
@ -52,11 +48,7 @@ class CefCookieStoreProxy : public net::CookieStore {
private:
net::CookieStore* GetCookieStore();
// The |parent_| pointer is kept alive by CefURLRequestContextGetterProxy
// which has a ref to the owning CefURLRequestContextGetterImpl.
CefURLRequestContextImpl* parent_;
CefRefPtr<CefRequestContextHandler> handler_;
std::unique_ptr<CefCookieStoreSource> const source_;
std::unique_ptr<net::CookieChangeDispatcher> null_dispatcher_;
DISALLOW_COPY_AND_ASSIGN(CefCookieStoreProxy);

View File

@ -0,0 +1,110 @@
// Copyright (c) 2018 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/browser/net/cookie_store_source.h"
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/cookie_manager_impl.h"
#include "libcef/browser/net/url_request_context_impl.h"
#include "libcef/browser/thread_util.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "net/extras/sqlite/sqlite_persistent_cookie_store.h"
CefCookieStoreHandlerSource::CefCookieStoreHandlerSource(
CefURLRequestContextImpl* parent,
CefRefPtr<CefRequestContextHandler> handler)
: parent_(parent), handler_(handler) {
DCHECK(parent_);
DCHECK(handler_);
}
net::CookieStore* CefCookieStoreHandlerSource::GetCookieStore() {
CEF_REQUIRE_IOT();
CefRefPtr<CefCookieManager> manager = handler_->GetCookieManager();
if (manager) {
// Use the cookie store provided by the manager. May be nullptr if the
// cookie manager is blocking.
return reinterpret_cast<CefCookieManagerImpl*>(manager.get())
->GetExistingCookieStore();
}
DCHECK(parent_);
if (parent_) {
// Use the cookie store from the parent.
net::CookieStore* cookie_store = parent_->cookie_store();
DCHECK(cookie_store);
if (!cookie_store)
LOG(ERROR) << "Cookie store does not exist";
return cookie_store;
}
return nullptr;
}
CefCookieStoreOwnerSource::CefCookieStoreOwnerSource() {}
void CefCookieStoreOwnerSource::SetCookieStoragePath(
const base::FilePath& path,
bool persist_session_cookies) {
CEF_REQUIRE_IOT();
if (cookie_store_ && ((path_.empty() && path.empty()) || path_ == path)) {
// The path has not changed so don't do anything.
return;
}
scoped_refptr<net::SQLitePersistentCookieStore> persistent_store;
if (!path.empty()) {
// TODO(cef): Move directory creation to the blocking pool instead of
// allowing file IO on this thread.
base::ThreadRestrictions::ScopedAllowIO allow_io;
if (base::DirectoryExists(path) || base::CreateDirectory(path)) {
const base::FilePath& cookie_path = path.AppendASCII("Cookies");
persistent_store = new net::SQLitePersistentCookieStore(
cookie_path,
content::BrowserThread::GetTaskRunnerForThread(
content::BrowserThread::IO),
// Intentionally using the background task runner exposed by CEF to
// facilitate unit test expectations. This task runner MUST be
// configured with BLOCK_SHUTDOWN.
CefContentBrowserClient::Get()->background_task_runner(),
persist_session_cookies, NULL);
} else {
NOTREACHED() << "The cookie storage directory could not be created";
}
}
// 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.
std::unique_ptr<net::CookieMonster> cookie_monster(
new net::CookieMonster(persistent_store.get(), nullptr));
if (persistent_store.get() && persist_session_cookies)
cookie_monster->SetPersistSessionCookies(true);
path_ = path;
// Restore the previously supported schemes.
CefCookieManagerImpl::SetCookieMonsterSchemes(cookie_monster.get(),
supported_schemes_);
cookie_store_ = std::move(cookie_monster);
}
void CefCookieStoreOwnerSource::SetCookieSupportedSchemes(
const std::vector<std::string>& schemes) {
CEF_REQUIRE_IOT();
supported_schemes_ = schemes;
CefCookieManagerImpl::SetCookieMonsterSchemes(
static_cast<net::CookieMonster*>(cookie_store_.get()),
supported_schemes_);
}
net::CookieStore* CefCookieStoreOwnerSource::GetCookieStore() {
CEF_REQUIRE_IOT();
return cookie_store_.get();
}

View File

@ -0,0 +1,73 @@
// Copyright (c) 2018 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_LIBCEF_BROWSER_COOKIE_STORE_SOURCE_H_
#define CEF_LIBCEF_BROWSER_COOKIE_STORE_SOURCE_H_
#pragma once
#include <memory>
#include <string>
#include <vector>
#include "include/cef_request_context_handler.h"
#include "base/macros.h"
namespace base {
class FilePath;
}
namespace net {
class CookieStore;
}
class CefURLRequestContextImpl;
// Abstract base class for CookieStore sources. Only accessed on the IO thread.
class CefCookieStoreSource {
public:
virtual net::CookieStore* GetCookieStore() = 0;
virtual ~CefCookieStoreSource() {}
};
// Sources a cookie store that is created/owned by a CefCookieManager or the
// parent context. Life span is controlled by CefURLRequestContextProxy. See
// browser_context.h for an object relationship diagram.
class CefCookieStoreHandlerSource : public CefCookieStoreSource {
public:
CefCookieStoreHandlerSource(CefURLRequestContextImpl* parent,
CefRefPtr<CefRequestContextHandler> handler);
net::CookieStore* GetCookieStore() override;
private:
// The |parent_| pointer is kept alive by CefURLRequestContextGetterProxy
// which has a ref to the owning CefURLRequestContextGetterImpl.
CefURLRequestContextImpl* parent_;
CefRefPtr<CefRequestContextHandler> handler_;
DISALLOW_COPY_AND_ASSIGN(CefCookieStoreHandlerSource);
};
// Sources a cookie store that is created/owned by this object. Life span is
// controlled by the owning URLRequestContext.
class CefCookieStoreOwnerSource : public CefCookieStoreSource {
public:
CefCookieStoreOwnerSource();
void SetCookieStoragePath(const base::FilePath& path,
bool persist_session_cookies);
void SetCookieSupportedSchemes(const std::vector<std::string>& schemes);
net::CookieStore* GetCookieStore() override;
private:
std::unique_ptr<net::CookieStore> cookie_store_;
base::FilePath path_;
std::vector<std::string> supported_schemes_;
DISALLOW_COPY_AND_ASSIGN(CefCookieStoreOwnerSource);
};
#endif // CEF_LIBCEF_BROWSER_COOKIE_STORE_SOURCE_H_

View File

@ -10,6 +10,8 @@
#include "libcef/browser/content_browser_client.h"
#include "libcef/browser/cookie_manager_impl.h"
#include "libcef/browser/net/cookie_store_proxy.h"
#include "libcef/browser/net/cookie_store_source.h"
#include "libcef/browser/net/network_delegate.h"
#include "libcef/browser/net/scheme_handler.h"
#include "libcef/browser/net/url_request_interceptor.h"
@ -18,7 +20,6 @@
#include "libcef/common/content_client.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/stl_util.h"
@ -43,7 +44,6 @@
#include "net/cert/multi_log_ct_verifier.h"
#include "net/cookies/cookie_monster.h"
#include "net/dns/host_resolver.h"
#include "net/extras/sqlite/sqlite_persistent_cookie_store.h"
#include "net/ftp/ftp_network_layer.h"
#include "net/http/http_auth_handler_factory.h"
#include "net/http/http_auth_preferences.h"
@ -473,57 +473,21 @@ void CefURLRequestContextGetterImpl::SetCookieStoragePath(
const base::FilePath& path,
bool persist_session_cookies) {
CEF_REQUIRE_IOT();
if (io_state_->url_request_context_->cookie_store() &&
((io_state_->cookie_store_path_.empty() && path.empty()) ||
io_state_->cookie_store_path_ == path)) {
// The path has not changed so don't do anything.
return;
if (!io_state_->cookie_source_) {
// Use a proxy because we can't change the URLRequestContext's CookieStore
// during runtime.
io_state_->cookie_source_ = new CefCookieStoreOwnerSource();
io_state_->storage_->set_cookie_store(std::make_unique<CefCookieStoreProxy>(
base::WrapUnique(io_state_->cookie_source_)));
}
scoped_refptr<net::SQLitePersistentCookieStore> persistent_store;
if (!path.empty()) {
// TODO(cef): Move directory creation to the blocking pool instead of
// allowing file IO on this thread.
base::ThreadRestrictions::ScopedAllowIO allow_io;
if (base::DirectoryExists(path) || base::CreateDirectory(path)) {
const base::FilePath& cookie_path = path.AppendASCII("Cookies");
persistent_store = new net::SQLitePersistentCookieStore(
cookie_path, BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
// Intentionally using the background task runner exposed by CEF to
// facilitate unit test expectations. This task runner MUST be
// configured with BLOCK_SHUTDOWN.
CefContentBrowserClient::Get()->background_task_runner(),
persist_session_cookies, NULL);
} else {
NOTREACHED() << "The cookie storage directory could not be created";
}
}
// 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.
std::unique_ptr<net::CookieMonster> cookie_monster(
new net::CookieMonster(persistent_store.get(), NULL));
if (persistent_store.get() && persist_session_cookies)
cookie_monster->SetPersistSessionCookies(true);
io_state_->cookie_store_path_ = path;
// Restore the previously supported schemes.
CefCookieManagerImpl::SetCookieMonsterSchemes(
cookie_monster.get(), io_state_->cookie_supported_schemes_);
io_state_->storage_->set_cookie_store(std::move(cookie_monster));
io_state_->cookie_source_->SetCookieStoragePath(path,
persist_session_cookies);
}
void CefURLRequestContextGetterImpl::SetCookieSupportedSchemes(
const std::vector<std::string>& schemes) {
CEF_REQUIRE_IOT();
io_state_->cookie_supported_schemes_ = schemes;
CefCookieManagerImpl::SetCookieMonsterSchemes(
static_cast<net::CookieMonster*>(GetExistingCookieStore()),
io_state_->cookie_supported_schemes_);
io_state_->cookie_source_->SetCookieSupportedSchemes(schemes);
}
void CefURLRequestContextGetterImpl::AddHandler(
@ -540,9 +504,8 @@ void CefURLRequestContextGetterImpl::AddHandler(
net::CookieStore* CefURLRequestContextGetterImpl::GetExistingCookieStore()
const {
CEF_REQUIRE_IOT();
if (io_state_->url_request_context_ &&
io_state_->url_request_context_->cookie_store()) {
return io_state_->url_request_context_->cookie_store();
if (io_state_->cookie_source_) {
return io_state_->cookie_source_->GetCookieStore();
}
LOG(ERROR) << "Cookie store does not exist";

View File

@ -22,6 +22,7 @@
#include "content/public/browser/browser_context.h"
#include "net/url_request/url_request_job_factory.h"
class CefCookieStoreOwnerSource;
class PrefRegistrySimple;
class PrefService;
@ -113,8 +114,8 @@ class CefURLRequestContextGetterImpl : public CefURLRequestContextGetter {
content::ProtocolHandlerMap protocol_handlers_;
content::URLRequestInterceptorScopedVector request_interceptors_;
base::FilePath cookie_store_path_;
std::vector<std::string> cookie_supported_schemes_;
// Owned by the URLRequestContextStorage.
CefCookieStoreOwnerSource* cookie_source_ = nullptr;
std::vector<CefRefPtr<CefRequestContextHandler>> handler_list_;

View File

@ -5,6 +5,7 @@
#include "libcef/browser/net/url_request_context_proxy.h"
#include "libcef/browser/net/cookie_store_proxy.h"
#include "libcef/browser/net/cookie_store_source.h"
#include "libcef/browser/net/url_request_context_impl.h"
#include "libcef/browser/thread_util.h"
@ -16,7 +17,8 @@ CefURLRequestContextProxy::CefURLRequestContextProxy(
DCHECK(handler.get());
// Cookie store that proxies to the browser implementation.
cookie_store_proxy_.reset(new CefCookieStoreProxy(parent, handler));
cookie_store_proxy_.reset(new CefCookieStoreProxy(
std::make_unique<CefCookieStoreHandlerSource>(parent, handler)));
set_cookie_store(cookie_store_proxy_.get());
// All other values refer to the parent request context.