blob: dab430a675454ee75c7bcfab1034b5328260cd61 [file] [log] [blame]
// Copyright 2017 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 "content/network/restricted_cookie_manager.h"
#include <algorithm>
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/time/time.h"
#include "net/cookies/cookie_constants.h"
#include "net/cookies/cookie_monster.h"
#include "net/cookies/cookie_store.h"
#include "net/cookies/cookie_store_test_callbacks.h"
#include "services/network/public/interfaces/cookie_manager.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
// Synchronous proxies to a wrapped RestrictedCookieManager's methods.
class RestrictedCookieManagerSync {
public:
// Caller must guarantee that |*cookie_service| outlives the
// SynchronousCookieManager.
explicit RestrictedCookieManagerSync(
network::mojom::RestrictedCookieManager* cookie_service)
: cookie_service_(cookie_service) {}
~RestrictedCookieManagerSync() {}
std::vector<net::CanonicalCookie> GetAllForUrl(
const GURL& url,
const GURL& site_for_cookies,
network::mojom::CookieManagerGetOptionsPtr options) {
base::RunLoop run_loop;
std::vector<net::CanonicalCookie> cookies;
cookie_service_->GetAllForUrl(
url, site_for_cookies, std::move(options),
base::BindOnce(&RestrictedCookieManagerSync::GetAllForUrlCallback,
&run_loop, &cookies));
run_loop.Run();
return cookies;
}
bool SetCanonicalCookie(const net::CanonicalCookie& cookie,
const GURL& url,
const GURL& site_for_cookies) {
base::RunLoop run_loop;
bool result = false;
cookie_service_->SetCanonicalCookie(
cookie, url, site_for_cookies,
base::BindOnce(&RestrictedCookieManagerSync::SetCanonicalCookieCallback,
&run_loop, &result));
run_loop.Run();
return result;
}
private:
static void GetAllForUrlCallback(
base::RunLoop* run_loop,
std::vector<net::CanonicalCookie>* cookies_out,
const std::vector<net::CanonicalCookie>& cookies) {
*cookies_out = cookies;
run_loop->Quit();
}
static void SetCanonicalCookieCallback(base::RunLoop* run_loop,
bool* result_out,
bool result) {
*result_out = result;
run_loop->Quit();
}
network::mojom::RestrictedCookieManager* cookie_service_;
DISALLOW_COPY_AND_ASSIGN(RestrictedCookieManagerSync);
};
class RestrictedCookieManagerTest : public testing::Test {
public:
RestrictedCookieManagerTest()
: cookie_monster_(nullptr, nullptr),
service_(std::make_unique<RestrictedCookieManager>(&cookie_monster_,
MSG_ROUTING_NONE,
MSG_ROUTING_NONE)),
binding_(service_.get(), mojo::MakeRequest(&service_ptr_)) {
sync_service_ =
std::make_unique<RestrictedCookieManagerSync>(service_ptr_.get());
}
~RestrictedCookieManagerTest() override {}
// Set a canonical cookie directly into the store.
bool SetCanonicalCookie(const net::CanonicalCookie& cookie,
bool secure_source,
bool can_modify_httponly) {
net::ResultSavingCookieCallback<bool> callback;
cookie_monster_.SetCanonicalCookieAsync(
std::make_unique<net::CanonicalCookie>(cookie), secure_source,
can_modify_httponly,
base::BindOnce(&net::ResultSavingCookieCallback<bool>::Run,
base::Unretained(&callback)));
callback.WaitUntilDone();
return callback.result();
}
// Simplified helper for SetCanonicalCookie.
//
// Creates a CanonicalCookie that is not secure, not http-only,
// and not restricted to first parties. Crashes if the creation fails.
void SetSessionCookie(const char* name,
const char* value,
const char* domain,
const char* path) {
CHECK(SetCanonicalCookie(
net::CanonicalCookie(name, value, domain, path, base::Time(),
base::Time(), base::Time(), /* secure = */ false,
/* httponly = */ false,
net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_DEFAULT),
/* secure_source = */ true, /* can_modify_httponly = */ true));
}
protected:
base::MessageLoopForIO message_loop_;
net::CookieMonster cookie_monster_;
std::unique_ptr<content::RestrictedCookieManager> service_;
network::mojom::RestrictedCookieManagerPtr service_ptr_;
mojo::Binding<network::mojom::RestrictedCookieManager> binding_;
std::unique_ptr<RestrictedCookieManagerSync> sync_service_;
};
namespace {
bool CompareCanonicalCookies(const net::CanonicalCookie& c1,
const net::CanonicalCookie& c2) {
return c1.FullCompare(c2);
}
} // anonymous namespace
TEST_F(RestrictedCookieManagerTest, GetAllForUrlBlankFilter) {
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
SetSessionCookie("other-cookie-name", "other-cookie-value", "not-example.com",
"/");
auto options = network::mojom::CookieManagerGetOptions::New();
options->name = "";
options->match_type = network::mojom::CookieMatchType::STARTS_WITH;
std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
GURL("http://example.com/test/"), GURL("http://example.com"),
std::move(options));
ASSERT_EQ(2u, cookies.size());
std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
EXPECT_EQ("cookie-name", cookies[0].Name());
EXPECT_EQ("cookie-value", cookies[0].Value());
EXPECT_EQ("cookie-name-2", cookies[1].Name());
EXPECT_EQ("cookie-value-2", cookies[1].Value());
}
TEST_F(RestrictedCookieManagerTest, GetAllForUrlEmptyFilter) {
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
auto options = network::mojom::CookieManagerGetOptions::New();
options->name = "";
options->match_type = network::mojom::CookieMatchType::EQUALS;
std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
GURL("http://example.com/test/"), GURL("http://example.com"),
std::move(options));
ASSERT_EQ(0u, cookies.size());
std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
}
TEST_F(RestrictedCookieManagerTest, GetAllForUrlEqualsMatch) {
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
auto options = network::mojom::CookieManagerGetOptions::New();
options->name = "cookie-name";
options->match_type = network::mojom::CookieMatchType::EQUALS;
std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
GURL("http://example.com/test/"), GURL("http://example.com"),
std::move(options));
ASSERT_EQ(1u, cookies.size());
EXPECT_EQ("cookie-name", cookies[0].Name());
EXPECT_EQ("cookie-value", cookies[0].Value());
}
TEST_F(RestrictedCookieManagerTest, GetAllForUrlStartsWithMatch) {
SetSessionCookie("cookie-name", "cookie-value", "example.com", "/");
SetSessionCookie("cookie-name-2", "cookie-value-2", "example.com", "/");
SetSessionCookie("cookie-name-2b", "cookie-value-2b", "example.com", "/");
SetSessionCookie("cookie-name-3b", "cookie-value-3b", "example.com", "/");
auto options = network::mojom::CookieManagerGetOptions::New();
options->name = "cookie-name-2";
options->match_type = network::mojom::CookieMatchType::STARTS_WITH;
std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
GURL("http://example.com/test/"), GURL("http://example.com"),
std::move(options));
ASSERT_EQ(2u, cookies.size());
std::sort(cookies.begin(), cookies.end(), &CompareCanonicalCookies);
EXPECT_EQ("cookie-name-2", cookies[0].Name());
EXPECT_EQ("cookie-value-2", cookies[0].Value());
EXPECT_EQ("cookie-name-2b", cookies[1].Name());
EXPECT_EQ("cookie-value-2b", cookies[1].Value());
}
TEST_F(RestrictedCookieManagerTest, SetCanonicalCookie) {
EXPECT_TRUE(sync_service_->SetCanonicalCookie(
net::CanonicalCookie(
"new-name", "new-value", "example.com", "/", base::Time(),
base::Time(), base::Time(), /* secure = */ false,
/* httponly = */ false, net::CookieSameSite::NO_RESTRICTION,
net::COOKIE_PRIORITY_DEFAULT),
GURL("http://example.com/test/"), GURL("http://example.com")));
auto options = network::mojom::CookieManagerGetOptions::New();
options->name = "new-name";
options->match_type = network::mojom::CookieMatchType::EQUALS;
std::vector<net::CanonicalCookie> cookies = sync_service_->GetAllForUrl(
GURL("http://example.com/test/"), GURL("http://example.com"),
std::move(options));
ASSERT_EQ(1u, cookies.size());
EXPECT_EQ("new-name", cookies[0].Name());
EXPECT_EQ("new-value", cookies[0].Value());
}
} // namespace content