mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-22 09:12:13 -05:00
LibURL: Replace Host's Empty state with making Url's Host optional
A couple of reasons: - Origin's Host (when in the tuple state) can't be null - There's an "empty host" concept in the spec which is NOT the same as a null Host, and that was confusing me.
This commit is contained in:
parent
8b984c0c57
commit
90e763de4c
Notes:
github-actions[bot]
2024-11-30 11:24:09 +00:00
Author: https://github.com/AtkinsSJ Commit: https://github.com/LadybirdBrowser/ladybird/commit/90e763de4c8 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/2610 Reviewed-by: https://github.com/shannonbooth ✅
17 changed files with 44 additions and 42 deletions
|
@ -36,9 +36,9 @@ struct ProxyData {
|
|||
|
||||
proxy_data.type = ProxyData::Type::SOCKS5;
|
||||
|
||||
if (!url.host().has<URL::IPv4Address>())
|
||||
if (!url.host().has_value() || !url.host()->has<URL::IPv4Address>())
|
||||
return Error::from_string_literal("Invalid proxy host, must be an IPv4 address");
|
||||
proxy_data.host_ipv4 = url.host().get<URL::IPv4Address>();
|
||||
proxy_data.host_ipv4 = url.host()->get<URL::IPv4Address>();
|
||||
|
||||
auto port = url.port();
|
||||
if (!port.has_value())
|
||||
|
|
|
@ -26,6 +26,6 @@ using IPv6Address = Array<u16, 8>;
|
|||
// https://url.spec.whatwg.org/#concept-host
|
||||
// A host is a domain, an IP address, an opaque host, or an empty host. Typically a host serves as a network address,
|
||||
// but it is sometimes used as opaque identifier in URLs where a network address is not necessary.
|
||||
using Host = Variant<IPv4Address, IPv6Address, String, Empty>;
|
||||
using Host = Variant<IPv4Address, IPv6Address, String>;
|
||||
|
||||
}
|
||||
|
|
|
@ -1574,7 +1574,7 @@ URL Parser::basic_parse(StringView raw_input, Optional<URL> const& base_url, URL
|
|||
continue;
|
||||
}
|
||||
// 5. Otherwise, if state override is given and url’s host is null, append the empty string to url’s path.
|
||||
else if (state_override.has_value() && url->host().has<Empty>()) {
|
||||
else if (state_override.has_value() && !url->host().has_value()) {
|
||||
url->append_slash();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -88,7 +88,7 @@ void URL::set_host(Host host)
|
|||
// https://url.spec.whatwg.org/#concept-host-serializer
|
||||
ErrorOr<String> URL::serialized_host() const
|
||||
{
|
||||
return Parser::serialize_host(m_data->host);
|
||||
return Parser::serialize_host(m_data->host.value());
|
||||
}
|
||||
|
||||
void URL::set_port(Optional<u16> port)
|
||||
|
@ -119,7 +119,7 @@ void URL::append_path(StringView path)
|
|||
bool URL::cannot_have_a_username_or_password_or_port() const
|
||||
{
|
||||
// A URL cannot have a username/password/port if its host is null or the empty string, or its scheme is "file".
|
||||
return m_data->host.has<Empty>() || m_data->host == String {} || m_data->scheme == "file"sv;
|
||||
return !m_data->host.has_value() || m_data->host == String {} || m_data->scheme == "file"sv;
|
||||
}
|
||||
|
||||
// FIXME: This is by no means complete.
|
||||
|
@ -142,8 +142,8 @@ bool URL::compute_validity() const
|
|||
return false;
|
||||
}
|
||||
|
||||
// NOTE: A file URL's host should be the empty string for localhost, not null.
|
||||
if (m_data->scheme == "file" && m_data->host.has<Empty>())
|
||||
// FIXME: A file URL's host should be the empty string for localhost, not null.
|
||||
if (m_data->scheme == "file" && !m_data->host.has_value())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
@ -252,7 +252,7 @@ ByteString URL::serialize(ExcludeFragment exclude_fragment) const
|
|||
output.append(':');
|
||||
|
||||
// 2. If url’s host is non-null:
|
||||
if (!m_data->host.has<Empty>()) {
|
||||
if (m_data->host.has_value()) {
|
||||
// 1. Append "//" to output.
|
||||
output.append("//"sv);
|
||||
|
||||
|
@ -285,7 +285,7 @@ ByteString URL::serialize(ExcludeFragment exclude_fragment) const
|
|||
if (cannot_be_a_base_url()) {
|
||||
output.append(m_data->paths[0]);
|
||||
} else {
|
||||
if (m_data->host.has<Empty>() && m_data->paths.size() > 1 && m_data->paths[0].is_empty())
|
||||
if (!m_data->host.has_value() && m_data->paths.size() > 1 && m_data->paths[0].is_empty())
|
||||
output.append("/."sv);
|
||||
for (auto& segment : m_data->paths) {
|
||||
output.append('/');
|
||||
|
@ -321,7 +321,7 @@ ByteString URL::serialize_for_display() const
|
|||
builder.append(m_data->scheme);
|
||||
builder.append(':');
|
||||
|
||||
if (!m_data->host.has<Empty>()) {
|
||||
if (m_data->host.has_value()) {
|
||||
builder.append("//"sv);
|
||||
builder.append(serialized_host().release_value_but_fixme_should_propagate_errors());
|
||||
if (m_data->port.has_value())
|
||||
|
@ -331,7 +331,7 @@ ByteString URL::serialize_for_display() const
|
|||
if (cannot_be_a_base_url()) {
|
||||
builder.append(m_data->paths[0]);
|
||||
} else {
|
||||
if (m_data->host.has<Empty>() && m_data->paths.size() > 1 && m_data->paths[0].is_empty())
|
||||
if (!m_data->host.has_value() && m_data->paths.size() > 1 && m_data->paths[0].is_empty())
|
||||
builder.append("/."sv);
|
||||
for (auto& segment : m_data->paths) {
|
||||
builder.append('/');
|
||||
|
@ -391,7 +391,7 @@ Origin URL::origin() const
|
|||
// -> "wss"
|
||||
if (scheme().is_one_of("ftp"sv, "http"sv, "https"sv, "ws"sv, "wss"sv)) {
|
||||
// Return the tuple origin (url’s scheme, url’s host, url’s port, null).
|
||||
return Origin(scheme().to_byte_string(), host(), port());
|
||||
return Origin(scheme().to_byte_string(), host().value(), port());
|
||||
}
|
||||
|
||||
// -> "file"
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
String const& scheme() const { return m_data->scheme; }
|
||||
String const& username() const { return m_data->username; }
|
||||
String const& password() const { return m_data->password; }
|
||||
Host const& host() const { return m_data->host; }
|
||||
Optional<Host> const& host() const { return m_data->host; }
|
||||
ErrorOr<String> serialized_host() const;
|
||||
ByteString basename() const;
|
||||
Optional<String> const& query() const { return m_data->query; }
|
||||
|
@ -171,7 +171,7 @@ private:
|
|||
String password;
|
||||
|
||||
// A URL’s host is null or a host. It is initially null.
|
||||
Host host;
|
||||
Optional<Host> host;
|
||||
|
||||
// A URL’s port is either null or a 16-bit unsigned integer that identifies a networking port. It is initially null.
|
||||
Optional<u16> port;
|
||||
|
|
|
@ -284,7 +284,7 @@ WebIDL::ExceptionOr<String> DOMURL::host() const
|
|||
auto& url = m_url;
|
||||
|
||||
// 2. If url’s host is null, then return the empty string.
|
||||
if (url.host().has<Empty>())
|
||||
if (!url.host().has_value())
|
||||
return String {};
|
||||
|
||||
// 3. If url’s port is null, return url’s host, serialized.
|
||||
|
@ -312,7 +312,7 @@ WebIDL::ExceptionOr<String> DOMURL::hostname() const
|
|||
auto& vm = realm().vm();
|
||||
|
||||
// 1. If this’s URL’s host is null, then return the empty string.
|
||||
if (m_url.host().has<Empty>())
|
||||
if (!m_url.host().has_value())
|
||||
return String {};
|
||||
|
||||
// 2. Return this’s URL’s host, serialized.
|
||||
|
@ -477,6 +477,7 @@ void DOMURL::set_hash(String const& hash)
|
|||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#concept-domain
|
||||
// FIXME: Move into URL::Host
|
||||
bool host_is_domain(URL::Host const& host)
|
||||
{
|
||||
// A domain is a non-empty ASCII string that identifies a realm within a network.
|
||||
|
|
|
@ -322,7 +322,7 @@ WebIDL::ExceptionOr<GC::Ptr<PendingResponse>> main_fetch(JS::Realm& realm, Infra
|
|||
// - request’s current URL’s scheme is "http"
|
||||
request->current_url().scheme() == "http"sv
|
||||
// - request’s current URL’s host is a domain
|
||||
&& DOMURL::host_is_domain(request->current_url().host())
|
||||
&& request->current_url().host().has_value() && DOMURL::host_is_domain(request->current_url().host().value())
|
||||
// FIXME: - Matching request’s current URL’s host per Known HSTS Host Domain Name Matching results in either a
|
||||
// superdomain match with an asserted includeSubDomains directive or a congruent match (with or without an
|
||||
// asserted includeSubDomains directive) [HSTS]; or DNS resolution for the request finds a matching HTTPS RR
|
||||
|
|
|
@ -44,7 +44,7 @@ bool url_matches_about_blank(URL::URL const& url)
|
|||
&& url.paths().size() == 1 && url.paths()[0] == "blank"sv
|
||||
&& url.username().is_empty()
|
||||
&& url.password().is_empty()
|
||||
&& url.host().has<Empty>();
|
||||
&& !url.host().has_value();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/urls-and-fetching.html#matches-about:srcdoc
|
||||
|
@ -56,7 +56,7 @@ bool url_matches_about_srcdoc(URL::URL const& url)
|
|||
&& !url.query().has_value()
|
||||
&& url.username().is_empty()
|
||||
&& url.password().is_empty()
|
||||
&& url.host().has<Empty>();
|
||||
&& !url.host().has_value();
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/document-sequences.html#determining-the-origin
|
||||
|
|
|
@ -167,7 +167,7 @@ String HTMLHyperlinkElementUtils::host() const
|
|||
auto const& url = m_url;
|
||||
|
||||
// 3. If url or url's host is null, return the empty string.
|
||||
if (!url.has_value() || url->host().has<Empty>())
|
||||
if (!url.has_value() || !url->host().has_value())
|
||||
return String {};
|
||||
|
||||
// 4. If url's port is null, return url's host, serialized.
|
||||
|
@ -206,7 +206,8 @@ String HTMLHyperlinkElementUtils::hostname() const
|
|||
URL::URL url(href());
|
||||
|
||||
// 3. If url or url's host is null, return the empty string.
|
||||
if (url.host().has<Empty>())
|
||||
// FIXME: How can url be null here?
|
||||
if (!url.host().has_value())
|
||||
return String {};
|
||||
|
||||
// 4. Return url's host, serialized.
|
||||
|
|
|
@ -203,7 +203,7 @@ WebIDL::ExceptionOr<String> Location::host() const
|
|||
auto url = this->url();
|
||||
|
||||
// 3. If url's host is null, return the empty string.
|
||||
if (url.host().has<Empty>())
|
||||
if (!url.host().has_value())
|
||||
return String {};
|
||||
|
||||
// 4. If url's port is null, return url's host, serialized.
|
||||
|
@ -233,7 +233,7 @@ WebIDL::ExceptionOr<String> Location::hostname() const
|
|||
auto url = this->url();
|
||||
|
||||
// 2. If this's url's host is null, return the empty string.
|
||||
if (url.host().has<Empty>())
|
||||
if (!url.host().has_value())
|
||||
return String {};
|
||||
|
||||
// 3. Return this's url's host, serialized.
|
||||
|
|
|
@ -46,7 +46,7 @@ WebIDL::ExceptionOr<String> WorkerLocation::host() const
|
|||
auto const& url = m_global_scope->url();
|
||||
|
||||
// 2. If url's host is null, return the empty string.
|
||||
if (url.host().has<Empty>())
|
||||
if (!url.host().has_value())
|
||||
return String {};
|
||||
|
||||
// 3. If url's port is null, return url's host, serialized.
|
||||
|
@ -67,11 +67,11 @@ WebIDL::ExceptionOr<String> WorkerLocation::hostname() const
|
|||
auto const& host = m_global_scope->url().host();
|
||||
|
||||
// 2. If host is null, return the empty string.
|
||||
if (host.has<Empty>())
|
||||
if (!host.has_value())
|
||||
return String {};
|
||||
|
||||
// 3. Return host, serialized.
|
||||
return TRY_OR_THROW_OOM(vm, URL::Parser::serialize_host(host));
|
||||
return TRY_OR_THROW_OOM(vm, URL::Parser::serialize_host(host.value()));
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/workers.html#dom-workerlocation-port
|
||||
|
|
|
@ -20,7 +20,7 @@ void upgrade_a_mixed_content_request_to_a_potentially_trustworthy_url_if_appropr
|
|||
SecureContexts::is_url_potentially_trustworthy(request.url()) == SecureContexts::Trustworthiness::PotentiallyTrustworthy
|
||||
|
||||
// 2. request’s URL’s host is an IP address.
|
||||
|| request.url().host().has<URL::IPv4Address>() || request.url().host().has<URL::IPv6Address>()
|
||||
|| (request.url().host().has_value() && (request.url().host()->has<URL::IPv4Address>() || request.url().host()->has<URL::IPv6Address>()))
|
||||
|
||||
// 3. § 4.3 Does settings prohibit mixed security contexts? returns "Does Not Restrict Mixed Security Contents" when applied to request’s client.
|
||||
|| does_settings_prohibit_mixed_security_contexts(request.client()) == ProhibitsMixedSecurityContexts::DoesNotRestrictMixedSecurityContexts
|
||||
|
|
|
@ -494,7 +494,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::open(String const& method_string, Stri
|
|||
// NOTE: This is handled in the overload lacking the async argument.
|
||||
|
||||
// 8. If parsedURL’s host is non-null, then:
|
||||
if (!parsed_url.host().has<Empty>()) {
|
||||
if (parsed_url.host().has_value()) {
|
||||
// 1. If the username argument is not null, set the username given parsedURL and username.
|
||||
if (username.has_value())
|
||||
parsed_url.set_username(username.value());
|
||||
|
|
|
@ -220,7 +220,7 @@ void CookieJar::expire_cookies_with_time_offset(AK::Duration offset)
|
|||
// https://www.ietf.org/archive/id/draft-ietf-httpbis-rfc6265bis-15.html#section-5.1.2
|
||||
Optional<String> CookieJar::canonicalize_domain(const URL::URL& url)
|
||||
{
|
||||
if (!url.is_valid() || url.host().has<Empty>())
|
||||
if (!url.is_valid() || !url.host().has_value())
|
||||
return {};
|
||||
|
||||
// 1. Convert the host name to a sequence of individual domain name labels.
|
||||
|
|
|
@ -570,7 +570,7 @@ void ViewImplementation::handle_web_content_process_crash(LoadErrorPage load_err
|
|||
builder.append(escape_html_entities(m_url.to_byte_string()));
|
||||
builder.append("</title></head><body>"sv);
|
||||
builder.append("<h1>Web page crashed"sv);
|
||||
if (!m_url.host().has<Empty>()) {
|
||||
if (m_url.host().has_value()) {
|
||||
builder.appendff(" on {}", escape_html_entities(m_url.serialized_host().release_value_but_fixme_should_propagate_errors()));
|
||||
}
|
||||
builder.append("</h1>"sv);
|
||||
|
|
|
@ -206,7 +206,7 @@ TEST_CASE(about_url)
|
|||
URL::URL url("about:blank"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "about");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.serialize_path(), "blank");
|
||||
EXPECT(!url.query().has_value());
|
||||
EXPECT(!url.fragment().has_value());
|
||||
|
@ -218,7 +218,7 @@ TEST_CASE(mailto_url)
|
|||
URL::URL url("mailto:mail@example.com"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "mailto");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.port_or_default(), 0);
|
||||
EXPECT_EQ(url.path_segment_count(), 1u);
|
||||
EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com");
|
||||
|
@ -232,7 +232,7 @@ TEST_CASE(mailto_url_with_subject)
|
|||
URL::URL url("mailto:mail@example.com?subject=test"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "mailto");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.port_or_default(), 0);
|
||||
EXPECT_EQ(url.path_segment_count(), 1u);
|
||||
EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com");
|
||||
|
|
|
@ -14,7 +14,7 @@ TEST_CASE(data_url)
|
|||
URL::URL url("data:text/html,test"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.serialize(), "data:text/html,test");
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
|
@ -27,7 +27,7 @@ TEST_CASE(data_url_default_mime_type)
|
|||
URL::URL url("data:,test"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.serialize(), "data:,test");
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
|
@ -40,7 +40,7 @@ TEST_CASE(data_url_encoded)
|
|||
URL::URL url("data:text/html,Hello%20friends%2C%0X%X0"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.serialize(), "data:text/html,Hello%20friends%2C%0X%X0");
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
|
@ -53,7 +53,7 @@ TEST_CASE(data_url_base64_encoded)
|
|||
URL::URL url("data:text/html;base64,dGVzdA=="sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.serialize(), "data:text/html;base64,dGVzdA==");
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
|
@ -66,7 +66,7 @@ TEST_CASE(data_url_base64_encoded_default_mime_type)
|
|||
URL::URL url("data:;base64,dGVzdA=="sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.serialize(), "data:;base64,dGVzdA==");
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
|
@ -79,7 +79,7 @@ TEST_CASE(data_url_base64_encoded_with_whitespace)
|
|||
URL::URL url("data: text/html ; bAsE64 , dGVz dA== "sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
EXPECT_EQ(url.serialize(), "data: text/html ; bAsE64 , dGVz dA==");
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
|
@ -92,7 +92,7 @@ TEST_CASE(data_url_base64_encoded_with_inline_whitespace)
|
|||
URL::URL url("data:text/javascript;base64,%20ZD%20Qg%0D%0APS%20An%20Zm91cic%0D%0A%207%20"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
EXPECT_EQ(data_url.mime_type.serialized(), "text/javascript");
|
||||
|
@ -105,7 +105,7 @@ TEST_CASE(data_url_completed_with_fragment)
|
|||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT_EQ(url.fragment(), "a");
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT(!url.host().has_value());
|
||||
|
||||
auto data_url = TRY_OR_FAIL(Web::Fetch::Infrastructure::process_data_url(url));
|
||||
EXPECT_EQ(data_url.mime_type.serialized(), "text/plain");
|
||||
|
|
Loading…
Reference in a new issue