mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
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:
parent
768f070b86
commit
8751be09f9
Notes:
sideshowbarker
2024-07-18 02:13:10 +09:00
Author: https://github.com/shannonbooth Commit: https://github.com/SerenityOS/serenity/commit/8751be09f9 Pull-request: https://github.com/SerenityOS/serenity/pull/20245 Reviewed-by: https://github.com/kennethmyhra ✅
36 changed files with 175 additions and 143 deletions
31
AK/URL.cpp
31
AK/URL.cpp
|
@ -101,12 +101,18 @@ void URL::set_password(DeprecatedString password, ApplyPercentEncoding apply_per
|
|||
m_valid = compute_validity();
|
||||
}
|
||||
|
||||
void URL::set_host(DeprecatedString host)
|
||||
void URL::set_host(Host host)
|
||||
{
|
||||
m_host = move(host);
|
||||
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)
|
||||
{
|
||||
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".
|
||||
// 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.
|
||||
|
@ -192,7 +198,7 @@ bool URL::compute_validity() const
|
|||
}
|
||||
|
||||
// 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 true;
|
||||
|
@ -227,7 +233,7 @@ URL URL::create_with_file_scheme(DeprecatedString const& path, DeprecatedString
|
|||
url.set_scheme("file");
|
||||
// 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.
|
||||
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());
|
||||
if (path.ends_with('/'))
|
||||
url.append_slash();
|
||||
|
@ -243,7 +249,8 @@ URL URL::create_with_help_scheme(DeprecatedString const& path, DeprecatedString
|
|||
url.set_scheme("help");
|
||||
// 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.
|
||||
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());
|
||||
if (path.ends_with('/'))
|
||||
url.append_slash();
|
||||
|
@ -309,7 +316,7 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
|
|||
output.append(':');
|
||||
|
||||
// 2. If url’s host is non-null:
|
||||
if (!m_host.is_null()) {
|
||||
if (!m_host.has<Empty>()) {
|
||||
// 1. Append "//" to output.
|
||||
output.append("//"sv);
|
||||
|
||||
|
@ -329,7 +336,7 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
|
|||
}
|
||||
|
||||
// 3. Append url’s host, serialized, to output.
|
||||
output.append(m_host);
|
||||
output.append(serialized_host().release_value_but_fixme_should_propagate_errors());
|
||||
|
||||
// 4. If url’s port is non-null, append U+003A (:) followed by url’s port, serialized, to output.
|
||||
if (m_port.has_value())
|
||||
|
@ -342,7 +349,7 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
|
|||
if (cannot_be_a_base_url()) {
|
||||
output.append(m_paths[0]);
|
||||
} 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);
|
||||
for (auto& segment : m_paths) {
|
||||
output.append('/');
|
||||
|
@ -379,9 +386,9 @@ DeprecatedString URL::serialize_for_display() const
|
|||
builder.append(m_scheme);
|
||||
builder.append(':');
|
||||
|
||||
if (!m_host.is_null()) {
|
||||
if (!m_host.has<Empty>()) {
|
||||
builder.append("//"sv);
|
||||
builder.append(m_host);
|
||||
builder.append(serialized_host().release_value_but_fixme_should_propagate_errors());
|
||||
if (m_port.has_value())
|
||||
builder.appendff(":{}", *m_port);
|
||||
}
|
||||
|
@ -389,7 +396,7 @@ DeprecatedString URL::serialize_for_display() const
|
|||
if (cannot_be_a_base_url()) {
|
||||
builder.append(m_paths[0]);
|
||||
} 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);
|
||||
for (auto& segment : m_paths) {
|
||||
builder.append('/');
|
||||
|
@ -437,7 +444,7 @@ DeprecatedString URL::serialize_origin() const
|
|||
StringBuilder builder;
|
||||
builder.append(m_scheme);
|
||||
builder.append("://"sv);
|
||||
builder.append(m_host);
|
||||
builder.append(serialized_host().release_value_but_fixme_should_propagate_errors());
|
||||
if (m_port.has_value())
|
||||
builder.appendff(":{}", *m_port);
|
||||
return builder.to_deprecated_string();
|
||||
|
|
7
AK/URL.h
7
AK/URL.h
|
@ -79,7 +79,8 @@ public:
|
|||
DeprecatedString const& scheme() const { return m_scheme; }
|
||||
DeprecatedString username(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 query(ApplyPercentDecoding = ApplyPercentDecoding::No) const;
|
||||
DeprecatedString fragment(ApplyPercentDecoding = ApplyPercentDecoding::Yes) const;
|
||||
|
@ -101,7 +102,7 @@ public:
|
|||
void set_scheme(DeprecatedString);
|
||||
void set_username(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_paths(Vector<DeprecatedString>, ApplyPercentEncoding = ApplyPercentEncoding::Yes);
|
||||
void set_query(DeprecatedString, ApplyPercentEncoding = ApplyPercentEncoding::Yes);
|
||||
|
@ -178,7 +179,7 @@ private:
|
|||
DeprecatedString m_password;
|
||||
|
||||
// A URL’s host is null or a host. It is initially null.
|
||||
DeprecatedString m_host;
|
||||
Host m_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> m_port;
|
||||
|
|
|
@ -32,7 +32,7 @@ static void report_validation_error(SourceLocation const& location = SourceLocat
|
|||
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;
|
||||
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 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 {
|
||||
|
@ -549,7 +549,7 @@ static bool ends_in_a_number_checker(StringView input)
|
|||
|
||||
// https://url.spec.whatwg.org/#concept-host-parser
|
||||
// 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:
|
||||
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));
|
||||
if (!address.has_value())
|
||||
return {};
|
||||
|
||||
StringBuilder output;
|
||||
serialize_ipv6_address(*address, output);
|
||||
return output.to_deprecated_string();
|
||||
return address.release_value();
|
||||
}
|
||||
|
||||
// 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: 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.
|
||||
auto forbidden_host_characters = "\0\t\n\r #%/:<>?@[\\]^|"sv;
|
||||
for (auto character : forbidden_host_characters) {
|
||||
if (ascii_domain.view().contains(character)) {
|
||||
if (ascii_domain.bytes_as_string_view().contains(character)) {
|
||||
report_validation_error();
|
||||
return {};
|
||||
}
|
||||
|
@ -598,11 +599,7 @@ static Optional<DeprecatedString> parse_host(StringView input, bool is_not_speci
|
|||
if (!ipv4_host.has_value())
|
||||
return {};
|
||||
|
||||
auto result = serialize_ipv4_address(*ipv4_host);
|
||||
if (result.is_error())
|
||||
return {};
|
||||
|
||||
return result.release_value().to_deprecated_string();
|
||||
return ipv4_host.release_value();
|
||||
}
|
||||
|
||||
// 9. Return asciiDomain.
|
||||
|
@ -880,7 +877,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
|
|||
return *url;
|
||||
|
||||
// 4. If url’s 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;
|
||||
}
|
||||
|
||||
|
@ -1319,7 +1316,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
|
|||
url->m_scheme = "file";
|
||||
|
||||
// 2. Set url’s host to the empty string.
|
||||
url->m_host = "";
|
||||
url->m_host = String {};
|
||||
|
||||
// 3. If c is U+002F (/) or U+005C (\), then:
|
||||
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:
|
||||
else if (buffer.is_empty()) {
|
||||
// 1. Set url’s host to the empty string.
|
||||
url->m_host = "";
|
||||
url->m_host = String {};
|
||||
|
||||
// 2. If state override is given, then return.
|
||||
if (state_override.has_value())
|
||||
|
@ -1442,8 +1439,8 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
|
|||
return {};
|
||||
|
||||
// 3. If host is "localhost", then set host to the empty string.
|
||||
if (host.value() == "localhost")
|
||||
host = "";
|
||||
if (host.value().has<String>() && host.value().get<String>() == "localhost"sv)
|
||||
host = String {};
|
||||
|
||||
// 4. Set url’s host to host.
|
||||
url->m_host = host.release_value();
|
||||
|
@ -1498,7 +1495,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_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().is_empty()) {
|
||||
else if (state_override.has_value() && url->host().has<Empty>()) {
|
||||
url->append_slash();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -49,7 +49,7 @@ void LocationEdit::highlight_location()
|
|||
if (url.is_valid() && !hasFocus()) {
|
||||
if (url.scheme() == "http" || url.scheme() == "https" || url.scheme() == "gemini") {
|
||||
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
|
||||
// for now just highlight the whole host
|
||||
|
|
|
@ -53,7 +53,7 @@ void WebSocketImplQt::connect(WebSocket::ConnectionInfo const& connection_info)
|
|||
if (connection_info.is_secure()) {
|
||||
auto ssl_socket = make<QSslSocket>();
|
||||
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());
|
||||
QObject::connect(ssl_socket.ptr(), &QSslSocket::alertReceived, [this](QSsl::AlertLevel level, QSsl::AlertType, QString const&) {
|
||||
if (level == QSsl::AlertLevel::Fatal)
|
||||
|
@ -63,7 +63,7 @@ void WebSocketImplQt::connect(WebSocket::ConnectionInfo const& connection_info)
|
|||
} else {
|
||||
m_socket = make<QTcpSocket>();
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ TEST_CASE(basic)
|
|||
URL url("http://www.serenityos.org"sv);
|
||||
EXPECT_EQ(url.is_valid(), true);
|
||||
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.serialize_path(), "/");
|
||||
EXPECT(url.query().is_null());
|
||||
|
@ -32,7 +32,7 @@ TEST_CASE(basic)
|
|||
URL url("https://www.serenityos.org/index.html"sv);
|
||||
EXPECT_EQ(url.is_valid(), true);
|
||||
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.serialize_path(), "/index.html");
|
||||
EXPECT(url.query().is_null());
|
||||
|
@ -42,7 +42,7 @@ TEST_CASE(basic)
|
|||
URL url("https://www.serenityos.org1/index.html"sv);
|
||||
EXPECT_EQ(url.is_valid(), true);
|
||||
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.serialize_path(), "/index.html");
|
||||
EXPECT(url.query().is_null());
|
||||
|
@ -52,7 +52,7 @@ TEST_CASE(basic)
|
|||
URL url("https://localhost:1234/~anon/test/page.html"sv);
|
||||
EXPECT_EQ(url.is_valid(), true);
|
||||
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.serialize_path(), "/~anon/test/page.html");
|
||||
EXPECT(url.query().is_null());
|
||||
|
@ -62,7 +62,7 @@ TEST_CASE(basic)
|
|||
URL url("http://www.serenityos.org/index.html?#"sv);
|
||||
EXPECT_EQ(url.is_valid(), true);
|
||||
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.serialize_path(), "/index.html");
|
||||
EXPECT_EQ(url.query(), "");
|
||||
|
@ -72,7 +72,7 @@ TEST_CASE(basic)
|
|||
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(url.host(), "www.serenityos.org");
|
||||
EXPECT_EQ(MUST(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");
|
||||
|
@ -82,7 +82,7 @@ TEST_CASE(basic)
|
|||
URL url("http://www.serenityos.org/index.html#fragment"sv);
|
||||
EXPECT_EQ(url.is_valid(), true);
|
||||
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.serialize_path(), "/index.html");
|
||||
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);
|
||||
EXPECT_EQ(url.is_valid(), true);
|
||||
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.serialize_path(), "/index.html");
|
||||
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);
|
||||
EXPECT(url.is_valid());
|
||||
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.serialize_path(), "/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);
|
||||
EXPECT(url.is_valid());
|
||||
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(), "file:///my/file");
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ TEST_CASE(file_url_without_hostname)
|
|||
URL url("file:///my/file"sv);
|
||||
EXPECT(url.is_valid());
|
||||
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(), "file:///my/file");
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ TEST_CASE(about_url)
|
|||
URL url("about:blank"sv);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "about");
|
||||
EXPECT(url.host().is_null());
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT_EQ(url.serialize_path(), "blank");
|
||||
EXPECT(url.query().is_null());
|
||||
EXPECT(url.fragment().is_null());
|
||||
|
@ -217,7 +217,7 @@ TEST_CASE(mailto_url)
|
|||
URL url("mailto:mail@example.com"sv);
|
||||
EXPECT(url.is_valid());
|
||||
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.path_segment_count(), 1u);
|
||||
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);
|
||||
EXPECT(url.is_valid());
|
||||
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_payload(), "test");
|
||||
EXPECT(!url.data_payload_is_base64());
|
||||
|
@ -243,7 +243,7 @@ TEST_CASE(data_url_default_mime_type)
|
|||
URL url("data:,test"sv);
|
||||
EXPECT(url.is_valid());
|
||||
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_payload(), "test");
|
||||
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);
|
||||
EXPECT(url.is_valid());
|
||||
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_payload(), "Hello friends,%0X%X0");
|
||||
EXPECT(!url.data_payload_is_base64());
|
||||
|
@ -267,7 +267,7 @@ TEST_CASE(data_url_base64_encoded)
|
|||
URL url("data:text/html;base64,test"sv);
|
||||
EXPECT(url.is_valid());
|
||||
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_payload(), "test");
|
||||
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);
|
||||
EXPECT(url.is_valid());
|
||||
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_payload(), "test");
|
||||
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);
|
||||
EXPECT(url.is_valid());
|
||||
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_payload(), " test with whitespace ");
|
||||
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);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.scheme(), "data");
|
||||
EXPECT(url.host().is_null());
|
||||
EXPECT(url.host().has<Empty>());
|
||||
EXPECT_EQ(url.data_mime_type(), "text/javascript");
|
||||
EXPECT(url.data_payload_is_base64());
|
||||
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);
|
||||
EXPECT(url.is_valid());
|
||||
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(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;
|
||||
URL url(ipv6_url);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(MUST(url.serialized_host()), "[::1]"sv);
|
||||
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;
|
||||
URL url(ipv6_url);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(MUST(url.serialized_host()), "[0:f::f:f:0:0]"sv);
|
||||
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;
|
||||
URL url(ipv6_url);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(MUST(url.serialized_host()), "[2001:db8:85a3::8a2e:370:7334]"sv);
|
||||
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;
|
||||
URL url(ipv4_url);
|
||||
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;
|
||||
URL url(ipv4_url);
|
||||
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;
|
||||
URL url(ipv4_url);
|
||||
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;
|
||||
URL url(ipv4_url);
|
||||
EXPECT(url.is_valid());
|
||||
EXPECT_EQ(url.host(), "52.251.94.56"sv);
|
||||
EXPECT_EQ(MUST(url.serialized_host()), "52.251.94.56"sv);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,8 +248,8 @@ void URLProvider::query(DeprecatedString const& query, Function<void(Vector<Nonn
|
|||
|
||||
if (url.scheme().is_empty())
|
||||
url.set_scheme("http");
|
||||
if (url.host().is_empty())
|
||||
url.set_host(query);
|
||||
if (url.host().has<Empty>() || url.host() == String {})
|
||||
url.set_host(String::from_deprecated_string(query).release_value_but_fixme_should_propagate_errors());
|
||||
if (url.path_segment_count() == 0)
|
||||
url.set_paths({ "" });
|
||||
|
||||
|
|
|
@ -208,7 +208,10 @@ Optional<DeprecatedString> CookieJar::canonicalize_domain(const URL& url)
|
|||
return {};
|
||||
|
||||
// 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)
|
||||
|
|
|
@ -107,10 +107,10 @@ void Tab::update_status(Optional<String> text_override, i32 count_waiting)
|
|||
|
||||
if (count_waiting == 0) {
|
||||
// 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 {
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ HelpWindow::HelpWindow(GUI::Window* parent)
|
|||
m_webview = splitter.add<WebView::OutOfProcessWebView>();
|
||||
m_webview->on_link_click = [this](auto& url, auto&, auto&&) {
|
||||
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 entry = LexicalPath::basename(example_path);
|
||||
auto doc_option = m_docs.get_object(entry);
|
||||
|
@ -122,11 +122,11 @@ HelpWindow::HelpWindow(GUI::Window* parent)
|
|||
|
||||
widget->add_sheet(sheet.release_nonnull());
|
||||
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());
|
||||
m_webview->load(URL::create_with_data("text/html", render(entry)));
|
||||
} else {
|
||||
dbgln("Invalid spreadsheet action domain '{}'", url.host());
|
||||
dbgln("Invalid spreadsheet action domain '{}'", url.serialized_host().release_value_but_fixme_should_propagate_errors());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -264,7 +264,7 @@ Optional<Position> Sheet::position_from_url(const URL& url) const
|
|||
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());
|
||||
return {};
|
||||
}
|
||||
|
@ -757,7 +757,7 @@ URL Position::to_url(Sheet const& sheet) const
|
|||
{
|
||||
URL url;
|
||||
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_fragment(to_cell_identifier(sheet));
|
||||
return url;
|
||||
|
|
|
@ -36,10 +36,9 @@ struct ProxyData {
|
|||
|
||||
proxy_data.type = ProxyData::Type::SOCKS5;
|
||||
|
||||
auto host_ipv4 = IPv4Address::from_string(url.host());
|
||||
if (!host_ipv4.has_value())
|
||||
if (!url.host().has<URL::IPv4Address>())
|
||||
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();
|
||||
if (!port.has_value())
|
||||
|
|
|
@ -179,8 +179,9 @@ void UrlBox::highlight_url()
|
|||
|
||||
if (url.is_valid() && !is_focused()) {
|
||||
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_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
|
||||
// for now just highlight the whole host
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <AK/Base64.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/URLParser.h>
|
||||
#include <LibHTTP/HttpRequest.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(" 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())
|
||||
TRY(builder.try_appendff(":{}", *m_url.port()));
|
||||
TRY(builder.try_append("\r\n"sv));
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
if (url.host() != "man")
|
||||
if (url.host() != String::from_utf8_short_string("man"sv))
|
||||
return Error::from_string_view("Bad help operation"sv);
|
||||
if (url.path_segment_count() < 2)
|
||||
return Error::from_string_view("Bad help page URL"sv);
|
||||
|
|
|
@ -2316,8 +2316,7 @@ DeprecatedString Document::domain() const
|
|||
return DeprecatedString::empty();
|
||||
|
||||
// 3. Return effectiveDomain, serialized.
|
||||
// FIXME: Implement host serialization.
|
||||
return effective_domain.release_value();
|
||||
return URLParser::serialize_host(effective_domain.release_value()).release_value_but_fixme_should_propagate_errors().to_deprecated_string();
|
||||
}
|
||||
|
||||
void Document::set_domain(DeprecatedString const& domain)
|
||||
|
|
|
@ -256,7 +256,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> main_fetch(JS::
|
|||
// - request’s current URL’s scheme is "http"
|
||||
request->current_url().scheme() == "http"sv
|
||||
// - request’s current URL’s 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 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 @@ static bool url_matches_about_blank(AK::URL const& url)
|
|||
&& url.serialize_path() == "blank"sv
|
||||
&& url.username().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.
|
||||
|
|
|
@ -167,15 +167,15 @@ DeprecatedString HTMLHyperlinkElementUtils::host() const
|
|||
auto& url = m_url;
|
||||
|
||||
// 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();
|
||||
|
||||
// 4. If url's port is null, return url's host, serialized.
|
||||
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.
|
||||
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
|
||||
|
@ -205,11 +205,14 @@ DeprecatedString HTMLHyperlinkElementUtils::hostname() const
|
|||
// 1. Reinitialize 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.
|
||||
//
|
||||
if (url.host().has<Empty>())
|
||||
return DeprecatedString::empty();
|
||||
|
||||
// 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)
|
||||
|
|
|
@ -153,15 +153,15 @@ WebIDL::ExceptionOr<String> Location::host() const
|
|||
auto url = this->url();
|
||||
|
||||
// 3. If url's host is null, return the empty string.
|
||||
if (url.host().is_null())
|
||||
if (url.host().has<Empty>())
|
||||
return String {};
|
||||
|
||||
// 4. If url's port is null, return url's host, serialized.
|
||||
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.
|
||||
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&)
|
||||
|
@ -183,11 +183,11 @@ 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().is_null())
|
||||
if (url.host().has<Empty>())
|
||||
return String {};
|
||||
|
||||
// 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&)
|
||||
|
|
|
@ -217,7 +217,7 @@ static bool url_matches_about_blank(AK::URL const& url)
|
|||
&& url.serialize_path() == "blank"sv
|
||||
&& url.username().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
|
||||
|
|
|
@ -8,13 +8,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/DeprecatedString.h>
|
||||
#include <AK/URL.h>
|
||||
#include <AK/URLParser.h>
|
||||
|
||||
namespace Web::HTML {
|
||||
|
||||
class Origin {
|
||||
public:
|
||||
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_host(host)
|
||||
, m_port(port)
|
||||
|
@ -22,10 +24,10 @@ public:
|
|||
}
|
||||
|
||||
// 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& host() const { return m_host; }
|
||||
AK::URL::Host const& host() const { return m_host; }
|
||||
u16 port() const { return m_port; }
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/origin.html#same-origin
|
||||
|
@ -81,7 +83,7 @@ public:
|
|||
result.append("://"sv);
|
||||
|
||||
// 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.
|
||||
if (port() != 0) {
|
||||
|
@ -93,11 +95,11 @@ public:
|
|||
}
|
||||
|
||||
// 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.
|
||||
if (is_opaque())
|
||||
return Optional<DeprecatedString> {};
|
||||
return {};
|
||||
|
||||
// FIXME: 2. If origin's domain is non-null, then return origin's domain.
|
||||
|
||||
|
@ -109,7 +111,7 @@ public:
|
|||
|
||||
private:
|
||||
DeprecatedString m_scheme;
|
||||
DeprecatedString m_host;
|
||||
AK::URL::Host m_host;
|
||||
u16 m_port { 0 };
|
||||
};
|
||||
|
||||
|
@ -120,7 +122,10 @@ template<>
|
|||
struct Traits<Web::HTML::Origin> : public GenericTraits<Web::HTML::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
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/URLParser.h>
|
||||
#include <LibWeb/HTML/WorkerGlobalScope.h>
|
||||
#include <LibWeb/HTML/WorkerLocation.h>
|
||||
|
||||
|
@ -43,15 +44,15 @@ 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().is_empty())
|
||||
if (url.host().has<Empty>())
|
||||
return String {};
|
||||
|
||||
// 3. If url's port is null, return url's host, serialized.
|
||||
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.
|
||||
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
|
||||
|
@ -64,11 +65,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.is_empty())
|
||||
if (host.has<Empty>())
|
||||
return String {};
|
||||
|
||||
// 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
|
||||
|
|
|
@ -28,20 +28,29 @@ Trustworthiness is_origin_potentially_trustworthy(HTML::Origin const& origin)
|
|||
return Trustworthiness::PotentiallyTrustworthy;
|
||||
|
||||
// 4. If origin’s 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)
|
||||
return Trustworthiness::PotentiallyTrustworthy;
|
||||
if (auto ipv6_address = IPv6Address::from_string(origin.host()); ipv6_address.has_value() && ipv6_address == IPv6Address::loopback())
|
||||
return Trustworthiness::PotentiallyTrustworthy;
|
||||
// FIXME: This would be nicer if URL::IPv4Address and URL::IPv6Address were instances of AK::IPv4Address and AK::IPv6Address
|
||||
if (origin.host().has<AK::URL::IPv4Address>()) {
|
||||
if ((origin.host().get<AK::URL::IPv4Address>() & 0xff000000) != 0)
|
||||
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:
|
||||
// - origin’s host is "localhost" or "localhost."
|
||||
// - origin’s host ends with ".localhost" or ".localhost."
|
||||
// then return "Potentially Trustworthy".
|
||||
// Note: See § 5.2 localhost for details on the requirements here.
|
||||
if (origin.host().is_one_of("localhost"sv, "localhost.")
|
||||
|| origin.host().ends_with(".localhost"sv)
|
||||
|| origin.host().ends_with(".localhost."sv)) {
|
||||
return Trustworthiness::PotentiallyTrustworthy;
|
||||
if (origin.host().has<String>()) {
|
||||
auto const& host = origin.host().get<String>();
|
||||
if (host.is_one_of("localhost"sv, "localhost.")
|
||||
|| host.ends_with_bytes(".localhost"sv)
|
||||
|| host.ends_with_bytes(".localhost."sv)) {
|
||||
return Trustworthiness::PotentiallyTrustworthy;
|
||||
}
|
||||
}
|
||||
|
||||
// 6. If origin’s scheme is "file", return "Potentially Trustworthy".
|
||||
|
|
|
@ -235,15 +235,15 @@ WebIDL::ExceptionOr<String> URL::host() const
|
|||
auto& url = m_url;
|
||||
|
||||
// 2. If url’s host is null, then return the empty string.
|
||||
if (url.host().is_null())
|
||||
if (url.host().has<Empty>())
|
||||
return String {};
|
||||
|
||||
// 3. If url’s port is null, return url’s host, serialized.
|
||||
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 U+003A (:) 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()));
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
// 1. If this’s URL’s host is null, then return the empty string.
|
||||
if (m_url.host().is_null())
|
||||
if (m_url.host().has<Empty>())
|
||||
return String {};
|
||||
|
||||
// 2. Return this’s URL’s 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①
|
||||
|
@ -473,7 +473,7 @@ HTML::Origin url_origin(AK::URL const& url)
|
|||
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.
|
||||
// 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
|
||||
|
|
|
@ -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.
|
||||
|
||||
// 8. If parsedURL’s 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.
|
||||
if (username.has_value())
|
||||
parsed_url.set_username(username.value().to_deprecated_string());
|
||||
|
|
|
@ -42,17 +42,19 @@ 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_deprecated_string();
|
||||
if (connection_info.is_secure()) {
|
||||
TLS::Options options;
|
||||
options.set_alert_handler([this](auto) {
|
||||
on_connection_error();
|
||||
});
|
||||
|
||||
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(
|
||||
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()) {
|
||||
|
|
|
@ -171,7 +171,7 @@ void WebSocket::send_client_handshake()
|
|||
|
||||
// 4. Host
|
||||
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)
|
||||
builder.appendff(":{}", url.port_or_default());
|
||||
else if (m_connection.is_secure() && url.port_or_default() != 443)
|
||||
|
|
|
@ -344,8 +344,8 @@ void ViewImplementation::handle_web_content_process_crash()
|
|||
builder.append(escape_html_entities(m_url.to_deprecated_string()));
|
||||
builder.append("</title></head><body>"sv);
|
||||
builder.append("<h1>Web page crashed"sv);
|
||||
if (!m_url.host().is_empty()) {
|
||||
builder.appendff(" on {}", escape_html_entities(m_url.host()));
|
||||
if (!m_url.host().has<Empty>()) {
|
||||
builder.appendff(" on {}", escape_html_entities(m_url.serialized_host().release_value_but_fixme_should_propagate_errors()));
|
||||
}
|
||||
builder.append("</h1>"sv);
|
||||
auto escaped_url = escape_html_entities(m_url.to_deprecated_string());
|
||||
|
|
|
@ -23,7 +23,7 @@ void request_did_finish(URL const& url, Core::Socket const* socket)
|
|||
|
||||
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 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()) {
|
||||
|
|
|
@ -37,14 +37,14 @@ struct Proxy {
|
|||
ErrorOr<NonnullOwnPtr<StorageType>> tunnel(URL const& url, Args&&... args)
|
||||
{
|
||||
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 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()));
|
||||
return TRY(SocketType::connect(url.host(), *proxy_client_storage, forward<Args>(args)...));
|
||||
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.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>) {
|
||||
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 {
|
||||
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 = {})
|
||||
{
|
||||
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 };
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ void ConnectionFromClient::ensure_connection(URL const& url, ::RequestServer::Ca
|
|||
}
|
||||
|
||||
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);
|
||||
(void)gethostbyname(host.characters());
|
||||
});
|
||||
|
@ -156,7 +156,8 @@ void ConnectionFromClient::ensure_connection(URL const& url, ::RequestServer::Ca
|
|||
auto& job = Job::ensure(url);
|
||||
dbgln("EnsureConnection: Pre-connect to {}", url);
|
||||
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())
|
||||
ConnectionCache::get_or_create_connection(cache, url, job);
|
||||
};
|
||||
|
|
|
@ -112,10 +112,10 @@ void ConnectionFromClient::load_url(const URL& url)
|
|||
|
||||
#if defined(AK_OS_SERENITY)
|
||||
DeprecatedString process_name;
|
||||
if (url.host().is_empty())
|
||||
if (url.host().has<Empty>() || url.host() == String {})
|
||||
process_name = "WebContent";
|
||||
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());
|
||||
#endif
|
||||
|
|
|
@ -679,7 +679,7 @@ ErrorOr<void> BarewordLiteral::highlight_in_editor(Line::Editor& editor, Shell&
|
|||
if (FileSystem::exists(m_text)) {
|
||||
auto realpath = shell.resolve_path(m_text.bytes_as_string_view());
|
||||
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()) });
|
||||
}
|
||||
return {};
|
||||
|
@ -2620,7 +2620,7 @@ ErrorOr<void> PathRedirectionNode::highlight_in_editor(Line::Editor& editor, She
|
|||
if (!path.starts_with('/'))
|
||||
path = String::formatted("{}/{}", shell.cwd, path).release_value_but_fixme_should_propagate_errors();
|
||||
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()) });
|
||||
}
|
||||
return {};
|
||||
|
@ -3214,7 +3214,7 @@ ErrorOr<void> Juxtaposition::highlight_in_editor(Line::Editor& editor, Shell& sh
|
|||
if (FileSystem::exists(path)) {
|
||||
auto realpath = shell.resolve_path(path);
|
||||
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()) });
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ RecursionDecision MarkdownLinkage::visit(Markdown::Text::LinkNode const& link_no
|
|||
return RecursionDecision::Recurse;
|
||||
}
|
||||
if (url.scheme() == "help") {
|
||||
if (url.host() != "man") {
|
||||
if (url.host() != String::from_utf8_short_string("man"sv)) {
|
||||
warnln("help:// URL without 'man': {}", href);
|
||||
m_has_invalid_link = true;
|
||||
return RecursionDecision::Recurse;
|
||||
|
|
|
@ -343,7 +343,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
|
|||
if (output_name.is_empty() || output_name == "/") {
|
||||
int i = -1;
|
||||
do {
|
||||
output_name = url.host();
|
||||
output_name = url.serialized_host().release_value_but_fixme_should_propagate_errors().to_deprecated_string();
|
||||
if (i > -1)
|
||||
output_name = DeprecatedString::formatted("{}.{}", output_name, i);
|
||||
++i;
|
||||
|
|
Loading…
Reference in a new issue