AK: Serialize URL hosts with 'concept-host-serializer'

In order to follow spec text to achieve this, we need to change the
underlying representation of a host in AK::URL to deserialized format.
Before this, we were parsing the host and then immediately serializing
it again.

Making that change resulted in a whole bunch of fallout.

After this change, callers can access the serialized data through
this concept-host-serializer. The functional end result of this
change is that IPv6 hosts are now correctly serialized to be
surrounded with '[' and ']'.
This commit is contained in:
Shannon Booth 2023-07-27 21:40:41 +12:00 committed by Andreas Kling
parent 768f070b86
commit 8751be09f9
Notes: sideshowbarker 2024-07-18 02:13:10 +09:00
36 changed files with 175 additions and 143 deletions

View file

@ -101,12 +101,18 @@ void URL::set_password(DeprecatedString password, ApplyPercentEncoding apply_per
m_valid = compute_validity(); m_valid = compute_validity();
} }
void URL::set_host(DeprecatedString host) void URL::set_host(Host host)
{ {
m_host = move(host); m_host = move(host);
m_valid = compute_validity(); m_valid = compute_validity();
} }
// https://url.spec.whatwg.org/#concept-host-serializer
ErrorOr<String> URL::serialized_host() const
{
return URLParser::serialize_host(m_host);
}
void URL::set_port(Optional<u16> port) void URL::set_port(Optional<u16> port)
{ {
if (port == default_port_for_scheme(m_scheme)) { if (port == default_port_for_scheme(m_scheme)) {
@ -157,7 +163,7 @@ 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". // A URL cannot have a username/password/port if its host is null or the empty string, or its scheme is "file".
// FIXME: The spec does not mention anything to do with 'cannot be a base URL'. // FIXME: The spec does not mention anything to do with 'cannot be a base URL'.
return m_host.is_null() || m_host.is_empty() || m_cannot_be_a_base_url || m_scheme == "file"sv; return m_host.has<Empty>() || m_host == String {} || m_cannot_be_a_base_url || m_scheme == "file"sv;
} }
// FIXME: This is by no means complete. // FIXME: This is by no means complete.
@ -192,7 +198,7 @@ bool URL::compute_validity() const
} }
// NOTE: A file URL's host should be the empty string for localhost, not null. // NOTE: A file URL's host should be the empty string for localhost, not null.
if (m_scheme == "file" && m_host.is_null()) if (m_scheme == "file" && m_host.has<Empty>())
return false; return false;
return true; return true;
@ -227,7 +233,7 @@ URL URL::create_with_file_scheme(DeprecatedString const& path, DeprecatedString
url.set_scheme("file"); url.set_scheme("file");
// NOTE: If the hostname is localhost (or null, which implies localhost), it should be set to the empty string. // NOTE: If the hostname is localhost (or null, which implies localhost), it should be set to the empty string.
// This is because a file URL always needs a non-null hostname. // This is because a file URL always needs a non-null hostname.
url.set_host(hostname.is_null() || hostname == "localhost" ? DeprecatedString::empty() : hostname); url.set_host(hostname.is_null() || hostname == "localhost" ? String {} : String::from_deprecated_string(hostname).release_value_but_fixme_should_propagate_errors());
url.set_paths(lexical_path.parts()); url.set_paths(lexical_path.parts());
if (path.ends_with('/')) if (path.ends_with('/'))
url.append_slash(); url.append_slash();
@ -243,7 +249,8 @@ URL URL::create_with_help_scheme(DeprecatedString const& path, DeprecatedString
url.set_scheme("help"); url.set_scheme("help");
// NOTE: If the hostname is localhost (or null, which implies localhost), it should be set to the empty string. // NOTE: If the hostname is localhost (or null, which implies localhost), it should be set to the empty string.
// This is because a file URL always needs a non-null hostname. // This is because a file URL always needs a non-null hostname.
url.set_host(hostname.is_null() || hostname == "localhost" ? DeprecatedString::empty() : hostname); url.set_host(hostname.is_null() || hostname == "localhost" ? String {} : String::from_deprecated_string(hostname).release_value_but_fixme_should_propagate_errors());
url.set_paths(lexical_path.parts()); url.set_paths(lexical_path.parts());
if (path.ends_with('/')) if (path.ends_with('/'))
url.append_slash(); url.append_slash();
@ -309,7 +316,7 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
output.append(':'); output.append(':');
// 2. If urls host is non-null: // 2. If urls host is non-null:
if (!m_host.is_null()) { if (!m_host.has<Empty>()) {
// 1. Append "//" to output. // 1. Append "//" to output.
output.append("//"sv); output.append("//"sv);
@ -329,7 +336,7 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
} }
// 3. Append urls host, serialized, to output. // 3. Append urls host, serialized, to output.
output.append(m_host); output.append(serialized_host().release_value_but_fixme_should_propagate_errors());
// 4. If urls port is non-null, append U+003A (:) followed by urls port, serialized, to output. // 4. If urls port is non-null, append U+003A (:) followed by urls port, serialized, to output.
if (m_port.has_value()) if (m_port.has_value())
@ -342,7 +349,7 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
if (cannot_be_a_base_url()) { if (cannot_be_a_base_url()) {
output.append(m_paths[0]); output.append(m_paths[0]);
} else { } else {
if (m_host.is_null() && m_paths.size() > 1 && m_paths[0].is_empty()) if (m_host.has<Empty>() && m_paths.size() > 1 && m_paths[0].is_empty())
output.append("/."sv); output.append("/."sv);
for (auto& segment : m_paths) { for (auto& segment : m_paths) {
output.append('/'); output.append('/');
@ -379,9 +386,9 @@ DeprecatedString URL::serialize_for_display() const
builder.append(m_scheme); builder.append(m_scheme);
builder.append(':'); builder.append(':');
if (!m_host.is_null()) { if (!m_host.has<Empty>()) {
builder.append("//"sv); builder.append("//"sv);
builder.append(m_host); builder.append(serialized_host().release_value_but_fixme_should_propagate_errors());
if (m_port.has_value()) if (m_port.has_value())
builder.appendff(":{}", *m_port); builder.appendff(":{}", *m_port);
} }
@ -389,7 +396,7 @@ DeprecatedString URL::serialize_for_display() const
if (cannot_be_a_base_url()) { if (cannot_be_a_base_url()) {
builder.append(m_paths[0]); builder.append(m_paths[0]);
} else { } else {
if (m_host.is_null() && m_paths.size() > 1 && m_paths[0].is_empty()) if (m_host.has<Empty>() && m_paths.size() > 1 && m_paths[0].is_empty())
builder.append("/."sv); builder.append("/."sv);
for (auto& segment : m_paths) { for (auto& segment : m_paths) {
builder.append('/'); builder.append('/');
@ -437,7 +444,7 @@ DeprecatedString URL::serialize_origin() const
StringBuilder builder; StringBuilder builder;
builder.append(m_scheme); builder.append(m_scheme);
builder.append("://"sv); builder.append("://"sv);
builder.append(m_host); builder.append(serialized_host().release_value_but_fixme_should_propagate_errors());
if (m_port.has_value()) if (m_port.has_value())
builder.appendff(":{}", *m_port); builder.appendff(":{}", *m_port);
return builder.to_deprecated_string(); return builder.to_deprecated_string();

View file

@ -79,7 +79,8 @@ public:
DeprecatedString const& scheme() const { return m_scheme; } DeprecatedString const& scheme() const { return m_scheme; }
DeprecatedString username(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const; DeprecatedString username(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const;
DeprecatedString password(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const; DeprecatedString password(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const;
DeprecatedString const& host() const { return m_host; } Host const& host() const { return m_host; }
ErrorOr<String> serialized_host() const;
DeprecatedString basename(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const; DeprecatedString basename(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const;
DeprecatedString query(ApplyPercentDecoding = ApplyPercentDecoding::No) const; DeprecatedString query(ApplyPercentDecoding = ApplyPercentDecoding::No) const;
DeprecatedString fragment(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const; DeprecatedString fragment(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const;
@ -101,7 +102,7 @@ public:
void set_scheme(DeprecatedString); void set_scheme(DeprecatedString);
void set_username(DeprecatedString, ApplyPercentEncoding = ApplyPercentEncoding::Yes); void set_username(DeprecatedString, ApplyPercentEncoding = ApplyPercentEncoding::Yes);
void set_password(DeprecatedString, ApplyPercentEncoding = ApplyPercentEncoding::Yes); void set_password(DeprecatedString, ApplyPercentEncoding = ApplyPercentEncoding::Yes);
void set_host(DeprecatedString); void set_host(Host);
void set_port(Optional<u16>); void set_port(Optional<u16>);
void set_paths(Vector<DeprecatedString>, ApplyPercentEncoding = ApplyPercentEncoding::Yes); void set_paths(Vector<DeprecatedString>, ApplyPercentEncoding = ApplyPercentEncoding::Yes);
void set_query(DeprecatedString, ApplyPercentEncoding = ApplyPercentEncoding::Yes); void set_query(DeprecatedString, ApplyPercentEncoding = ApplyPercentEncoding::Yes);
@ -178,7 +179,7 @@ private:
DeprecatedString m_password; DeprecatedString m_password;
// A URLs host is null or a host. It is initially null. // A URLs host is null or a host. It is initially null.
DeprecatedString m_host; Host m_host;
// A URLs port is either null or a 16-bit unsigned integer that identifies a networking port. It is initially null. // A URLs port is either null or a 16-bit unsigned integer that identifies a networking port. It is initially null.
Optional<u16> m_port; Optional<u16> m_port;

View file

@ -32,7 +32,7 @@ static void report_validation_error(SourceLocation const& location = SourceLocat
dbgln_if(URL_PARSER_DEBUG, "URLParser::basic_parse: Validation error! {}", location); dbgln_if(URL_PARSER_DEBUG, "URLParser::basic_parse: Validation error! {}", location);
} }
static Optional<DeprecatedString> parse_opaque_host(StringView input) static Optional<URL::Host> parse_opaque_host(StringView input)
{ {
auto forbidden_host_characters_excluding_percent = "\0\t\n\r #/:<>?@[\\]^|"sv; auto forbidden_host_characters_excluding_percent = "\0\t\n\r #/:<>?@[\\]^|"sv;
for (auto character : forbidden_host_characters_excluding_percent) { for (auto character : forbidden_host_characters_excluding_percent) {
@ -43,7 +43,7 @@ static Optional<DeprecatedString> parse_opaque_host(StringView input)
} }
// FIXME: If input contains a code point that is not a URL code point and not U+0025 (%), validation error. // FIXME: If input contains a code point that is not a URL code point and not U+0025 (%), validation error.
// FIXME: If input contains a U+0025 (%) and the two code points following it are not ASCII hex digits, validation error. // FIXME: If input contains a U+0025 (%) and the two code points following it are not ASCII hex digits, validation error.
return URL::percent_encode(input, URL::PercentEncodeSet::C0Control); return String::from_deprecated_string(URL::percent_encode(input, URL::PercentEncodeSet::C0Control)).release_value_but_fixme_should_propagate_errors();
} }
struct ParsedIPv4Number { struct ParsedIPv4Number {
@ -549,7 +549,7 @@ static bool ends_in_a_number_checker(StringView input)
// https://url.spec.whatwg.org/#concept-host-parser // https://url.spec.whatwg.org/#concept-host-parser
// NOTE: This is a very bare-bones implementation. // NOTE: This is a very bare-bones implementation.
static Optional<DeprecatedString> parse_host(StringView input, bool is_not_special = false) static Optional<URL::Host> parse_host(StringView input, bool is_not_special = false)
{ {
// 1. If input starts with U+005B ([), then: // 1. If input starts with U+005B ([), then:
if (input.starts_with('[')) { if (input.starts_with('[')) {
@ -563,10 +563,7 @@ static Optional<DeprecatedString> parse_host(StringView input, bool is_not_speci
auto address = parse_ipv6_address(input.substring_view(1, input.length() - 2)); auto address = parse_ipv6_address(input.substring_view(1, input.length() - 2));
if (!address.has_value()) if (!address.has_value())
return {}; return {};
return address.release_value();
StringBuilder output;
serialize_ipv6_address(*address, output);
return output.to_deprecated_string();
} }
// 2. If isNotSpecial is true, then return the result of opaque-host parsing input. // 2. If isNotSpecial is true, then return the result of opaque-host parsing input.
@ -581,12 +578,16 @@ static Optional<DeprecatedString> parse_host(StringView input, bool is_not_speci
// FIXME: 5. Let asciiDomain be the result of running domain to ASCII on domain. // FIXME: 5. Let asciiDomain be the result of running domain to ASCII on domain.
// FIXME: 6. If asciiDomain is failure, then return failure. // FIXME: 6. If asciiDomain is failure, then return failure.
auto& ascii_domain = domain; auto ascii_domain_or_error = String::from_deprecated_string(domain);
if (ascii_domain_or_error.is_error())
return {};
auto ascii_domain = ascii_domain_or_error.release_value();
// 7. If asciiDomain contains a forbidden domain code point, domain-invalid-code-point validation error, return failure. // 7. If asciiDomain contains a forbidden domain code point, domain-invalid-code-point validation error, return failure.
auto forbidden_host_characters = "\0\t\n\r #%/:<>?@[\\]^|"sv; auto forbidden_host_characters = "\0\t\n\r #%/:<>?@[\\]^|"sv;
for (auto character : forbidden_host_characters) { for (auto character : forbidden_host_characters) {
if (ascii_domain.view().contains(character)) { if (ascii_domain.bytes_as_string_view().contains(character)) {
report_validation_error(); report_validation_error();
return {}; return {};
} }
@ -598,11 +599,7 @@ static Optional<DeprecatedString> parse_host(StringView input, bool is_not_speci
if (!ipv4_host.has_value()) if (!ipv4_host.has_value())
return {}; return {};
auto result = serialize_ipv4_address(*ipv4_host); return ipv4_host.release_value();
if (result.is_error())
return {};
return result.release_value().to_deprecated_string();
} }
// 9. Return asciiDomain. // 9. Return asciiDomain.
@ -880,7 +877,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
return *url; return *url;
// 4. If urls scheme is "file" and its host is an empty host, then return. // 4. If urls scheme is "file" and its host is an empty host, then return.
if (url->scheme() == "file"sv && url->host().is_empty()) if (url->scheme() == "file"sv && url->host() == String {})
return *url; return *url;
} }
@ -1319,7 +1316,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
url->m_scheme = "file"; url->m_scheme = "file";
// 2. Set urls host to the empty string. // 2. Set urls host to the empty string.
url->m_host = ""; url->m_host = String {};
// 3. If c is U+002F (/) or U+005C (\), then: // 3. If c is U+002F (/) or U+005C (\), then:
if (code_point == '/' || code_point == '\\') { if (code_point == '/' || code_point == '\\') {
@ -1422,7 +1419,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// 2. Otherwise, if buffer is the empty string, then: // 2. Otherwise, if buffer is the empty string, then:
else if (buffer.is_empty()) { else if (buffer.is_empty()) {
// 1. Set urls host to the empty string. // 1. Set urls host to the empty string.
url->m_host = ""; url->m_host = String {};
// 2. If state override is given, then return. // 2. If state override is given, then return.
if (state_override.has_value()) if (state_override.has_value())
@ -1442,8 +1439,8 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
return {}; return {};
// 3. If host is "localhost", then set host to the empty string. // 3. If host is "localhost", then set host to the empty string.
if (host.value() == "localhost") if (host.value().has<String>() && host.value().get<String>() == "localhost"sv)
host = ""; host = String {};
// 4. Set urls host to host. // 4. Set urls host to host.
url->m_host = host.release_value(); url->m_host = host.release_value();
@ -1498,7 +1495,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
continue; continue;
} }
// 5. Otherwise, if state override is given and urls host is null, append the empty string to urls path. // 5. Otherwise, if state override is given and urls host is null, append the empty string to urls path.
else if (state_override.has_value() && url->host().is_empty()) { else if (state_override.has_value() && url->host().has<Empty>()) {
url->append_slash(); url->append_slash();
} }
break; break;

View file

@ -49,7 +49,7 @@ void LocationEdit::highlight_location()
if (url.is_valid() && !hasFocus()) { if (url.is_valid() && !hasFocus()) {
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gemini") { if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gemini") {
int host_start = (url.scheme().length() + 3) - cursorPosition(); int host_start = (url.scheme().length() + 3) - cursorPosition();
auto host_length = url.host().length(); auto host_length = url.serialized_host().release_value_but_fixme_should_propagate_errors().bytes().size();
// FIXME: Maybe add a generator to use https://publicsuffix.org/list/public_suffix_list.dat // FIXME: Maybe add a generator to use https://publicsuffix.org/list/public_suffix_list.dat
// for now just highlight the whole host // for now just highlight the whole host

View file

@ -53,7 +53,7 @@ void WebSocketImplQt::connect(WebSocket::ConnectionInfo const& connection_info)
if (connection_info.is_secure()) { if (connection_info.is_secure()) {
auto ssl_socket = make<QSslSocket>(); auto ssl_socket = make<QSslSocket>();
ssl_socket->connectToHostEncrypted( ssl_socket->connectToHostEncrypted(
qstring_from_ak_deprecated_string(connection_info.url().host()), qstring_from_ak_string(connection_info.url().serialized_host().release_value_but_fixme_should_propagate_errors()),
connection_info.url().port_or_default()); connection_info.url().port_or_default());
QObject::connect(ssl_socket.ptr(), &QSslSocket::alertReceived, [this](QSsl::AlertLevel level, QSsl::AlertType, QString const&) { QObject::connect(ssl_socket.ptr(), &QSslSocket::alertReceived, [this](QSsl::AlertLevel level, QSsl::AlertType, QString const&) {
if (level == QSsl::AlertLevel::Fatal) if (level == QSsl::AlertLevel::Fatal)
@ -63,7 +63,7 @@ void WebSocketImplQt::connect(WebSocket::ConnectionInfo const& connection_info)
} else { } else {
m_socket = make<QTcpSocket>(); m_socket = make<QTcpSocket>();
m_socket->connectToHost( m_socket->connectToHost(
qstring_from_ak_deprecated_string(connection_info.url().host()), qstring_from_ak_string(connection_info.url().serialized_host().release_value_but_fixme_should_propagate_errors()),
connection_info.url().port_or_default()); connection_info.url().port_or_default());
} }

View file

@ -22,7 +22,7 @@ TEST_CASE(basic)
URL url("http://www.serenityos.org"sv); URL url("http://www.serenityos.org"sv);
EXPECT_EQ(url.is_valid(), true); EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http"); EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(url.host(), "www.serenityos.org"); EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80); EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/"); EXPECT_EQ(url.serialize_path(), "/");
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
@ -32,7 +32,7 @@ TEST_CASE(basic)
URL url("https://www.serenityos.org/index.html"sv); URL url("https://www.serenityos.org/index.html"sv);
EXPECT_EQ(url.is_valid(), true); EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "https"); EXPECT_EQ(url.scheme(), "https");
EXPECT_EQ(url.host(), "www.serenityos.org"); EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 443); EXPECT_EQ(url.port_or_default(), 443);
EXPECT_EQ(url.serialize_path(), "/index.html"); EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
@ -42,7 +42,7 @@ TEST_CASE(basic)
URL url("https://www.serenityos.org1/index.html"sv); URL url("https://www.serenityos.org1/index.html"sv);
EXPECT_EQ(url.is_valid(), true); EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "https"); EXPECT_EQ(url.scheme(), "https");
EXPECT_EQ(url.host(), "www.serenityos.org1"); EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org1");
EXPECT_EQ(url.port_or_default(), 443); EXPECT_EQ(url.port_or_default(), 443);
EXPECT_EQ(url.serialize_path(), "/index.html"); EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
@ -52,7 +52,7 @@ TEST_CASE(basic)
URL url("https://localhost:1234/~anon/test/page.html"sv); URL url("https://localhost:1234/~anon/test/page.html"sv);
EXPECT_EQ(url.is_valid(), true); EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "https"); EXPECT_EQ(url.scheme(), "https");
EXPECT_EQ(url.host(), "localhost"); EXPECT_EQ(MUST(url.serialized_host()), "localhost");
EXPECT_EQ(url.port_or_default(), 1234); EXPECT_EQ(url.port_or_default(), 1234);
EXPECT_EQ(url.serialize_path(), "/~anon/test/page.html"); EXPECT_EQ(url.serialize_path(), "/~anon/test/page.html");
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
@ -62,7 +62,7 @@ TEST_CASE(basic)
URL url("http://www.serenityos.org/index.html?#"sv); URL url("http://www.serenityos.org/index.html?#"sv);
EXPECT_EQ(url.is_valid(), true); EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http"); EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(url.host(), "www.serenityos.org"); EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80); EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html"); EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT_EQ(url.query(), ""); EXPECT_EQ(url.query(), "");
@ -72,7 +72,7 @@ TEST_CASE(basic)
URL url("http://www.serenityos.org/index.html?foo=1&bar=2"sv); URL url("http://www.serenityos.org/index.html?foo=1&bar=2"sv);
EXPECT_EQ(url.is_valid(), true); EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http"); EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(url.host(), "www.serenityos.org"); EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80); EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html"); EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT_EQ(url.query(), "foo=1&bar=2"); EXPECT_EQ(url.query(), "foo=1&bar=2");
@ -82,7 +82,7 @@ TEST_CASE(basic)
URL url("http://www.serenityos.org/index.html#fragment"sv); URL url("http://www.serenityos.org/index.html#fragment"sv);
EXPECT_EQ(url.is_valid(), true); EXPECT_EQ(url.is_valid(), true);
EXPECT_EQ(url.scheme(), "http"); EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(url.host(), "www.serenityos.org"); EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80); EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html"); EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
@ -92,7 +92,7 @@ TEST_CASE(basic)
URL url("http://www.serenityos.org/index.html?foo=1&bar=2&baz=/?#frag/ment?test#"sv); 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.is_valid(), true);
EXPECT_EQ(url.scheme(), "http"); EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(url.host(), "www.serenityos.org"); EXPECT_EQ(MUST(url.serialized_host()), "www.serenityos.org");
EXPECT_EQ(url.port_or_default(), 80); EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html"); EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT_EQ(url.query(), "foo=1&bar=2&baz=/?"); EXPECT_EQ(url.query(), "foo=1&bar=2&baz=/?");
@ -128,7 +128,7 @@ TEST_CASE(file_url_with_hostname)
URL url("file://courage/my/file"sv); URL url("file://courage/my/file"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file"); EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(url.host(), "courage"); EXPECT_EQ(MUST(url.serialized_host()), "courage");
EXPECT_EQ(url.port_or_default(), 0); EXPECT_EQ(url.port_or_default(), 0);
EXPECT_EQ(url.serialize_path(), "/my/file"); EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file://courage/my/file"); EXPECT_EQ(url.serialize(), "file://courage/my/file");
@ -141,7 +141,7 @@ TEST_CASE(file_url_with_localhost)
URL url("file://localhost/my/file"sv); URL url("file://localhost/my/file"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file"); EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(url.host(), ""); EXPECT_EQ(MUST(url.serialized_host()), "");
EXPECT_EQ(url.serialize_path(), "/my/file"); EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file:///my/file"); EXPECT_EQ(url.serialize(), "file:///my/file");
} }
@ -151,7 +151,7 @@ TEST_CASE(file_url_without_hostname)
URL url("file:///my/file"sv); URL url("file:///my/file"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file"); EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(url.host(), ""); EXPECT_EQ(MUST(url.serialized_host()), "");
EXPECT_EQ(url.serialize_path(), "/my/file"); EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file:///my/file"); EXPECT_EQ(url.serialize(), "file:///my/file");
} }
@ -205,7 +205,7 @@ TEST_CASE(about_url)
URL url("about:blank"sv); URL url("about:blank"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "about"); EXPECT_EQ(url.scheme(), "about");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.serialize_path(), "blank"); EXPECT_EQ(url.serialize_path(), "blank");
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
EXPECT(url.fragment().is_null()); EXPECT(url.fragment().is_null());
@ -217,7 +217,7 @@ TEST_CASE(mailto_url)
URL url("mailto:mail@example.com"sv); URL url("mailto:mail@example.com"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "mailto"); EXPECT_EQ(url.scheme(), "mailto");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.port_or_default(), 0); EXPECT_EQ(url.port_or_default(), 0);
EXPECT_EQ(url.path_segment_count(), 1u); EXPECT_EQ(url.path_segment_count(), 1u);
EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com"); EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com");
@ -231,7 +231,7 @@ TEST_CASE(data_url)
URL url("data:text/html,test"sv); URL url("data:text/html,test"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "data"); EXPECT_EQ(url.scheme(), "data");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.data_mime_type(), "text/html"); EXPECT_EQ(url.data_mime_type(), "text/html");
EXPECT_EQ(url.data_payload(), "test"); EXPECT_EQ(url.data_payload(), "test");
EXPECT(!url.data_payload_is_base64()); EXPECT(!url.data_payload_is_base64());
@ -243,7 +243,7 @@ TEST_CASE(data_url_default_mime_type)
URL url("data:,test"sv); URL url("data:,test"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "data"); EXPECT_EQ(url.scheme(), "data");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.data_mime_type(), "text/plain"); EXPECT_EQ(url.data_mime_type(), "text/plain");
EXPECT_EQ(url.data_payload(), "test"); EXPECT_EQ(url.data_payload(), "test");
EXPECT(!url.data_payload_is_base64()); EXPECT(!url.data_payload_is_base64());
@ -255,7 +255,7 @@ TEST_CASE(data_url_encoded)
URL url("data:text/html,Hello%20friends%2C%0X%X0"sv); URL url("data:text/html,Hello%20friends%2C%0X%X0"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "data"); EXPECT_EQ(url.scheme(), "data");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.data_mime_type(), "text/html"); EXPECT_EQ(url.data_mime_type(), "text/html");
EXPECT_EQ(url.data_payload(), "Hello friends,%0X%X0"); EXPECT_EQ(url.data_payload(), "Hello friends,%0X%X0");
EXPECT(!url.data_payload_is_base64()); EXPECT(!url.data_payload_is_base64());
@ -267,7 +267,7 @@ TEST_CASE(data_url_base64_encoded)
URL url("data:text/html;base64,test"sv); URL url("data:text/html;base64,test"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "data"); EXPECT_EQ(url.scheme(), "data");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.data_mime_type(), "text/html"); EXPECT_EQ(url.data_mime_type(), "text/html");
EXPECT_EQ(url.data_payload(), "test"); EXPECT_EQ(url.data_payload(), "test");
EXPECT(url.data_payload_is_base64()); EXPECT(url.data_payload_is_base64());
@ -279,7 +279,7 @@ TEST_CASE(data_url_base64_encoded_default_mime_type)
URL url("data:;base64,test"sv); URL url("data:;base64,test"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "data"); EXPECT_EQ(url.scheme(), "data");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.data_mime_type(), "text/plain"); EXPECT_EQ(url.data_mime_type(), "text/plain");
EXPECT_EQ(url.data_payload(), "test"); EXPECT_EQ(url.data_payload(), "test");
EXPECT(url.data_payload_is_base64()); EXPECT(url.data_payload_is_base64());
@ -291,7 +291,7 @@ TEST_CASE(data_url_base64_encoded_with_whitespace)
URL url("data: text/html ; bAsE64 , test with whitespace "sv); URL url("data: text/html ; bAsE64 , test with whitespace "sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "data"); EXPECT_EQ(url.scheme(), "data");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.data_mime_type(), "text/html"); EXPECT_EQ(url.data_mime_type(), "text/html");
EXPECT_EQ(url.data_payload(), " test with whitespace "); EXPECT_EQ(url.data_payload(), " test with whitespace ");
EXPECT(url.data_payload_is_base64()); EXPECT(url.data_payload_is_base64());
@ -303,7 +303,7 @@ TEST_CASE(data_url_base64_encoded_with_inline_whitespace)
URL url("data:text/javascript;base64,%20ZD%20Qg%0D%0APS%20An%20Zm91cic%0D%0A%207%20"sv); URL url("data:text/javascript;base64,%20ZD%20Qg%0D%0APS%20An%20Zm91cic%0D%0A%207%20"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "data"); EXPECT_EQ(url.scheme(), "data");
EXPECT(url.host().is_null()); EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.data_mime_type(), "text/javascript"); EXPECT_EQ(url.data_mime_type(), "text/javascript");
EXPECT(url.data_payload_is_base64()); EXPECT(url.data_payload_is_base64());
EXPECT_EQ(url.data_payload(), " ZD Qg\r\nPS An Zm91cic\r\n 7 "sv); EXPECT_EQ(url.data_payload(), " ZD Qg\r\nPS An Zm91cic\r\n 7 "sv);
@ -371,7 +371,7 @@ TEST_CASE(complete_url)
URL url = base_url.complete_url("test.html"sv); URL url = base_url.complete_url("test.html"sv);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "http"); EXPECT_EQ(url.scheme(), "http");
EXPECT_EQ(url.host(), "serenityos.org"); EXPECT_EQ(MUST(url.serialized_host()), "serenityos.org");
EXPECT_EQ(url.serialize_path(), "/test.html"); EXPECT_EQ(url.serialize_path(), "/test.html");
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
EXPECT(url.query().is_null()); EXPECT(url.query().is_null());
@ -445,6 +445,7 @@ TEST_CASE(ipv6_address)
constexpr auto ipv6_url = "http://[::1]/index.html"sv; constexpr auto ipv6_url = "http://[::1]/index.html"sv;
URL url(ipv6_url); URL url(ipv6_url);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "[::1]"sv);
EXPECT_EQ(url, ipv6_url); EXPECT_EQ(url, ipv6_url);
} }
@ -452,6 +453,7 @@ TEST_CASE(ipv6_address)
constexpr auto ipv6_url = "http://[0:f:0:0:f:f:0:0]/index.html"sv; constexpr auto ipv6_url = "http://[0:f:0:0:f:f:0:0]/index.html"sv;
URL url(ipv6_url); URL url(ipv6_url);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "[0:f::f:f:0:0]"sv);
EXPECT_EQ(url, ipv6_url); EXPECT_EQ(url, ipv6_url);
} }
@ -459,6 +461,7 @@ TEST_CASE(ipv6_address)
constexpr auto ipv6_url = "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/index.html"sv; constexpr auto ipv6_url = "https://[2001:0db8:85a3:0000:0000:8a2e:0370:7334]/index.html"sv;
URL url(ipv6_url); URL url(ipv6_url);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(MUST(url.serialized_host()), "[2001:db8:85a3::8a2e:370:7334]"sv);
EXPECT_EQ(url, ipv6_url); EXPECT_EQ(url, ipv6_url);
} }
@ -475,14 +478,14 @@ TEST_CASE(ipv4_address)
constexpr auto ipv4_url = "http://127.0.0.1/index.html"sv; constexpr auto ipv4_url = "http://127.0.0.1/index.html"sv;
URL url(ipv4_url); URL url(ipv4_url);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.host(), "127.0.0.1"sv); EXPECT_EQ(MUST(url.serialized_host()), "127.0.0.1"sv);
} }
{ {
constexpr auto ipv4_url = "http://0x.0x.0"sv; constexpr auto ipv4_url = "http://0x.0x.0"sv;
URL url(ipv4_url); URL url(ipv4_url);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.host(), "0.0.0.0"sv); EXPECT_EQ(MUST(url.serialized_host()), "0.0.0.0"sv);
} }
{ {
@ -495,13 +498,13 @@ TEST_CASE(ipv4_address)
constexpr auto ipv4_url = "http://256"sv; constexpr auto ipv4_url = "http://256"sv;
URL url(ipv4_url); URL url(ipv4_url);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.host(), "0.0.1.0"sv); EXPECT_EQ(MUST(url.serialized_host()), "0.0.1.0"sv);
} }
{ {
constexpr auto ipv4_url = "http://888888888"sv; constexpr auto ipv4_url = "http://888888888"sv;
URL url(ipv4_url); URL url(ipv4_url);
EXPECT(url.is_valid()); EXPECT(url.is_valid());
EXPECT_EQ(url.host(), "52.251.94.56"sv); EXPECT_EQ(MUST(url.serialized_host()), "52.251.94.56"sv);
} }
} }

