AK: Port URL::m_query from DeprecatedString to String

This commit is contained in:
Shannon Booth 2023-08-12 19:28:19 +12:00 committed by Andrew Kaster
parent 55a01e72ca
commit 21fe86d235
Notes: sideshowbarker 2024-07-17 02:55:44 +09:00
14 changed files with 63 additions and 75 deletions

View file

@ -62,11 +62,6 @@ DeprecatedString URL::basename() const
return percent_decode(last_segment);
}
DeprecatedString URL::query() const
{
return m_query;
}
DeprecatedString URL::fragment() const
{
return percent_decode(m_fragment);
@ -145,11 +140,6 @@ void URL::append_path(StringView path)
m_paths.append(deprecated_string_percent_encode(path, PercentEncodeSet::Path));
}
void URL::set_query(StringView query)
{
m_query = deprecated_string_percent_encode(query, is_special() ? PercentEncodeSet::SpecialQuery : PercentEncodeSet::Query);
}
void URL::set_fragment(StringView fragment)
{
m_fragment = deprecated_string_percent_encode(fragment, PercentEncodeSet::Fragment);
@ -346,9 +336,9 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
}
// 5. If urls query is non-null, append U+003F (?), followed by urls query, to output.
if (!m_query.is_null()) {
if (m_query.has_value()) {
output.append('?');
output.append(m_query);
output.append(*m_query);
}
// 6. If exclude fragment is false and urls fragment is non-null, then append U+0023 (#), followed by urls fragment, to output.
@ -391,9 +381,9 @@ DeprecatedString URL::serialize_for_display() const
}
}
if (!m_query.is_null()) {
if (m_query.has_value()) {
builder.append('?');
builder.append(m_query);
builder.append(*m_query);
}
if (!m_fragment.is_null()) {

View file

@ -82,7 +82,7 @@ public:
Host const& host() const { return m_host; }
ErrorOr<String> serialized_host() const;
DeprecatedString basename() const;
DeprecatedString query() const;
Optional<String> const& query() const { return m_query; }
// NOTE: fragment() is percent-decoded, raw_fragment() is not.
DeprecatedString fragment() const;
DeprecatedString raw_fragment() const;
@ -103,7 +103,7 @@ public:
void set_host(Host);
void set_port(Optional<u16>);
void set_paths(Vector<DeprecatedString> const&);
void set_query(StringView);
void set_query(Optional<String> query) { m_query = move(query); }
void set_fragment(StringView fragment);
void set_cannot_be_a_base_url(bool value) { m_cannot_be_a_base_url = value; }
void append_path(StringView);
@ -182,7 +182,7 @@ private:
Vector<DeprecatedString> m_paths;
// A URLs query is either null or an ASCII string. It is initially null.
DeprecatedString m_query;
Optional<String> m_query;
// A URLs fragment is either null or an ASCII string that can be used for further processing on the resource the URLs other components identify. It is initially null.
DeprecatedString m_fragment;

View file

@ -994,7 +994,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// 2. If c is U+003F (?), then set urls query to the empty string, and state to query state.
if (code_point == '?') {
url->m_query = "";
url->m_query = String {};
state = State::Query;
}
// 3. Otherwise, if c is U+0023 (#), set urls fragment to the empty string and state to fragment state.
@ -1304,7 +1304,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// 2. If c is U+003F (?), then set urls query to the empty string and state to query state.
if (code_point == '?') {
url->m_query = "";
url->m_query = String {};
state = State::Query;
}
// 3. Otherwise, if c is U+0023 (#), set urls fragment to the empty string and state to fragment state.
@ -1445,7 +1445,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
}
// 2. Otherwise, if state override is not given and c is U+003F (?), set urls query to the empty string and state to query state.
else if (!state_override.has_value() && code_point == '?') {
url->m_query = "";
url->m_query = String {};
state = State::Query;
}
// 3. Otherwise, if state override is not given and c is U+0023 (#), set urls fragment to the empty string and state to fragment state.
@ -1514,7 +1514,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// 6. If c is U+003F (?), then set urls query to the empty string and state to query state.
if (code_point == '?') {
url->m_query = "";
url->m_query = String {};
state = State::Query;
}
// 7. If c is U+0023 (#), then set urls fragment to the empty string and state to fragment state.
@ -1543,7 +1543,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// 1. If c is U+003F (?), then set urls query to the empty string and state to query state.
if (code_point == '?') {
url->m_paths[0] = buffer.string_view();
url->m_query = "";
url->m_query = String {};
buffer.clear();
state = State::Query;
}
@ -1584,14 +1584,13 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// * c is the EOF code point
if ((!state_override.has_value() && code_point == '#')
|| code_point == end_of_file) {
VERIFY(url->m_query == "");
// then:
// 1. Let queryPercentEncodeSet be the special-query percent-encode set if url is special; otherwise the query percent-encode set.
auto query_percent_encode_set = url->is_special() ? URL::PercentEncodeSet::SpecialQuery : URL::PercentEncodeSet::Query;
// 2. Percent-encode after encoding, with encoding, buffer, and queryPercentEncodeSet, and append the result to urls query.
url->m_query = percent_encode_after_encoding(buffer.string_view(), query_percent_encode_set);
url->m_query = String::from_deprecated_string(percent_encode_after_encoding(buffer.string_view(), query_percent_encode_set)).release_value_but_fixme_should_propagate_errors();
// 3. Set buffer to the empty string.
buffer.clear();

View file

@ -24,7 +24,7 @@ TEST_CASE(basic)
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());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
}
{
@ -34,7 +34,7 @@ TEST_CASE(basic)
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());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
}
{
@ -44,7 +44,7 @@ TEST_CASE(basic)
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());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
}
{
@ -54,7 +54,7 @@ TEST_CASE(basic)
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());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
}
{
@ -84,7 +84,7 @@ TEST_CASE(basic)
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());
EXPECT(!url.query().has_value());
EXPECT_EQ(url.fragment(), "fragment");
}
{
@ -130,7 +130,7 @@ TEST_CASE(file_url_with_hostname)
EXPECT_EQ(url.port_or_default(), 0);
EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file://courage/my/file");
EXPECT(url.query().is_null());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
}
@ -160,7 +160,7 @@ TEST_CASE(file_url_with_encoded_characters)
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(url.serialize_path(), "/my/file/test#file.txt");
EXPECT(url.query().is_null());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
}
@ -170,7 +170,7 @@ TEST_CASE(file_url_with_fragment)
EXPECT(url.is_valid());
EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT(url.query().is_null());
EXPECT(!url.query().has_value());
EXPECT_EQ(url.fragment(), "fragment");
}
@ -205,7 +205,7 @@ TEST_CASE(about_url)
EXPECT_EQ(url.scheme(), "about");
EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.serialize_path(), "blank");
EXPECT(url.query().is_null());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT_EQ(url.serialize(), "about:blank");
}
@ -219,7 +219,7 @@ TEST_CASE(mailto_url)
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");
EXPECT(url.query().is_null());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT_EQ(url.serialize(), "mailto:mail@example.com");
}
@ -379,7 +379,7 @@ TEST_CASE(create_with_file_scheme)
EXPECT_EQ(url.path_segment_at_index(1), "anon");
EXPECT_EQ(url.path_segment_at_index(2), "README.md");
EXPECT_EQ(url.serialize_path(), "/home/anon/README.md");
EXPECT(url.query().is_null());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
url = URL::create_with_file_scheme("/home/anon/");
@ -402,8 +402,7 @@ TEST_CASE(complete_url)
EXPECT_EQ(url.scheme(), "http");
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());
EXPECT(!url.query().has_value());
EXPECT_EQ(url.cannot_be_a_base_url(), false);
EXPECT(base_url.complete_url("../index.html#fragment"sv).equals(base_url));
@ -435,7 +434,7 @@ TEST_CASE(unicode)
URL url { "http://example.com/_ünicöde_téxt_©"sv };
EXPECT(url.is_valid());
EXPECT_EQ(url.serialize_path(), "/_ünicöde_téxt_©");
EXPECT(url.query().is_null());
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
}

