blob: 3e6b3f2b06a3ed88adcf78a80813f1546984e965 [file] [log] [blame]
// 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_sequence.h"
#include "base/threading/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(base::OnceClosure task) {
GetCookieStoreTaskRunner()->PostTask(FROM_HERE, std::move(task));
}
class AwCookieChangedSubscription
: public net::CookieStore::CookieChangedSubscription {
public:
explicit AwCookieChangedSubscription(
std::unique_ptr<net::CookieStore::CookieChangedCallbackList::Subscription>
subscription)
: subscription_(std::move(subscription)) {}
private:
std::unique_ptr<net::CookieStore::CookieChangedCallbackList::Subscription>
subscription_;
DISALLOW_COPY_AND_ASSIGN(AwCookieChangedSubscription);
};
// 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) {}
std::unique_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 std::make_unique<AwCookieChangedSubscription>(
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::RefCountedDeleteOnSequence<NestedSubscription> {
public:
NestedSubscription(const GURL& url,
const std::string& name,
base::WeakPtr<SubscriptionWrapper> subscription_wrapper)
: base::RefCountedDeleteOnSequence<NestedSubscription>(
GetCookieStoreTaskRunner()),
subscription_wrapper_(subscription_wrapper),
client_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
PostTaskToCookieStoreTaskRunner(
base::Bind(&NestedSubscription::Subscribe, this, url, name));
}
private:
friend class base::RefCountedDeleteOnSequence<NestedSubscription>;
friend class base::DeleteHelper<NestedSubscription>;
~NestedSubscription() {}
void Subscribe(const GURL& url, const std::string& name) {
subscription_ = GetCookieStore()->AddCallbackForCookie(
url, name, base::Bind(&NestedSubscription::OnChanged, this));
}
void OnChanged(const net::CanonicalCookie& cookie,
net::CookieStore::ChangeCause cause) {
client_task_runner_->PostTask(
FROM_HERE, base::Bind(&SubscriptionWrapper::OnChanged,
subscription_wrapper_, cookie, cause));
}
base::WeakPtr<SubscriptionWrapper> subscription_wrapper_;
scoped_refptr<base::TaskRunner> client_task_runner_;
std::unique_ptr<net::CookieStore::CookieChangedSubscription> subscription_;
DISALLOW_COPY_AND_ASSIGN(NestedSubscription);
};
void OnChanged(const net::CanonicalCookie& cookie,
net::CookieStore::ChangeCause cause) {
callback_list_.Notify(cookie, cause);
}
// 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,
net::CookieStore::SetCookiesCallback callback) {
GetCookieStore()->SetCookieWithOptionsAsync(url, cookie_line, options,
std::move(callback));
}
void SetCanonicalCookieAsyncOnCookieThread(
std::unique_ptr<net::CanonicalCookie> cookie,
bool secure_source,
bool modify_http_only,
net::CookieStore::SetCookiesCallback callback) {
GetCookieStore()->SetCanonicalCookieAsync(
std::move(cookie), secure_source, modify_http_only, std::move(callback));
}
void GetCookieListWithOptionsAsyncOnCookieThread(
const GURL& url,
const net::CookieOptions& options,
net::CookieStore::GetCookieListCallback callback) {
GetCookieStore()->GetCookieListWithOptionsAsync(url, options,
std::move(callback));
}
void GetAllCookiesAsyncOnCookieThread(
net::CookieStore::GetCookieListCallback callback) {
GetCookieStore()->GetAllCookiesAsync(std::move(callback));
}
void DeleteCookieAsyncOnCookieThread(const GURL& url,
const std::string& cookie_name,
base::OnceClosure callback) {
GetCookieStore()->DeleteCookieAsync(url, cookie_name, std::move(callback));
}
void DeleteCanonicalCookieAsyncOnCookieThread(
const net::CanonicalCookie& cookie,
net::CookieStore::DeleteCallback callback) {
GetCookieStore()->DeleteCanonicalCookieAsync(cookie, std::move(callback));
}
void DeleteAllCreatedBetweenAsyncOnCookieThread(
const base::Time& delete_begin,
const base::Time& delete_end,
net::CookieStore::DeleteCallback callback) {
GetCookieStore()->DeleteAllCreatedBetweenAsync(delete_begin, delete_end,
std::move(callback));
}
void DeleteAllCreatedBetweenWithPredicateAsyncOnCookieThread(
const base::Time& delete_begin,
const base::Time& delete_end,
const net::CookieStore::CookiePredicate& predicate,
net::CookieStore::DeleteCallback callback) {
GetCookieStore()->DeleteAllCreatedBetweenWithPredicateAsync(
delete_begin, delete_end, predicate, std::move(callback));
}
void DeleteSessionCookiesAsyncOnCookieThread(
net::CookieStore::DeleteCallback callback) {
GetCookieStore()->DeleteSessionCookiesAsync(std::move(callback));
}
void FlushStoreOnCookieThread(base::OnceClosure callback) {
GetCookieStore()->FlushStore(std::move(callback));
}
void SetForceKeepSessionStateOnCookieThread() {
GetCookieStore()->SetForceKeepSessionState();
}
} // namespace
AwCookieStoreWrapper::AwCookieStoreWrapper()
: client_task_runner_(base::ThreadTaskRunnerHandle::Get()),
weak_factory_(this) {}
AwCookieStoreWrapper::~AwCookieStoreWrapper() {}
void AwCookieStoreWrapper::SetCookieWithOptionsAsync(
const GURL& url,
const std::string& cookie_line,
const net::CookieOptions& options,
net::CookieStore::SetCookiesCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(base::BindOnce(
&SetCookieWithOptionsAsyncOnCookieThread, url, cookie_line, options,
CreateWrappedCallback<bool>(std::move(callback))));
}
void AwCookieStoreWrapper::SetCanonicalCookieAsync(
std::unique_ptr<net::CanonicalCookie> cookie,
bool secure_source,
bool modify_http_only,
SetCookiesCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(base::BindOnce(
&SetCanonicalCookieAsyncOnCookieThread, std::move(cookie), secure_source,
modify_http_only, CreateWrappedCallback<bool>(std::move(callback))));
}
void AwCookieStoreWrapper::GetCookieListWithOptionsAsync(
const GURL& url,
const net::CookieOptions& options,
GetCookieListCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(base::BindOnce(
&GetCookieListWithOptionsAsyncOnCookieThread, url, options,
CreateWrappedCallback<const net::CookieList&>(std::move(callback))));
}
void AwCookieStoreWrapper::GetAllCookiesAsync(GetCookieListCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(base::BindOnce(
&GetAllCookiesAsyncOnCookieThread,
CreateWrappedCallback<const net::CookieList&>(std::move(callback))));
}
void AwCookieStoreWrapper::DeleteCookieAsync(const GURL& url,
const std::string& cookie_name,
base::OnceClosure callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(
base::BindOnce(&DeleteCookieAsyncOnCookieThread, url, cookie_name,
CreateWrappedClosureCallback(std::move(callback))));
}
void AwCookieStoreWrapper::DeleteCanonicalCookieAsync(
const net::CanonicalCookie& cookie,
DeleteCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(
base::BindOnce(&DeleteCanonicalCookieAsyncOnCookieThread, cookie,
CreateWrappedCallback<uint32_t>(std::move(callback))));
}
void AwCookieStoreWrapper::DeleteAllCreatedBetweenAsync(
const base::Time& delete_begin,
const base::Time& delete_end,
DeleteCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(base::BindOnce(
&DeleteAllCreatedBetweenAsyncOnCookieThread, delete_begin, delete_end,
CreateWrappedCallback<uint32_t>(std::move(callback))));
}
void AwCookieStoreWrapper::DeleteAllCreatedBetweenWithPredicateAsync(
const base::Time& delete_begin,
const base::Time& delete_end,
const CookiePredicate& predicate,
DeleteCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(
base::BindOnce(&DeleteAllCreatedBetweenWithPredicateAsyncOnCookieThread,
delete_begin, delete_end, predicate,
CreateWrappedCallback<uint32_t>(std::move(callback))));
}
void AwCookieStoreWrapper::DeleteSessionCookiesAsync(DeleteCallback callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(
base::BindOnce(&DeleteSessionCookiesAsyncOnCookieThread,
CreateWrappedCallback<uint32_t>(std::move(callback))));
}
void AwCookieStoreWrapper::FlushStore(base::OnceClosure callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(
base::BindOnce(&FlushStoreOnCookieThread,
CreateWrappedClosureCallback(std::move(callback))));
}
void AwCookieStoreWrapper::SetForceKeepSessionState() {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
PostTaskToCookieStoreTaskRunner(
base::Bind(&SetForceKeepSessionStateOnCookieThread));
}
std::unique_ptr<net::CookieStore::CookieChangedSubscription>
AwCookieStoreWrapper::AddCallbackForCookie(
const GURL& url,
const std::string& name,
const CookieChangedCallback& callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
// 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);
}
std::unique_ptr<net::CookieStore::CookieChangedSubscription>
AwCookieStoreWrapper::AddCallbackForAllChanges(
const CookieChangedCallback& callback) {
// TODO(rdsmith): Implement when needed by Android Webview consumer.
CHECK(false);
return nullptr;
}
bool AwCookieStoreWrapper::IsEphemeral() {
return GetCookieStore()->IsEphemeral();
}
base::OnceClosure AwCookieStoreWrapper::CreateWrappedClosureCallback(
base::OnceClosure callback) {
if (callback.is_null())
return callback;
return base::BindOnce(
base::IgnoreResult(&base::TaskRunner::PostTask), client_task_runner_,
FROM_HERE,
base::BindOnce(&AwCookieStoreWrapper::RunClosureCallback,
weak_factory_.GetWeakPtr(), std::move(callback)));
}
void AwCookieStoreWrapper::RunClosureCallback(base::OnceClosure callback) {
DCHECK(client_task_runner_->RunsTasksInCurrentSequence());
std::move(callback).Run();
}
} // namespace android_webview