View file

@ -248,8 +248,8 @@ void URLProvider::query(DeprecatedString const& query, Function<void(Vector<Nonn
if (url.scheme().is_empty()) if (url.scheme().is_empty())
url.set_scheme("http"); url.set_scheme("http");
if (url.host().is_empty()) if (url.host().has<Empty>() || url.host() == String {})
url.set_host(query); url.set_host(String::from_deprecated_string(query).release_value_but_fixme_should_propagate_errors());
if (url.path_segment_count() == 0) if (url.path_segment_count() == 0)
url.set_paths({ "" }); url.set_paths({ "" });

View file

@ -208,7 +208,10 @@ Optional<DeprecatedString> CookieJar::canonicalize_domain(const URL& url)
return {}; return {};
// FIXME: Implement RFC 5890 to "Convert each label that is not a Non-Reserved LDH (NR-LDH) label to an A-label". // FIXME: Implement RFC 5890 to "Convert each label that is not a Non-Reserved LDH (NR-LDH) label to an A-label".
return url.host().to_lowercase(); if (url.host().has<Empty>())
return {};
return url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string().to_lowercase();
} }
bool CookieJar::domain_matches(DeprecatedString const& string, DeprecatedString const& domain_string) bool CookieJar::domain_matches(DeprecatedString const& string, DeprecatedString const& domain_string)

View file

@ -107,10 +107,10 @@ void Tab::update_status(Optional<String> text_override, i32 count_waiting)
if (count_waiting == 0) { if (count_waiting == 0) {
// ex: "Loading google.com" // ex: "Loading google.com"
m_statusbar->set_text(String::formatted("Loading {}", m_navigating_url->host()).release_value_but_fixme_should_propagate_errors()); m_statusbar->set_text(String::formatted("Loading {}", m_navigating_url->serialized_host().release_value_but_fixme_should_propagate_errors()).release_value_but_fixme_should_propagate_errors());
} else { } else {
// ex: "google.com is waiting on 5 resources" // ex: "google.com is waiting on 5 resources"
m_statusbar->set_text(String::formatted("{} is waiting on {} resource{}", m_navigating_url->host(), count_waiting, count_waiting == 1 ? ""sv : "s"sv).release_value_but_fixme_should_propagate_errors()); m_statusbar->set_text(String::formatted("{} is waiting on {} resource{}", m_navigating_url->serialized_host().release_value_but_fixme_should_propagate_errors(), count_waiting, count_waiting == 1 ? ""sv : "s"sv).release_value_but_fixme_should_propagate_errors());
} }
} }

View file

@ -83,7 +83,7 @@ HelpWindow::HelpWindow(GUI::Window* parent)
m_webview = splitter.add<WebView::OutOfProcessWebView>(); m_webview = splitter.add<WebView::OutOfProcessWebView>();
m_webview->on_link_click = [this](auto& url, auto&, auto&&) { m_webview->on_link_click = [this](auto& url, auto&, auto&&) {
VERIFY(url.scheme() == "spreadsheet"); VERIFY(url.scheme() == "spreadsheet");
if (url.host() == "example") { if (url.host().template has<String>() && url.host().template get<String>() == "example"sv) {
auto example_path = url.serialize_path(); auto example_path = url.serialize_path();
auto entry = LexicalPath::basename(example_path); auto entry = LexicalPath::basename(example_path);
auto doc_option = m_docs.get_object(entry); auto doc_option = m_docs.get_object(entry);
@ -122,11 +122,11 @@ HelpWindow::HelpWindow(GUI::Window* parent)
widget->add_sheet(sheet.release_nonnull()); widget->add_sheet(sheet.release_nonnull());
window->show(); window->show();
} else if (url.host() == "doc") { } else if (url.host() == String::from_utf8_short_string("doc"sv)) {
auto entry = LexicalPath::basename(url.serialize_path()); auto entry = LexicalPath::basename(url.serialize_path());
m_webview->load(URL::create_with_data("text/html", render(entry))); m_webview->load(URL::create_with_data("text/html", render(entry)));
} else { } else {
dbgln("Invalid spreadsheet action domain '{}'", url.host()); dbgln("Invalid spreadsheet action domain '{}'", url.serialized_host().release_value_but_fixme_should_propagate_errors());
} }
}; };

