Commit fc932768 authored by Kouhei Ueno's avatar Kouhei Ueno Committed by Commit Bot

Introduce OriginsList

This CL introduces OriginsList, which can be used to keep track of a
{allow,deny} list of domains.

The OriginsList will be used in the subsequent CLs to keep track of
the origins who opt-in to "Accept: application/signed-exchange"
header.

Bug: 887201
Change-Id: Ie926587a016dab76a585088be76a70e0b62e51dc
Reviewed-on: https://chromium-review.googlesource.com/1235362Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarTsuyoshi Horo <horo@chromium.org>
Reviewed-by: default avatarKunihiko Sakamoto <ksakamoto@chromium.org>
Commit-Queue: Kouhei Ueno <kouhei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#593133}
parent 00d70d01
......@@ -1775,6 +1775,8 @@ jumbo_source_set("browser") {
"web_contents/web_drag_source_mac.mm",
"web_contents/web_drag_utils_win.cc",
"web_contents/web_drag_utils_win.h",
"web_package/origins_list.cc",
"web_package/origins_list.h",
"web_package/signed_exchange_cert_fetcher.cc",
"web_package/signed_exchange_cert_fetcher.h",
"web_package/signed_exchange_cert_fetcher_factory.cc",
......
// Copyright 2018 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/browser/web_package/origins_list.h"
#include "base/strings/string_split.h"
#include "url/gurl.h"
namespace content {
namespace signed_exchange_utils {
constexpr char kSubdomainMatchPrefix[] = "*.";
OriginsList::OriginsList() = default;
OriginsList::OriginsList(base::StringPiece str) {
std::vector<base::StringPiece> elements = base::SplitStringPiece(
str, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
for (base::StringPiece element : elements) {
bool subdomain_match = false;
if (base::StartsWith(element, kSubdomainMatchPrefix,
base::CompareCase::SENSITIVE)) {
subdomain_match = true;
element.remove_prefix(sizeof(kSubdomainMatchPrefix) - 1);
}
if (base::StartsWith(element,
"https:", base::CompareCase::INSENSITIVE_ASCII)) {
LOG(ERROR) << "OriginsList entry should omit https scheme: \"" << element
<< "\"";
continue;
}
std::string url_str("https://");
element.AppendToString(&url_str);
GURL url(url_str);
if (!url.is_valid()) {
LOG(ERROR) << "Failed to parse an OriginsList entry to a valid Origin: \""
<< element << "\"";
continue;
}
DCHECK(url.SchemeIs("https"));
url::Origin origin = url::Origin::Create(url);
if (subdomain_match) {
subdomain_match_origins_.push_back(origin);
} else {
exact_match_origins_.insert(origin);
}
}
}
OriginsList::OriginsList(OriginsList&&) = default;
OriginsList::~OriginsList() = default;
bool OriginsList::IsEmpty() const {
return exact_match_origins_.empty() && subdomain_match_origins_.empty();
}
bool OriginsList::Match(const url::Origin& origin) const {
// OriginsList only contains HTTPS scheme origins.
if (origin.scheme() != url::kHttpsScheme) {
return false;
}
if (exact_match_origins_.find(origin) != exact_match_origins_.end()) {
return true;
}
for (const auto& subdomain_match_origin : subdomain_match_origins_) {
if (origin.DomainIs(subdomain_match_origin.host()) &&
origin.port() == subdomain_match_origin.port()) {
return true;
}
}
return false;
}
} // namespace signed_exchange_utils
} // namespace content
// Copyright 2018 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.
#ifndef CONTENT_BROWSER_WEB_PACKAGE_ORIGINS_LIST_H_
#define CONTENT_BROWSER_WEB_PACKAGE_ORIGINS_LIST_H_
#include <vector>
#include "base/containers/flat_set.h"
#include "base/strings/string_piece.h"
#include "content/common/content_export.h"
#include "url/origin.h"
namespace content {
namespace signed_exchange_utils {
// OriginsList can query if a particular origin |Match|.
// OriginsList can only match HTTPS origins.
class CONTENT_EXPORT OriginsList {
public:
OriginsList();
// Creates an OriginsList from comma-separated list of hosts.
//
// Entries starting with "*." will match with subdomains.
//
// For example, "example.com,*.google.com" will create an
// OriginsList that match exactly "example.com" but not its
// subdomains, and all subdomains of "google.com".
//
// Note: Entries should NOT start with "https://", but start from hostname.
explicit OriginsList(base::StringPiece str);
OriginsList(OriginsList&&);
~OriginsList();
// Returns true when |this| has an empty list to match
// (i.e. no origins would match).
bool IsEmpty() const;
bool Match(const url::Origin& origin) const;
private:
base::flat_set<url::Origin> exact_match_origins_;
std::vector<url::Origin> subdomain_match_origins_;
};
} // namespace signed_exchange_utils
} // namespace content
#endif // CONTENT_BROWSER_WEB_PACKAGE_ORIGINS_LIST_H_
// Copyright 2018 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/browser/web_package/origins_list.h"
#include "base/callback.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
#include "url/origin.h"
namespace content {
namespace signed_exchange_utils {
TEST(OriginsList, IsEmpty) {
OriginsList origins_list;
EXPECT_TRUE(origins_list.IsEmpty());
}
TEST(OriginsList, ExactMatch) {
OriginsList origins_list(
"example.com,test.example.com,https://invalid.entry,example.net:1234");
EXPECT_FALSE(origins_list.IsEmpty());
static constexpr const char* kShouldMatchList[] = {
"https://example.com", "https://test.example.com",
"https://example.net:1234",
};
for (const char* should_match : kShouldMatchList) {
EXPECT_TRUE(origins_list.Match(url::Origin::Create(GURL(should_match))))
<< "OriginList should match url: " << should_match;
}
static constexpr const char* kShouldNotMatchList[] = {
"http://example.com", "https://subdomain.example.com",
"https://notexample.com", "https://invalid.entry",
"https://example.net", "https://example.net:5432",
};
for (const char* should_not_match : kShouldNotMatchList) {
EXPECT_FALSE(
origins_list.Match(url::Origin::Create(GURL(should_not_match))))
<< "OriginList should not match url: " << should_not_match;
}
}
TEST(OriginsList, SubdomainMatch) {
OriginsList origins_list("*.example.com,*.example.net:1234");
EXPECT_FALSE(origins_list.IsEmpty());
static constexpr const char* kShouldMatchList[] = {
"https://example.com", "https://test.example.com",
"https://test.test2.example.com", "https://test.example.net:1234",
};
for (const char* should_match : kShouldMatchList) {
EXPECT_TRUE(origins_list.Match(url::Origin::Create(GURL(should_match))))
<< "OriginList should match url: " << should_match;
}
static constexpr const char* kShouldNotMatchList[] = {
"http://example.com", "https://notexample.com",
"https://test.example.net", "https://test.example.net:5432",
};
for (const char* should_not_match : kShouldNotMatchList) {
EXPECT_FALSE(
origins_list.Match(url::Origin::Create(GURL(should_not_match))))
<< "OriginList should not match url: " << should_not_match;
}
}
} // namespace signed_exchange_utils
} // namespace content
......@@ -1608,6 +1608,7 @@ test("content_unittests") {
"../browser/web_contents/web_contents_view_mac_unittest.mm",
"../browser/web_contents/web_drag_dest_mac_unittest.mm",
"../browser/web_contents/web_drag_source_mac_unittest.mm",
"../browser/web_package/origins_list_unittest.cc",
"../browser/web_package/signed_exchange_cert_fetcher_unittest.cc",
"../browser/web_package/signed_exchange_certificate_chain_unittest.cc",
"../browser/web_package/signed_exchange_envelope_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment