summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--android_webview/BUILD.gn2
-rw-r--r--android_webview/android_webview.gyp2
-rw-r--r--android_webview/android_webview_tests.gypi1
-rw-r--r--android_webview/browser/aw_browser_context.cc6
-rw-r--r--android_webview/browser/aw_browser_context.h5
-rw-r--r--android_webview/browser/net/aw_cookie_store_wrapper.cc357
-rw-r--r--android_webview/browser/net/aw_cookie_store_wrapper.h132
-rw-r--r--android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc49
-rw-r--r--android_webview/browser/net/aw_url_request_context_getter.cc5
-rw-r--r--android_webview/browser/net/aw_url_request_context_getter.h1
-rw-r--r--android_webview/browser/net/init_native_callback.h14
-rw-r--r--android_webview/native/cookie_manager.cc257
-rw-r--r--android_webview/test/BUILD.gn1
13 files changed, 681 insertions, 151 deletions
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index c9505c3..d3efe00 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -446,6 +446,8 @@ source_set("common") {
"browser/jni_dependency_factory.h",
"browser/net/android_stream_reader_url_request_job.cc",
"browser/net/android_stream_reader_url_request_job.h",
+ "browser/net/aw_cookie_store_wrapper.cc",
+ "browser/net/aw_cookie_store_wrapper.h",
"browser/net/aw_http_user_agent_settings.cc",
"browser/net/aw_http_user_agent_settings.h",
"browser/net/aw_network_change_notifier.cc",
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp
index f9cd183..8378d0e 100644
--- a/android_webview/android_webview.gyp
+++ b/android_webview/android_webview.gyp
@@ -350,6 +350,8 @@
'browser/gl_view_renderer_manager.h',
'browser/net/android_stream_reader_url_request_job.cc',
'browser/net/android_stream_reader_url_request_job.h',
+ 'browser/net/aw_cookie_store_wrapper.cc',
+ 'browser/net/aw_cookie_store_wrapper.h',
'browser/net/aw_http_user_agent_settings.h',
'browser/net/aw_http_user_agent_settings.cc',
'browser/net/aw_network_change_notifier.cc',
diff --git a/android_webview/android_webview_tests.gypi b/android_webview/android_webview_tests.gypi
index 6a2cf65..ab92ffc 100644
--- a/android_webview/android_webview_tests.gypi
+++ b/android_webview/android_webview_tests.gypi
@@ -146,6 +146,7 @@
'browser/aw_form_database_service_unittest.cc',
'browser/browser_view_renderer_unittest.cc',
'browser/net/android_stream_reader_url_request_job_unittest.cc',
+ 'browser/net/aw_cookie_store_wrapper_unittest.cc',
'browser/net/input_stream_reader_unittest.cc',
'browser/test/fake_window.cc',
'browser/test/fake_window.h',
diff --git a/android_webview/browser/aw_browser_context.cc b/android_webview/browser/aw_browser_context.cc
index a5e985f..02aa751 100644
--- a/android_webview/browser/aw_browser_context.cc
+++ b/android_webview/browser/aw_browser_context.cc
@@ -15,7 +15,6 @@
#include "android_webview/browser/aw_resource_context.h"
#include "android_webview/browser/jni_dependency_factory.h"
#include "android_webview/browser/net/aw_url_request_context_getter.h"
-#include "android_webview/browser/net/init_native_callback.h"
#include "android_webview/common/aw_content_client.h"
#include "base/base_paths_android.h"
#include "base/bind.h"
@@ -42,7 +41,6 @@
#include "content/public/browser/ssl_host_state_delegate.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/browser/web_contents.h"
-#include "net/cookies/cookie_store.h"
#include "net/proxy/proxy_config_service_android.h"
#include "net/proxy/proxy_service.h"
@@ -182,7 +180,6 @@ void AwBrowserContext::SetLegacyCacheRemovalDelayForTest(int delay_ms) {
}
void AwBrowserContext::PreMainMessageLoopRun() {
- cookie_store_ = CreateCookieStore(this);
FilePath cache_path;
const FilePath fallback_cache_dir =
GetPath().Append(FILE_PATH_LITERAL("Cache"));
@@ -205,8 +202,7 @@ void AwBrowserContext::PreMainMessageLoopRun() {
InitUserPrefService();
url_request_context_getter_ = new AwURLRequestContextGetter(
- cache_path, cookie_store_.get(), CreateProxyConfigService(),
- user_pref_service_.get());
+ cache_path, CreateProxyConfigService(), user_pref_service_.get());
data_reduction_proxy_io_data_.reset(
new data_reduction_proxy::DataReductionProxyIOData(
diff --git a/android_webview/browser/aw_browser_context.h b/android_webview/browser/aw_browser_context.h
index 94f9f57..84f477d 100644
--- a/android_webview/browser/aw_browser_context.h
+++ b/android_webview/browser/aw_browser_context.h
@@ -37,10 +37,6 @@ class DataReductionProxyService;
class DataReductionProxySettings;
}
-namespace net {
-class CookieStore;
-}
-
namespace policy {
class URLBlacklistManager;
class BrowserPolicyConnectorBase;
@@ -149,7 +145,6 @@ class AwBrowserContext : public content::BrowserContext,
base::FilePath context_storage_path_;
JniDependencyFactory* native_factory_;
- scoped_refptr<net::CookieStore> cookie_store_;
scoped_refptr<AwURLRequestContextGetter> url_request_context_getter_;
scoped_refptr<AwQuotaManagerBridge> quota_manager_bridge_;
scoped_ptr<AwFormDatabaseService> form_database_service_;
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.cc b/android_webview/browser/net/aw_cookie_store_wrapper.cc
new file mode 100644
index 0000000..6b9b063
--- /dev/null
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.cc
@@ -0,0 +1,357 @@
+// Copyright 2016 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.
+
+#include "android_webview/browser/net/aw_cookie_store_wrapper.h"
+
+#include <string>
+
+#include "android_webview/browser/net/init_native_callback.h"
+#include "base/memory/ref_counted_delete_on_message_loop.h"
+#include "base/thread_task_runner_handle.h"
+#include "url/gurl.h"
+
+namespace android_webview {
+
+namespace {
+
+// Posts |task| to the thread that the global CookieStore lives on.
+void PostTaskToCookieStoreTaskRunner(const base::Closure& task) {
+ GetCookieStoreTaskRunner()->PostTask(FROM_HERE, task);
+}
+
+// Wraps a subscription to cookie change notifications for the global
+// CookieStore for a consumer that lives on another thread. Handles passing
+// messages between thread, and destroys itself when the consumer unsubscribes.
+// Must be created on the consumer's thread. Each instance only supports a
+// single subscription.
+class SubscriptionWrapper {
+ public:
+ SubscriptionWrapper() : weak_factory_(this) {}
+
+ scoped_ptr<net::CookieStore::CookieChangedSubscription> Subscribe(
+ const GURL& url,
+ const std::string& name,
+ const net::CookieStore::CookieChangedCallback& callback) {
+ // This class is only intended to be used for a single subscription.
+ DCHECK(callback_list_.empty());
+
+ nested_subscription_ =
+ new NestedSubscription(url, name, weak_factory_.GetWeakPtr());
+ return callback_list_.Add(callback);
+ }
+
+ private:
+ // The NestedSubscription is responsible for creating and managing the
+ // underlying subscription to the real CookieStore, and posting notifications
+ // back to |callback_list_|.
+ class NestedSubscription
+ : public base::RefCountedDeleteOnMessageLoop<NestedSubscription> {
+ public:
+ NestedSubscription(const GURL& url,
+ const std::string& name,
+ base::WeakPtr<SubscriptionWrapper> subscription_wrapper)
+ : base::RefCountedDeleteOnMessageLoop<NestedSubscription>(
+ GetCookieStoreTaskRunner()),
+ subscription_wrapper_(subscription_wrapper),
+ client_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&NestedSubscription::Subscribe, this, url, name));
+ }
+
+ private:
+ friend class base::RefCountedDeleteOnMessageLoop<NestedSubscription>;
+ friend class base::DeleteHelper<NestedSubscription>;
+
+ ~NestedSubscription() {}
+
+ void Subscribe(const GURL& url, const std::string& name) {
+ GetCookieStore()->AddCallbackForCookie(
+ url, name, base::Bind(&NestedSubscription::OnChanged, this));
+ }
+
+ void OnChanged(const net::CanonicalCookie& cookie, bool removed) {
+ client_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&SubscriptionWrapper::OnChanged,
+ subscription_wrapper_, cookie, removed));
+ }
+
+ base::WeakPtr<SubscriptionWrapper> subscription_wrapper_;
+ scoped_refptr<base::TaskRunner> client_task_runner_;
+
+ scoped_ptr<net::CookieStore::CookieChangedSubscription> subscription_;
+
+ DISALLOW_COPY_AND_ASSIGN(NestedSubscription);
+ };
+
+ void OnChanged(const net::CanonicalCookie& cookie, bool removed) {
+ callback_list_.Notify(cookie, removed);
+ }
+
+ // The "list" only had one entry, so can just clean up now.
+ void OnUnsubscribe() { delete this; }
+
+ scoped_refptr<NestedSubscription> nested_subscription_;
+ net::CookieStore::CookieChangedCallbackList callback_list_;
+ base::WeakPtrFactory<SubscriptionWrapper> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(SubscriptionWrapper);
+};
+
+void SetCookieWithOptionsAsyncOnCookieThread(
+ const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options,
+ const net::CookieStore::SetCookiesCallback& callback) {
+ GetCookieStore()->SetCookieWithOptionsAsync(url, cookie_line, options,
+ callback);
+}
+
+void SetCookieWithDetailsAsyncOnCookieThread(
+ const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ base::Time creation_time,
+ base::Time expiration_time,
+ base::Time last_access_time,
+ bool secure,
+ bool http_only,
+ bool same_site,
+ bool enforce_strict_secure,
+ net::CookiePriority priority,
+ const net::CookieStore::SetCookiesCallback& callback) {
+ GetCookieStore()->SetCookieWithDetailsAsync(
+ url, name, value, domain, path, creation_time, expiration_time,
+ last_access_time, secure, http_only, same_site, enforce_strict_secure,
+ priority, callback);
+}
+
+void GetCookiesWithOptionsAsyncOnCookieThread(
+ const GURL& url,
+ const net::CookieOptions& options,
+ const net::CookieStore::GetCookiesCallback& callback) {
+ GetCookieStore()->GetCookiesWithOptionsAsync(url, options, callback);
+}
+
+void GetCookieListWithOptionsAsyncOnCookieThread(
+ const GURL& url,
+ const net::CookieOptions& options,
+ const net::CookieStore::GetCookieListCallback& callback) {
+ GetCookieStore()->GetCookieListWithOptionsAsync(url, options, callback);
+}
+
+void GetAllCookiesAsyncOnCookieThread(
+ const net::CookieStore::GetCookieListCallback& callback) {
+ GetCookieStore()->GetAllCookiesAsync(callback);
+}
+
+void DeleteCookieAsyncOnCookieThread(const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) {
+ GetCookieStore()->DeleteCookieAsync(url, cookie_name, callback);
+}
+
+void DeleteCanonicalCookieAsyncOnCookieThread(
+ const net::CanonicalCookie& cookie,
+ const net::CookieStore::DeleteCallback& callback) {
+ GetCookieStore()->DeleteCanonicalCookieAsync(cookie, callback);
+}
+
+void DeleteAllCreatedBetweenAsyncOnCookieThread(
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const net::CookieStore::DeleteCallback& callback) {
+ GetCookieStore()->DeleteAllCreatedBetweenAsync(delete_begin, delete_end,
+ callback);
+}
+
+void DeleteAllCreatedBetweenForHostAsyncOnCookieThread(
+ const base::Time delete_begin,
+ const base::Time delete_end,
+ const GURL& url,
+ const net::CookieStore::DeleteCallback& callback) {
+ GetCookieStore()->DeleteAllCreatedBetweenForHostAsync(
+ delete_begin, delete_end, url, callback);
+}
+
+void DeleteSessionCookiesAsyncOnCookieThread(
+ const net::CookieStore::DeleteCallback& callback) {
+ GetCookieStore()->DeleteSessionCookiesAsync(callback);
+}
+
+void FlushStoreOnCookieThread(const base::Closure& callback) {
+ GetCookieStore()->FlushStore(callback);
+}
+
+void SetForceKeepSessionStateOnCookieThread() {
+ GetCookieStore()->SetForceKeepSessionState();
+}
+
+} // namespace
+
+AwCookieStoreWrapper::AwCookieStoreWrapper()
+ : client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
+ weak_factory_(this) {}
+
+void AwCookieStoreWrapper::SetCookieWithOptionsAsync(
+ const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options,
+ const net::CookieStore::SetCookiesCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&SetCookieWithOptionsAsyncOnCookieThread, url, cookie_line,
+ options, CreateWrappedCallback<bool>(callback)));
+}
+
+void AwCookieStoreWrapper::SetCookieWithDetailsAsync(
+ const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ base::Time creation_time,
+ base::Time expiration_time,
+ base::Time last_access_time,
+ bool secure,
+ bool http_only,
+ bool same_site,
+ bool enforce_strict_secure,
+ net::CookiePriority priority,
+ const SetCookiesCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&SetCookieWithDetailsAsyncOnCookieThread, url, name, value,
+ domain, path, creation_time, expiration_time, last_access_time,
+ secure, http_only, same_site, enforce_strict_secure, priority,
+ CreateWrappedCallback<bool>(callback)));
+}
+
+void AwCookieStoreWrapper::GetCookiesWithOptionsAsync(
+ const GURL& url,
+ const net::CookieOptions& options,
+ const GetCookiesCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&GetCookiesWithOptionsAsyncOnCookieThread, url, options,
+ CreateWrappedCallback<const std::string&>(callback)));
+}
+
+void AwCookieStoreWrapper::GetCookieListWithOptionsAsync(
+ const GURL& url,
+ const net::CookieOptions& options,
+ const GetCookieListCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&GetCookieListWithOptionsAsyncOnCookieThread, url, options,
+ CreateWrappedCallback<const net::CookieList&>(callback)));
+}
+
+void AwCookieStoreWrapper::GetAllCookiesAsync(
+ const GetCookieListCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&GetAllCookiesAsyncOnCookieThread,
+ CreateWrappedCallback<const net::CookieList&>(callback)));
+}
+
+void AwCookieStoreWrapper::DeleteCookieAsync(const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&DeleteCookieAsyncOnCookieThread, url, cookie_name,
+ CreateWrappedClosureCallback(callback)));
+}
+
+void AwCookieStoreWrapper::DeleteCanonicalCookieAsync(
+ const net::CanonicalCookie& cookie,
+ const DeleteCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&DeleteCanonicalCookieAsyncOnCookieThread, cookie,
+ CreateWrappedCallback<int>(callback)));
+}
+
+void AwCookieStoreWrapper::DeleteAllCreatedBetweenAsync(
+ const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const DeleteCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&DeleteAllCreatedBetweenAsyncOnCookieThread, delete_begin,
+ delete_end, CreateWrappedCallback<int>(callback)));
+}
+
+void AwCookieStoreWrapper::DeleteAllCreatedBetweenForHostAsync(
+ const base::Time delete_begin,
+ const base::Time delete_end,
+ const GURL& url,
+ const DeleteCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(base::Bind(
+ &DeleteAllCreatedBetweenForHostAsyncOnCookieThread, delete_begin,
+ delete_end, url, CreateWrappedCallback<int>(callback)));
+}
+
+void AwCookieStoreWrapper::DeleteSessionCookiesAsync(
+ const DeleteCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&DeleteSessionCookiesAsyncOnCookieThread,
+ CreateWrappedCallback<int>(callback)));
+}
+
+void AwCookieStoreWrapper::FlushStore(const base::Closure& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(base::Bind(
+ &FlushStoreOnCookieThread, CreateWrappedClosureCallback(callback)));
+}
+
+void AwCookieStoreWrapper::SetForceKeepSessionState() {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ PostTaskToCookieStoreTaskRunner(
+ base::Bind(&SetForceKeepSessionStateOnCookieThread));
+}
+
+net::CookieMonster* AwCookieStoreWrapper::GetCookieMonster() {
+ return nullptr;
+}
+
+scoped_ptr<net::CookieStore::CookieChangedSubscription>
+AwCookieStoreWrapper::AddCallbackForCookie(
+ const GURL& url,
+ const std::string& name,
+ const CookieChangedCallback& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+
+ // The SubscriptionWrapper is owned by the subscription itself, and has no
+ // connection to the AwCookieStoreWrapper after creation. Other CookieStore
+ // implementations DCHECK if a subscription outlasts the cookie store,
+ // unfortunately, this design makes DCHECKing if there's an outstanding
+ // subscription when the AwCookieStoreWrapper is destroyed a bit ugly.
+ // TODO(mmenke): Still worth adding a DCHECK?
+ SubscriptionWrapper* subscription = new SubscriptionWrapper();
+ return subscription->Subscribe(url, name, callback);
+}
+
+AwCookieStoreWrapper::~AwCookieStoreWrapper() {}
+
+base::Closure AwCookieStoreWrapper::CreateWrappedClosureCallback(
+ const base::Closure& callback) {
+ if (callback.is_null())
+ return callback;
+ return base::Bind(base::IgnoreResult(&base::TaskRunner::PostTask),
+ client_task_runner_, FROM_HERE,
+ base::Bind(&AwCookieStoreWrapper::RunClosureCallback,
+ weak_factory_.GetWeakPtr(), callback));
+}
+
+void AwCookieStoreWrapper::RunClosureCallback(const base::Closure& callback) {
+ DCHECK(client_task_runner_->RunsTasksOnCurrentThread());
+ callback.Run();
+}
+
+} // namespace android_webview
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper.h b/android_webview/browser/net/aw_cookie_store_wrapper.h
new file mode 100644
index 0000000..e308fb1
--- /dev/null
+++ b/android_webview/browser/net/aw_cookie_store_wrapper.h
@@ -0,0 +1,132 @@
+// Copyright 2016 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.
+
+#include <string>
+
+#include "base/bind.h"
+#include "base/location.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/weak_ptr.h"
+#include "base/single_thread_task_runner.h"
+#include "base/task_runner.h"
+#include "base/time/time.h"
+#include "net/cookies/canonical_cookie.h"
+#include "net/cookies/cookie_constants.h"
+#include "net/cookies/cookie_store.h"
+
+namespace android_webview {
+
+// A cross-threaded cookie store implementation that wraps the CookieManager's
+// CookieStore. It posts tasks to the CookieStore's thread, and invokes
+// callbacks on the originating thread. Deleting it cancels pending callbacks.
+// This is needed to allow Webview to run the CookieStore on its own thread, to
+// enable synchronous calls into the store on the IO Thread from Java.
+//
+// AwCookieStoreWrapper will only grab the CookieStore pointer from the
+// CookieManager when it's needed, allowing for lazy creation of the
+// CookieStore.
+//
+// AwCookieStoreWrapper may only be called from the thread on which it's
+// created.
+//
+// The CookieManager must outlive the AwCookieStoreWrapper.
+class AwCookieStoreWrapper : public net::CookieStore {
+ public:
+ AwCookieStoreWrapper();
+
+ // CookieStore implementation:
+ void SetCookieWithOptionsAsync(const GURL& url,
+ const std::string& cookie_line,
+ const net::CookieOptions& options,
+ const SetCookiesCallback& callback) override;
+ void SetCookieWithDetailsAsync(const GURL& url,
+ const std::string& name,
+ const std::string& value,
+ const std::string& domain,
+ const std::string& path,
+ base::Time creation_time,
+ base::Time expiration_time,
+ base::Time last_access_time,
+ bool secure,
+ bool http_only,
+ bool same_site,
+ bool enforce_strict_secure,
+ net::CookiePriority priority,
+ const SetCookiesCallback& callback) override;
+ void GetCookiesWithOptionsAsync(const GURL& url,
+ const net::CookieOptions& options,
+ const GetCookiesCallback& callback) override;
+ void GetCookieListWithOptionsAsync(
+ const GURL& url,
+ const net::CookieOptions& options,
+ const GetCookieListCallback& callback) override;
+ void GetAllCookiesAsync(const GetCookieListCallback& callback) override;
+ void DeleteCookieAsync(const GURL& url,
+ const std::string& cookie_name,
+ const base::Closure& callback) override;
+ void DeleteCanonicalCookieAsync(const net::CanonicalCookie& cookie,
+ const DeleteCallback& callback) override;
+ void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
+ const base::Time& delete_end,
+ const DeleteCallback& callback) override;
+ void DeleteAllCreatedBetweenForHostAsync(
+ const base::Time delete_begin,
+ const base::Time delete_end,
+ const GURL& url,
+ const DeleteCallback& callback) override;
+ void DeleteSessionCookiesAsync(const DeleteCallback& callback) override;
+ void FlushStore(const base::Closure& callback) override;
+ void SetForceKeepSessionState() override;
+ net::CookieMonster* GetCookieMonster() override;
+ scoped_ptr<CookieChangedSubscription> AddCallbackForCookie(
+ const GURL& url,
+ const std::string& name,
+ const CookieChangedCallback& callback) override;
+
+ private:
+ ~AwCookieStoreWrapper() override;
+
+ // Used by CreateWrappedCallback below. Takes an arugment of Type and posts
+ // a task to |task_runner| to invoke |callback| with that argument. If
+ // |weak_cookie_store| is deleted before the task is run, the task will not
+ // be run.
+ template <class Type>
+ static void RunCallbackOnClientThread(
+ base::TaskRunner* task_runner,
+ base::WeakPtr<AwCookieStoreWrapper> weak_cookie_store,
+ base::Callback<void(Type)> callback,
+ Type argument) {
+ task_runner->PostTask(
+ FROM_HERE,
+ base::Bind(&AwCookieStoreWrapper::RunClosureCallback, weak_cookie_store,
+ base::Bind(callback, argument)));
+ }
+
+ // Returns a base::Callback that takes an argument of Type and posts a task to
+ // the |client_task_runner_| to invoke |callback| with that argument.
+ template <class Type>
+ base::Callback<void(Type)> CreateWrappedCallback(
+ base::Callback<void(Type)> callback) {
+ if (callback.is_null())
+ return callback;
+ return base::Bind(&AwCookieStoreWrapper::RunCallbackOnClientThread<Type>,
+ client_task_runner_, weak_factory_.GetWeakPtr(),
+ callback);
+ }
+
+ // Returns a base::Closure that posts a task to the |client_task_runner_| to
+ // invoke |callback|.
+ base::Closure CreateWrappedClosureCallback(const base::Closure& callback);
+
+ // Runs |callback|. Used to prevent callbacks from being invoked after the
+ // AwCookieStoreWrapper has been destroyed.
+ void RunClosureCallback(const base::Closure& callback);
+
+ scoped_refptr<base::SingleThreadTaskRunner> client_task_runner_;
+
+ base::WeakPtrFactory<AwCookieStoreWrapper> weak_factory_;
+};
+
+} // namesspace android_webview
diff --git a/android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc b/android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc
new file mode 100644
index 0000000..3567afc
--- /dev/null
+++ b/android_webview/browser/net/aw_cookie_store_wrapper_unittest.cc
@@ -0,0 +1,49 @@
+// Copyright 2016 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.
+
+#include "android_webview/browser/net/aw_cookie_store_wrapper.h"
+
+#include "base/memory/ref_counted.h"
+#include "net/cookies/cookie_store.h"
+#include "net/cookies/cookie_store_test_callbacks.h"
+#include "net/cookies/cookie_store_unittest.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace android_webview {
+
+struct AwCookieStoreWrapperTestTraits {
+ static scoped_refptr<net::CookieStore> Create() {
+ scoped_refptr<net::CookieStore> cookie_store(new AwCookieStoreWrapper());
+
+ // Android Webview can run multiple tests without restarting the binary,
+ // so have to delete any cookies the global store may have from an earlier
+ // test.
+ net::ResultSavingCookieCallback<int> callback;
+ cookie_store->DeleteAllAsync(
+ base::Bind(&net::ResultSavingCookieCallback<int>::Run,
+ base::Unretained(&callback)));
+ callback.WaitUntilDone();
+
+ return cookie_store;
+ }
+
+ static const bool is_cookie_monster = false;
+ static const bool supports_http_only = true;
+ static const bool supports_non_dotted_domains = true;
+ static const bool preserves_trailing_dots = true;
+ static const bool filters_schemes = true;
+ static const bool has_path_prefix_bug = false;
+ static const int creation_time_granularity_in_ms = 0;
+ static const bool enforce_strict_secure = false;
+};
+
+} // namespace android_webview
+
+// Run the standard cookie tests with AwCookieStoreWrapper. Macro must be in
+// net namespace.
+namespace net {
+INSTANTIATE_TYPED_TEST_CASE_P(AwCookieStoreWrapper,
+ CookieStoreTest,
+ android_webview::AwCookieStoreWrapperTestTraits);
+} // namespace net
diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc
index 7b54fa9..600ea17 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -9,6 +9,7 @@
#include "android_webview/browser/aw_browser_context.h"
#include "android_webview/browser/aw_content_browser_client.h"
+#include "android_webview/browser/net/aw_cookie_store_wrapper.h"
#include "android_webview/browser/net/aw_http_user_agent_settings.h"
#include "android_webview/browser/net/aw_network_delegate.h"
#include "android_webview/browser/net/aw_request_interceptor.h"
@@ -166,13 +167,11 @@ scoped_ptr<net::URLRequestJobFactory> CreateJobFactory(
AwURLRequestContextGetter::AwURLRequestContextGetter(
const base::FilePath& cache_path,
- net::CookieStore* cookie_store,
scoped_ptr<net::ProxyConfigService> config_service,
PrefService* user_pref_service)
: cache_path_(cache_path),
net_log_(new net::NetLog()),
proxy_config_service_(std::move(config_service)),
- cookie_store_(cookie_store),
http_user_agent_settings_(new AwHttpUserAgentSettings()) {
// CreateSystemProxyConfigService for Android must be called on main thread.
DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -201,6 +200,8 @@ void AwURLRequestContextGetter::InitializeURLRequestContext() {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK(!url_request_context_);
+ cookie_store_ = new AwCookieStoreWrapper();
+
net::URLRequestContextBuilder builder;
scoped_ptr<AwNetworkDelegate> aw_network_delegate(new AwNetworkDelegate());
diff --git a/android_webview/browser/net/aw_url_request_context_getter.h b/android_webview/browser/net/aw_url_request_context_getter.h
index 46c2146..763a45c 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.h
+++ b/android_webview/browser/net/aw_url_request_context_getter.h
@@ -36,7 +36,6 @@ class AwURLRequestContextGetter : public net::URLRequestContextGetter {
public:
AwURLRequestContextGetter(
const base::FilePath& cache_path,
- net::CookieStore* cookie_store,
scoped_ptr<net::ProxyConfigService> config_service,
PrefService* pref_service);
diff --git a/android_webview/browser/net/init_native_callback.h b/android_webview/browser/net/init_native_callback.h
index d98867c..34a65c6 100644
--- a/android_webview/browser/net/init_native_callback.h
+++ b/android_webview/browser/net/init_native_callback.h
@@ -8,6 +8,10 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+namespace base {
+class SingleThreadTaskRunner;
+}
+
namespace net {
class CookieStore;
class URLRequestInterceptor;
@@ -16,9 +20,13 @@ class URLRequestInterceptor;
namespace android_webview {
class AwBrowserContext;
-// Called when the CookieMonster needs to be created.
-scoped_refptr<net::CookieStore> CreateCookieStore(
- AwBrowserContext* browser_context);
+// Gets the TaskRunner that the CookieStore must be called on.
+scoped_refptr<base::SingleThreadTaskRunner> GetCookieStoreTaskRunner();
+
+// Gets a pointer to the CookieStore managed by the CookieManager.
+// The CookieStore is never deleted. May only be called on the
+// CookieStore's TaskRunner.
+net::CookieStore* GetCookieStore();
// Called lazily when the job factory is being constructed.
scoped_ptr<net::URLRequestInterceptor>
diff --git a/android_webview/native/cookie_manager.cc b/android_webview/native/cookie_manager.cc
index 08f8246..ebbc67f 100644
--- a/android_webview/native/cookie_manager.cc
+++ b/android_webview/native/cookie_manager.cc
@@ -20,6 +20,7 @@
#include "base/files/file_util.h"
#include "base/lazy_instance.h"
#include "base/location.h"
+#include "base/logging.h"
#include "base/path_service.h"
#include "base/single_thread_task_runner.h"
#include "base/synchronization/lock.h"
@@ -33,6 +34,7 @@
#include "jni/AwCookieManager_jni.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_options.h"
+#include "net/cookies/cookie_store.h"
#include "net/extras/sqlite/cookie_crypto_delegate.h"
#include "net/url_request/url_request_context.h"
#include "url/url_constants.h"
@@ -44,7 +46,6 @@ using base::android::ConvertJavaStringToUTF16;
using base::android::ScopedJavaGlobalRef;
using content::BrowserThread;
using net::CookieList;
-using net::CookieMonster;
// In the future, we may instead want to inject an explicit CookieStore
// dependency into this object during process initialization to avoid
@@ -74,8 +75,8 @@ class BoolCookieCallbackHolder {
void Invoke(bool result) {
if (!callback_.is_null()) {
JNIEnv* env = base::android::AttachCurrentThread();
- Java_AwCookieManager_invokeBooleanCookieCallback(
- env, callback_.obj(), result);
+ Java_AwCookieManager_invokeBooleanCookieCallback(env, callback_.obj(),
+ result);
}
}
@@ -144,19 +145,28 @@ void GetUserDataDir(FilePath* user_data_dir) {
}
}
+// CookieManager creates and owns Webview's CookieStore, in addition to handling
+// calls into the CookieStore from Java.
+//
+// Since Java calls can be made on the IO Thread, and must synchronously return
+// a result, and the CookieStore API allows it to asynchronously return results,
+// the CookieStore must be run on its own thread, to prevent deadlock.
class CookieManager {
public:
static CookieManager* GetInstance();
- scoped_refptr<net::CookieStore> GetCookieStore();
+ // Returns the TaskRunner on which the CookieStore lives.
+ base::SingleThreadTaskRunner* GetCookieStoreTaskRunner();
+ // Returns the CookieStore, creating it if necessary. This must only be called
+ // on the CookieStore TaskRunner.
+ net::CookieStore* GetCookieStore();
void SetShouldAcceptCookies(bool accept);
bool GetShouldAcceptCookies();
void SetCookie(const GURL& host,
const std::string& cookie_value,
scoped_ptr<BoolCookieCallbackHolder> callback);
- void SetCookieSync(const GURL& host,
- const std::string& cookie_value);
+ void SetCookieSync(const GURL& host, const std::string& cookie_value);
std::string GetCookie(const GURL& host);
void RemoveSessionCookies(scoped_ptr<BoolCookieCallbackHolder> callback);
void RemoveAllCookies(scoped_ptr<BoolCookieCallbackHolder> callback);
@@ -179,10 +189,9 @@ class CookieManager {
void ExecCookieTaskSync(const base::Callback<void(base::Closure)>& task);
void ExecCookieTask(const base::Closure& task);
- void SetCookieHelper(
- const GURL& host,
- const std::string& value,
- BoolCallback callback);
+ void SetCookieHelper(const GURL& host,
+ const std::string& value,
+ BoolCallback callback);
void GetCookieValueAsyncHelper(const GURL& host,
std::string* result,
@@ -200,93 +209,58 @@ class CookieManager {
void HasCookiesAsyncHelper(bool* result, base::Closure complete);
void HasCookiesCompleted(base::Closure complete,
bool* result,
- const CookieList& cookies);
+ const net::CookieList& cookies);
- void CreateCookieMonster(
- const FilePath& user_data_dir,
- const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
- const scoped_refptr<base::SequencedTaskRunner>& background_task_runner);
- void EnsureCookieMonsterExistsLocked();
- bool AllowFileSchemeCookiesLocked();
- void SetAcceptFileSchemeCookiesLocked(bool accept);
+ // This protects the following two bools, as they're used on multiple threads.
+ base::Lock accept_file_scheme_cookies_lock_;
+ // True if cookies should be allowed for file URLs. Can only be changed prior
+ // to creating the CookieStore.
+ bool accept_file_scheme_cookies_;
+ // True once the cookie store has been created. Just used to track when
+ // |accept_file_scheme_cookies_| can no longer be modified.
+ bool cookie_store_created_;
- scoped_refptr<net::CookieMonster> cookie_monster_;
- scoped_refptr<base::SingleThreadTaskRunner> cookie_monster_task_runner_;
- base::Lock cookie_monster_lock_;
+ base::Thread cookie_store_client_thread_;
+ base::Thread cookie_store_backend_thread_;
- scoped_ptr<base::Thread> cookie_monster_client_thread_;
- scoped_ptr<base::Thread> cookie_monster_backend_thread_;
+ scoped_refptr<base::SingleThreadTaskRunner> cookie_store_task_runner_;
+ scoped_refptr<net::CookieStore> cookie_store_;
DISALLOW_COPY_AND_ASSIGN(CookieManager);
};
base::LazyInstance<CookieManager>::Leaky g_lazy_instance;
+} // namespace
+
// static
CookieManager* CookieManager::GetInstance() {
return g_lazy_instance.Pointer();
}
-CookieManager::CookieManager() {
+CookieManager::CookieManager()
+ : accept_file_scheme_cookies_(kDefaultFileSchemeAllowed),
+ cookie_store_created_(false),
+ cookie_store_client_thread_("CookieMonsterClient"),
+ cookie_store_backend_thread_("CookieMonsterBackend") {
+ cookie_store_client_thread_.Start();
+ cookie_store_backend_thread_.Start();
+ cookie_store_task_runner_ = cookie_store_client_thread_.task_runner();
}
CookieManager::~CookieManager() {
}
-void CookieManager::CreateCookieMonster(
- const FilePath& user_data_dir,
- const scoped_refptr<base::SequencedTaskRunner>& client_task_runner,
- const scoped_refptr<base::SequencedTaskRunner>& background_task_runner) {
- FilePath cookie_store_path =
- user_data_dir.Append(FILE_PATH_LITERAL("Cookies"));
-
- background_task_runner->PostTask(
- FROM_HERE,
- base::Bind(ImportLegacyCookieStore, cookie_store_path));
-
- content::CookieStoreConfig cookie_config(
- cookie_store_path,
- content::CookieStoreConfig::RESTORED_SESSION_COOKIES,
- NULL, NULL);
- cookie_config.client_task_runner = client_task_runner;
- cookie_config.background_task_runner = background_task_runner;
- net::CookieStore* cookie_store = content::CreateCookieStore(cookie_config);
- cookie_monster_ = cookie_store->GetCookieMonster();
- SetAcceptFileSchemeCookiesLocked(kDefaultFileSchemeAllowed);
-}
-
-void CookieManager::EnsureCookieMonsterExistsLocked() {
- cookie_monster_lock_.AssertAcquired();
- if (cookie_monster_.get()) {
- return;
- }
-
- // Create cookie monster using WebView-specific threads, as the rest of the
- // browser has not been started yet.
- FilePath user_data_dir;
- GetUserDataDir(&user_data_dir);
- cookie_monster_client_thread_.reset(
- new base::Thread("CookieMonsterClient"));
- cookie_monster_client_thread_->Start();
- cookie_monster_task_runner_ = cookie_monster_client_thread_->task_runner();
- cookie_monster_backend_thread_.reset(
- new base::Thread("CookieMonsterBackend"));
- cookie_monster_backend_thread_->Start();
-
- CreateCookieMonster(user_data_dir, cookie_monster_task_runner_,
- cookie_monster_backend_thread_->task_runner());
-}
-
-// Executes the |task| on the |cookie_monster_proxy_| message loop and
-// waits for it to complete before returning.
-
+// Executes the |task| on |cookie_store_task_runner_| and waits for it to
+// complete before returning.
+//
// To execute a CookieTask synchronously you must arrange for Signal to be
// called on the waitable event at some point. You can call the bool or int
// versions of ExecCookieTaskSync, these will supply the caller with a dummy
// callback which takes an int/bool, throws it away and calls Signal.
// Alternatively you can call the version which supplies a Closure in which
// case you must call Run on it when you want the unblock the calling code.
-
+//
// Ignore a bool callback.
void CookieManager::ExecCookieTaskSync(
const base::Callback<void(BoolCallback)>& task) {
@@ -317,17 +291,57 @@ void CookieManager::ExecCookieTaskSync(
completion.Wait();
}
-// Executes the |task| on the |cookie_monster_proxy_| message loop.
+// Executes the |task| using |cookie_store_task_runner_|.
void CookieManager::ExecCookieTask(const base::Closure& task) {
- base::AutoLock lock(cookie_monster_lock_);
- EnsureCookieMonsterExistsLocked();
- cookie_monster_task_runner_->PostTask(FROM_HERE, task);
-}
+ cookie_store_task_runner_->PostTask(FROM_HERE, task);
+}
+
+base::SingleThreadTaskRunner* CookieManager::GetCookieStoreTaskRunner() {
+ return cookie_store_task_runner_.get();
+}
+
+net::CookieStore* CookieManager::GetCookieStore() {
+ DCHECK(cookie_store_task_runner_->RunsTasksOnCurrentThread());
+
+ if (!cookie_store_) {
+ FilePath user_data_dir;
+ GetUserDataDir(&user_data_dir);
+ FilePath cookie_store_path =
+ user_data_dir.Append(FILE_PATH_LITERAL("Cookies"));
+
+ cookie_store_backend_thread_.task_runner()->PostTask(
+ FROM_HERE, base::Bind(ImportLegacyCookieStore, cookie_store_path));
+
+ content::CookieStoreConfig cookie_config(
+ cookie_store_path, content::CookieStoreConfig::RESTORED_SESSION_COOKIES,
+ nullptr, nullptr);
+ cookie_config.client_task_runner = cookie_store_task_runner_;
+ cookie_config.background_task_runner =
+ cookie_store_backend_thread_.task_runner();
+
+ {
+ base::AutoLock lock(accept_file_scheme_cookies_lock_);
+
+ // There are some unknowns about how to correctly handle file:// cookies,
+ // and our implementation for this is not robust. http://crbug.com/582985
+ //
+ // TODO(mmenke): This call should be removed once we can deprecate and
+ // remove the Android WebView 'CookieManager::setAcceptFileSchemeCookies'
+ // method. Until then, note that this is just not a great idea.
+ cookie_config.cookieable_schemes.insert(
+ cookie_config.cookieable_schemes.begin(),
+ net::CookieMonster::kDefaultCookieableSchemes,
+ net::CookieMonster::kDefaultCookieableSchemes +
+ net::CookieMonster::kDefaultCookieableSchemesCount);
+ if (accept_file_scheme_cookies_)
+ cookie_config.cookieable_schemes.push_back(url::kFileScheme);
+ cookie_store_created_ = true;
+ }
+
+ cookie_store_ = content::CreateCookieStore(cookie_config);
+ }
-scoped_refptr<net::CookieStore> CookieManager::GetCookieStore() {
- base::AutoLock lock(cookie_monster_lock_);
- EnsureCookieMonsterExistsLocked();
- return cookie_monster_;
+ return cookie_store_.get();
}
void CookieManager::SetShouldAcceptCookies(bool accept) {
@@ -366,8 +380,7 @@ void CookieManager::SetCookieHelper(
net::CookieOptions options;
options.set_include_httponly();
- cookie_monster_->SetCookieWithOptionsAsync(
- host, value, options, callback);
+ GetCookieStore()->SetCookieWithOptionsAsync(host, value, options, callback);
}
std::string CookieManager::GetCookie(const GURL& host) {
@@ -386,13 +399,9 @@ void CookieManager::GetCookieValueAsyncHelper(
net::CookieOptions options;
options.set_include_httponly();
- cookie_monster_->GetCookiesWithOptionsAsync(
- host,
- options,
- base::Bind(&CookieManager::GetCookieValueCompleted,
- base::Unretained(this),
- complete,
- result));
+ GetCookieStore()->GetCookiesWithOptionsAsync(
+ host, options, base::Bind(&CookieManager::GetCookieValueCompleted,
+ base::Unretained(this), complete, result));
}
void CookieManager::GetCookieValueCompleted(base::Closure complete,
@@ -418,9 +427,8 @@ void CookieManager::RemoveSessionCookiesSync() {
void CookieManager::RemoveSessionCookiesHelper(
BoolCallback callback) {
- cookie_monster_->DeleteSessionCookiesAsync(
- base::Bind(&CookieManager::RemoveCookiesCompleted,
- base::Unretained(this),
+ GetCookieStore()->DeleteSessionCookiesAsync(
+ base::Bind(&CookieManager::RemoveCookiesCompleted, base::Unretained(this),
callback));
}
@@ -446,9 +454,8 @@ void CookieManager::RemoveAllCookiesSync() {
void CookieManager::RemoveAllCookiesHelper(
const BoolCallback callback) {
- cookie_monster_->DeleteAllAsync(
- base::Bind(&CookieManager::RemoveCookiesCompleted,
- base::Unretained(this),
+ GetCookieStore()->DeleteAllAsync(
+ base::Bind(&CookieManager::RemoveCookiesCompleted, base::Unretained(this),
callback));
}
@@ -464,7 +471,7 @@ void CookieManager::FlushCookieStore() {
void CookieManager::FlushCookieStoreAsyncHelper(
base::Closure complete) {
- cookie_monster_->FlushStore(complete);
+ GetCookieStore()->FlushStore(complete);
}
bool CookieManager::HasCookies() {
@@ -479,11 +486,9 @@ bool CookieManager::HasCookies() {
// should not be needed.
void CookieManager::HasCookiesAsyncHelper(bool* result,
base::Closure complete) {
- cookie_monster_->GetAllCookiesAsync(
- base::Bind(&CookieManager::HasCookiesCompleted,
- base::Unretained(this),
- complete,
- result));
+ GetCookieStore()->GetAllCookiesAsync(
+ base::Bind(&CookieManager::HasCookiesCompleted, base::Unretained(this),
+ complete, result));
}
void CookieManager::HasCookiesCompleted(base::Closure complete,
@@ -494,42 +499,17 @@ void CookieManager::HasCookiesCompleted(base::Closure complete,
}
bool CookieManager::AllowFileSchemeCookies() {
- base::AutoLock lock(cookie_monster_lock_);
- EnsureCookieMonsterExistsLocked();
- return AllowFileSchemeCookiesLocked();
-}
-
-bool CookieManager::AllowFileSchemeCookiesLocked() {
- return cookie_monster_->IsCookieableScheme(url::kFileScheme);
+ base::AutoLock lock(accept_file_scheme_cookies_lock_);
+ return accept_file_scheme_cookies_;
}
void CookieManager::SetAcceptFileSchemeCookies(bool accept) {
- base::AutoLock lock(cookie_monster_lock_);
- EnsureCookieMonsterExistsLocked();
- SetAcceptFileSchemeCookiesLocked(accept);
-}
-
-void CookieManager::SetAcceptFileSchemeCookiesLocked(bool accept) {
- // There are some unknowns about how to correctly handle file:// cookies,
- // and our implementation for this is not robust. http://crbug.com/582985
- //
- // TODO(mmenke): This call should be removed once we can deprecate and remove
- // the Android WebView 'CookieManager::setAcceptFileSchemeCookies' method.
- // Until then, note that this is just not a great idea.
- std::vector<std::string> schemes;
- schemes.insert(schemes.begin(),
- net::CookieMonster::kDefaultCookieableSchemes,
- net::CookieMonster::kDefaultCookieableSchemes +
- net::CookieMonster::kDefaultCookieableSchemesCount);
-
- if (accept)
- schemes.push_back(url::kFileScheme);
-
- cookie_monster_->SetCookieableSchemes(schemes);
+ base::AutoLock lock(accept_file_scheme_cookies_lock_);
+ // Can only modify this before the cookie store is created.
+ if (!cookie_store_created_)
+ accept_file_scheme_cookies_ = accept;
}
-} // namespace
-
static void SetShouldAcceptCookies(JNIEnv* env,
const JavaParamRef<jobject>& obj,
jboolean accept) {
@@ -623,8 +603,15 @@ static void SetAcceptFileSchemeCookies(JNIEnv* env,
return CookieManager::GetInstance()->SetAcceptFileSchemeCookies(accept);
}
-scoped_refptr<net::CookieStore> CreateCookieStore(
- AwBrowserContext* browser_context) {
+// The following two methods are used to avoid a circular project dependency.
+// TODO(mmenke): This is weird. Maybe there should be a leaky Singleton in
+// browser/net that creates and owns there?
+
+scoped_refptr<base::SingleThreadTaskRunner> GetCookieStoreTaskRunner() {
+ return CookieManager::GetInstance()->GetCookieStoreTaskRunner();
+}
+
+net::CookieStore* GetCookieStore() {
return CookieManager::GetInstance()->GetCookieStore();
}
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn
index 72f4dd6..92b46fa 100644
--- a/android_webview/test/BUILD.gn
+++ b/android_webview/test/BUILD.gn
@@ -129,6 +129,7 @@ test("android_webview_unittests") {
"../browser/aw_static_cookie_policy_unittest.cc",
"../browser/browser_view_renderer_unittest.cc",
"../browser/net/android_stream_reader_url_request_job_unittest.cc",
+ "../browser/net/aw_cookie_store_wrapper_unittest.cc",
"../browser/net/input_stream_reader_unittest.cc",
"../browser/test/fake_window.cc",
"../browser/test/fake_window.h",