123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777 |
- // Copyright 2015 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 <stddef.h>
- #include <stdint.h>
- #include "base/memory/raw_ptr.h"
- #include "testing/gmock/include/gmock/gmock.h"
- #include "testing/gtest/include/gtest/gtest.h"
- #include "url/gurl.h"
- #include "url/origin.h"
- #include "url/origin_abstract_tests.h"
- #include "url/url_util.h"
- namespace url {
- class OriginTest : public ::testing::Test {
- public:
- void SetUp() override {
- // Add two schemes which are local but nonstandard.
- AddLocalScheme("local-but-nonstandard");
- AddLocalScheme("also-local-but-nonstandard");
- // Add a scheme that's both local and standard.
- AddStandardScheme("local-and-standard", SchemeType::SCHEME_WITH_HOST);
- AddLocalScheme("local-and-standard");
- // Add a scheme that's standard but no-access. We still want these to
- // form valid SchemeHostPorts, even though they always commit as opaque
- // origins, so that they can represent the source of the resource even if
- // it's not committable as a non-opaque origin.
- AddStandardScheme("standard-but-noaccess", SchemeType::SCHEME_WITH_HOST);
- AddNoAccessScheme("standard-but-noaccess");
- }
- ::testing::AssertionResult DoEqualityComparisons(const url::Origin& a,
- const url::Origin& b,
- bool should_compare_equal) {
- ::testing::AssertionResult failure = ::testing::AssertionFailure();
- failure << "DoEqualityComparisons failure. Expecting "
- << (should_compare_equal ? "equality" : "inequality")
- << " between:\n a\n Which is: " << a
- << "\n b\n Which is: " << b << "\nThe following check failed: ";
- if (a.IsSameOriginWith(b) != should_compare_equal)
- return failure << "a.IsSameOriginWith(b)";
- if (b.IsSameOriginWith(a) != should_compare_equal)
- return failure << "b.IsSameOriginWith(a)";
- if ((a == b) != should_compare_equal)
- return failure << "(a == b)";
- if ((b == a) != should_compare_equal)
- return failure << "(b == a)";
- if ((b != a) != !should_compare_equal)
- return failure << "(b != a)";
- if ((a != b) != !should_compare_equal)
- return failure << "(a != b)";
- return ::testing::AssertionSuccess();
- }
- bool HasNonceTokenBeenInitialized(const url::Origin& origin) {
- EXPECT_TRUE(origin.opaque());
- // Avoid calling nonce_.token() here, to not trigger lazy initialization.
- return !origin.nonce_->token_.is_empty();
- }
- Origin::Nonce CreateNonce() { return Origin::Nonce(); }
- Origin::Nonce CreateNonce(base::UnguessableToken nonce) {
- return Origin::Nonce(nonce);
- }
- const base::UnguessableToken* GetNonce(const Origin& origin) {
- return origin.GetNonceForSerialization();
- }
- // Wrappers around url::Origin methods to expose it to tests.
- absl::optional<Origin> UnsafelyCreateOpaqueOriginWithoutNormalization(
- base::StringPiece precursor_scheme,
- base::StringPiece precursor_host,
- uint16_t precursor_port,
- const Origin::Nonce& nonce) {
- return Origin::UnsafelyCreateOpaqueOriginWithoutNormalization(
- precursor_scheme, precursor_host, precursor_port, nonce);
- }
- absl::optional<std::string> SerializeWithNonce(const Origin& origin) {
- return origin.SerializeWithNonce();
- }
- absl::optional<std::string> SerializeWithNonceAndInitIfNeeded(
- Origin& origin) {
- return origin.SerializeWithNonceAndInitIfNeeded();
- }
- absl::optional<Origin> Deserialize(const std::string& value) {
- return Origin::Deserialize(value);
- }
- private:
- ScopedSchemeRegistryForTests scoped_registry_;
- };
- TEST_F(OriginTest, OpaqueOriginComparison) {
- // A default-constructed Origin should should be cross origin to everything
- // but itself.
- url::Origin opaque_a, opaque_b;
- EXPECT_TRUE(opaque_a.opaque());
- EXPECT_EQ("", opaque_a.scheme());
- EXPECT_EQ("", opaque_a.host());
- EXPECT_EQ(0, opaque_a.port());
- EXPECT_EQ(SchemeHostPort(), opaque_a.GetTupleOrPrecursorTupleIfOpaque());
- EXPECT_FALSE(opaque_a.GetTupleOrPrecursorTupleIfOpaque().IsValid());
- EXPECT_TRUE(opaque_b.opaque());
- EXPECT_EQ("", opaque_b.scheme());
- EXPECT_EQ("", opaque_b.host());
- EXPECT_EQ(0, opaque_b.port());
- EXPECT_EQ(SchemeHostPort(), opaque_b.GetTupleOrPrecursorTupleIfOpaque());
- EXPECT_FALSE(opaque_b.GetTupleOrPrecursorTupleIfOpaque().IsValid());
- // Two default-constructed Origins should always be cross origin to each
- // other.
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, false));
- EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
- // The streaming operator should not trigger lazy initialization to the token.
- std::ostringstream stream;
- stream << opaque_a;
- EXPECT_STREQ("null [internally: (nonce TBD) anonymous]",
- stream.str().c_str());
- EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
- // None of the operations thus far should have triggered lazy-generation of
- // the UnguessableToken. Copying an origin, however, should trigger this.
- EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
- EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_b));
- opaque_b = opaque_a;
- EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_a));
- EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, true));
- EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
- // Move-initializing to a fresh Origin should restore the lazy initialization.
- opaque_a = url::Origin();
- EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
- EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, false));
- EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
- // Comparing two opaque Origins with matching SchemeHostPorts should trigger
- // lazy initialization.
- EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
- EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
- bool should_swap = opaque_b < opaque_a;
- EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_a));
- EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
- if (should_swap)
- std::swap(opaque_a, opaque_b);
- EXPECT_LT(opaque_a, opaque_b);
- EXPECT_FALSE(opaque_b < opaque_a);
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, false));
- EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
- EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
- EXPECT_LT(opaque_a, url::Origin::Create(GURL("http://www.google.com")));
- EXPECT_LT(opaque_b, url::Origin::Create(GURL("http://www.google.com")));
- EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL(), opaque_b));
- EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL("about:blank"), opaque_b));
- EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL("about:srcdoc"), opaque_b));
- EXPECT_EQ(opaque_b,
- url::Origin::Resolve(GURL("about:blank?hello#whee"), opaque_b));
- }
- TEST_F(OriginTest, ConstructFromTuple) {
- struct TestCases {
- const char* const scheme;
- const char* const host;
- const uint16_t port;
- } cases[] = {
- {"http", "example.com", 80},
- {"http", "example.com", 123},
- {"https", "example.com", 443},
- };
- for (const auto& test_case : cases) {
- testing::Message scope_message;
- scope_message << test_case.scheme << "://" << test_case.host << ":"
- << test_case.port;
- SCOPED_TRACE(scope_message);
- Origin origin = Origin::CreateFromNormalizedTuple(
- test_case.scheme, test_case.host, test_case.port);
- EXPECT_EQ(test_case.scheme, origin.scheme());
- EXPECT_EQ(test_case.host, origin.host());
- EXPECT_EQ(test_case.port, origin.port());
- }
- }
- TEST_F(OriginTest, Serialization) {
- struct TestCases {
- const char* const url;
- const char* const expected;
- const char* const expected_log;
- } cases[] = {
- {"http://192.168.9.1/", "http://192.168.9.1"},
- {"http://[2001:db8::1]/", "http://[2001:db8::1]"},
- {"http://☃.net/", "http://xn--n3h.net"},
- {"http://example.com/", "http://example.com"},
- {"http://example.com:123/", "http://example.com:123"},
- {"https://example.com/", "https://example.com"},
- {"https://example.com:123/", "https://example.com:123"},
- {"file:///etc/passwd", "file://", "file:// [internally: file://]"},
- {"file://example.com/etc/passwd", "file://",
- "file:// [internally: file://example.com]"},
- {"data:,", "null", "null [internally: (nonce TBD) anonymous]"},
- };
- for (const auto& test_case : cases) {
- SCOPED_TRACE(test_case.url);
- GURL url(test_case.url);
- EXPECT_TRUE(url.is_valid());
- Origin origin = Origin::Create(url);
- std::string serialized = origin.Serialize();
- ExpectParsedUrlsEqual(GURL(serialized), origin.GetURL());
- EXPECT_EQ(test_case.expected, serialized);
- // The '<<' operator sometimes produces additional information.
- std::stringstream out;
- out << origin;
- if (test_case.expected_log)
- EXPECT_EQ(test_case.expected_log, out.str());
- else
- EXPECT_EQ(test_case.expected, out.str());
- }
- }
- TEST_F(OriginTest, Comparison) {
- // These URLs are arranged in increasing order:
- const char* const urls[] = {
- "data:uniqueness", "http://a:80", "http://b:80",
- "https://a:80", "https://b:80", "http://a:81",
- "http://b:81", "https://a:81", "https://b:81",
- };
- // Validate the comparison logic still works when creating a canonical origin,
- // when any created opaque origins contain a nonce.
- {
- // Pre-create the origins, as the internal nonce for unique origins changes
- // with each freshly-constructed Origin (that's not copied).
- std::vector<Origin> origins;
- for (const auto* test_url : urls)
- origins.push_back(Origin::Create(GURL(test_url)));
- for (size_t i = 0; i < origins.size(); i++) {
- const Origin& current = origins[i];
- for (size_t j = i; j < origins.size(); j++) {
- const Origin& to_compare = origins[j];
- EXPECT_EQ(i < j, current < to_compare) << i << " < " << j;
- EXPECT_EQ(j < i, to_compare < current) << j << " < " << i;
- }
- }
- }
- }
- TEST_F(OriginTest, UnsafelyCreate) {
- struct TestCase {
- const char* scheme;
- const char* host;
- uint16_t port;
- } cases[] = {
- {"http", "example.com", 80},
- {"http", "example.com", 123},
- {"https", "example.com", 443},
- {"https", "example.com", 123},
- {"http", "example.com", 0}, // 0 is a valid port for http.
- {"file", "", 0}, // 0 indicates "no port" for file: scheme.
- {"file", "example.com", 0},
- };
- for (const auto& test : cases) {
- SCOPED_TRACE(testing::Message()
- << test.scheme << "://" << test.host << ":" << test.port);
- absl::optional<url::Origin> origin =
- url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(
- test.scheme, test.host, test.port);
- ASSERT_TRUE(origin);
- EXPECT_EQ(test.scheme, origin->scheme());
- EXPECT_EQ(test.host, origin->host());
- EXPECT_EQ(test.port, origin->port());
- EXPECT_FALSE(origin->opaque());
- EXPECT_TRUE(origin->IsSameOriginWith(*origin));
- ExpectParsedUrlsEqual(GURL(origin->Serialize()), origin->GetURL());
- base::UnguessableToken nonce = base::UnguessableToken::Create();
- absl::optional<url::Origin> opaque_origin =
- UnsafelyCreateOpaqueOriginWithoutNormalization(
- test.scheme, test.host, test.port, CreateNonce(nonce));
- ASSERT_TRUE(opaque_origin);
- EXPECT_TRUE(opaque_origin->opaque());
- EXPECT_FALSE(*opaque_origin == origin);
- EXPECT_EQ(opaque_origin->GetTupleOrPrecursorTupleIfOpaque(),
- origin->GetTupleOrPrecursorTupleIfOpaque());
- EXPECT_EQ(opaque_origin,
- UnsafelyCreateOpaqueOriginWithoutNormalization(
- test.scheme, test.host, test.port, CreateNonce(nonce)));
- EXPECT_FALSE(*opaque_origin == origin->DeriveNewOpaqueOrigin());
- }
- }
- TEST_F(OriginTest, UnsafelyCreateUniqueOnInvalidInput) {
- url::AddStandardScheme("host-only", url::SCHEME_WITH_HOST);
- url::AddStandardScheme("host-port-only", url::SCHEME_WITH_HOST_AND_PORT);
- struct TestCases {
- const char* scheme;
- const char* host;
- uint16_t port = 80;
- } cases[] = {{"", "", 33},
- {"data", "", 0},
- {"blob", "", 0},
- {"filesystem", "", 0},
- {"data", "example.com"},
- {"http", "☃.net"},
- {"http\nmore", "example.com"},
- {"http\rmore", "example.com"},
- {"http\n", "example.com"},
- {"http\r", "example.com"},
- {"http", "example.com\nnot-example.com"},
- {"http", "example.com\rnot-example.com"},
- {"http", "example.com\n"},
- {"http", "example.com\r"},
- {"unknown-scheme", "example.com"},
- {"host-only", "\r", 0},
- {"host-only", "example.com", 22},
- {"file", "", 123}}; // file: shouldn't have a port.
- for (const auto& test : cases) {
- SCOPED_TRACE(testing::Message()
- << test.scheme << "://" << test.host << ":" << test.port);
- EXPECT_FALSE(UnsafelyCreateOpaqueOriginWithoutNormalization(
- test.scheme, test.host, test.port, CreateNonce()));
- EXPECT_FALSE(url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(
- test.scheme, test.host, test.port));
- }
- // An empty scheme/host/port tuple is not a valid tuple origin.
- EXPECT_FALSE(
- url::Origin::UnsafelyCreateTupleOriginWithoutNormalization("", "", 0));
- // Opaque origins with unknown precursors are allowed.
- base::UnguessableToken token = base::UnguessableToken::Create();
- absl::optional<url::Origin> anonymous_opaque =
- UnsafelyCreateOpaqueOriginWithoutNormalization("", "", 0,
- CreateNonce(token));
- ASSERT_TRUE(anonymous_opaque)
- << "An invalid tuple is a valid input to "
- << "UnsafelyCreateOpaqueOriginWithoutNormalization, so long as it is "
- << "the canonical form of the invalid tuple.";
- EXPECT_TRUE(anonymous_opaque->opaque());
- EXPECT_EQ(*GetNonce(anonymous_opaque.value()), token);
- EXPECT_EQ(anonymous_opaque->GetTupleOrPrecursorTupleIfOpaque(),
- url::SchemeHostPort());
- }
- TEST_F(OriginTest, UnsafelyCreateUniqueViaEmbeddedNulls) {
- struct TestCases {
- base::StringPiece scheme;
- base::StringPiece host;
- uint16_t port = 80;
- } cases[] = {{{"http\0more", 9}, {"example.com", 11}},
- {{"http\0", 5}, {"example.com", 11}},
- {{"\0http", 5}, {"example.com", 11}},
- {{"http"}, {"example.com\0not-example.com", 27}},
- {{"http"}, {"example.com\0", 12}},
- {{"http"}, {"\0example.com", 12}},
- {{""}, {"\0", 1}, 0},
- {{"\0", 1}, {""}, 0}};
- for (const auto& test : cases) {
- SCOPED_TRACE(testing::Message()
- << test.scheme << "://" << test.host << ":" << test.port);
- EXPECT_FALSE(url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(
- test.scheme, test.host, test.port));
- EXPECT_FALSE(UnsafelyCreateOpaqueOriginWithoutNormalization(
- test.scheme, test.host, test.port, CreateNonce()));
- }
- }
- TEST_F(OriginTest, DomainIs) {
- const struct {
- const char* url;
- const char* lower_ascii_domain;
- bool expected_domain_is;
- } kTestCases[] = {
- {"http://google.com/foo", "google.com", true},
- {"http://www.google.com:99/foo", "google.com", true},
- {"http://www.google.com.cn/foo", "google.com", false},
- {"http://www.google.comm", "google.com", false},
- {"http://www.iamnotgoogle.com/foo", "google.com", false},
- {"http://www.google.com/foo", "Google.com", false},
- // If the host ends with a dot, it matches domains with or without a dot.
- {"http://www.google.com./foo", "google.com", true},
- {"http://www.google.com./foo", "google.com.", true},
- {"http://www.google.com./foo", ".com", true},
- {"http://www.google.com./foo", ".com.", true},
- // But, if the host doesn't end with a dot and the input domain does, then
- // it's considered to not match.
- {"http://google.com/foo", "google.com.", false},
- // If the host ends with two dots, it doesn't match.
- {"http://www.google.com../foo", "google.com", false},
- // Filesystem scheme.
- {"filesystem:http://www.google.com:99/foo/", "google.com", true},
- {"filesystem:http://www.iamnotgoogle.com/foo/", "google.com", false},
- // File scheme.
- {"file:///home/user/text.txt", "", false},
- {"file:///home/user/text.txt", "txt", false},
- };
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message()
- << "(url, domain): (" << test_case.url << ", "
- << test_case.lower_ascii_domain << ")");
- GURL url(test_case.url);
- ASSERT_TRUE(url.is_valid());
- Origin origin = Origin::Create(url);
- EXPECT_EQ(test_case.expected_domain_is,
- origin.DomainIs(test_case.lower_ascii_domain));
- EXPECT_FALSE(
- origin.DeriveNewOpaqueOrigin().DomainIs(test_case.lower_ascii_domain));
- }
- // If the URL is invalid, DomainIs returns false.
- GURL invalid_url("google.com");
- ASSERT_FALSE(invalid_url.is_valid());
- EXPECT_FALSE(Origin::Create(invalid_url).DomainIs("google.com"));
- // Unique origins.
- EXPECT_FALSE(Origin().DomainIs(""));
- EXPECT_FALSE(Origin().DomainIs("com"));
- }
- TEST_F(OriginTest, DebugAlias) {
- Origin origin1 = Origin::Create(GURL("https://foo.com/bar"));
- DEBUG_ALIAS_FOR_ORIGIN(origin1_debug_alias, origin1);
- EXPECT_STREQ("https://foo.com", origin1_debug_alias);
- }
- TEST_F(OriginTest, CanBeDerivedFrom) {
- AddStandardScheme("new-standard", SchemeType::SCHEME_WITH_HOST);
- Origin opaque_unique_origin = Origin();
- Origin regular_origin = Origin::Create(GURL("https://a.com/"));
- Origin opaque_precursor_origin = regular_origin.DeriveNewOpaqueOrigin();
- Origin file_origin = Origin::Create(GURL("file:///foo/bar"));
- Origin file_opaque_precursor_origin = file_origin.DeriveNewOpaqueOrigin();
- Origin file_host_origin = Origin::Create(GURL("file://a.com/foo/bar"));
- Origin file_host_opaque_precursor_origin =
- file_host_origin.DeriveNewOpaqueOrigin();
- Origin non_standard_scheme_origin =
- Origin::Create(GURL("non-standard-scheme:foo"));
- Origin non_standard_opaque_precursor_origin =
- non_standard_scheme_origin.DeriveNewOpaqueOrigin();
- // Also, add new standard scheme that is local to the test.
- Origin new_standard_origin = Origin::Create(GURL("new-standard://host/"));
- Origin new_standard_opaque_precursor_origin =
- new_standard_origin.DeriveNewOpaqueOrigin();
- // No access schemes always get unique opaque origins.
- Origin no_access_origin =
- Origin::Create(GURL("standard-but-noaccess://b.com"));
- Origin no_access_opaque_precursor_origin =
- no_access_origin.DeriveNewOpaqueOrigin();
- Origin local_non_standard_origin =
- Origin::Create(GURL("local-but-nonstandard://a.com"));
- Origin local_non_standard_opaque_precursor_origin =
- local_non_standard_origin.DeriveNewOpaqueOrigin();
- // Call origin.CanBeDerivedFrom(url) for each of the following test cases
- // and ensure that it returns |expected_value|
- const struct {
- const char* url;
- raw_ptr<Origin> origin;
- bool expected_value;
- } kTestCases[] = {
- {"https://a.com", ®ular_origin, true},
- // Web URL can commit in an opaque origin with precursor information.
- // Example: iframe sandbox navigated to a.com.
- {"https://a.com", &opaque_precursor_origin, true},
- // URL that comes from the web can never commit in an opaque unique
- // origin. It must have precursor information.
- {"https://a.com", &opaque_unique_origin, false},
- // Cross-origin URLs should never work.
- {"https://b.com", ®ular_origin, false},
- {"https://b.com", &opaque_precursor_origin, false},
- // data: URL can never commit in a regular, non-opaque origin.
- {"data:text/html,foo", ®ular_origin, false},
- // This is the default case: data: URLs commit in opaque origin carrying
- // precursor information for the origin that created them.
- {"data:text/html,foo", &opaque_precursor_origin, true},
- // Browser-initiated navigations can result in data: URL committing in
- // opaque unique origin.
- {"data:text/html,foo", &opaque_unique_origin, true},
- // about:blank can commit in regular origin (default case for iframes).
- {"about:blank", ®ular_origin, true},
- // This can happen if data: URL that originated at a.com creates an
- // about:blank iframe.
- {"about:blank", &opaque_precursor_origin, true},
- // Browser-initiated navigations can result in about:blank URL committing
- // in opaque unique origin.
- {"about:blank", &opaque_unique_origin, true},
- // Default behavior of srcdoc is to inherit the origin of the parent
- // document.
- {"about:srcdoc", ®ular_origin, true},
- // This happens for sandboxed srcdoc iframe.
- {"about:srcdoc", &opaque_precursor_origin, true},
- // This can happen with browser-initiated navigation to about:blank or
- // data: URL, which in turn add srcdoc iframe.
- {"about:srcdoc", &opaque_unique_origin, true},
- // Just like srcdoc, blob: URLs can be created in all the cases.
- {"blob:https://a.com/foo", ®ular_origin, true},
- {"blob:https://a.com/foo", &opaque_precursor_origin, true},
- {"blob:https://a.com/foo", &opaque_unique_origin, true},
- {"filesystem:https://a.com/foo", ®ular_origin, true},
- {"filesystem:https://a.com/foo", &opaque_precursor_origin, true},
- // Unlike blob: URLs, filesystem: ones cannot be created in an unique
- // opaque origin.
- {"filesystem:https://a.com/foo", &opaque_unique_origin, false},
- // file: URLs cannot result in regular web origins, regardless of
- // opaqueness.
- {"file:///etc/passwd", ®ular_origin, false},
- {"file:///etc/passwd", &opaque_precursor_origin, false},
- // However, they can result in regular file: origin and an opaque one
- // containing another file: origin as precursor.
- {"file:///etc/passwd", &file_origin, true},
- {"file:///etc/passwd", &file_opaque_precursor_origin, true},
- // It should not be possible to get an opaque unique origin for file:
- // as it is a standard scheme and will always result in a tuple origin
- // or will always be derived by other origin.
- // Note: file:// URLs should become unique opaque origins at some point.
- {"file:///etc/passwd", &opaque_unique_origin, false},
- // The same set as above, but including a host.
- {"file://a.com/etc/passwd", ®ular_origin, false},
- {"file://a.com/etc/passwd", &opaque_precursor_origin, false},
- {"file://a.com/etc/passwd", &file_host_origin, true},
- {"file://a.com/etc/passwd", &file_host_opaque_precursor_origin, true},
- {"file://a.com/etc/passwd", &opaque_unique_origin, false},
- // Locally registered standard scheme should behave the same way
- // as built-in standard schemes.
- {"new-standard://host/foo", &new_standard_origin, true},
- {"new-standard://host/foo", &new_standard_opaque_precursor_origin, true},
- {"new-standard://host/foo", &opaque_unique_origin, false},
- {"new-standard://host2/foo", &new_standard_origin, false},
- {"new-standard://host2/foo", &new_standard_opaque_precursor_origin,
- false},
- // A non-standard scheme should never commit in an standard origin or
- // opaque origin with standard precursor information.
- {"non-standard-scheme://a.com/foo", ®ular_origin, false},
- {"non-standard-scheme://a.com/foo", &opaque_precursor_origin, false},
- // However, it should be fine to commit in unique opaque origins or in its
- // own origin.
- // Note: since non-standard scheme URLs don't parse out anything
- // but the scheme, using a random different hostname here would work.
- {"non-standard-scheme://b.com/foo2", &opaque_unique_origin, true},
- {"non-standard-scheme://b.com/foo3", &non_standard_scheme_origin, true},
- {"non-standard-scheme://b.com/foo4",
- &non_standard_opaque_precursor_origin, true},
- // No access scheme can only commit in opaque origin.
- {"standard-but-noaccess://a.com/foo", ®ular_origin, false},
- {"standard-but-noaccess://a.com/foo", &opaque_precursor_origin, false},
- {"standard-but-noaccess://a.com/foo", &opaque_unique_origin, true},
- {"standard-but-noaccess://a.com/foo", &no_access_origin, true},
- {"standard-but-noaccess://a.com/foo", &no_access_opaque_precursor_origin,
- true},
- {"standard-but-noaccess://b.com/foo", &no_access_origin, true},
- {"standard-but-noaccess://b.com/foo", &no_access_opaque_precursor_origin,
- true},
- // Local schemes can be non-standard, verify they also work as expected.
- {"local-but-nonstandard://a.com", ®ular_origin, false},
- {"local-but-nonstandard://a.com", &opaque_precursor_origin, false},
- {"local-but-nonstandard://a.com", &opaque_unique_origin, true},
- {"local-but-nonstandard://a.com", &local_non_standard_origin, true},
- {"local-but-nonstandard://a.com",
- &local_non_standard_opaque_precursor_origin, true},
- };
- for (const auto& test_case : kTestCases) {
- SCOPED_TRACE(testing::Message() << "(origin, url): (" << *test_case.origin
- << ", " << test_case.url << ")");
- EXPECT_EQ(test_case.expected_value,
- test_case.origin->CanBeDerivedFrom(GURL(test_case.url)));
- }
- }
- TEST_F(OriginTest, GetDebugString) {
- Origin http_origin = Origin::Create(GURL("http://192.168.9.1"));
- EXPECT_STREQ(http_origin.GetDebugString().c_str(), "http://192.168.9.1");
- Origin http_opaque_origin = http_origin.DeriveNewOpaqueOrigin();
- EXPECT_THAT(
- http_opaque_origin.GetDebugString().c_str(),
- ::testing::MatchesRegex(
- "null \\[internally: \\(\\w*\\) derived from http://192.168.9.1\\]"));
- EXPECT_THAT(
- http_opaque_origin.GetDebugString(false /* include_nonce */).c_str(),
- ::testing::MatchesRegex(
- "null \\[internally: derived from http://192.168.9.1\\]"));
- Origin data_origin = Origin::Create(GURL("data:"));
- EXPECT_STREQ(data_origin.GetDebugString().c_str(),
- "null [internally: (nonce TBD) anonymous]");
- // The nonce of the origin will be initialized if a new opaque origin is
- // derived.
- Origin data_derived_origin = data_origin.DeriveNewOpaqueOrigin();
- EXPECT_THAT(
- data_derived_origin.GetDebugString().c_str(),
- ::testing::MatchesRegex("null \\[internally: \\(\\w*\\) anonymous\\]"));
- EXPECT_THAT(
- data_derived_origin.GetDebugString(false /* include_nonce */).c_str(),
- ::testing::MatchesRegex("null \\[internally: anonymous\\]"));
- Origin file_origin = Origin::Create(GURL("file:///etc/passwd"));
- EXPECT_STREQ(file_origin.GetDebugString().c_str(),
- "file:// [internally: file://]");
- Origin file_server_origin =
- Origin::Create(GURL("file://example.com/etc/passwd"));
- EXPECT_STREQ(file_server_origin.GetDebugString().c_str(),
- "file:// [internally: file://example.com]");
- }
- TEST_F(OriginTest, Deserialize) {
- std::vector<GURL> valid_urls = {
- GURL("https://a.com"), GURL("http://a"),
- GURL("http://a:80"), GURL("file://a.com/etc/passwd"),
- GURL("file:///etc/passwd"), GURL("http://192.168.1.1"),
- GURL("http://[2001:db8::1]/"),
- };
- for (const GURL& url : valid_urls) {
- SCOPED_TRACE(url.spec());
- Origin origin = Origin::Create(url);
- absl::optional<std::string> serialized = SerializeWithNonce(origin);
- ASSERT_TRUE(serialized);
- absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
- ASSERT_TRUE(deserialized.has_value());
- EXPECT_TRUE(DoEqualityComparisons(origin, deserialized.value(), true));
- EXPECT_EQ(origin.GetDebugString(), deserialized.value().GetDebugString());
- }
- }
- TEST_F(OriginTest, DeserializeInvalid) {
- EXPECT_EQ(absl::nullopt, Deserialize(std::string()));
- EXPECT_EQ(absl::nullopt, Deserialize("deadbeef"));
- EXPECT_EQ(absl::nullopt, Deserialize("0123456789"));
- EXPECT_EQ(absl::nullopt, Deserialize("https://a.com"));
- EXPECT_EQ(absl::nullopt, Deserialize("https://192.168.1.1"));
- }
- TEST_F(OriginTest, SerializeTBDNonce) {
- std::vector<GURL> invalid_urls = {
- GURL("data:uniqueness"), GURL("data:,"),
- GURL("data:text/html,Hello!"), GURL("javascript:alert(1)"),
- GURL("about:blank"), GURL("google.com"),
- };
- for (const GURL& url : invalid_urls) {
- SCOPED_TRACE(url.spec());
- Origin origin = Origin::Create(url);
- absl::optional<std::string> serialized = SerializeWithNonce(origin);
- absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
- ASSERT_TRUE(deserialized.has_value());
- // Can't use DoEqualityComparisons here since empty nonces are never ==
- // unless they are the same object.
- EXPECT_EQ(origin.GetDebugString(), deserialized.value().GetDebugString());
- }
- {
- // Same basic test as above, but without a GURL to create tuple_.
- Origin opaque;
- absl::optional<std::string> serialized = SerializeWithNonce(opaque);
- ASSERT_TRUE(serialized);
- absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
- ASSERT_TRUE(deserialized.has_value());
- // Can't use DoEqualityComparisons here since empty nonces are never ==
- // unless they are the same object.
- EXPECT_EQ(opaque.GetDebugString(), deserialized.value().GetDebugString());
- }
- // Now force initialization of the nonce prior to serialization.
- for (const GURL& url : invalid_urls) {
- SCOPED_TRACE(url.spec());
- Origin origin = Origin::Create(url);
- absl::optional<std::string> serialized =
- SerializeWithNonceAndInitIfNeeded(origin);
- absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
- ASSERT_TRUE(deserialized.has_value());
- // The nonce should have been initialized prior to Serialization().
- EXPECT_EQ(origin, deserialized.value());
- }
- }
- TEST_F(OriginTest, DeserializeValidNonce) {
- Origin opaque;
- GetNonce(opaque);
- absl::optional<std::string> serialized = SerializeWithNonce(opaque);
- ASSERT_TRUE(serialized);
- absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
- ASSERT_TRUE(deserialized.has_value());
- EXPECT_TRUE(DoEqualityComparisons(opaque, deserialized.value(), true));
- EXPECT_EQ(opaque.GetDebugString(), deserialized.value().GetDebugString());
- }
- TEST_F(OriginTest, IsSameOriginWith) {
- url::Origin opaque_origin;
- GURL foo_url = GURL("https://foo.com/path");
- url::Origin foo_origin = url::Origin::Create(foo_url);
- GURL bar_url = GURL("https://bar.com/path");
- url::Origin bar_origin = url::Origin::Create(bar_url);
- EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_origin));
- EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_url));
- EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_origin));
- EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_url));
- EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_origin));
- EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_url));
- // Documenting legacy behavior. This doesn't necessarily mean that the legacy
- // behavior is correct (or desirable in the long-term).
- EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL("about:blank")));
- EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL())); // Invalid GURL.
- EXPECT_TRUE(foo_origin.IsSameOriginWith(GURL("blob:https://foo.com/guid")));
- }
- INSTANTIATE_TYPED_TEST_SUITE_P(UrlOrigin,
- AbstractOriginTest,
- UrlOriginTestTraits);
- } // namespace url
|