View file

@ -264,7 +264,7 @@ Optional<Position> Sheet::position_from_url(const URL& url) const
return {}; return {};
} }
if (url.scheme() != "spreadsheet" || url.host() != "cell") { if (url.scheme() != "spreadsheet" || url.host() != String::from_utf8_short_string("cell"sv)) {
dbgln("Bad url: {}", url.to_deprecated_string()); dbgln("Bad url: {}", url.to_deprecated_string());
return {}; return {};
} }
@ -757,7 +757,7 @@ URL Position::to_url(Sheet const& sheet) const
{ {
URL url; URL url;
url.set_scheme("spreadsheet"); url.set_scheme("spreadsheet");
url.set_host("cell"); url.set_host(String::from_utf8_short_string("cell"sv));
url.set_paths({ DeprecatedString::number(getpid()) }); url.set_paths({ DeprecatedString::number(getpid()) });
url.set_fragment(to_cell_identifier(sheet)); url.set_fragment(to_cell_identifier(sheet));
return url; return url;

View file

@ -36,10 +36,9 @@ struct ProxyData {
proxy_data.type = ProxyData::Type::SOCKS5; proxy_data.type = ProxyData::Type::SOCKS5;
auto host_ipv4 = IPv4Address::from_string(url.host()); if (!url.host().has<URL::IPv4Address>())
if (!host_ipv4.has_value())
return Error::from_string_literal("Invalid proxy host, must be an IPv4 address"); return Error::from_string_literal("Invalid proxy host, must be an IPv4 address");
proxy_data.host_ipv4 = host_ipv4->to_u32(); proxy_data.host_ipv4 = url.host().get<URL::IPv4Address>();
auto port = url.port(); auto port = url.port();
if (!port.has_value()) if (!port.has_value())

View file

@ -179,8 +179,9 @@ void UrlBox::highlight_url()
if (url.is_valid() && !is_focused()) { if (url.is_valid() && !is_focused()) {
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gemini") { if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gemini") {
auto serialized_host = url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string();
auto host_start = url.scheme().length() + 3; auto host_start = url.scheme().length() + 3;
auto host_length = url.host().length(); auto host_length = serialized_host.length();
// FIXME: Maybe add a generator to use https://publicsuffix.org/list/public_suffix_list.dat // FIXME: Maybe add a generator to use https://publicsuffix.org/list/public_suffix_list.dat
// for now just highlight the whole host // for now just highlight the whole host

View file

@ -7,6 +7,7 @@
#include <AK/Base64.h> #include <AK/Base64.h>
#include <AK/StringBuilder.h> #include <AK/StringBuilder.h>
#include <AK/URLParser.h>
#include <LibHTTP/HttpRequest.h> #include <LibHTTP/HttpRequest.h>
#include <LibHTTP/Job.h> #include <LibHTTP/Job.h>
@ -57,7 +58,7 @@ ErrorOr<ByteBuffer> HttpRequest::to_raw_request() const
TRY(builder.try_append(m_url.query())); TRY(builder.try_append(m_url.query()));
} }
TRY(builder.try_append(" HTTP/1.1\r\nHost: "sv)); TRY(builder.try_append(" HTTP/1.1\r\nHost: "sv));
TRY(builder.try_append(m_url.host())); TRY(builder.try_append(TRY(m_url.serialized_host())));
if (m_url.port().has_value()) if (m_url.port().has_value())
TRY(builder.try_appendff(":{}", *m_url.port())); TRY(builder.try_appendff(":{}", *m_url.port()));
TRY(builder.try_append("\r\n"sv)); TRY(builder.try_append("\r\n"sv));

View file

@ -82,7 +82,7 @@ ErrorOr<NonnullRefPtr<PageNode const>> Node::try_create_from_query(Vector<String
ErrorOr<NonnullRefPtr<Node const>> Node::try_find_from_help_url(URL const& url) ErrorOr<NonnullRefPtr<Node const>> Node::try_find_from_help_url(URL const& url)
{ {
if (url.host() != "man") if (url.host() != String::from_utf8_short_string("man"sv))
return Error::from_string_view("Bad help operation"sv); return Error::from_string_view("Bad help operation"sv);
if (url.path_segment_count() < 2) if (url.path_segment_count() < 2)
return Error::from_string_view("Bad help page URL"sv); return Error::from_string_view("Bad help page URL"sv);

View file

@ -2316,8 +2316,7 @@ DeprecatedString Document::domain() const
return DeprecatedString::empty(); return DeprecatedString::empty();
// 3. Return effectiveDomain, serialized. // 3. Return effectiveDomain, serialized.
// FIXME: Implement host serialization. return URLParser::serialize_host(effective_domain.release_value()).release_value_but_fixme_should_propagate_errors().to_deprecated_string();
return effective_domain.release_value();
} }
void Document::set_domain(DeprecatedString const& domain) void Document::set_domain(DeprecatedString const& domain)

View file

@ -256,7 +256,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
// - requests current URLs scheme is "http" // - requests current URLs scheme is "http"
request->current_url().scheme() == "http"sv request->current_url().scheme() == "http"sv
// - requests current URLs host is a domain // - requests current URLs host is a domain
&& URL::host_is_domain(request->current_url().host()) && URL::host_is_domain(request->current_url().serialized_host().release_value_but_fixme_should_propagate_errors())
// FIXME: - Matching requests current URLs host per Known HSTS Host Domain Name Matching results in either a // FIXME: - Matching requests current URLs 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 // 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 // asserted includeSubDomains directive) [HSTS]; or DNS resolution for the request finds a matching HTTPS RR

View file

@ -44,7 +44,7 @@ static bool url_matches_about_blank(AK::URL const& url)
&& url.serialize_path() == "blank"sv && url.serialize_path() == "blank"sv
&& url.username().is_empty() && url.username().is_empty()
&& url.password().is_empty() && url.password().is_empty()
&& url.host().is_null(); && url.host().has<Empty>();
} }
// FIXME: This is an outdated older version of "determining the origin" and should be removed. // FIXME: This is an outdated older version of "determining the origin" and should be removed.

View file

@ -167,15 +167,15 @@ DeprecatedString HTMLHyperlinkElementUtils::host() const
auto& url = m_url; auto& url = m_url;
// 3. If url or url's host is null, return the empty string. // 3. If url or url's host is null, return the empty string.
if (!url.has_value() || url->host().is_null()) if (!url.has_value() || url->host().has<Empty>())
return DeprecatedString::empty(); return DeprecatedString::empty();
// 4. If url's port is null, return url's host, serialized. // 4. If url's port is null, return url's host, serialized.
if (!url->port().has_value()) if (!url->port().has_value())
return url->host(); return url->serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string();
// 5. Return url's host, serialized, followed by ":" and url's port, serialized. // 5. Return url's host, serialized, followed by ":" and url's port, serialized.
return DeprecatedString::formatted("{}:{}", url->host(), url->port().value()); return DeprecatedString::formatted("{}:{}", url->serialized_host().release_value_but_fixme_should_propagate_errors(), url->port().value());
} }
// https://html.spec.whatwg.org/multipage/links.html#dom-hyperlink-host // https://html.spec.whatwg.org/multipage/links.html#dom-hyperlink-host
@ -205,11 +205,14 @@ DeprecatedString HTMLHyperlinkElementUtils::hostname() const
// 1. Reinitialize url. // 1. Reinitialize url.
// //
// 2. Let url be this element's url. // 2. Let url be this element's url.
// AK::URL url(href());
// 3. If url or url's host is null, return the empty string. // 3. If url or url's host is null, return the empty string.
// if (url.host().has<Empty>())
return DeprecatedString::empty();
// 4. Return url's host, serialized. // 4. Return url's host, serialized.
return AK::URL(href()).host(); return url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string();
} }
void HTMLHyperlinkElementUtils::set_hostname(DeprecatedString hostname) void HTMLHyperlinkElementUtils::set_hostname(DeprecatedString hostname)

