123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- // Copyright 2019 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 "fuchsia_web/webengine/browser/cookie_manager_impl.h"
- #include <lib/fidl/cpp/binding.h>
- #include "base/fuchsia/fuchsia_logging.h"
- #include "mojo/public/cpp/bindings/pending_remote.h"
- #include "mojo/public/cpp/bindings/receiver.h"
- #include "net/cookies/canonical_cookie.h"
- #include "net/cookies/cookie_change_dispatcher.h"
- #include "services/network/public/mojom/network_context.mojom.h"
- #include "url/gurl.h"
- namespace {
- fuchsia::web::Cookie ConvertCanonicalCookie(
- const net::CanonicalCookie& canonical_cookie,
- net::CookieChangeCause cause) {
- fuchsia::web::CookieId id;
- id.set_name(canonical_cookie.Name());
- id.set_domain(canonical_cookie.Domain());
- id.set_path(canonical_cookie.Path());
- fuchsia::web::Cookie cookie;
- cookie.set_id(std::move(id));
- switch (cause) {
- case net::CookieChangeCause::INSERTED:
- cookie.set_value(canonical_cookie.Value());
- break;
- case net::CookieChangeCause::EXPLICIT:
- case net::CookieChangeCause::UNKNOWN_DELETION:
- case net::CookieChangeCause::OVERWRITE:
- case net::CookieChangeCause::EXPIRED:
- case net::CookieChangeCause::EVICTED:
- case net::CookieChangeCause::EXPIRED_OVERWRITE:
- break;
- };
- return cookie;
- }
- class CookiesIteratorImpl final : public fuchsia::web::CookiesIterator,
- public network::mojom::CookieChangeListener {
- public:
- // |this| will delete itself when |mojo_request| or |changes| disconnect.
- CookiesIteratorImpl(
- mojo::PendingReceiver<network::mojom::CookieChangeListener> mojo_receiver,
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> changes)
- : CookiesIteratorImpl(std::move(changes)) {
- mojo_receiver_.Bind(std::move(mojo_receiver));
- mojo_receiver_.set_disconnect_handler(base::BindOnce(
- &CookiesIteratorImpl::OnMojoError, base::Unretained(this)));
- }
- // |this| will delete itself when |iterator| disconnects, or if a GetNext()
- // leaves |queued_cookies_| empty.
- CookiesIteratorImpl(
- const std::vector<net::CanonicalCookie>& cookies,
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> iterator)
- : CookiesIteratorImpl(std::move(iterator)) {
- for (const auto& cookie : cookies) {
- queued_cookies_[cookie.UniqueKey()] =
- ConvertCanonicalCookie(cookie, net::CookieChangeCause::INSERTED);
- }
- }
- // Same as above except it takes CookieAccessResultList instead of just
- // CookieList.
- CookiesIteratorImpl(
- const std::vector<net::CookieWithAccessResult>&
- cookies_with_access_results,
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> iterator)
- : CookiesIteratorImpl(std::move(iterator)) {
- for (const auto& cookie_with_access_result : cookies_with_access_results) {
- queued_cookies_[cookie_with_access_result.cookie.UniqueKey()] =
- ConvertCanonicalCookie(cookie_with_access_result.cookie,
- net::CookieChangeCause::INSERTED);
- }
- }
- CookiesIteratorImpl(const CookiesIteratorImpl&) = delete;
- CookiesIteratorImpl& operator=(const CookiesIteratorImpl&) = delete;
- ~CookiesIteratorImpl() override = default;
- // fuchsia::web::CookiesIterator implementation:
- void GetNext(GetNextCallback callback) override {
- DCHECK(!get_next_callback_);
- get_next_callback_ = std::move(callback);
- MaybeSendQueuedCookies();
- }
- private:
- explicit CookiesIteratorImpl(
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> iterator)
- : mojo_receiver_(this), fidl_binding_(this) {
- fidl_binding_.Bind(std::move(iterator));
- fidl_binding_.set_error_handler([this](zx_status_t status) {
- ZX_LOG_IF(ERROR, status != ZX_ERR_PEER_CLOSED, status)
- << "CookieChangeListener disconnected.";
- delete this;
- });
- }
- void OnMojoError() {
- LOG(ERROR) << "NetworkService disconnected CookiesIterator.";
- fidl_binding_.Close(ZX_ERR_UNAVAILABLE);
- delete this;
- }
- void MaybeSendQueuedCookies() {
- // Assuming cookies values never exceed 4KB in size, plus some overhead for
- // the name, domain and path, and that Zircon messages can be up to 64KB.
- constexpr int kMaxCookiesPerMessage = 8;
- if (!get_next_callback_)
- return;
- if (mojo_receiver_.is_bound() && queued_cookies_.empty())
- return;
- // Build a vector of Cookies to return to the caller.
- fuchsia::web::CookiesIterator::GetNextCallback callback(
- std::move(get_next_callback_));
- std::vector<fuchsia::web::Cookie> cookies;
- while (!queued_cookies_.empty() && cookies.size() < kMaxCookiesPerMessage) {
- auto cookie = queued_cookies_.begin();
- cookies.emplace_back(std::move(cookie->second));
- queued_cookies_.erase(cookie);
- }
- callback(std::move(cookies));
- // If this is a one-off CookieIterator then tear down once |queued_cookies_|
- // is empty.
- if (queued_cookies_.empty() && !mojo_receiver_.is_bound())
- delete this;
- }
- // network::mojom::CookieChangeListener implementation:
- void OnCookieChange(const net::CookieChangeInfo& change) override {
- queued_cookies_[change.cookie.UniqueKey()] =
- ConvertCanonicalCookie(change.cookie, change.cause);
- MaybeSendQueuedCookies();
- }
- mojo::Receiver<network::mojom::CookieChangeListener> mojo_receiver_;
- fidl::Binding<fuchsia::web::CookiesIterator> fidl_binding_;
- GetNextCallback get_next_callback_;
- // Map from "unique key"s (see net::CanonicalCookie::UniqueKey()) to the
- // corresponding fuchsia::web::Cookie.
- std::map<net::CanonicalCookie::UniqueCookieKey, fuchsia::web::Cookie>
- queued_cookies_;
- };
- void OnAllCookiesReceived(
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> iterator,
- const std::vector<net::CanonicalCookie>& cookies) {
- new CookiesIteratorImpl(cookies, std::move(iterator));
- }
- void OnCookiesAndExcludedReceived(
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> iterator,
- const std::vector<net::CookieWithAccessResult>& cookies_with_access_results,
- const std::vector<net::CookieWithAccessResult>& excluded_cookies) {
- // Since CookieOptions::set_return_excluded_cookies() is not used when calling
- // the Mojo GetCookieList() API, |excluded_cookies| should be empty.
- DCHECK(excluded_cookies.empty());
- new CookiesIteratorImpl(cookies_with_access_results, std::move(iterator));
- }
- } // namespace
- CookieManagerImpl::CookieManagerImpl(
- GetNetworkContextCallback get_network_context)
- : get_network_context_(std::move(get_network_context)) {}
- CookieManagerImpl::~CookieManagerImpl() = default;
- void CookieManagerImpl::ObserveCookieChanges(
- fidl::StringPtr url,
- fidl::StringPtr name,
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> changes) {
- EnsureCookieManager();
- mojo::PendingRemote<network::mojom::CookieChangeListener> mojo_listener;
- new CookiesIteratorImpl(mojo_listener.InitWithNewPipeAndPassReceiver(),
- std::move(changes));
- if (url) {
- absl::optional<std::string> maybe_name;
- if (name)
- maybe_name = *name;
- cookie_manager_->AddCookieChangeListener(GURL(*url), maybe_name,
- std::move(mojo_listener));
- } else {
- cookie_manager_->AddGlobalChangeListener(std::move(mojo_listener));
- }
- }
- void CookieManagerImpl::GetCookieList(
- fidl::StringPtr url,
- fidl::StringPtr name,
- fidl::InterfaceRequest<fuchsia::web::CookiesIterator> iterator) {
- EnsureCookieManager();
- if (!url && !name) {
- cookie_manager_->GetAllCookies(
- base::BindOnce(&OnAllCookiesReceived, std::move(iterator)));
- } else {
- if (!name) {
- // Include HTTP and 1st-party-only cookies in those returned.
- net::CookieOptions options;
- options.set_include_httponly();
- options.set_same_site_cookie_context(
- net::CookieOptions::SameSiteCookieContext::MakeInclusive());
- cookie_manager_->GetCookieList(
- GURL(*url), options, net::CookiePartitionKeyCollection::Todo(),
- base::BindOnce(&OnCookiesAndExcludedReceived, std::move(iterator)));
- } else {
- // TODO(858853): Support filtering by name.
- iterator.Close(ZX_ERR_NOT_SUPPORTED);
- }
- }
- }
- void CookieManagerImpl::EnsureCookieManager() {
- if (cookie_manager_.is_bound())
- return;
- get_network_context_.Run()->GetCookieManager(
- cookie_manager_.BindNewPipeAndPassReceiver());
- cookie_manager_.set_disconnect_handler(base::BindOnce(
- &CookieManagerImpl::OnMojoDisconnect, base::Unretained(this)));
- }
- void CookieManagerImpl::OnMojoDisconnect() {
- LOG(ERROR) << "NetworkService disconnected CookieManager.";
- if (on_mojo_disconnected_for_test_)
- std::move(on_mojo_disconnected_for_test_).Run();
- cookie_manager_.reset();
- }
|