origin_unittest.cc 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include <stddef.h>
  5. #include <stdint.h>
  6. #include "base/memory/raw_ptr.h"
  7. #include "testing/gmock/include/gmock/gmock.h"
  8. #include "testing/gtest/include/gtest/gtest.h"
  9. #include "url/gurl.h"
  10. #include "url/origin.h"
  11. #include "url/origin_abstract_tests.h"
  12. #include "url/url_util.h"
  13. namespace url {
  14. class OriginTest : public ::testing::Test {
  15. public:
  16. void SetUp() override {
  17. // Add two schemes which are local but nonstandard.
  18. AddLocalScheme("local-but-nonstandard");
  19. AddLocalScheme("also-local-but-nonstandard");
  20. // Add a scheme that's both local and standard.
  21. AddStandardScheme("local-and-standard", SchemeType::SCHEME_WITH_HOST);
  22. AddLocalScheme("local-and-standard");
  23. // Add a scheme that's standard but no-access. We still want these to
  24. // form valid SchemeHostPorts, even though they always commit as opaque
  25. // origins, so that they can represent the source of the resource even if
  26. // it's not committable as a non-opaque origin.
  27. AddStandardScheme("standard-but-noaccess", SchemeType::SCHEME_WITH_HOST);
  28. AddNoAccessScheme("standard-but-noaccess");
  29. }
  30. ::testing::AssertionResult DoEqualityComparisons(const url::Origin& a,
  31. const url::Origin& b,
  32. bool should_compare_equal) {
  33. ::testing::AssertionResult failure = ::testing::AssertionFailure();
  34. failure << "DoEqualityComparisons failure. Expecting "
  35. << (should_compare_equal ? "equality" : "inequality")
  36. << " between:\n a\n Which is: " << a
  37. << "\n b\n Which is: " << b << "\nThe following check failed: ";
  38. if (a.IsSameOriginWith(b) != should_compare_equal)
  39. return failure << "a.IsSameOriginWith(b)";
  40. if (b.IsSameOriginWith(a) != should_compare_equal)
  41. return failure << "b.IsSameOriginWith(a)";
  42. if ((a == b) != should_compare_equal)
  43. return failure << "(a == b)";
  44. if ((b == a) != should_compare_equal)
  45. return failure << "(b == a)";
  46. if ((b != a) != !should_compare_equal)
  47. return failure << "(b != a)";
  48. if ((a != b) != !should_compare_equal)
  49. return failure << "(a != b)";
  50. return ::testing::AssertionSuccess();
  51. }
  52. bool HasNonceTokenBeenInitialized(const url::Origin& origin) {
  53. EXPECT_TRUE(origin.opaque());
  54. // Avoid calling nonce_.token() here, to not trigger lazy initialization.
  55. return !origin.nonce_->token_.is_empty();
  56. }
  57. Origin::Nonce CreateNonce() { return Origin::Nonce(); }
  58. Origin::Nonce CreateNonce(base::UnguessableToken nonce) {
  59. return Origin::Nonce(nonce);
  60. }
  61. const base::UnguessableToken* GetNonce(const Origin& origin) {
  62. return origin.GetNonceForSerialization();
  63. }
  64. // Wrappers around url::Origin methods to expose it to tests.
  65. absl::optional<Origin> UnsafelyCreateOpaqueOriginWithoutNormalization(
  66. base::StringPiece precursor_scheme,
  67. base::StringPiece precursor_host,
  68. uint16_t precursor_port,
  69. const Origin::Nonce& nonce) {
  70. return Origin::UnsafelyCreateOpaqueOriginWithoutNormalization(
  71. precursor_scheme, precursor_host, precursor_port, nonce);
  72. }
  73. absl::optional<std::string> SerializeWithNonce(const Origin& origin) {
  74. return origin.SerializeWithNonce();
  75. }
  76. absl::optional<std::string> SerializeWithNonceAndInitIfNeeded(
  77. Origin& origin) {
  78. return origin.SerializeWithNonceAndInitIfNeeded();
  79. }
  80. absl::optional<Origin> Deserialize(const std::string& value) {
  81. return Origin::Deserialize(value);
  82. }
  83. private:
  84. ScopedSchemeRegistryForTests scoped_registry_;
  85. };
  86. TEST_F(OriginTest, OpaqueOriginComparison) {
  87. // A default-constructed Origin should should be cross origin to everything
  88. // but itself.
  89. url::Origin opaque_a, opaque_b;
  90. EXPECT_TRUE(opaque_a.opaque());
  91. EXPECT_EQ("", opaque_a.scheme());
  92. EXPECT_EQ("", opaque_a.host());
  93. EXPECT_EQ(0, opaque_a.port());
  94. EXPECT_EQ(SchemeHostPort(), opaque_a.GetTupleOrPrecursorTupleIfOpaque());
  95. EXPECT_FALSE(opaque_a.GetTupleOrPrecursorTupleIfOpaque().IsValid());
  96. EXPECT_TRUE(opaque_b.opaque());
  97. EXPECT_EQ("", opaque_b.scheme());
  98. EXPECT_EQ("", opaque_b.host());
  99. EXPECT_EQ(0, opaque_b.port());
  100. EXPECT_EQ(SchemeHostPort(), opaque_b.GetTupleOrPrecursorTupleIfOpaque());
  101. EXPECT_FALSE(opaque_b.GetTupleOrPrecursorTupleIfOpaque().IsValid());
  102. // Two default-constructed Origins should always be cross origin to each
  103. // other.
  104. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, false));
  105. EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
  106. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
  107. // The streaming operator should not trigger lazy initialization to the token.
  108. std::ostringstream stream;
  109. stream << opaque_a;
  110. EXPECT_STREQ("null [internally: (nonce TBD) anonymous]",
  111. stream.str().c_str());
  112. EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
  113. // None of the operations thus far should have triggered lazy-generation of
  114. // the UnguessableToken. Copying an origin, however, should trigger this.
  115. EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
  116. EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_b));
  117. opaque_b = opaque_a;
  118. EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_a));
  119. EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
  120. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, true));
  121. EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
  122. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
  123. // Move-initializing to a fresh Origin should restore the lazy initialization.
  124. opaque_a = url::Origin();
  125. EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
  126. EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
  127. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, false));
  128. EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
  129. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
  130. // Comparing two opaque Origins with matching SchemeHostPorts should trigger
  131. // lazy initialization.
  132. EXPECT_FALSE(HasNonceTokenBeenInitialized(opaque_a));
  133. EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
  134. bool should_swap = opaque_b < opaque_a;
  135. EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_a));
  136. EXPECT_TRUE(HasNonceTokenBeenInitialized(opaque_b));
  137. if (should_swap)
  138. std::swap(opaque_a, opaque_b);
  139. EXPECT_LT(opaque_a, opaque_b);
  140. EXPECT_FALSE(opaque_b < opaque_a);
  141. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_b, false));
  142. EXPECT_TRUE(DoEqualityComparisons(opaque_b, opaque_b, true));
  143. EXPECT_TRUE(DoEqualityComparisons(opaque_a, opaque_a, true));
  144. EXPECT_LT(opaque_a, url::Origin::Create(GURL("http://www.google.com")));
  145. EXPECT_LT(opaque_b, url::Origin::Create(GURL("http://www.google.com")));
  146. EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL(), opaque_b));
  147. EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL("about:blank"), opaque_b));
  148. EXPECT_EQ(opaque_b, url::Origin::Resolve(GURL("about:srcdoc"), opaque_b));
  149. EXPECT_EQ(opaque_b,
  150. url::Origin::Resolve(GURL("about:blank?hello#whee"), opaque_b));
  151. }
  152. TEST_F(OriginTest, ConstructFromTuple) {
  153. struct TestCases {
  154. const char* const scheme;
  155. const char* const host;
  156. const uint16_t port;
  157. } cases[] = {
  158. {"http", "example.com", 80},
  159. {"http", "example.com", 123},
  160. {"https", "example.com", 443},
  161. };
  162. for (const auto& test_case : cases) {
  163. testing::Message scope_message;
  164. scope_message << test_case.scheme << "://" << test_case.host << ":"
  165. << test_case.port;
  166. SCOPED_TRACE(scope_message);
  167. Origin origin = Origin::CreateFromNormalizedTuple(
  168. test_case.scheme, test_case.host, test_case.port);
  169. EXPECT_EQ(test_case.scheme, origin.scheme());
  170. EXPECT_EQ(test_case.host, origin.host());
  171. EXPECT_EQ(test_case.port, origin.port());
  172. }
  173. }
  174. TEST_F(OriginTest, Serialization) {
  175. struct TestCases {
  176. const char* const url;
  177. const char* const expected;
  178. const char* const expected_log;
  179. } cases[] = {
  180. {"http://192.168.9.1/", "http://192.168.9.1"},
  181. {"http://[2001:db8::1]/", "http://[2001:db8::1]"},
  182. {"http://☃.net/", "http://xn--n3h.net"},
  183. {"http://example.com/", "http://example.com"},
  184. {"http://example.com:123/", "http://example.com:123"},
  185. {"https://example.com/", "https://example.com"},
  186. {"https://example.com:123/", "https://example.com:123"},
  187. {"file:///etc/passwd", "file://", "file:// [internally: file://]"},
  188. {"file://example.com/etc/passwd", "file://",
  189. "file:// [internally: file://example.com]"},
  190. {"data:,", "null", "null [internally: (nonce TBD) anonymous]"},
  191. };
  192. for (const auto& test_case : cases) {
  193. SCOPED_TRACE(test_case.url);
  194. GURL url(test_case.url);
  195. EXPECT_TRUE(url.is_valid());
  196. Origin origin = Origin::Create(url);
  197. std::string serialized = origin.Serialize();
  198. ExpectParsedUrlsEqual(GURL(serialized), origin.GetURL());
  199. EXPECT_EQ(test_case.expected, serialized);
  200. // The '<<' operator sometimes produces additional information.
  201. std::stringstream out;
  202. out << origin;
  203. if (test_case.expected_log)
  204. EXPECT_EQ(test_case.expected_log, out.str());
  205. else
  206. EXPECT_EQ(test_case.expected, out.str());
  207. }
  208. }
  209. TEST_F(OriginTest, Comparison) {
  210. // These URLs are arranged in increasing order:
  211. const char* const urls[] = {
  212. "data:uniqueness", "http://a:80", "http://b:80",
  213. "https://a:80", "https://b:80", "http://a:81",
  214. "http://b:81", "https://a:81", "https://b:81",
  215. };
  216. // Validate the comparison logic still works when creating a canonical origin,
  217. // when any created opaque origins contain a nonce.
  218. {
  219. // Pre-create the origins, as the internal nonce for unique origins changes
  220. // with each freshly-constructed Origin (that's not copied).
  221. std::vector<Origin> origins;
  222. for (const auto* test_url : urls)
  223. origins.push_back(Origin::Create(GURL(test_url)));
  224. for (size_t i = 0; i < origins.size(); i++) {
  225. const Origin& current = origins[i];
  226. for (size_t j = i; j < origins.size(); j++) {
  227. const Origin& to_compare = origins[j];
  228. EXPECT_EQ(i < j, current < to_compare) << i << " < " << j;
  229. EXPECT_EQ(j < i, to_compare < current) << j << " < " << i;
  230. }
  231. }
  232. }
  233. }
  234. TEST_F(OriginTest, UnsafelyCreate) {
  235. struct TestCase {
  236. const char* scheme;
  237. const char* host;
  238. uint16_t port;
  239. } cases[] = {
  240. {"http", "example.com", 80},
  241. {"http", "example.com", 123},
  242. {"https", "example.com", 443},
  243. {"https", "example.com", 123},
  244. {"http", "example.com", 0}, // 0 is a valid port for http.
  245. {"file", "", 0}, // 0 indicates "no port" for file: scheme.
  246. {"file", "example.com", 0},
  247. };
  248. for (const auto& test : cases) {
  249. SCOPED_TRACE(testing::Message()
  250. << test.scheme << "://" << test.host << ":" << test.port);
  251. absl::optional<url::Origin> origin =
  252. url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(
  253. test.scheme, test.host, test.port);
  254. ASSERT_TRUE(origin);
  255. EXPECT_EQ(test.scheme, origin->scheme());
  256. EXPECT_EQ(test.host, origin->host());
  257. EXPECT_EQ(test.port, origin->port());
  258. EXPECT_FALSE(origin->opaque());
  259. EXPECT_TRUE(origin->IsSameOriginWith(*origin));
  260. ExpectParsedUrlsEqual(GURL(origin->Serialize()), origin->GetURL());
  261. base::UnguessableToken nonce = base::UnguessableToken::Create();
  262. absl::optional<url::Origin> opaque_origin =
  263. UnsafelyCreateOpaqueOriginWithoutNormalization(
  264. test.scheme, test.host, test.port, CreateNonce(nonce));
  265. ASSERT_TRUE(opaque_origin);
  266. EXPECT_TRUE(opaque_origin->opaque());
  267. EXPECT_FALSE(*opaque_origin == origin);
  268. EXPECT_EQ(opaque_origin->GetTupleOrPrecursorTupleIfOpaque(),
  269. origin->GetTupleOrPrecursorTupleIfOpaque());
  270. EXPECT_EQ(opaque_origin,
  271. UnsafelyCreateOpaqueOriginWithoutNormalization(
  272. test.scheme, test.host, test.port, CreateNonce(nonce)));
  273. EXPECT_FALSE(*opaque_origin == origin->DeriveNewOpaqueOrigin());
  274. }
  275. }
  276. TEST_F(OriginTest, UnsafelyCreateUniqueOnInvalidInput) {
  277. url::AddStandardScheme("host-only", url::SCHEME_WITH_HOST);
  278. url::AddStandardScheme("host-port-only", url::SCHEME_WITH_HOST_AND_PORT);
  279. struct TestCases {
  280. const char* scheme;
  281. const char* host;
  282. uint16_t port = 80;
  283. } cases[] = {{"", "", 33},
  284. {"data", "", 0},
  285. {"blob", "", 0},
  286. {"filesystem", "", 0},
  287. {"data", "example.com"},
  288. {"http", "☃.net"},
  289. {"http\nmore", "example.com"},
  290. {"http\rmore", "example.com"},
  291. {"http\n", "example.com"},
  292. {"http\r", "example.com"},
  293. {"http", "example.com\nnot-example.com"},
  294. {"http", "example.com\rnot-example.com"},
  295. {"http", "example.com\n"},
  296. {"http", "example.com\r"},
  297. {"unknown-scheme", "example.com"},
  298. {"host-only", "\r", 0},
  299. {"host-only", "example.com", 22},
  300. {"file", "", 123}}; // file: shouldn't have a port.
  301. for (const auto& test : cases) {
  302. SCOPED_TRACE(testing::Message()
  303. << test.scheme << "://" << test.host << ":" << test.port);
  304. EXPECT_FALSE(UnsafelyCreateOpaqueOriginWithoutNormalization(
  305. test.scheme, test.host, test.port, CreateNonce()));
  306. EXPECT_FALSE(url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(
  307. test.scheme, test.host, test.port));
  308. }
  309. // An empty scheme/host/port tuple is not a valid tuple origin.
  310. EXPECT_FALSE(
  311. url::Origin::UnsafelyCreateTupleOriginWithoutNormalization("", "", 0));
  312. // Opaque origins with unknown precursors are allowed.
  313. base::UnguessableToken token = base::UnguessableToken::Create();
  314. absl::optional<url::Origin> anonymous_opaque =
  315. UnsafelyCreateOpaqueOriginWithoutNormalization("", "", 0,
  316. CreateNonce(token));
  317. ASSERT_TRUE(anonymous_opaque)
  318. << "An invalid tuple is a valid input to "
  319. << "UnsafelyCreateOpaqueOriginWithoutNormalization, so long as it is "
  320. << "the canonical form of the invalid tuple.";
  321. EXPECT_TRUE(anonymous_opaque->opaque());
  322. EXPECT_EQ(*GetNonce(anonymous_opaque.value()), token);
  323. EXPECT_EQ(anonymous_opaque->GetTupleOrPrecursorTupleIfOpaque(),
  324. url::SchemeHostPort());
  325. }
  326. TEST_F(OriginTest, UnsafelyCreateUniqueViaEmbeddedNulls) {
  327. struct TestCases {
  328. base::StringPiece scheme;
  329. base::StringPiece host;
  330. uint16_t port = 80;
  331. } cases[] = {{{"http\0more", 9}, {"example.com", 11}},
  332. {{"http\0", 5}, {"example.com", 11}},
  333. {{"\0http", 5}, {"example.com", 11}},
  334. {{"http"}, {"example.com\0not-example.com", 27}},
  335. {{"http"}, {"example.com\0", 12}},
  336. {{"http"}, {"\0example.com", 12}},
  337. {{""}, {"\0", 1}, 0},
  338. {{"\0", 1}, {""}, 0}};
  339. for (const auto& test : cases) {
  340. SCOPED_TRACE(testing::Message()
  341. << test.scheme << "://" << test.host << ":" << test.port);
  342. EXPECT_FALSE(url::Origin::UnsafelyCreateTupleOriginWithoutNormalization(
  343. test.scheme, test.host, test.port));
  344. EXPECT_FALSE(UnsafelyCreateOpaqueOriginWithoutNormalization(
  345. test.scheme, test.host, test.port, CreateNonce()));
  346. }
  347. }
  348. TEST_F(OriginTest, DomainIs) {
  349. const struct {
  350. const char* url;
  351. const char* lower_ascii_domain;
  352. bool expected_domain_is;
  353. } kTestCases[] = {
  354. {"http://google.com/foo", "google.com", true},
  355. {"http://www.google.com:99/foo", "google.com", true},
  356. {"http://www.google.com.cn/foo", "google.com", false},
  357. {"http://www.google.comm", "google.com", false},
  358. {"http://www.iamnotgoogle.com/foo", "google.com", false},
  359. {"http://www.google.com/foo", "Google.com", false},
  360. // If the host ends with a dot, it matches domains with or without a dot.
  361. {"http://www.google.com./foo", "google.com", true},
  362. {"http://www.google.com./foo", "google.com.", true},
  363. {"http://www.google.com./foo", ".com", true},
  364. {"http://www.google.com./foo", ".com.", true},
  365. // But, if the host doesn't end with a dot and the input domain does, then
  366. // it's considered to not match.
  367. {"http://google.com/foo", "google.com.", false},
  368. // If the host ends with two dots, it doesn't match.
  369. {"http://www.google.com../foo", "google.com", false},
  370. // Filesystem scheme.
  371. {"filesystem:http://www.google.com:99/foo/", "google.com", true},
  372. {"filesystem:http://www.iamnotgoogle.com/foo/", "google.com", false},
  373. // File scheme.
  374. {"file:///home/user/text.txt", "", false},
  375. {"file:///home/user/text.txt", "txt", false},
  376. };
  377. for (const auto& test_case : kTestCases) {
  378. SCOPED_TRACE(testing::Message()
  379. << "(url, domain): (" << test_case.url << ", "
  380. << test_case.lower_ascii_domain << ")");
  381. GURL url(test_case.url);
  382. ASSERT_TRUE(url.is_valid());
  383. Origin origin = Origin::Create(url);
  384. EXPECT_EQ(test_case.expected_domain_is,
  385. origin.DomainIs(test_case.lower_ascii_domain));
  386. EXPECT_FALSE(
  387. origin.DeriveNewOpaqueOrigin().DomainIs(test_case.lower_ascii_domain));
  388. }
  389. // If the URL is invalid, DomainIs returns false.
  390. GURL invalid_url("google.com");
  391. ASSERT_FALSE(invalid_url.is_valid());
  392. EXPECT_FALSE(Origin::Create(invalid_url).DomainIs("google.com"));
  393. // Unique origins.
  394. EXPECT_FALSE(Origin().DomainIs(""));
  395. EXPECT_FALSE(Origin().DomainIs("com"));
  396. }
  397. TEST_F(OriginTest, DebugAlias) {
  398. Origin origin1 = Origin::Create(GURL("https://foo.com/bar"));
  399. DEBUG_ALIAS_FOR_ORIGIN(origin1_debug_alias, origin1);
  400. EXPECT_STREQ("https://foo.com", origin1_debug_alias);
  401. }
  402. TEST_F(OriginTest, CanBeDerivedFrom) {
  403. AddStandardScheme("new-standard", SchemeType::SCHEME_WITH_HOST);
  404. Origin opaque_unique_origin = Origin();
  405. Origin regular_origin = Origin::Create(GURL("https://a.com/"));
  406. Origin opaque_precursor_origin = regular_origin.DeriveNewOpaqueOrigin();
  407. Origin file_origin = Origin::Create(GURL("file:///foo/bar"));
  408. Origin file_opaque_precursor_origin = file_origin.DeriveNewOpaqueOrigin();
  409. Origin file_host_origin = Origin::Create(GURL("file://a.com/foo/bar"));
  410. Origin file_host_opaque_precursor_origin =
  411. file_host_origin.DeriveNewOpaqueOrigin();
  412. Origin non_standard_scheme_origin =
  413. Origin::Create(GURL("non-standard-scheme:foo"));
  414. Origin non_standard_opaque_precursor_origin =
  415. non_standard_scheme_origin.DeriveNewOpaqueOrigin();
  416. // Also, add new standard scheme that is local to the test.
  417. Origin new_standard_origin = Origin::Create(GURL("new-standard://host/"));
  418. Origin new_standard_opaque_precursor_origin =
  419. new_standard_origin.DeriveNewOpaqueOrigin();
  420. // No access schemes always get unique opaque origins.
  421. Origin no_access_origin =
  422. Origin::Create(GURL("standard-but-noaccess://b.com"));
  423. Origin no_access_opaque_precursor_origin =
  424. no_access_origin.DeriveNewOpaqueOrigin();
  425. Origin local_non_standard_origin =
  426. Origin::Create(GURL("local-but-nonstandard://a.com"));
  427. Origin local_non_standard_opaque_precursor_origin =
  428. local_non_standard_origin.DeriveNewOpaqueOrigin();
  429. // Call origin.CanBeDerivedFrom(url) for each of the following test cases
  430. // and ensure that it returns |expected_value|
  431. const struct {
  432. const char* url;
  433. raw_ptr<Origin> origin;
  434. bool expected_value;
  435. } kTestCases[] = {
  436. {"https://a.com", &regular_origin, true},
  437. // Web URL can commit in an opaque origin with precursor information.
  438. // Example: iframe sandbox navigated to a.com.
  439. {"https://a.com", &opaque_precursor_origin, true},
  440. // URL that comes from the web can never commit in an opaque unique
  441. // origin. It must have precursor information.
  442. {"https://a.com", &opaque_unique_origin, false},
  443. // Cross-origin URLs should never work.
  444. {"https://b.com", &regular_origin, false},
  445. {"https://b.com", &opaque_precursor_origin, false},
  446. // data: URL can never commit in a regular, non-opaque origin.
  447. {"data:text/html,foo", &regular_origin, false},
  448. // This is the default case: data: URLs commit in opaque origin carrying
  449. // precursor information for the origin that created them.
  450. {"data:text/html,foo", &opaque_precursor_origin, true},
  451. // Browser-initiated navigations can result in data: URL committing in
  452. // opaque unique origin.
  453. {"data:text/html,foo", &opaque_unique_origin, true},
  454. // about:blank can commit in regular origin (default case for iframes).
  455. {"about:blank", &regular_origin, true},
  456. // This can happen if data: URL that originated at a.com creates an
  457. // about:blank iframe.
  458. {"about:blank", &opaque_precursor_origin, true},
  459. // Browser-initiated navigations can result in about:blank URL committing
  460. // in opaque unique origin.
  461. {"about:blank", &opaque_unique_origin, true},
  462. // Default behavior of srcdoc is to inherit the origin of the parent
  463. // document.
  464. {"about:srcdoc", &regular_origin, true},
  465. // This happens for sandboxed srcdoc iframe.
  466. {"about:srcdoc", &opaque_precursor_origin, true},
  467. // This can happen with browser-initiated navigation to about:blank or
  468. // data: URL, which in turn add srcdoc iframe.
  469. {"about:srcdoc", &opaque_unique_origin, true},
  470. // Just like srcdoc, blob: URLs can be created in all the cases.
  471. {"blob:https://a.com/foo", &regular_origin, true},
  472. {"blob:https://a.com/foo", &opaque_precursor_origin, true},
  473. {"blob:https://a.com/foo", &opaque_unique_origin, true},
  474. {"filesystem:https://a.com/foo", &regular_origin, true},
  475. {"filesystem:https://a.com/foo", &opaque_precursor_origin, true},
  476. // Unlike blob: URLs, filesystem: ones cannot be created in an unique
  477. // opaque origin.
  478. {"filesystem:https://a.com/foo", &opaque_unique_origin, false},
  479. // file: URLs cannot result in regular web origins, regardless of
  480. // opaqueness.
  481. {"file:///etc/passwd", &regular_origin, false},
  482. {"file:///etc/passwd", &opaque_precursor_origin, false},
  483. // However, they can result in regular file: origin and an opaque one
  484. // containing another file: origin as precursor.
  485. {"file:///etc/passwd", &file_origin, true},
  486. {"file:///etc/passwd", &file_opaque_precursor_origin, true},
  487. // It should not be possible to get an opaque unique origin for file:
  488. // as it is a standard scheme and will always result in a tuple origin
  489. // or will always be derived by other origin.
  490. // Note: file:// URLs should become unique opaque origins at some point.
  491. {"file:///etc/passwd", &opaque_unique_origin, false},
  492. // The same set as above, but including a host.
  493. {"file://a.com/etc/passwd", &regular_origin, false},
  494. {"file://a.com/etc/passwd", &opaque_precursor_origin, false},
  495. {"file://a.com/etc/passwd", &file_host_origin, true},
  496. {"file://a.com/etc/passwd", &file_host_opaque_precursor_origin, true},
  497. {"file://a.com/etc/passwd", &opaque_unique_origin, false},
  498. // Locally registered standard scheme should behave the same way
  499. // as built-in standard schemes.
  500. {"new-standard://host/foo", &new_standard_origin, true},
  501. {"new-standard://host/foo", &new_standard_opaque_precursor_origin, true},
  502. {"new-standard://host/foo", &opaque_unique_origin, false},
  503. {"new-standard://host2/foo", &new_standard_origin, false},
  504. {"new-standard://host2/foo", &new_standard_opaque_precursor_origin,
  505. false},
  506. // A non-standard scheme should never commit in an standard origin or
  507. // opaque origin with standard precursor information.
  508. {"non-standard-scheme://a.com/foo", &regular_origin, false},
  509. {"non-standard-scheme://a.com/foo", &opaque_precursor_origin, false},
  510. // However, it should be fine to commit in unique opaque origins or in its
  511. // own origin.
  512. // Note: since non-standard scheme URLs don't parse out anything
  513. // but the scheme, using a random different hostname here would work.
  514. {"non-standard-scheme://b.com/foo2", &opaque_unique_origin, true},
  515. {"non-standard-scheme://b.com/foo3", &non_standard_scheme_origin, true},
  516. {"non-standard-scheme://b.com/foo4",
  517. &non_standard_opaque_precursor_origin, true},
  518. // No access scheme can only commit in opaque origin.
  519. {"standard-but-noaccess://a.com/foo", &regular_origin, false},
  520. {"standard-but-noaccess://a.com/foo", &opaque_precursor_origin, false},
  521. {"standard-but-noaccess://a.com/foo", &opaque_unique_origin, true},
  522. {"standard-but-noaccess://a.com/foo", &no_access_origin, true},
  523. {"standard-but-noaccess://a.com/foo", &no_access_opaque_precursor_origin,
  524. true},
  525. {"standard-but-noaccess://b.com/foo", &no_access_origin, true},
  526. {"standard-but-noaccess://b.com/foo", &no_access_opaque_precursor_origin,
  527. true},
  528. // Local schemes can be non-standard, verify they also work as expected.
  529. {"local-but-nonstandard://a.com", &regular_origin, false},
  530. {"local-but-nonstandard://a.com", &opaque_precursor_origin, false},
  531. {"local-but-nonstandard://a.com", &opaque_unique_origin, true},
  532. {"local-but-nonstandard://a.com", &local_non_standard_origin, true},
  533. {"local-but-nonstandard://a.com",
  534. &local_non_standard_opaque_precursor_origin, true},
  535. };
  536. for (const auto& test_case : kTestCases) {
  537. SCOPED_TRACE(testing::Message() << "(origin, url): (" << *test_case.origin
  538. << ", " << test_case.url << ")");
  539. EXPECT_EQ(test_case.expected_value,
  540. test_case.origin->CanBeDerivedFrom(GURL(test_case.url)));
  541. }
  542. }
  543. TEST_F(OriginTest, GetDebugString) {
  544. Origin http_origin = Origin::Create(GURL("http://192.168.9.1"));
  545. EXPECT_STREQ(http_origin.GetDebugString().c_str(), "http://192.168.9.1");
  546. Origin http_opaque_origin = http_origin.DeriveNewOpaqueOrigin();
  547. EXPECT_THAT(
  548. http_opaque_origin.GetDebugString().c_str(),
  549. ::testing::MatchesRegex(
  550. "null \\[internally: \\(\\w*\\) derived from http://192.168.9.1\\]"));
  551. EXPECT_THAT(
  552. http_opaque_origin.GetDebugString(false /* include_nonce */).c_str(),
  553. ::testing::MatchesRegex(
  554. "null \\[internally: derived from http://192.168.9.1\\]"));
  555. Origin data_origin = Origin::Create(GURL("data:"));
  556. EXPECT_STREQ(data_origin.GetDebugString().c_str(),
  557. "null [internally: (nonce TBD) anonymous]");
  558. // The nonce of the origin will be initialized if a new opaque origin is
  559. // derived.
  560. Origin data_derived_origin = data_origin.DeriveNewOpaqueOrigin();
  561. EXPECT_THAT(
  562. data_derived_origin.GetDebugString().c_str(),
  563. ::testing::MatchesRegex("null \\[internally: \\(\\w*\\) anonymous\\]"));
  564. EXPECT_THAT(
  565. data_derived_origin.GetDebugString(false /* include_nonce */).c_str(),
  566. ::testing::MatchesRegex("null \\[internally: anonymous\\]"));
  567. Origin file_origin = Origin::Create(GURL("file:///etc/passwd"));
  568. EXPECT_STREQ(file_origin.GetDebugString().c_str(),
  569. "file:// [internally: file://]");
  570. Origin file_server_origin =
  571. Origin::Create(GURL("file://example.com/etc/passwd"));
  572. EXPECT_STREQ(file_server_origin.GetDebugString().c_str(),
  573. "file:// [internally: file://example.com]");
  574. }
  575. TEST_F(OriginTest, Deserialize) {
  576. std::vector<GURL> valid_urls = {
  577. GURL("https://a.com"), GURL("http://a"),
  578. GURL("http://a:80"), GURL("file://a.com/etc/passwd"),
  579. GURL("file:///etc/passwd"), GURL("http://192.168.1.1"),
  580. GURL("http://[2001:db8::1]/"),
  581. };
  582. for (const GURL& url : valid_urls) {
  583. SCOPED_TRACE(url.spec());
  584. Origin origin = Origin::Create(url);
  585. absl::optional<std::string> serialized = SerializeWithNonce(origin);
  586. ASSERT_TRUE(serialized);
  587. absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
  588. ASSERT_TRUE(deserialized.has_value());
  589. EXPECT_TRUE(DoEqualityComparisons(origin, deserialized.value(), true));
  590. EXPECT_EQ(origin.GetDebugString(), deserialized.value().GetDebugString());
  591. }
  592. }
  593. TEST_F(OriginTest, DeserializeInvalid) {
  594. EXPECT_EQ(absl::nullopt, Deserialize(std::string()));
  595. EXPECT_EQ(absl::nullopt, Deserialize("deadbeef"));
  596. EXPECT_EQ(absl::nullopt, Deserialize("0123456789"));
  597. EXPECT_EQ(absl::nullopt, Deserialize("https://a.com"));
  598. EXPECT_EQ(absl::nullopt, Deserialize("https://192.168.1.1"));
  599. }
  600. TEST_F(OriginTest, SerializeTBDNonce) {
  601. std::vector<GURL> invalid_urls = {
  602. GURL("data:uniqueness"), GURL("data:,"),
  603. GURL("data:text/html,Hello!"), GURL("javascript:alert(1)"),
  604. GURL("about:blank"), GURL("google.com"),
  605. };
  606. for (const GURL& url : invalid_urls) {
  607. SCOPED_TRACE(url.spec());
  608. Origin origin = Origin::Create(url);
  609. absl::optional<std::string> serialized = SerializeWithNonce(origin);
  610. absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
  611. ASSERT_TRUE(deserialized.has_value());
  612. // Can't use DoEqualityComparisons here since empty nonces are never ==
  613. // unless they are the same object.
  614. EXPECT_EQ(origin.GetDebugString(), deserialized.value().GetDebugString());
  615. }
  616. {
  617. // Same basic test as above, but without a GURL to create tuple_.
  618. Origin opaque;
  619. absl::optional<std::string> serialized = SerializeWithNonce(opaque);
  620. ASSERT_TRUE(serialized);
  621. absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
  622. ASSERT_TRUE(deserialized.has_value());
  623. // Can't use DoEqualityComparisons here since empty nonces are never ==
  624. // unless they are the same object.
  625. EXPECT_EQ(opaque.GetDebugString(), deserialized.value().GetDebugString());
  626. }
  627. // Now force initialization of the nonce prior to serialization.
  628. for (const GURL& url : invalid_urls) {
  629. SCOPED_TRACE(url.spec());
  630. Origin origin = Origin::Create(url);
  631. absl::optional<std::string> serialized =
  632. SerializeWithNonceAndInitIfNeeded(origin);
  633. absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
  634. ASSERT_TRUE(deserialized.has_value());
  635. // The nonce should have been initialized prior to Serialization().
  636. EXPECT_EQ(origin, deserialized.value());
  637. }
  638. }
  639. TEST_F(OriginTest, DeserializeValidNonce) {
  640. Origin opaque;
  641. GetNonce(opaque);
  642. absl::optional<std::string> serialized = SerializeWithNonce(opaque);
  643. ASSERT_TRUE(serialized);
  644. absl::optional<Origin> deserialized = Deserialize(std::move(*serialized));
  645. ASSERT_TRUE(deserialized.has_value());
  646. EXPECT_TRUE(DoEqualityComparisons(opaque, deserialized.value(), true));
  647. EXPECT_EQ(opaque.GetDebugString(), deserialized.value().GetDebugString());
  648. }
  649. TEST_F(OriginTest, IsSameOriginWith) {
  650. url::Origin opaque_origin;
  651. GURL foo_url = GURL("https://foo.com/path");
  652. url::Origin foo_origin = url::Origin::Create(foo_url);
  653. GURL bar_url = GURL("https://bar.com/path");
  654. url::Origin bar_origin = url::Origin::Create(bar_url);
  655. EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_origin));
  656. EXPECT_FALSE(opaque_origin.IsSameOriginWith(foo_url));
  657. EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_origin));
  658. EXPECT_TRUE(foo_origin.IsSameOriginWith(foo_url));
  659. EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_origin));
  660. EXPECT_FALSE(foo_origin.IsSameOriginWith(bar_url));
  661. // Documenting legacy behavior. This doesn't necessarily mean that the legacy
  662. // behavior is correct (or desirable in the long-term).
  663. EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL("about:blank")));
  664. EXPECT_FALSE(foo_origin.IsSameOriginWith(GURL())); // Invalid GURL.
  665. EXPECT_TRUE(foo_origin.IsSameOriginWith(GURL("blob:https://foo.com/guid")));
  666. }
  667. INSTANTIATE_TYPED_TEST_SUITE_P(UrlOrigin,
  668. AbstractOriginTest,
  669. UrlOriginTestTraits);
  670. } // namespace url