View file

@ -153,15 +153,15 @@ WebIDL::ExceptionOr<String> Location::host() const
auto url = this->url(); auto url = this->url();
// 3. If url's host is null, return the empty string. // 3. If url's host is null, return the empty string.
if (url.host().is_null()) if (url.host().has<Empty>())
return String {}; return String {};
// 4. If url's port is null, return url's host, serialized. // 4. If url's port is null, return url's host, serialized.
if (!url.port().has_value()) if (!url.port().has_value())
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(url.host())); return TRY_OR_THROW_OOM(vm, url.serialized_host());
// 5. Return url's host, serialized, followed by ":" and url's port, serialized. // 5. Return url's host, serialized, followed by ":" and url's port, serialized.
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.host(), *url.port())); return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", TRY_OR_THROW_OOM(vm, url.serialized_host()), *url.port()));
} }
WebIDL::ExceptionOr<void> Location::set_host(String const&) WebIDL::ExceptionOr<void> Location::set_host(String const&)
@ -183,11 +183,11 @@ WebIDL::ExceptionOr<String> Location::hostname() const
auto url = this->url(); auto url = this->url();
// 2. If this's url's host is null, return the empty string. // 2. If this's url's host is null, return the empty string.
if (url.host().is_null()) if (url.host().has<Empty>())
return String {}; return String {};
// 3. Return this's url's host, serialized. // 3. Return this's url's host, serialized.
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(url.host())); return TRY_OR_THROW_OOM(vm, url.serialized_host());
} }
WebIDL::ExceptionOr<void> Location::set_hostname(String const&) WebIDL::ExceptionOr<void> Location::set_hostname(String const&)

