origin.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  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 "url/origin.h"
  5. #include <stdint.h>
  6. #include <algorithm>
  7. #include <ostream>
  8. #include <string>
  9. #include <tuple>
  10. #include <utility>
  11. #include "base/base64.h"
  12. #include "base/check.h"
  13. #include "base/check_op.h"
  14. #include "base/containers/contains.h"
  15. #include "base/containers/span.h"
  16. #include "base/debug/crash_logging.h"
  17. #include "base/pickle.h"
  18. #include "base/strings/strcat.h"
  19. #include "base/strings/string_piece.h"
  20. #include "base/unguessable_token.h"
  21. #include "third_party/perfetto/include/perfetto/tracing/traced_value.h"
  22. #include "url/gurl.h"
  23. #include "url/scheme_host_port.h"
  24. #include "url/url_constants.h"
  25. #include "url/url_util.h"
  26. namespace url {
  27. Origin::Origin() : nonce_(Nonce()) {}
  28. Origin Origin::Create(const GURL& url) {
  29. if (!url.is_valid())
  30. return Origin();
  31. SchemeHostPort tuple;
  32. if (url.SchemeIsFileSystem()) {
  33. tuple = SchemeHostPort(*url.inner_url());
  34. } else if (url.SchemeIsBlob()) {
  35. // If we're dealing with a 'blob:' URL, https://url.spec.whatwg.org/#origin
  36. // defines the origin as the origin of the URL which results from parsing
  37. // the "path", which boils down to everything after the scheme. GURL's
  38. // 'GetContent()' gives us exactly that.
  39. tuple = SchemeHostPort(GURL(url.GetContent()));
  40. } else {
  41. tuple = SchemeHostPort(url);
  42. // It's SchemeHostPort's responsibility to filter out unrecognized schemes;
  43. // sanity check that this is happening.
  44. DCHECK(!tuple.IsValid() || url.IsStandard() ||
  45. base::Contains(GetLocalSchemes(), url.scheme_piece()) ||
  46. AllowNonStandardSchemesForAndroidWebView());
  47. }
  48. if (!tuple.IsValid())
  49. return Origin();
  50. return Origin(std::move(tuple));
  51. }
  52. Origin Origin::Resolve(const GURL& url, const Origin& base_origin) {
  53. if (url.SchemeIs(kAboutScheme) || url.is_empty())
  54. return base_origin;
  55. Origin result = Origin::Create(url);
  56. if (!result.opaque())
  57. return result;
  58. return base_origin.DeriveNewOpaqueOrigin();
  59. }
  60. Origin::Origin(const Origin&) = default;
  61. Origin& Origin::operator=(const Origin&) = default;
  62. Origin::Origin(Origin&&) noexcept = default;
  63. Origin& Origin::operator=(Origin&&) noexcept = default;
  64. Origin::~Origin() = default;
  65. // static
  66. absl::optional<Origin> Origin::UnsafelyCreateTupleOriginWithoutNormalization(
  67. base::StringPiece scheme,
  68. base::StringPiece host,
  69. uint16_t port) {
  70. SchemeHostPort tuple(std::string(scheme), std::string(host), port,
  71. SchemeHostPort::CHECK_CANONICALIZATION);
  72. if (!tuple.IsValid())
  73. return absl::nullopt;
  74. return Origin(std::move(tuple));
  75. }
  76. // static
  77. absl::optional<Origin> Origin::UnsafelyCreateOpaqueOriginWithoutNormalization(
  78. base::StringPiece precursor_scheme,
  79. base::StringPiece precursor_host,
  80. uint16_t precursor_port,
  81. const Origin::Nonce& nonce) {
  82. SchemeHostPort precursor(std::string(precursor_scheme),
  83. std::string(precursor_host), precursor_port,
  84. SchemeHostPort::CHECK_CANONICALIZATION);
  85. // For opaque origins, it is okay for the SchemeHostPort to be invalid;
  86. // however, this should only arise when the arguments indicate the
  87. // canonical representation of the invalid SchemeHostPort.
  88. if (!precursor.IsValid() &&
  89. !(precursor_scheme.empty() && precursor_host.empty() &&
  90. precursor_port == 0)) {
  91. return absl::nullopt;
  92. }
  93. return Origin(std::move(nonce), std::move(precursor));
  94. }
  95. // static
  96. Origin Origin::CreateFromNormalizedTuple(std::string scheme,
  97. std::string host,
  98. uint16_t port) {
  99. SchemeHostPort tuple(std::move(scheme), std::move(host), port,
  100. SchemeHostPort::ALREADY_CANONICALIZED);
  101. if (!tuple.IsValid())
  102. return Origin();
  103. return Origin(std::move(tuple));
  104. }
  105. // static
  106. Origin Origin::CreateOpaqueFromNormalizedPrecursorTuple(
  107. std::string precursor_scheme,
  108. std::string precursor_host,
  109. uint16_t precursor_port,
  110. const Origin::Nonce& nonce) {
  111. SchemeHostPort precursor(std::move(precursor_scheme),
  112. std::move(precursor_host), precursor_port,
  113. SchemeHostPort::ALREADY_CANONICALIZED);
  114. // For opaque origins, it is okay for the SchemeHostPort to be invalid.
  115. return Origin(std::move(nonce), std::move(precursor));
  116. }
  117. std::string Origin::Serialize() const {
  118. if (opaque())
  119. return "null";
  120. if (scheme() == kFileScheme)
  121. return "file://";
  122. return tuple_.Serialize();
  123. }
  124. GURL Origin::GetURL() const {
  125. if (opaque())
  126. return GURL();
  127. if (scheme() == kFileScheme)
  128. return GURL("file:///");
  129. return tuple_.GetURL();
  130. }
  131. const base::UnguessableToken* Origin::GetNonceForSerialization() const {
  132. return nonce_ ? &nonce_->token() : nullptr;
  133. }
  134. bool Origin::IsSameOriginWith(const Origin& other) const {
  135. // scheme/host/port must match, even for opaque origins where |tuple_| holds
  136. // the precursor origin.
  137. return std::tie(tuple_, nonce_) == std::tie(other.tuple_, other.nonce_);
  138. }
  139. bool Origin::IsSameOriginWith(const GURL& url) const {
  140. if (opaque())
  141. return false;
  142. // The `url::Origin::Create` call here preserves how IsSameOriginWith was used
  143. // historically, even though in some scenarios it is not clearly correct:
  144. // - Origin of about:blank and about:srcdoc cannot be correctly
  145. // computed/recovered.
  146. // - Ideally passing an invalid `url` would be a caller error (e.g. a DCHECK).
  147. // - The caller intent is not always clear wrt handling the outer-vs-inner
  148. // origins/URLs in blob: and filesystem: schemes.
  149. return IsSameOriginWith(url::Origin::Create(url));
  150. }
  151. bool Origin::CanBeDerivedFrom(const GURL& url) const {
  152. DCHECK(url.is_valid());
  153. // For "no access" schemes, blink's SecurityOrigin will always create an
  154. // opaque unique one. However, about: scheme is also registered as such but
  155. // does not behave this way, therefore exclude it from this check.
  156. if (base::Contains(url::GetNoAccessSchemes(), url.scheme()) &&
  157. !url.SchemeIs(kAboutScheme)) {
  158. // If |this| is not opaque, definitely return false as the expectation
  159. // is for opaque origin.
  160. if (!opaque())
  161. return false;
  162. // And if it is unique opaque origin, it definitely is fine. But if there
  163. // is a precursor stored, we should fall through to compare the tuples.
  164. if (!tuple_.IsValid())
  165. return true;
  166. }
  167. SchemeHostPort url_tuple;
  168. // Optimization for the common, success case: Scheme/Host/Port match on the
  169. // precursor, and the URL is standard. Opaqueness does not matter as a tuple
  170. // origin can always create an opaque tuple origin.
  171. if (url.IsStandard()) {
  172. // Note: if extra copies of the scheme and host are undesirable, this check
  173. // can be implemented using StringPiece comparisons, but it has to account
  174. // explicitly checks on port numbers.
  175. if (url.SchemeIsFileSystem()) {
  176. url_tuple = SchemeHostPort(*url.inner_url());
  177. } else {
  178. url_tuple = SchemeHostPort(url);
  179. }
  180. return url_tuple == tuple_;
  181. // Blob URLs still contain an inner origin, however it is not accessible
  182. // through inner_url(), therefore it requires specific case to handle it.
  183. } else if (url.SchemeIsBlob()) {
  184. // If |this| doesn't contain any precursor information, it is an unique
  185. // opaque origin. It is valid case, as any browser-initiated navigation
  186. // to about:blank or data: URL will result in a document with such
  187. // origin and it is valid for it to create blob: URLs.
  188. if (!tuple_.IsValid())
  189. return true;
  190. url_tuple = SchemeHostPort(GURL(url.GetContent()));
  191. return url_tuple == tuple_;
  192. }
  193. // At this point, the URL has non-standard scheme.
  194. DCHECK(!url.IsStandard());
  195. // All about: URLs (about:blank, about:srcdoc) inherit their origin from
  196. // the context which navigated them, which means that they can be in any
  197. // type of origin.
  198. if (url.SchemeIs(kAboutScheme))
  199. return true;
  200. // All data: URLs commit in opaque origins, therefore |this| must be opaque
  201. // if |url| has data: scheme.
  202. if (url.SchemeIs(kDataScheme))
  203. return opaque();
  204. // If |this| does not have valid precursor tuple, it is unique opaque origin,
  205. // which is what we expect non-standard schemes to get.
  206. if (!tuple_.IsValid())
  207. return true;
  208. // However, when there is precursor present, the schemes must match.
  209. return url.scheme() == tuple_.scheme();
  210. }
  211. bool Origin::DomainIs(base::StringPiece canonical_domain) const {
  212. return !opaque() && url::DomainIs(tuple_.host(), canonical_domain);
  213. }
  214. bool Origin::operator<(const Origin& other) const {
  215. return std::tie(tuple_, nonce_) < std::tie(other.tuple_, other.nonce_);
  216. }
  217. Origin Origin::DeriveNewOpaqueOrigin() const {
  218. return Origin(Nonce(), tuple_);
  219. }
  220. std::string Origin::GetDebugString(bool include_nonce) const {
  221. // Handle non-opaque origins first, as they are simpler.
  222. if (!opaque()) {
  223. std::string out = Serialize();
  224. if (scheme() == kFileScheme)
  225. base::StrAppend(&out, {" [internally: ", tuple_.Serialize(), "]"});
  226. return out;
  227. }
  228. // For opaque origins, log the nonce and precursor as well. Without this,
  229. // EXPECT_EQ failures between opaque origins are nearly impossible to
  230. // understand.
  231. std::string out = base::StrCat({Serialize(), " [internally:"});
  232. if (include_nonce) {
  233. out += " (";
  234. if (nonce_->raw_token().is_empty())
  235. out += "nonce TBD";
  236. else
  237. out += nonce_->raw_token().ToString();
  238. out += ")";
  239. }
  240. if (!tuple_.IsValid())
  241. base::StrAppend(&out, {" anonymous]"});
  242. else
  243. base::StrAppend(&out, {" derived from ", tuple_.Serialize(), "]"});
  244. return out;
  245. }
  246. Origin::Origin(SchemeHostPort tuple) : tuple_(std::move(tuple)) {
  247. DCHECK(!opaque());
  248. DCHECK(tuple_.IsValid());
  249. }
  250. // Constructs an opaque origin derived from |precursor|.
  251. Origin::Origin(const Nonce& nonce, SchemeHostPort precursor)
  252. : tuple_(std::move(precursor)), nonce_(std::move(nonce)) {
  253. DCHECK(opaque());
  254. // |precursor| is retained, but not accessible via scheme()/host()/port().
  255. DCHECK_EQ("", scheme());
  256. DCHECK_EQ("", host());
  257. DCHECK_EQ(0U, port());
  258. }
  259. absl::optional<std::string> Origin::SerializeWithNonce() const {
  260. return SerializeWithNonceImpl();
  261. }
  262. absl::optional<std::string> Origin::SerializeWithNonceAndInitIfNeeded() {
  263. GetNonceForSerialization();
  264. return SerializeWithNonceImpl();
  265. }
  266. // The pickle is saved in the following format, in order:
  267. // string - tuple_.GetURL().spec().
  268. // uint64_t (if opaque) - high bits of nonce if opaque. 0 if not initialized.
  269. // uint64_t (if opaque) - low bits of nonce if opaque. 0 if not initialized.
  270. absl::optional<std::string> Origin::SerializeWithNonceImpl() const {
  271. if (!opaque() && !tuple_.IsValid())
  272. return absl::nullopt;
  273. base::Pickle pickle;
  274. pickle.WriteString(tuple_.Serialize());
  275. if (opaque() && !nonce_->raw_token().is_empty()) {
  276. pickle.WriteUInt64(nonce_->token().GetHighForSerialization());
  277. pickle.WriteUInt64(nonce_->token().GetLowForSerialization());
  278. } else if (opaque()) {
  279. // Nonce hasn't been initialized.
  280. pickle.WriteUInt64(0);
  281. pickle.WriteUInt64(0);
  282. }
  283. base::span<const uint8_t> data(static_cast<const uint8_t*>(pickle.data()),
  284. pickle.size());
  285. // Base64 encode the data to make it nicer to play with.
  286. return base::Base64Encode(data);
  287. }
  288. // static
  289. absl::optional<Origin> Origin::Deserialize(const std::string& value) {
  290. std::string data;
  291. if (!base::Base64Decode(value, &data))
  292. return absl::nullopt;
  293. base::Pickle pickle(reinterpret_cast<char*>(&data[0]), data.size());
  294. base::PickleIterator reader(pickle);
  295. std::string pickled_url;
  296. if (!reader.ReadString(&pickled_url))
  297. return absl::nullopt;
  298. GURL url(pickled_url);
  299. // If only a tuple was serialized, then this origin is not opaque. For opaque
  300. // origins, we expect two uint64's to be left in the pickle.
  301. bool is_opaque = !reader.ReachedEnd();
  302. // Opaque origins without a tuple are ok.
  303. if (!is_opaque && !url.is_valid())
  304. return absl::nullopt;
  305. SchemeHostPort tuple(url);
  306. // Possible successful early return if the pickled Origin was not opaque.
  307. if (!is_opaque) {
  308. Origin origin(tuple);
  309. if (origin.opaque())
  310. return absl::nullopt; // Something went horribly wrong.
  311. return origin;
  312. }
  313. uint64_t nonce_high = 0;
  314. if (!reader.ReadUInt64(&nonce_high))
  315. return absl::nullopt;
  316. uint64_t nonce_low = 0;
  317. if (!reader.ReadUInt64(&nonce_low))
  318. return absl::nullopt;
  319. Origin::Nonce nonce;
  320. if (nonce_high != 0 && nonce_low != 0) {
  321. // The serialized nonce wasn't empty, so copy it here.
  322. nonce = Origin::Nonce(
  323. base::UnguessableToken::Deserialize(nonce_high, nonce_low));
  324. }
  325. Origin origin;
  326. origin.nonce_ = std::move(nonce);
  327. origin.tuple_ = tuple;
  328. return origin;
  329. }
  330. void Origin::WriteIntoTrace(perfetto::TracedValue context) const {
  331. std::move(context).WriteString(GetDebugString());
  332. }
  333. std::ostream& operator<<(std::ostream& out, const url::Origin& origin) {
  334. out << origin.GetDebugString();
  335. return out;
  336. }
  337. std::ostream& operator<<(std::ostream& out, const url::Origin::Nonce& nonce) {
  338. // Subtle: don't let logging trigger lazy-generation of the token value.
  339. if (nonce.raw_token().is_empty())
  340. return (out << "(nonce TBD)");
  341. else
  342. return (out << nonce.raw_token());
  343. }
  344. bool IsSameOriginWith(const GURL& a, const GURL& b) {
  345. return Origin::Create(a).IsSameOriginWith(Origin::Create(b));
  346. }
  347. Origin::Nonce::Nonce() = default;
  348. Origin::Nonce::Nonce(const base::UnguessableToken& token) : token_(token) {
  349. CHECK(!token_.is_empty());
  350. }
  351. const base::UnguessableToken& Origin::Nonce::token() const {
  352. // Inspecting the value of a nonce triggers lazy-generation.
  353. // TODO(dcheng): UnguessableToken::is_empty should go away -- what sentinel
  354. // value to use instead?
  355. if (token_.is_empty())
  356. token_ = base::UnguessableToken::Create();
  357. return token_;
  358. }
  359. const base::UnguessableToken& Origin::Nonce::raw_token() const {
  360. return token_;
  361. }
  362. // Copying a Nonce triggers lazy-generation of the token.
  363. Origin::Nonce::Nonce(const Origin::Nonce& other) : token_(other.token()) {}
  364. Origin::Nonce& Origin::Nonce::operator=(const Origin::Nonce& other) {
  365. // Copying a Nonce triggers lazy-generation of the token.
  366. token_ = other.token();
  367. return *this;
  368. }
  369. // Moving a nonce does NOT trigger lazy-generation of the token.
  370. Origin::Nonce::Nonce(Origin::Nonce&& other) noexcept : token_(other.token_) {
  371. other.token_ = base::UnguessableToken(); // Reset |other|.
  372. }
  373. Origin::Nonce& Origin::Nonce::operator=(Origin::Nonce&& other) noexcept {
  374. token_ = other.token_;
  375. other.token_ = base::UnguessableToken(); // Reset |other|.
  376. return *this;
  377. }
  378. bool Origin::Nonce::operator<(const Origin::Nonce& other) const {
  379. // When comparing, lazy-generation is required of both tokens, so that an
  380. // ordering is established.
  381. return token() < other.token();
  382. }
  383. bool Origin::Nonce::operator==(const Origin::Nonce& other) const {
  384. // Equality testing doesn't actually require that the tokens be generated.
  385. // If the tokens are both zero, equality only holds if they're the same
  386. // object.
  387. return (other.token_ == token_) && !(token_.is_empty() && (&other != this));
  388. }
  389. bool Origin::Nonce::operator!=(const Origin::Nonce& other) const {
  390. return !(*this == other);
  391. }
  392. namespace debug {
  393. ScopedOriginCrashKey::ScopedOriginCrashKey(
  394. base::debug::CrashKeyString* crash_key,
  395. const url::Origin* value)
  396. : scoped_string_value_(
  397. crash_key,
  398. value ? value->GetDebugString(false /* include_nonce */)
  399. : "nullptr") {}
  400. ScopedOriginCrashKey::~ScopedOriginCrashKey() = default;
  401. } // namespace debug
  402. } // namespace url