LibURL: Make URL::serialized_host() infallible

This can no longer fail, so update the return type to match.

This makes a few more methods now unable to return errors, but one thing
at a time. 😅
This commit is contained in:
Sam Atkins 2024-11-28 14:32:07 +00:00 committed by Andreas Kling
parent 70c8535b8a
commit 900c131178
Notes: github-actions[bot] 2024-11-30 11:23:28 +00:00
13 changed files with 47 additions and 51 deletions

View file

@ -55,7 +55,7 @@ ErrorOr<ByteBuffer> HttpRequest::to_raw_request() const
TRY(builder.try_append(*m_url.query()));
}
TRY(builder.try_append(" HTTP/1.1\r\nHost: "sv));
TRY(builder.try_append(TRY(m_url.serialized_host())));
TRY(builder.try_append(m_url.serialized_host()));
if (m_url.port().has_value())
TRY(builder.try_appendff(":{}", *m_url.port()));
TRY(builder.try_append("\r\n"sv));

View file

@ -86,7 +86,7 @@ void URL::set_host(Host host)
}
// https://url.spec.whatwg.org/#concept-host-serializer
ErrorOr<String> URL::serialized_host() const
String URL::serialized_host() const
{
return m_data->host->serialize();
}
@ -273,7 +273,7 @@ ByteString URL::serialize(ExcludeFragment exclude_fragment) const
}
// 3. Append urls host, serialized, to output.
output.append(serialized_host().release_value_but_fixme_should_propagate_errors());
output.append(serialized_host());
// 4. If urls port is non-null, append U+003A (:) followed by urls port, serialized, to output.
if (m_data->port.has_value())
@ -324,7 +324,7 @@ ByteString URL::serialize_for_display() const
if (m_data->host.has_value()) {
builder.append("//"sv);
builder.append(serialized_host().release_value_but_fixme_should_propagate_errors());
builder.append(serialized_host());
if (m_data->port.has_value())
builder.appendff(":{}", *m_data->port);
}

View file

@ -84,7 +84,7 @@ public:
String const& username() const { return m_data->username; }
String const& password() const { return m_data->password; }
Optional<Host> const& host() const { return m_data->host; }
ErrorOr<String> serialized_host() const;
String serialized_host() const;
ByteString basename() const;
Optional<String> const& query() const { return m_data->query; }
Optional<String> const& fragment() const { return m_data->fragment; }

View file

@ -289,10 +289,10 @@ WebIDL::ExceptionOr<String> DOMURL::host() const
// 3. If urls port is null, return urls host, serialized.
if (!url.port().has_value())
return TRY_OR_THROW_OOM(vm, url.serialized_host());
return url.serialized_host();
// 4. Return urls host, serialized, followed by U+003A (:) and urls port, serialized.
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", TRY_OR_THROW_OOM(vm, url.serialized_host()), *url.port()));
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.serialized_host(), *url.port()));
}
// https://url.spec.whatwg.org/#dom-url-hostref-for-dom-url-host%E2%91%A0
@ -309,14 +309,12 @@ void DOMURL::set_host(String const& host)
// https://url.spec.whatwg.org/#dom-url-hostname
WebIDL::ExceptionOr<String> DOMURL::hostname() const
{
auto& vm = realm().vm();
// 1. If thiss URLs host is null, then return the empty string.
if (!m_url.host().has_value())
return String {};
// 2. Return thiss URLs host, serialized.
return TRY_OR_THROW_OOM(vm, m_url.serialized_host());
return m_url.serialized_host();
}
// https://url.spec.whatwg.org/#ref-for-dom-url-hostname①

View file

@ -172,10 +172,10 @@ String HTMLHyperlinkElementUtils::host() const
// 4. If url's port is null, return url's host, serialized.
if (!url->port().has_value())
return MUST(url->serialized_host());
return url->serialized_host();
// 5. Return url's host, serialized, followed by ":" and url's port, serialized.
return MUST(String::formatted("{}:{}", MUST(url->serialized_host()), url->port().value()));
return MUST(String::formatted("{}:{}", url->serialized_host(), url->port().value()));
}
// https://html.spec.whatwg.org/multipage/links.html#dom-hyperlink-host
@ -211,7 +211,7 @@ String HTMLHyperlinkElementUtils::hostname() const
return String {};
// 4. Return url's host, serialized.
return MUST(url.serialized_host());
return url.serialized_host();
}
void HTMLHyperlinkElementUtils::set_hostname(StringView hostname)