View file

@ -217,7 +217,7 @@ static bool url_matches_about_blank(AK::URL const& url)
&& url.serialize_path() == "blank"sv && url.serialize_path() == "blank"sv
&& url.username().is_empty() && url.username().is_empty()
&& url.password().is_empty() && url.password().is_empty()
&& url.host().is_null(); && url.host().has<Empty>();
} }
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements // https://html.spec.whatwg.org/multipage/iframe-embed-object.html#shared-attribute-processing-steps-for-iframe-and-frame-elements

View file

@ -8,13 +8,15 @@
#pragma once #pragma once
#include <AK/DeprecatedString.h> #include <AK/DeprecatedString.h>
#include <AK/URL.h>
#include <AK/URLParser.h>
namespace Web::HTML { namespace Web::HTML {
class Origin { class Origin {
public: public:
Origin() = default; Origin() = default;
Origin(DeprecatedString const& scheme, DeprecatedString const& host, u16 port) Origin(DeprecatedString const& scheme, AK::URL::Host const& host, u16 port)
: m_scheme(scheme) : m_scheme(scheme)
, m_host(host) , m_host(host)
, m_port(port) , m_port(port)
@ -22,10 +24,10 @@ public:
} }
// https://html.spec.whatwg.org/multipage/origin.html#concept-origin-opaque // https://html.spec.whatwg.org/multipage/origin.html#concept-origin-opaque
bool is_opaque() const { return m_scheme.is_null() && m_host.is_null() && m_port == 0; } bool is_opaque() const { return m_scheme.is_null() && m_host.has<Empty>() && m_port == 0; }
DeprecatedString const& scheme() const { return m_scheme; } DeprecatedString const& scheme() const { return m_scheme; }
DeprecatedString const& host() const { return m_host; } AK::URL::Host const& host() const { return m_host; }
u16 port() const { return m_port; } u16 port() const { return m_port; }
// https://html.spec.whatwg.org/multipage/origin.html#same-origin // https://html.spec.whatwg.org/multipage/origin.html#same-origin
@ -81,7 +83,7 @@ public:
result.append("://"sv); result.append("://"sv);
// 4. Append origin's host, serialized, to result. // 4. Append origin's host, serialized, to result.
result.append(host()); result.append(URLParser::serialize_host(host()).release_value_but_fixme_should_propagate_errors().to_deprecated_string());
// 5. If origin's port is non-null, append a U+003A COLON character (:), and origin's port, serialized, to result. // 5. If origin's port is non-null, append a U+003A COLON character (:), and origin's port, serialized, to result.
if (port() != 0) { if (port() != 0) {
@ -93,11 +95,11 @@ public:
} }
// https://html.spec.whatwg.org/multipage/origin.html#concept-origin-effective-domain // https://html.spec.whatwg.org/multipage/origin.html#concept-origin-effective-domain
Optional<DeprecatedString> effective_domain() const Optional<AK::URL::Host> effective_domain() const
{ {
// 1. If origin is an opaque origin, then return null. // 1. If origin is an opaque origin, then return null.
if (is_opaque()) if (is_opaque())
return Optional<DeprecatedString> {}; return {};
// FIXME: 2. If origin's domain is non-null, then return origin's domain. // FIXME: 2. If origin's domain is non-null, then return origin's domain.
@ -109,7 +111,7 @@ public:
private: private:
DeprecatedString m_scheme; DeprecatedString m_scheme;
DeprecatedString m_host; AK::URL::Host m_host;
u16 m_port { 0 }; u16 m_port { 0 };
}; };
@ -120,7 +122,10 @@ template<>
struct Traits<Web::HTML::Origin> : public GenericTraits<Web::HTML::Origin> { struct Traits<Web::HTML::Origin> : public GenericTraits<Web::HTML::Origin> {
static unsigned hash(Web::HTML::Origin const& origin) static unsigned hash(Web::HTML::Origin const& origin)
{ {
return pair_int_hash(origin.scheme().hash(), pair_int_hash(int_hash(origin.port()), origin.host().hash())); auto hash_without_host = pair_int_hash(origin.scheme().hash(), origin.port());
if (origin.host().has<Empty>())
return hash_without_host;
return pair_int_hash(hash_without_host, URLParser::serialize_host(origin.host()).release_value_but_fixme_should_propagate_errors().hash());
} }
}; };
} // namespace AK } // namespace AK

View file

@ -4,6 +4,7 @@
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
#include <AK/URLParser.h>
#include <LibWeb/HTML/WorkerGlobalScope.h> #include <LibWeb/HTML/WorkerGlobalScope.h>
#include <LibWeb/HTML/WorkerLocation.h> #include <LibWeb/HTML/WorkerLocation.h>
@ -43,15 +44,15 @@ WebIDL::ExceptionOr<String> WorkerLocation::host() const
auto const& url = m_global_scope->url(); auto const& url = m_global_scope->url();
// 2. If url's host is null, return the empty string. // 2. If url's host is null, return the empty string.
if (url.host().is_empty()) if (url.host().has<Empty>())
return String {}; return String {};
// 3. If url's port is null, return url's host, serialized. // 3. If url's port is null, return url's host, serialized.
if (!url.port().has_value()) if (!url.port().has_value())
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(url.host())); return TRY_OR_THROW_OOM(vm, url.serialized_host());
// 4. Return url's host, serialized, followed by ":" and url's port, serialized. // 4. Return url's host, serialized, followed by ":" and url's port, serialized.
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.host().view(), url.port().value())); return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", TRY_OR_THROW_OOM(vm, url.serialized_host()), url.port().value()));
} }
// https://html.spec.whatwg.org/multipage/workers.html#dom-workerlocation-hostname // https://html.spec.whatwg.org/multipage/workers.html#dom-workerlocation-hostname
@ -64,11 +65,11 @@ WebIDL::ExceptionOr<String> WorkerLocation::hostname() const
auto const& host = m_global_scope->url().host(); auto const& host = m_global_scope->url().host();
// 2. If host is null, return the empty string. // 2. If host is null, return the empty string.
if (host.is_empty()) if (host.has<Empty>())
return String {}; return String {};
// 3. Return host, serialized. // 3. Return host, serialized.
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(host)); return TRY_OR_THROW_OOM(vm, URLParser::serialize_host(host));
} }
// https://html.spec.whatwg.org/multipage/workers.html#dom-workerlocation-port // https://html.spec.whatwg.org/multipage/workers.html#dom-workerlocation-port

View file