View file

@ -53,9 +53,9 @@ ErrorOr<ByteBuffer> HttpRequest::to_raw_request() const
auto path = m_url.serialize_path();
VERIFY(!path.is_empty());
TRY(builder.try_append(URL::percent_encode(path, URL::PercentEncodeSet::EncodeURI)));
if (!m_url.query().is_empty()) {
if (m_url.query().has_value()) {
TRY(builder.try_append('?'));
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(TRY(m_url.serialized_host())));
@ -230,7 +230,7 @@ ErrorOr<HttpRequest, HttpRequest::ParseError> HttpRequest::from_raw_request(Read
if (url_parts.size() == 2) {
request.m_resource = url_parts[0];
request.m_url.set_paths({ url_parts[0] });
request.m_url.set_query(url_parts[1]);
request.m_url.set_query(String::from_deprecated_string(url_parts[1]).release_value_but_fixme_should_propagate_errors());
} else {
request.m_resource = resource;
request.m_url.set_paths({ resource });

View file

@ -616,7 +616,7 @@ ErrorOr<void> HTMLFormElement::mutate_action_url(AK::URL parsed_action, Vector<X
auto query = TRY(url_encode(pairs, encoding));
// 3. Set parsed action's query component to query.
parsed_action.set_query(query.to_deprecated_string());
parsed_action.set_query(query);
// 4. Plan to navigate to parsed action.
plan_to_navigate_to(move(parsed_action), target_navigable, history_handling);
@ -715,7 +715,7 @@ ErrorOr<void> HTMLFormElement::mail_with_headers(AK::URL parsed_action, Vector<X
TRY(headers.replace("+"sv, "%20"sv, ReplaceMode::All));
// 4. Set parsed action's query to headers.
parsed_action.set_query(headers.to_deprecated_string());
parsed_action.set_query(headers);
// 5. Plan to navigate to parsed action.
plan_to_navigate_to(move(parsed_action), target_navigable, history_handling);
@ -751,15 +751,15 @@ ErrorOr<void> HTMLFormElement::mail_as_body(AK::URL parsed_action, Vector<XHR::F
}
// 3. If parsed action's query is null, then set it to the empty string.
if (parsed_action.query().is_null())
parsed_action.set_query(DeprecatedString::empty());
if (!parsed_action.query().has_value())
parsed_action.set_query(String {});
StringBuilder query_builder;
TRY(query_builder.try_append(parsed_action.query()));
query_builder.append(*parsed_action.query());
// 4. If parsed action's query is not the empty string, then append a single U+0026 AMPERSAND character (&) to it.
if (!parsed_action.query().is_empty())
if (!parsed_action.query()->is_empty())
TRY(query_builder.try_append('&'));
// 5. Append "body=" to parsed action's query.
@ -768,7 +768,7 @@ ErrorOr<void> HTMLFormElement::mail_as_body(AK::URL parsed_action, Vector<XHR::F
// 6. Append body to parsed action's query.
TRY(query_builder.try_append(body));
parsed_action.set_query(query_builder.to_deprecated_string());
parsed_action.set_query(MUST(query_builder.to_string()));
// 7. Plan to navigate to parsed action.
plan_to_navigate_to(move(parsed_action), target_navigable, history_handling);

View file

@ -330,7 +330,7 @@ DeprecatedString HTMLHyperlinkElementUtils::search() const
// 2. Let url be this element's url.
// 3. If url is null, or url's query is either null or the empty string, return the empty string.
if (!m_url.has_value() || m_url->query().is_null() || m_url->query().is_empty())
if (!m_url.has_value() || m_url->query().has_value() || m_url->query()->is_empty())
return DeprecatedString::empty();
// 4. Return "?", followed by url's query.
@ -358,7 +358,7 @@ void HTMLHyperlinkElementUtils::set_search(DeprecatedString search)
// 2. Set url's query to the empty string.
auto url_copy = m_url; // We copy the URL here to follow other browser's behavior of reverting the search change if the parse failed.
url_copy->set_query(DeprecatedString::empty());
url_copy->set_query(String {});
// 3. Basic URL parse input, with null, this element's node document's document's character encoding, url as url, and query state as state override.
auto result_url = URLParser::basic_parse(input, {}, move(url_copy), URLParser::State::Query);

View file

@ -253,7 +253,7 @@ WebIDL::ExceptionOr<String> Location::search() const
auto url = this->url();
// 2. If this's url's query is either null or the empty string, return the empty string.
if (url.query().is_empty())
if (!url.query().has_value() || url.query()->is_empty())
return String {};
// 3. Return "?", followed by this's url's query.

View file

@ -106,11 +106,11 @@ WebIDL::ExceptionOr<String> WorkerLocation::search() const
auto const& query = m_global_scope->url().query();
// 2. If query is either null or the empty string, return the empty string.
if (query.is_empty())
if (!query.has_value() || query->is_empty())
return String {};
// 3. Return "?", followed by query.
return TRY_OR_THROW_OOM(vm, String::formatted("?{}", query.view()));
return TRY_OR_THROW_OOM(vm, String::formatted("?{}", *query));
}
// https://html.spec.whatwg.org/multipage/workers.html#dom-workerlocation-hash

View file

@ -50,8 +50,6 @@ static Optional<AK::URL> parse_api_url(String const& url, Optional<String> const
// https://url.spec.whatwg.org/#dom-url-url
WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> URL::construct_impl(JS::Realm& realm, String const& url, Optional<String> const& base)
{
auto& vm = realm.vm();
// 1. Let parsedURL be the result of running the API URL parser on url with base, if given.
auto parsed_url = parse_api_url(url, base);
@ -60,7 +58,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> URL::construct_impl(JS::Realm& realm,
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid URL"sv };
// 3. Let query be parsedURLs query, if that is non-null, and the empty string otherwise.
auto query = parsed_url->query().is_null() ? String {} : TRY_OR_THROW_OOM(vm, String::from_deprecated_string(parsed_url->query()));
auto query = parsed_url->query().value_or(String {});
// 4. Set thiss URL to parsedURL.
// 5. Set thiss query object to a new URLSearchParams object.
@ -182,8 +180,8 @@ WebIDL::ExceptionOr<void> URL::set_href(String const& href)
auto query = m_url.query();
// 6. If query is non-null, then set thiss query objects list to the result of parsing query.
if (!query.is_null())
m_query->m_list = TRY_OR_THROW_OOM(vm, url_decode(query));
if (query.has_value())
m_query->m_list = TRY_OR_THROW_OOM(vm, url_decode(*query));
return {};
}
@ -382,11 +380,11 @@ WebIDL::ExceptionOr<String> URL::search() const
auto& vm = realm().vm();
// 1. If thiss URLs query is either null or the empty string, then return the empty string.
if (m_url.query().is_null() || m_url.query().is_empty())
if (!m_url.query().has_value() || m_url.query()->is_empty())
return String {};
// 2. Return U+003F (?), followed by thiss URLs query.
return TRY_OR_THROW_OOM(vm, String::formatted("?{}", m_url.query()));
return TRY_OR_THROW_OOM(vm, String::formatted("?{}", *m_url.query()));
}
// https://url.spec.whatwg.org/#ref-for-dom-url-search%E2%91%A0
@ -417,7 +415,7 @@ WebIDL::ExceptionOr<void> URL::set_search(String const& search)
// 4. Set urls query to the empty string.
auto url_copy = url; // We copy the URL here to follow other browser's behavior of reverting the search change if the parse failed.
url_copy.set_query(DeprecatedString::empty());
url_copy.set_query(String {});
// 5. Basic URL parse input with url as url and query state as state override.
auto result_url = URLParser::basic_parse(input, {}, move(url_copy), URLParser::State::Query);

View file

@ -65,7 +65,7 @@ public:
WebIDL::ExceptionOr<String> to_json() const;
void set_query(Badge<URLSearchParams>, StringView query) { m_url.set_query(query); }
void set_query(Badge<URLSearchParams>, Optional<String> query) { m_url.set_query(move(query)); }
private:
URL(JS::Realm&, AK::URL, JS::NonnullGCPtr<URLSearchParams> query);

View file

@ -32,10 +32,11 @@ DeprecatedString ConnectionInfo::resource_name() const
// The path component
builder.append(path);
// "?" if the query component is non-empty
if (!m_url.query().is_empty())
if (m_url.query().has_value() && !m_url.query()->is_empty()) {
builder.append('?');
// the query component
builder.append(m_url.query());
// the query component
builder.append(*m_url.query());
}
return builder.to_deprecated_string();
}

View file

@ -393,15 +393,16 @@ bool Launcher::open_file_url(const URL& url)
Vector<DeprecatedString> additional_parameters;
DeprecatedString filepath = url.serialize_path();
auto parameters = url.query().split('&');
for (auto const& parameter : parameters) {
auto pair = parameter.split('=');
if (pair.size() == 2 && pair[0] == "line_number") {
auto line = pair[1].to_int();
if (line.has_value())
// TextEditor uses file:line:col to open a file at a specific line number
filepath = DeprecatedString::formatted("{}:{}", filepath, line.value());
}
if (url.query().has_value()) {
url.query()->bytes_as_string_view().for_each_split_view('&', SplitBehavior::Nothing, [&](auto parameter) {
auto pair = parameter.split_view('=');
if (pair.size() == 2 && pair[0] == "line_number") {
auto line = pair[1].to_int();
if (line.has_value())
// TextEditor uses file:line:col to open a file at a specific line number
filepath = DeprecatedString::formatted("{}:{}", filepath, line.value());
}
});
}
additional_parameters.append(filepath);

View file

@ -58,7 +58,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
if (access(full_path.characters(), F_OK) == 0) {
linked = true;
auto url = URL::create_with_file_scheme(full_path, {}, hostname);
url.set_query(DeprecatedString::formatted("line_number={}", source_position.line_number));
url.set_query(TRY(String::formatted("line_number={}", source_position.line_number)));
out("\033]8;;{}\033\\", url.serialize());
}