diff --git a/Libraries/LibURL/CMakeLists.txt b/Libraries/LibURL/CMakeLists.txt index 8b41bdc67c9..304b623a05f 100644 --- a/Libraries/LibURL/CMakeLists.txt +++ b/Libraries/LibURL/CMakeLists.txt @@ -4,6 +4,7 @@ set(SOURCES Host.cpp Origin.cpp Parser.cpp + Site.cpp URL.cpp ${PUBLIC_SUFFIX_SOURCES} ) diff --git a/Libraries/LibURL/Forward.h b/Libraries/LibURL/Forward.h index ec9da1963cb..58c0a8ad7e7 100644 --- a/Libraries/LibURL/Forward.h +++ b/Libraries/LibURL/Forward.h @@ -7,9 +7,11 @@ #pragma once namespace URL { +class Host; class Origin; -class URL; class Parser; +class Site; +class URL; struct BlobURLEntry; } diff --git a/Libraries/LibURL/Origin.cpp b/Libraries/LibURL/Origin.cpp index 0042d7a7515..9d14bac6675 100644 --- a/Libraries/LibURL/Origin.cpp +++ b/Libraries/LibURL/Origin.cpp @@ -6,9 +6,27 @@ #include #include +#include namespace URL { +// https://html.spec.whatwg.org/multipage/browsers.html#same-site +bool Origin::is_same_site(Origin const& other) const +{ + // 1. Let siteA be the result of obtaining a site given A. + auto site_a = Site::obtain(*this); + + // 2. Let siteB be the result of obtaining a site given B. + auto site_b = Site::obtain(other); + + // 3. If siteA is same site with siteB, then return true. + if (site_a.is_same_site(site_b)) + return true; + + // 4. Return false. + return false; +} + // https://html.spec.whatwg.org/multipage/origin.html#ascii-serialisation-of-an-origin String Origin::serialize() const { diff --git a/Libraries/LibURL/Origin.h b/Libraries/LibURL/Origin.h index 64ebe68604b..ecc0cb81c9f 100644 --- a/Libraries/LibURL/Origin.h +++ b/Libraries/LibURL/Origin.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include namespace URL { @@ -74,6 +75,9 @@ public: return false; } + // https://html.spec.whatwg.org/multipage/browsers.html#same-site + bool is_same_site(Origin const&) const; + // https://html.spec.whatwg.org/multipage/origin.html#ascii-serialisation-of-an-origin String serialize() const; diff --git a/Libraries/LibURL/Site.cpp b/Libraries/LibURL/Site.cpp new file mode 100644 index 00000000000..9f097f6f547 --- /dev/null +++ b/Libraries/LibURL/Site.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include + +namespace URL { + +// https://html.spec.whatwg.org/multipage/browsers.html#obtain-a-site +Site Site::obtain(Origin const& origin) +{ + // 1. If origin is an opaque origin, then return origin. + if (origin.is_opaque()) + return Site { origin }; + + // 2. If origin's host's registrable domain is null, then return (origin's scheme, origin's host). + auto origin_scheme = origin.scheme().value_or_lazy_evaluated([]() { return String {}; }); + + auto registrable_domain = origin.host().registrable_domain(); + if (!registrable_domain.has_value()) + return Site { SchemeAndHost { origin_scheme, origin.host() } }; + + // 3. Return (origin's scheme, origin's host's registrable domain). + return Site { SchemeAndHost { origin_scheme, Host { *registrable_domain } } }; +} + +Site::Site(Variant value) + : m_value(move(value)) +{ +} + +// https://html.spec.whatwg.org/multipage/browsers.html#concept-site-same-site +bool Site::is_same_site(Site const& other) const +{ + // 1. If A and B are the same opaque origin, then return true. + // NOTE: Origins in sites are always opaque. + // FIXME: Currently all opaque origins are identical, how should we distinguish them? + if (m_value.has() && other.m_value.has()) + return true; + + // 2. If A or B is an opaque origin, then return false. + if (m_value.has() || other.m_value.has()) + return false; + + // 3. If A's and B's scheme values are different, then return false. + auto& a = m_value.get(); + auto& b = other.m_value.get(); + if (a.scheme != b.scheme) + return false; + + // 4. If A's and B's host values are not equal, then return false. + if (a.host != b.host) + return false; + + // 5. Return true. + return true; +} + +// https://html.spec.whatwg.org/multipage/browsers.html#serialization-of-a-site +String Site::serialize() const +{ + // 1. If site is an opaque origin, then return "null". + if (m_value.has()) + return "null"_string; + + // 2. Let result be site[0]. + auto& [scheme, host] = m_value.get(); + StringBuilder result; + result.append(scheme); + + // 3. Append "://" to result. + result.append("://"sv); + + // 4. Append site[1], serialized, to result. + result.append(host.serialize()); + + // 5. Return result. + return result.to_string_without_validation(); +} + +} diff --git a/Libraries/LibURL/Site.h b/Libraries/LibURL/Site.h new file mode 100644 index 00000000000..2010a0bca6f --- /dev/null +++ b/Libraries/LibURL/Site.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2024, Sam Atkins + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include + +namespace URL { + +// https://html.spec.whatwg.org/multipage/browsers.html#scheme-and-host +// A scheme-and-host is a tuple of a scheme (an ASCII string) and a host (a host). +struct SchemeAndHost { + String scheme; + Host host; +}; + +// https://html.spec.whatwg.org/multipage/browsers.html#site +// A site is an opaque origin or a scheme-and-host. +class Site { +public: + static Site obtain(Origin const&); + + bool is_same_site(Site const& other) const; + + String serialize() const; + +private: + Site(Variant); + Variant m_value; +}; + +}