@ -28,20 +28,29 @@ Trustworthiness is_origin_potentially_trustworthy(HTML::Origin const& origin)
return Trustworthiness::PotentiallyTrustworthy; return Trustworthiness::PotentiallyTrustworthy;
// 4. If origins host matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy". // 4. If origins host matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy".
if (auto ipv4_address = IPv4Address::from_string(origin.host()); ipv4_address.has_value() && (ipv4_address->to_u32() & 0xff000000) != 0) // FIXME: This would be nicer if URL::IPv4Address and URL::IPv6Address were instances of AK::IPv4Address and AK::IPv6Address
return Trustworthiness::PotentiallyTrustworthy; if (origin.host().has<AK::URL::IPv4Address>()) {
if (auto ipv6_address = IPv6Address::from_string(origin.host()); ipv6_address.has_value() && ipv6_address == IPv6Address::loopback()) if ((origin.host().get<AK::URL::IPv4Address>() & 0xff000000) != 0)
return Trustworthiness::PotentiallyTrustworthy; return Trustworthiness::PotentiallyTrustworthy;
} else if (origin.host().has<AK::URL::IPv6Address>()) {
auto ipv6_address = origin.host().get<AK::URL::IPv6Address>();
static constexpr AK::URL::IPv6Address loopback { 0, 0, 0, 0, 0, 0, 0, 1 };
if (ipv6_address == loopback)
return Trustworthiness::PotentiallyTrustworthy;
}
// 5. If the user agent conforms to the name resolution rules in [let-localhost-be-localhost] and one of the following is true: // 5. If the user agent conforms to the name resolution rules in [let-localhost-be-localhost] and one of the following is true:
// - origins host is "localhost" or "localhost." // - origins host is "localhost" or "localhost."
// - origins host ends with ".localhost" or ".localhost." // - origins host ends with ".localhost" or ".localhost."
// then return "Potentially Trustworthy". // then return "Potentially Trustworthy".
// Note: See §5.2 localhost for details on the requirements here. // Note: See §5.2 localhost for details on the requirements here.
if (origin.host().is_one_of("localhost"sv, "localhost.") if (origin.host().has<String>()) {
|| origin.host().ends_with(".localhost"sv) auto const& host = origin.host().get<String>();
|| origin.host().ends_with(".localhost."sv)) { if (host.is_one_of("localhost"sv, "localhost.")
return Trustworthiness::PotentiallyTrustworthy; || host.ends_with_bytes(".localhost"sv)
|| host.ends_with_bytes(".localhost."sv)) {
return Trustworthiness::PotentiallyTrustworthy;
}
} }
// 6. If origins scheme is "file", return "Potentially Trustworthy". // 6. If origins scheme is "file", return "Potentially Trustworthy".

View file

@ -235,15 +235,15 @@ WebIDL::ExceptionOr<String> URL::host() const
auto& url = m_url; auto& url = m_url;
// 2. If urls host is null, then return the empty string. // 2. If urls host is null, then return the empty string.
if (url.host().is_null()) if (url.host().has<Empty>())
return String {}; return String {};
// 3. If urls port is null, return urls host, serialized. // 3. If urls port is null, return urls host, serialized.
if (!url.port().has_value()) if (!url.port().has_value())
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(url.host())); return TRY_OR_THROW_OOM(vm, url.serialized_host());
// 4. Return urls host, serialized, followed by U+003A (:) and urls port, serialized. // 4. Return urls host, serialized, followed by U+003A (:) and urls port, serialized.
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.host(), *url.port())); return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", TRY_OR_THROW_OOM(vm, url.serialized_host()), *url.port()));
} }
// https://url.spec.whatwg.org/#dom-url-hostref-for-dom-url-host%E2%91%A0 // https://url.spec.whatwg.org/#dom-url-hostref-for-dom-url-host%E2%91%A0
@ -265,11 +265,11 @@ WebIDL::ExceptionOr<String> URL::hostname() const
auto& vm = realm().vm(); auto& vm = realm().vm();
// 1. If thiss URLs host is null, then return the empty string. // 1. If thiss URLs host is null, then return the empty string.
if (m_url.host().is_null()) if (m_url.host().has<Empty>())
return String {}; return String {};
// 2. Return thiss URLs host, serialized. // 2. Return thiss URLs host, serialized.
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.host())); return TRY_OR_THROW_OOM(vm, m_url.serialized_host());
} }
// https://url.spec.whatwg.org/#ref-for-dom-url-hostname① // https://url.spec.whatwg.org/#ref-for-dom-url-hostname①
@ -473,7 +473,7 @@ HTML::Origin url_origin(AK::URL const& url)
if (url.scheme() == "file"sv) { if (url.scheme() == "file"sv) {
// Unfortunate as it is, this is left as an exercise to the reader. When in doubt, return a new opaque origin. // Unfortunate as it is, this is left as an exercise to the reader. When in doubt, return a new opaque origin.
// Note: We must return an origin with the `file://' protocol for `file://' iframes to work from `file://' pages. // Note: We must return an origin with the `file://' protocol for `file://' iframes to work from `file://' pages.
return HTML::Origin(url.scheme(), DeprecatedString(), 0); return HTML::Origin(url.scheme(), String {}, 0);
} }
// -> Otherwise // -> Otherwise

View file