View file

@ -208,10 +208,10 @@ WebIDL::ExceptionOr<String> Location::host() const
// 4. If url's port is null, return url's host, serialized.
if (!url.port().has_value())
return TRY_OR_THROW_OOM(vm, url.serialized_host());
return url.serialized_host();
// 5. Return url's host, serialized, followed by ":" and url's port, serialized.
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", TRY_OR_THROW_OOM(vm, url.serialized_host()), *url.port()));
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.serialized_host(), *url.port()));
}
WebIDL::ExceptionOr<void> Location::set_host(String const&)
@ -223,8 +223,6 @@ WebIDL::ExceptionOr<void> Location::set_host(String const&)
// https://html.spec.whatwg.org/multipage/history.html#dom-location-hostname
WebIDL::ExceptionOr<String> Location::hostname() const
{
auto& vm = this->vm();
// 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
auto const relevant_document = this->relevant_document();
if (relevant_document && !relevant_document->origin().is_same_origin_domain(entry_settings_object().origin()))
@ -237,7 +235,7 @@ WebIDL::ExceptionOr<String> Location::hostname() const
return String {};
// 3. Return this's url's host, serialized.
return TRY_OR_THROW_OOM(vm, url.serialized_host());
return url.serialized_host();
}
WebIDL::ExceptionOr<void> Location::set_hostname(String const&)

View file

@ -51,10 +51,10 @@ WebIDL::ExceptionOr<String> WorkerLocation::host() const
// 3. If url's port is null, return url's host, serialized.
if (!url.port().has_value())
return TRY_OR_THROW_OOM(vm, url.serialized_host());
return url.serialized_host();
// 4. Return url's host, serialized, followed by ":" and url's port, serialized.
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", TRY_OR_THROW_OOM(vm, url.serialized_host()), url.port().value()));
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.serialized_host(), url.port().value()));
}
// https://html.spec.whatwg.org/multipage/workers.html#dom-workerlocation-hostname

View file