@ -388,7 +388,7 @@ WebIDL::ExceptionOr<void> XMLHttpRequest::open(String const& method_string, Stri
// NOTE: This is handled in the overload lacking the async argument. // NOTE: This is handled in the overload lacking the async argument.
// 8. If parsedURLs host is non-null, then: // 8. If parsedURLs host is non-null, then:
if (!parsed_url.host().is_null()) { if (!parsed_url.host().has<Empty>()) {
// 1. If the username argument is not null, set the username given parsedURL and username. // 1. If the username argument is not null, set the username given parsedURL and username.
if (username.has_value()) if (username.has_value())
parsed_url.set_username(username.value().to_deprecated_string()); parsed_url.set_username(username.value().to_deprecated_string());

View file

@ -42,17 +42,19 @@ void WebSocketImplSerenity::connect(ConnectionInfo const& connection_info)
VERIFY(on_connection_error); VERIFY(on_connection_error);
VERIFY(on_ready_to_read); VERIFY(on_ready_to_read);
auto socket_result = [&]() -> ErrorOr<NonnullOwnPtr<Core::BufferedSocketBase>> { auto socket_result = [&]() -> ErrorOr<NonnullOwnPtr<Core::BufferedSocketBase>> {
auto host = TRY(connection_info.url().serialized_host()).to_deprecated_string();
if (connection_info.is_secure()) { if (connection_info.is_secure()) {
TLS::Options options; TLS::Options options;
options.set_alert_handler([this](auto) { options.set_alert_handler([this](auto) {
on_connection_error(); on_connection_error();
}); });
return TRY(Core::BufferedSocket<TLS::TLSv12>::create( return TRY(Core::BufferedSocket<TLS::TLSv12>::create(
TRY(TLS::TLSv12::connect(connection_info.url().host(), connection_info.url().port_or_default(), move(options))))); TRY(TLS::TLSv12::connect(host, connection_info.url().port_or_default(), move(options)))));
} }
return TRY(Core::BufferedTCPSocket::create( return TRY(Core::BufferedTCPSocket::create(
TRY(Core::TCPSocket::connect(connection_info.url().host(), connection_info.url().port_or_default())))); TRY(Core::TCPSocket::connect(host, connection_info.url().port_or_default()))));
}(); }();
if (socket_result.is_error()) { if (socket_result.is_error()) {

View file

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

View file

@ -344,8 +344,8 @@ void ViewImplementation::handle_web_content_process_crash()
builder.append(escape_html_entities(m_url.to_deprecated_string())); builder.append(escape_html_entities(m_url.to_deprecated_string()));
builder.append("</title></head><body>"sv); builder.append("</title></head><body>"sv);
builder.append("<h1>Web page crashed"sv); builder.append("<h1>Web page crashed"sv);
if (!m_url.host().is_empty()) { if (!m_url.host().has<Empty>()) {
builder.appendff(" on {}", escape_html_entities(m_url.host())); builder.appendff(" on {}", escape_html_entities(m_url.serialized_host().release_value_but_fixme_should_propagate_errors()));
} }
builder.append("</h1>"sv); builder.append("</h1>"sv);
auto escaped_url = escape_html_entities(m_url.to_deprecated_string()); auto escaped_url = escape_html_entities(m_url.to_deprecated_string());

View file

@ -23,7 +23,7 @@ void request_did_finish(URL const& url, Core::Socket const* socket)
dbgln_if(REQUESTSERVER_DEBUG, "Request for {} finished", url); dbgln_if(REQUESTSERVER_DEBUG, "Request for {} finished", url);
ConnectionKey partial_key { url.host(), url.port_or_default() }; ConnectionKey partial_key { url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string(), url.port_or_default() };
auto fire_off_next_job = [&](auto& cache) { auto fire_off_next_job = [&](auto& cache) {
auto it = find_if(cache.begin(), cache.end(), [&](auto& connection) { return connection.key.hostname == partial_key.hostname && connection.key.port == partial_key.port; }); auto it = find_if(cache.begin(), cache.end(), [&](auto& connection) { return connection.key.hostname == partial_key.hostname && connection.key.port == partial_key.port; });
if (it == cache.end()) { if (it == cache.end()) {

View file

@ -37,14 +37,14 @@ struct Proxy {
ErrorOr<NonnullOwnPtr<StorageType>> tunnel(URL const& url, Args&&... args) ErrorOr<NonnullOwnPtr<StorageType>> tunnel(URL const& url, Args&&... args)
{ {
if (data.type == Core::ProxyData::Direct) { if (data.type == Core::ProxyData::Direct) {
return TRY(SocketType::connect(url.host(), url.port_or_default(), forward<Args>(args)...)); return TRY(SocketType::connect(url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string(), url.port_or_default(), forward<Args>(args)...));
} }
if (data.type == Core::ProxyData::SOCKS5) { if (data.type == Core::ProxyData::SOCKS5) {
if constexpr (requires { SocketType::connect(declval<DeprecatedString>(), *proxy_client_storage, forward<Args>(args)...); }) { if constexpr (requires { SocketType::connect(declval<DeprecatedString>(), *proxy_client_storage, forward<Args>(args)...); }) {
proxy_client_storage = TRY(Core::SOCKSProxyClient::connect(data.host_ipv4, data.port, Core::SOCKSProxyClient::Version::V5, url.host(), url.port_or_default())); proxy_client_storage = TRY(Core::SOCKSProxyClient::connect(data.host_ipv4, data.port, Core::SOCKSProxyClient::Version::V5, url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string(), url.port_or_default()));
return TRY(SocketType::connect(url.host(), *proxy_client_storage, forward<Args>(args)...)); return TRY(SocketType::connect(url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string(), *proxy_client_storage, forward<Args>(args)...));
} else if constexpr (IsSame<SocketType, Core::TCPSocket>) { } else if constexpr (IsSame<SocketType, Core::TCPSocket>) {
return TRY(Core::SOCKSProxyClient::connect(data.host_ipv4, data.port, Core::SOCKSProxyClient::Version::V5, url.host(), url.port_or_default())); return TRY(Core::SOCKSProxyClient::connect(data.host_ipv4, data.port, Core::SOCKSProxyClient::Version::V5, url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string(), url.port_or_default()));
} else { } else {
return Error::from_string_literal("SOCKS5 not supported for this socket type"); return Error::from_string_literal("SOCKS5 not supported for this socket type");
} }
@ -173,7 +173,7 @@ ErrorOr<void> recreate_socket_if_needed(T& connection, URL const& url)
decltype(auto) get_or_create_connection(auto& cache, URL const& url, auto& job, Core::ProxyData proxy_data = {}) decltype(auto) get_or_create_connection(auto& cache, URL const& url, auto& job, Core::ProxyData proxy_data = {})
{ {
using CacheEntryType = RemoveCVReference<decltype(*cache.begin()->value)>; using CacheEntryType = RemoveCVReference<decltype(*cache.begin()->value)>;
auto& sockets_for_url = *cache.ensure({ url.host(), url.port_or_default(), proxy_data }, [] { return make<CacheEntryType>(); }); auto& sockets_for_url = *cache.ensure({ url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string(), url.port_or_default(), proxy_data }, [] { return make<CacheEntryType>(); });
Proxy proxy { proxy_data }; Proxy proxy { proxy_data };

View file

@ -147,7 +147,7 @@ void ConnectionFromClient::ensure_connection(URL const& url, ::RequestServer::Ca
} }
if (cache_level == CacheLevel::ResolveOnly) { if (cache_level == CacheLevel::ResolveOnly) {
return Core::deferred_invoke([host = url.host()] { return Core::deferred_invoke([host = url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string()] {
dbgln("EnsureConnection: DNS-preload for {}", host); dbgln("EnsureConnection: DNS-preload for {}", host);
(void)gethostbyname(host.characters()); (void)gethostbyname(host.characters());
}); });
@ -156,7 +156,8 @@ void ConnectionFromClient::ensure_connection(URL const& url, ::RequestServer::Ca
auto& job = Job::ensure(url); auto& job = Job::ensure(url);
dbgln("EnsureConnection: Pre-connect to {}", url); dbgln("EnsureConnection: Pre-connect to {}", url);
auto do_preconnect = [&](auto& cache) { auto do_preconnect = [&](auto& cache) {
auto it = cache.find({ url.host(), url.port_or_default() }); auto serialized_host = url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string();
auto it = cache.find({ serialized_host, url.port_or_default() });
if (it == cache.end() || it->value->is_empty()) if (it == cache.end() || it->value->is_empty())
ConnectionCache::get_or_create_connection(cache, url, job); ConnectionCache::get_or_create_connection(cache, url, job);
}; };

View file

@ -112,10 +112,10 @@ void ConnectionFromClient::load_url(const URL& url)
#if defined(AK_OS_SERENITY) #if defined(AK_OS_SERENITY)
DeprecatedString process_name; DeprecatedString process_name;
if (url.host().is_empty()) if (url.host().has<Empty>() || url.host() == String {})
process_name = "WebContent"; process_name = "WebContent";
else else
process_name = DeprecatedString::formatted("WebContent: {}", url.host()); process_name = DeprecatedString::formatted("WebContent: {}", url.serialized_host().release_value_but_fixme_should_propagate_errors());
pthread_setname_np(pthread_self(), process_name.characters()); pthread_setname_np(pthread_self(), process_name.characters());
#endif #endif

View file

@ -679,7 +679,7 @@ ErrorOr<void> BarewordLiteral::highlight_in_editor(Line::Editor& editor, Shell&
if (FileSystem::exists(m_text)) { if (FileSystem::exists(m_text)) {
auto realpath = shell.resolve_path(m_text.bytes_as_string_view()); auto realpath = shell.resolve_path(m_text.bytes_as_string_view());
auto url = URL::create_with_file_scheme(realpath); auto url = URL::create_with_file_scheme(realpath);
url.set_host(shell.hostname); url.set_host(TRY(String::from_deprecated_string(shell.hostname)));
editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Hyperlink(url.to_deprecated_string()) }); editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Hyperlink(url.to_deprecated_string()) });
} }
return {}; return {};
@ -2620,7 +2620,7 @@ ErrorOr<void> PathRedirectionNode::highlight_in_editor(Line::Editor& editor, She
if (!path.starts_with('/')) if (!path.starts_with('/'))
path = String::formatted("{}/{}", shell.cwd, path).release_value_but_fixme_should_propagate_errors(); path = String::formatted("{}/{}", shell.cwd, path).release_value_but_fixme_should_propagate_errors();
auto url = URL::create_with_file_scheme(path.to_deprecated_string()); auto url = URL::create_with_file_scheme(path.to_deprecated_string());
url.set_host(shell.hostname); url.set_host(TRY(String::from_deprecated_string(shell.hostname)));
editor.stylize({ position.start_offset, position.end_offset }, { Line::Style::Hyperlink(url.to_deprecated_string()) }); editor.stylize({ position.start_offset, position.end_offset }, { Line::Style::Hyperlink(url.to_deprecated_string()) });
} }
return {}; return {};
@ -3214,7 +3214,7 @@ ErrorOr<void> Juxtaposition::highlight_in_editor(Line::Editor& editor, Shell& sh
if (FileSystem::exists(path)) { if (FileSystem::exists(path)) {
auto realpath = shell.resolve_path(path); auto realpath = shell.resolve_path(path);
auto url = URL::create_with_file_scheme(realpath); auto url = URL::create_with_file_scheme(realpath);
url.set_host(shell.hostname); url.set_host(TRY(String::from_deprecated_string(shell.hostname)));
editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Hyperlink(url.to_deprecated_string()) }); editor.stylize({ m_position.start_offset, m_position.end_offset }, { Line::Style::Hyperlink(url.to_deprecated_string()) });
} }

View file

@ -191,7 +191,7 @@ RecursionDecision MarkdownLinkage::visit(Markdown::Text::LinkNode const& link_no
return RecursionDecision::Recurse; return RecursionDecision::Recurse;
} }
if (url.scheme() == "help") { if (url.scheme() == "help") {
if (url.host() != "man") { if (url.host() != String::from_utf8_short_string("man"sv)) {
warnln("help:// URL without 'man': {}", href); warnln("help:// URL without 'man': {}", href);
m_has_invalid_link = true; m_has_invalid_link = true;
return RecursionDecision::Recurse; return RecursionDecision::Recurse;

View file

@ -343,7 +343,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
if (output_name.is_empty() || output_name == "/") { if (output_name.is_empty() || output_name == "/") {
int i = -1; int i = -1;
do { do {
output_name = url.host(); output_name = url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string();
if (i > -1) if (i > -1)
output_name = DeprecatedString::formatted("{}.{}", output_name, i); output_name = DeprecatedString::formatted("{}.{}", output_name, i);
++i; ++i;