@ -43,7 +43,7 @@ void WebSocketImplSerenity::connect(ConnectionInfo const& connection_info)
VERIFY(on_connection_error);
VERIFY(on_ready_to_read);
auto socket_result = [&]() -> ErrorOr<NonnullOwnPtr<Core::BufferedSocketBase>> {
auto host = TRY(connection_info.url().serialized_host()).to_byte_string();
auto host = connection_info.url().serialized_host().to_byte_string();
if (connection_info.is_secure()) {
TLS::Options options;
options.set_alert_handler([this](auto) {

View file

@ -170,7 +170,7 @@ void WebSocket::send_client_handshake()
// 4. Host
auto url = m_connection.url();
builder.appendff("Host: {}", url.serialized_host().release_value_but_fixme_should_propagate_errors());
builder.appendff("Host: {}", url.serialized_host());
if (!m_connection.is_secure() && url.port_or_default() != 80)
builder.appendff(":{}", url.port_or_default());
else if (m_connection.is_secure() && url.port_or_default() != 443)

View file

@ -230,7 +230,7 @@ Optional<String> CookieJar::canonicalize_domain(const URL::URL& url)
// 3. Concatenate the resulting labels, separated by a %x2E (".") character.
// FIXME: Implement the above conversions.
return MUST(MUST(url.serialized_host()).to_lowercase());
return MUST(url.serialized_host().to_lowercase());
}
// https://www.ietf.org/archive/id/draft-ietf-httpbis-rfc6265bis-15.html#section-5.1.4

View file

@ -571,7 +571,7 @@ void ViewImplementation::handle_web_content_process_crash(LoadErrorPage load_err
builder.append("</title></head><body>"sv);
builder.append("<h1>Web page crashed"sv);
if (m_url.host().has_value()) {
builder.appendff(" on {}", escape_html_entities(m_url.serialized_host().release_value_but_fixme_should_propagate_errors()));
builder.appendff(" on {}", escape_html_entities(m_url.serialized_host()));
}
builder.append("</h1>"sv);
auto escaped_url = escape_html_entities(m_url.to_byte_string());

View file

@ -343,7 +343,7 @@ void ConnectionFromClient::start_request(i32 request_id, ByteString const& metho
return;
}
auto host = url.serialized_host().value().to_byte_string();
auto host = url.serialized_host().to_byte_string();
m_resolver->dns.lookup(host, DNS::Messages::Class::IN, Array { DNS::Messages::ResourceType::A, DNS::Messages::ResourceType::AAAA }.span())
->when_rejected([this, request_id](auto const& error) {
dbgln("StartRequest: DNS lookup failed: {}", error);
@ -598,7 +598,7 @@ void ConnectionFromClient::ensure_connection(URL::URL const& url, ::RequestServe
}
if (cache_level == CacheLevel::ResolveOnly) {
[[maybe_unused]] auto promise = m_resolver->dns.lookup(url.serialized_host().value().to_byte_string(), DNS::Messages::Class::IN, Array { DNS::Messages::ResourceType::A, DNS::Messages::ResourceType::AAAA }.span());
[[maybe_unused]] auto promise = m_resolver->dns.lookup(url.serialized_host().to_byte_string(), DNS::Messages::Class::IN, Array { DNS::Messages::ResourceType::A, DNS::Messages::ResourceType::AAAA }.span());
if constexpr (REQUESTSERVER_DEBUG) {
Core::ElapsedTimer timer;
timer.start();

View file

@ -21,7 +21,7 @@ TEST_CASE(basic)
URL::URL url("http://www.serenityos.org"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.serialized_host(), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/");
EXPECT(!url.query().has_value());
@ -31,7 +31,7 @@ TEST_CASE(basic)
URL::URL url("https://www.serenityos.org/index.html"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "https");
EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.serialized_host(), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 443);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(!url.query().has_value());
@ -41,7 +41,7 @@ TEST_CASE(basic)
URL::URL url("https://www.serenityos.org1/index.html"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "https");
EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org1");
EXPECT_EQ(url.serialized_host(), "www.serenityos.org1");
EXPECT_EQ(url.port_or_default(), 443);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(!url.query().has_value());
@ -51,7 +51,7 @@ TEST_CASE(basic)
URL::URL url("https://localhost:1234/~anon/test/page.html"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "https");
EXPECT_EQ(MUST(url.serialized_host()), "localhost");
EXPECT_EQ(url.serialized_host(), "localhost");
EXPECT_EQ(url.port_or_default(), 1234);
EXPECT_EQ(url.serialize_path(), "/~anon/test/page.html");
EXPECT(!url.query().has_value());
@ -61,7 +61,7 @@ TEST_CASE(basic)
URL::URL url("http://www.serenityos.org/index.html?#"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.serialized_host(), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT_EQ(url.query(), "");
@ -71,7 +71,7 @@ TEST_CASE(basic)
URL::URL url("http://www.serenityos.org/index.html?foo=1&bar=2"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.serialized_host(), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT_EQ(url.query(), "foo=1&bar=2");
@ -81,7 +81,7 @@ TEST_CASE(basic)
URL::URL url("http://www.serenityos.org/index.html#fragment"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.serialized_host(), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(!url.query().has_value());
@ -91,7 +91,7 @@ TEST_CASE(basic)
URL::URL url("http://www.serenityos.org/index.html?foo=1&bar=2&baz=/?#frag/ment?test#"sv);
EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.serialized_host(), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT_EQ(url.query(), "foo=1&bar=2&baz=/?");
@ -126,7 +126,7 @@ TEST_CASE(file_url_with_hostname)
URL::URL url("file://courage/my/file"sv);
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(MUST(url.serialized_host()), "courage");
EXPECT_EQ(url.serialized_host(), "courage");
EXPECT_EQ(url.port_or_default(), 0);
EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file://courage/my/file");
@ -139,7 +139,7 @@ TEST_CASE(file_url_with_localhost)
URL::URL url("file://localhost/my/file"sv);
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(MUST(url.serialized_host()), "");
EXPECT_EQ(url.serialized_host(), "");
EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file:///my/file");
}
@ -149,7 +149,7 @@ TEST_CASE(file_url_without_hostname)
URL::URL url("file:///my/file"sv);
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(MUST(url.serialized_host()), "");
EXPECT_EQ(url.serialized_host(), "");
EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file:///my/file");
}
@ -300,7 +300,7 @@ TEST_CASE(complete_url)
URL::URL url = base_url.complete_url("test.html"sv);
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "serenityos.org");
EXPECT_EQ(url.serialized_host(), "serenityos.org");
EXPECT_EQ(url.serialize_path(), "/test.html");
EXPECT(!url.query().has_value());
EXPECT_EQ(url.cannot_be_a_base_url(), false);
@ -410,7 +410,7 @@ TEST_CASE(ipv6_address)
constexpr auto ipv6_url = "http://[::1]/index.html"sv;
URL::URL url(ipv6_url);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "[::1]"sv);
EXPECT_EQ(url.serialized_host(), "[::1]"sv);
EXPECT_EQ(url, ipv6_url);
}
@ -418,7 +418,7 @@ TEST_CASE(ipv6_address)
constexpr auto ipv6_url = "http://[0:f:0:0:f:f:0:0]/index.html"sv;
URL::URL url(ipv6_url);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "[0:f::f:f:0:0]"sv);
EXPECT_EQ(url.serialized_host(), "[0:f::f:f:0:0]"sv);
EXPECT_EQ(url, ipv6_url);
}
@ -426,7 +426,7 @@ TEST_CASE(ipv6_address)
constexpr auto ipv6_url = "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/index.html"sv;
URL::URL url(ipv6_url);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "[2001:db8:85a3::8a2e:370:7334]"sv);
EXPECT_EQ(url.serialized_host(), "[2001:db8:85a3::8a2e:370:7334]"sv);
EXPECT_EQ(url, ipv6_url);
}
@ -443,14 +443,14 @@ TEST_CASE(ipv4_address)
constexpr auto ipv4_url = "http://127.0.0.1/index.html"sv;
URL::URL url(ipv4_url);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "127.0.0.1"sv);
EXPECT_EQ(url.serialized_host(), "127.0.0.1"sv);
}
{
constexpr auto ipv4_url = "http://0x.0x.0"sv;
URL::URL url(ipv4_url);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "0.0.0.0"sv);
EXPECT_EQ(url.serialized_host(), "0.0.0.0"sv);
}
{
@ -463,14 +463,14 @@ TEST_CASE(ipv4_address)
constexpr auto ipv4_url = "http://256"sv;
URL::URL url(ipv4_url);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "0.0.1.0"sv);
EXPECT_EQ(url.serialized_host(), "0.0.1.0"sv);
}
{
constexpr auto ipv4_url = "http://888888888"sv;
URL::URL url(ipv4_url);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "52.251.94.56"sv);
EXPECT_EQ(url.serialized_host(), "52.251.94.56"sv);
}
{
@ -486,7 +486,7 @@ TEST_CASE(username_and_password)
constexpr auto url_with_username_and_password = "http://username:password@test.com/index.html"sv;
URL::URL url(url_with_username_and_password);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
EXPECT_EQ(url.serialized_host(), "test.com"sv);
EXPECT_EQ(url.username(), "username"sv);
EXPECT_EQ(url.password(), "password"sv);
}
@ -495,7 +495,7 @@ TEST_CASE(username_and_password)
constexpr auto url_with_percent_encoded_credentials = "http://username%21%24%25:password%21%24%25@test.com/index.html"sv;
URL::URL url(url_with_percent_encoded_credentials);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
EXPECT_EQ(url.serialized_host(), "test.com"sv);
EXPECT_EQ(url.username(), "username%21%24%25");
EXPECT_EQ(url.password(), "password%21%24%25");
EXPECT_EQ(URL::percent_decode(url.username()), "username!$%"sv);
@ -507,7 +507,7 @@ TEST_CASE(username_and_password)
auto const& url_with_long_username = MUST(String::formatted("http://{}:@test.com/index.html", username));
URL::URL url(url_with_long_username);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
EXPECT_EQ(url.serialized_host(), "test.com"sv);
EXPECT_EQ(url.username(), username);
EXPECT(url.password().is_empty());
}
@ -517,7 +517,7 @@ TEST_CASE(username_and_password)
auto const& url_with_long_password = MUST(String::formatted("http://:{}@test.com/index.html", password));
URL::URL url(url_with_long_password);
EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "test.com"sv);
EXPECT_EQ(url.serialized_host(), "test.com"sv);
EXPECT(url.username().is_empty());
EXPECT_EQ(url.password(), password);
}
@ -530,7 +530,7 @@ TEST_CASE(ascii_only_url)
URL::URL url(upper_case_url);
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "example.com"sv);
EXPECT_EQ(url.serialized_host(), "example.com"sv);
EXPECT_EQ(url.to_byte_string(), "http://example.com/INDEX.HTML#FRAGMENT");
}
@ -539,7 +539,7 @@ TEST_CASE(ascii_only_url)
URL::URL url(mixed_case_url);
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(MUST(url.serialized_host()), "example.com"sv);
EXPECT_EQ(url.serialized_host(), "example.com"sv);
EXPECT_EQ(url.to_byte_string(), "http://example.com/iNdEx.HtMl#fRaGmEnT");
}
}