AK: Port URL::m_fragment from DeprecatedString to String

This commit is contained in:
Shannon Booth 2023-08-12 16:52:42 +12:00 committed by Andrew Kaster
parent 5663a2d3b4
commit 9d60f23abc
Notes: sideshowbarker 2024-07-17 03:00:02 +09:00
21 changed files with 68 additions and 76 deletions

View File

@ -62,11 +62,6 @@ DeprecatedString URL::basename() const
return percent_decode(last_segment);
}
DeprecatedString URL::fragment() const
{
return m_fragment;
}
// NOTE: This only exists for compatibility with the existing URL tests which check for both .is_null() and .is_empty().
static DeprecatedString deprecated_string_percent_encode(DeprecatedString const& input, URL::PercentEncodeSet set = URL::PercentEncodeSet::Userinfo, URL::SpaceAsPlus space_as_plus = URL::SpaceAsPlus::No)
{
@ -135,11 +130,6 @@ void URL::append_path(StringView path)
m_paths.append(deprecated_string_percent_encode(path, PercentEncodeSet::Path));
}
void URL::set_fragment(StringView fragment)
{
m_fragment = fragment;
}
// https://url.spec.whatwg.org/#cannot-have-a-username-password-port
bool URL::cannot_have_a_username_or_password_or_port() const
{
@ -215,7 +205,8 @@ URL URL::create_with_file_scheme(DeprecatedString const& path, DeprecatedString
url.set_paths(lexical_path.parts());
if (path.ends_with('/'))
url.append_slash();
url.set_fragment(fragment);
if (!fragment.is_null())
url.set_fragment(String::from_deprecated_string(fragment).release_value_but_fixme_should_propagate_errors());
return url;
}
@ -232,7 +223,8 @@ URL URL::create_with_help_scheme(DeprecatedString const& path, DeprecatedString
url.set_paths(lexical_path.parts());
if (path.ends_with('/'))
url.append_slash();
url.set_fragment(fragment);
if (!fragment.is_null())
url.set_fragment(String::from_deprecated_string(fragment).release_value_but_fixme_should_propagate_errors());
return url;
}
@ -337,9 +329,9 @@ DeprecatedString URL::serialize(ExcludeFragment exclude_fragment) const
}
// 6. If exclude fragment is false and urls fragment is non-null, then append U+0023 (#), followed by urls fragment, to output.
if (exclude_fragment == ExcludeFragment::No && !m_fragment.is_null()) {
if (exclude_fragment == ExcludeFragment::No && m_fragment.has_value()) {
output.append('#');
output.append(m_fragment);
output.append(*m_fragment);
}
// 7. Return output.
@ -381,9 +373,9 @@ DeprecatedString URL::serialize_for_display() const
builder.append(*m_query);
}
if (!m_fragment.is_null()) {
if (m_fragment.has_value()) {
builder.append('#');
builder.append(m_fragment);
builder.append(*m_fragment);
}
return builder.to_deprecated_string();

View File

@ -83,7 +83,7 @@ public:
ErrorOr<String> serialized_host() const;
DeprecatedString basename() const;
Optional<String> const& query() const { return m_query; }
DeprecatedString fragment() const;
Optional<String> const& fragment() const { return m_fragment; }
Optional<u16> port() const { return m_port; }
DeprecatedString path_segment_at_index(size_t index) const;
size_t path_segment_count() const { return m_paths.size(); }
@ -102,7 +102,7 @@ public:
void set_port(Optional<u16>);
void set_paths(Vector<DeprecatedString> const&);
void set_query(Optional<String> query) { m_query = move(query); }
void set_fragment(StringView fragment);
void set_fragment(Optional<String> fragment) { m_fragment = move(fragment); }
void set_cannot_be_a_base_url(bool value) { m_cannot_be_a_base_url = value; }
void append_path(StringView);
void append_slash()
@ -183,7 +183,7 @@ private:
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;
Optional<String> m_fragment;
bool m_cannot_be_a_base_url { false };
};

View File

@ -924,7 +924,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
url->m_scheme = base_url->m_scheme;
url->m_paths = base_url->m_paths;
url->m_query = base_url->m_query;
url->m_fragment = "";
url->m_fragment = String {};
url->m_cannot_be_a_base_url = true;
state = State::Fragment;
}
@ -999,7 +999,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
}
// 3. Otherwise, if c is U+0023 (#), set urls fragment to the empty string and state to fragment state.
else if (code_point == '#') {
url->m_fragment = "";
url->m_fragment = String {};
state = State::Fragment;
}
// 4. Otherwise, if c is not the EOF code point:
@ -1309,7 +1309,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
}
// 3. Otherwise, if c is U+0023 (#), set urls fragment to the empty string and state to fragment state.
else if (code_point == '#') {
url->m_fragment = "";
url->m_fragment = String {};
state = State::Fragment;
}
// 4. Otherwise, if c is not the EOF code point:
@ -1450,7 +1450,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
}
// 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.
else if (!state_override.has_value() && code_point == '#') {
url->m_fragment = "";
url->m_fragment = String {};
state = State::Fragment;
}
// 4. Otherwise, if c is not the EOF code point:
@ -1519,7 +1519,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
}
// 7. If c is U+0023 (#), then set urls fragment to the empty string and state to fragment state.
else if (code_point == '#') {
url->m_fragment = "";
url->m_fragment = String {};
state = State::Fragment;
}
}
@ -1551,7 +1551,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
else if (code_point == '#') {
// NOTE: This needs to be percent decoded since the member variables contain decoded data.
url->m_paths[0] = buffer.string_view();
url->m_fragment = "";
url->m_fragment = String {};
buffer.clear();
state = State::Fragment;
}
@ -1597,7 +1597,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// 4. If c is U+0023 (#), then set urls fragment to the empty string and state to fragment state.
if (code_point == '#') {
url->m_fragment = "";
url->m_fragment = String {};
state = State::Fragment;
}
}
@ -1627,7 +1627,7 @@ URL URLParser::basic_parse(StringView raw_input, Optional<URL> const& base_url,
// FIXME: 3. UTF-8 percent-encode c using the fragment percent-encode set and append the result to urls fragment.
buffer.append_code_point(code_point);
} else {
url->m_fragment = buffer.string_view();
url->m_fragment = buffer.to_string().release_value_but_fixme_should_propagate_errors();
buffer.clear();
}
break;

View File

@ -25,7 +25,7 @@ TEST_CASE(basic)
EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
{
URL url("https://www.serenityos.org/index.html"sv);
@ -35,7 +35,7 @@ TEST_CASE(basic)
EXPECT_EQ(url.port_or_default(), 443);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
{
URL url("https://www.serenityos.org1/index.html"sv);
@ -45,7 +45,7 @@ TEST_CASE(basic)
EXPECT_EQ(url.port_or_default(), 443);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
{
URL url("https://localhost:1234/~anon/test/page.html"sv);
@ -55,7 +55,7 @@ TEST_CASE(basic)
EXPECT_EQ(url.port_or_default(), 1234);
EXPECT_EQ(url.serialize_path(), "/~anon/test/page.html");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
{
URL url("http://www.serenityos.org/index.html?#"sv);
@ -75,7 +75,7 @@ TEST_CASE(basic)
EXPECT_EQ(url.port_or_default(), 80);
EXPECT_EQ(url.serialize_path(), "/index.html");
EXPECT_EQ(url.query(), "foo=1&bar=2");
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
{
URL url("http://www.serenityos.org/index.html#fragment"sv);
@ -131,7 +131,7 @@ TEST_CASE(file_url_with_hostname)
EXPECT_EQ(url.serialize_path(), "/my/file");
EXPECT_EQ(url.serialize(), "file://courage/my/file");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
TEST_CASE(file_url_with_localhost)
@ -161,7 +161,7 @@ TEST_CASE(file_url_with_encoded_characters)
EXPECT_EQ(url.scheme(), "file");
EXPECT_EQ(url.serialize_path(), "/my/file/test#file.txt");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
TEST_CASE(file_url_with_fragment)
@ -206,7 +206,7 @@ TEST_CASE(about_url)
EXPECT(url.host().has<Empty>());
EXPECT_EQ(url.serialize_path(), "blank");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
EXPECT_EQ(url.serialize(), "about:blank");
}
@ -220,7 +220,7 @@ TEST_CASE(mailto_url)
EXPECT_EQ(url.path_segment_count(), 1u);
EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
EXPECT_EQ(url.serialize(), "mailto:mail@example.com");
}
@ -234,7 +234,7 @@ TEST_CASE(mailto_url_with_subject)
EXPECT_EQ(url.path_segment_count(), 1u);
EXPECT_EQ(url.path_segment_at_index(0), "mail@example.com");
EXPECT_EQ(url.query(), "subject=test");
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
EXPECT_EQ(url.serialize(), "mailto:mail@example.com?subject=test");
}
@ -380,7 +380,7 @@ TEST_CASE(create_with_file_scheme)
EXPECT_EQ(url.path_segment_at_index(2), "README.md");
EXPECT_EQ(url.serialize_path(), "/home/anon/README.md");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
url = URL::create_with_file_scheme("/home/anon/");
EXPECT(url.is_valid());
@ -435,7 +435,7 @@ TEST_CASE(unicode)
EXPECT(url.is_valid());
EXPECT_EQ(url.serialize_path(), "/_ünicöde_téxt_©");
EXPECT(!url.query().has_value());
EXPECT(url.fragment().is_null());
EXPECT(!url.fragment().has_value());
}
TEST_CASE(complete_file_url_with_base)

View File

@ -93,7 +93,7 @@ HelpWindow::HelpWindow(GUI::Window* parent)
return;
}
auto& doc = doc_option.value();
auto name = url.fragment();
auto name = url.fragment().value_or(String {});
auto maybe_example_data = doc.get_object("example_data"sv);
if (!maybe_example_data.has_value()) {

View File

@ -271,7 +271,7 @@ Optional<Position> Sheet::position_from_url(const URL& url) const
// FIXME: Figure out a way to do this cross-process.
VERIFY(url.serialize_path() == DeprecatedString::formatted("/{}", getpid()));
return parse_cell_name(url.fragment());
return parse_cell_name(url.fragment().value_or(String {}));
}
Position Sheet::offset_relative_to(Position const& base, Position const& offset, Position const& offset_base) const
@ -757,7 +757,7 @@ URL Position::to_url(Sheet const& sheet) const
url.set_scheme("spreadsheet"_string);
url.set_host("cell"_string);
url.set_paths({ DeprecatedString::number(getpid()) });
url.set_fragment(to_cell_identifier(sheet));
url.set_fragment(String::from_deprecated_string(to_cell_identifier(sheet)).release_value());
return url;
}

View File

@ -1737,14 +1737,16 @@ Document::IndicatedPart Document::determine_the_indicated_part() const
// For an HTML document document, the following processing model must be followed to determine its indicated part:
// 1. Let fragment be document's URL's fragment.
auto fragment = url().fragment();
VERIFY(url().fragment().has_value());
auto fragment = url().fragment().value();
// 2. If fragment is the empty string, then return the special value top of the document.
if (fragment.is_empty())
return Document::TopOfTheDocument {};
// 3. Let potentialIndicatedElement be the result of finding a potential indicated element given document and fragment.
auto potential_indicated_element = find_a_potential_indicated_element(fragment);
auto* potential_indicated_element = find_a_potential_indicated_element(fragment.to_deprecated_string());
// 4. If potentialIndicatedElement is not null, then return potentialIndicatedElement.
if (potential_indicated_element)

View File

@ -1077,9 +1077,7 @@ WebIDL::ExceptionOr<Optional<JS::NonnullGCPtr<PendingResponse>>> http_redirect_f
: static_cast<Infrastructure::FilteredResponse const&>(response).internal_response();
// 3. Let locationURL be actualResponses location URL given requests current URLs fragment.
auto const& fragment = request->current_url().fragment();
auto fragment_string = fragment.is_null() ? Optional<String> {} : TRY_OR_THROW_OOM(vm, String::from_deprecated_string(fragment));
auto location_url_or_error = actual_response->location_url(fragment_string);
auto location_url_or_error = actual_response->location_url(request->current_url().fragment());
// 4. If locationURL is null, then return response.
if (!location_url_or_error.is_error() && !location_url_or_error.value().has_value())

View File

@ -118,8 +118,8 @@ ErrorOr<Optional<AK::URL>> Response::location_url(Optional<String> const& reques
return Error::from_string_view("Invalid 'Location' header URL"sv);
// 4. If location is a URL whose fragment is null, then set locations fragment to requestFragment.
if (location.fragment().is_null())
location.set_fragment(request_fragment.has_value() ? request_fragment->to_deprecated_string() : DeprecatedString {});
if (!location.fragment().has_value())
location.set_fragment(request_fragment);
// 5. Return location.
return location;

View File

@ -1167,7 +1167,7 @@ WebIDL::ExceptionOr<void> BrowsingContext::navigate(
// and resource's URL's fragment is non-null, then:
if (history_handling != HistoryHandlingBehavior::Reload
&& resource->url().equals(active_document()->url(), AK::URL::ExcludeFragment::Yes)
&& !resource->url().fragment().is_null()) {
&& resource->url().fragment().has_value()) {
// 1. Navigate to a fragment given browsingContext, resource's URL, historyHandling, and navigationId.
TRY(navigate_to_a_fragment(resource->url(), history_handling, *navigation_id));
@ -1406,7 +1406,7 @@ WebIDL::ExceptionOr<void> BrowsingContext::traverse_the_history(size_t entry_ind
}
// 10. If entry's persisted user state is null, and its URL's fragment is non-null, then scroll to the fragment.
if (!entry->url.fragment().is_null())
if (entry->url.fragment().has_value())
active_document()->scroll_to_the_fragment();
// 11. Set the current entry to entry.

View File

@ -378,11 +378,11 @@ DeprecatedString HTMLHyperlinkElementUtils::hash() const
// 2. Let url be this element's url.
// 3. If url is null, or url's fragment is either null or the empty string, return the empty string.
if (!m_url.has_value() || m_url->fragment().is_null() || m_url->fragment().is_empty())
if (!m_url.has_value() || !m_url->fragment().has_value() || m_url->fragment()->is_empty())
return DeprecatedString::empty();
// 4. Return "#", followed by url's fragment.
return DeprecatedString::formatted("#{}", m_url->fragment());
return DeprecatedString::formatted("#{}", *m_url->fragment());
}
void HTMLHyperlinkElementUtils::set_hash(DeprecatedString hash)
@ -406,7 +406,7 @@ void HTMLHyperlinkElementUtils::set_hash(DeprecatedString hash)
// 2. Set url's fragment to the empty string.
auto url_copy = m_url; // We copy the URL here to follow other browser's behavior of reverting the hash change if the parse failed.
url_copy->set_fragment(DeprecatedString::empty());
url_copy->set_fragment(String {});
// 3. Basic URL parse input, with url as url and fragment state as state override.
auto result_url = URLParser::basic_parse(input, {}, move(url_copy), URLParser::State::Fragment);

View File

@ -279,11 +279,11 @@ WebIDL::ExceptionOr<String> Location::hash() const
auto url = this->url();
// 2. If this's url's fragment is either null or the empty string, return the empty string.
if (url.fragment().is_empty())
if (!url.fragment().has_value() || url.fragment()->is_empty())
return String {};
// 3. Return "#", followed by this's url's fragment.
return TRY_OR_THROW_OOM(vm, String::formatted("#{}", url.fragment()));
return TRY_OR_THROW_OOM(vm, String::formatted("#{}", *url.fragment()));
}
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-location-hash
@ -307,7 +307,7 @@ WebIDL::ExceptionOr<void> Location::set_hash(String const& value)
auto input = value.bytes_as_string_view().trim("#"sv, TrimMode::Left);
// 5. Set copyURL's fragment to the empty string.
copy_url.set_fragment(""sv);
copy_url.set_fragment(String {});
// 6. Basic URL parse input, with copyURL as url and fragment state as state override.
auto result_url = URLParser::basic_parse(input, {}, copy_url, URLParser::State::Fragment);

View File

@ -543,9 +543,7 @@ static WebIDL::ExceptionOr<Optional<NavigationParams>> create_navigation_params_
response_origin = determine_the_origin(*response->url(), final_sandbox_flags, entry->document_state->initiator_origin(), {});
// 14. Set locationURL to response's location URL given currentURL's fragment.
auto const& fragment = current_url.fragment();
auto fragment_string = fragment.is_null() ? Optional<String> {} : TRY_OR_THROW_OOM(vm, String::from_deprecated_string(fragment));
auto location_url = response->location_url(fragment_string);
auto location_url = response->location_url(current_url.fragment());
VERIFY(!location_url.is_error());
@ -844,7 +842,7 @@ WebIDL::ExceptionOr<void> Navigable::navigate(
if (document_resource.has<Empty>()
&& !response
&& url.equals(active_session_history_entry()->url, AK::URL::ExcludeFragment::Yes)
&& !url.fragment().is_null()) {
&& url.fragment().has_value()) {
// 1. Navigate to a fragment given navigable, url, historyHandling, and navigationId.
TRY(navigate_to_a_fragment(url, history_handling, navigation_id));

View File

@ -123,11 +123,11 @@ WebIDL::ExceptionOr<String> WorkerLocation::hash() const
auto const& fragment = m_global_scope->url().fragment();
// 2. If fragment is either null or the empty string, return the empty string.
if (fragment.is_empty())
if (!fragment.has_value() || fragment->is_empty())
return String {};
// 3. Return "#", followed by fragment.
return TRY_OR_THROW_OOM(vm, String::formatted("#{}", fragment.view()));
return TRY_OR_THROW_OOM(vm, String::formatted("#{}", *fragment));
}
WorkerLocation::WorkerLocation(WorkerGlobalScope& global_scope)

View File

@ -302,8 +302,8 @@ void FrameLoader::resource_did_load()
return;
}
if (!url.fragment().is_empty())
browsing_context().scroll_to_anchor(url.fragment());
if (url.fragment().has_value() && !url.fragment()->is_empty())
browsing_context().scroll_to_anchor(url.fragment()->to_deprecated_string());
else
browsing_context().scroll_to({ 0, 0 });

View File

@ -284,8 +284,8 @@ bool EventHandler::handle_mouseup(CSSPixelPoint position, unsigned button, unsig
if (button == GUI::MouseButton::Primary) {
if (href.starts_with("javascript:"sv)) {
document->navigate_to_javascript_url(href);
} else if (!url.fragment().is_null() && url.equals(document->url(), AK::URL::ExcludeFragment::Yes)) {
m_browsing_context->scroll_to_anchor(url.fragment());
} else if (url.fragment().has_value() && url.equals(document->url(), AK::URL::ExcludeFragment::Yes)) {
m_browsing_context->scroll_to_anchor(url.fragment()->to_deprecated_string());
} else {
if (m_browsing_context->is_top_level()) {
if (auto* page = m_browsing_context->page())

View File

@ -87,9 +87,9 @@ JS::GCPtr<SVGGradientElement const> SVGGradientElement::linked_gradient() const
if (auto href = link; !href.is_empty()) {
auto url = document().parse_url(href);
auto id = url.fragment();
if (id.is_empty())
if (!id.has_value() || id->is_empty())
return {};
auto element = document().get_element_by_id(id);
auto element = document().get_element_by_id(id->to_deprecated_string());
if (!element)
return {};
if (!is<SVGGradientElement>(*element))

View File

@ -46,8 +46,10 @@ Optional<Gfx::PaintStyle const&> SVGGraphicsElement::svg_paint_computed_value_to
// FIXME: This entire function is an ad-hoc hack:
if (!paint_value.has_value() || !paint_value->is_url())
return {};
auto& url = paint_value->as_url();
auto gradient = document().get_element_by_id(url.fragment());
auto const& url = paint_value->as_url();
if (!url.fragment().has_value())
return {};
auto gradient = document().get_element_by_id(url.fragment()->to_deprecated_string());
if (!gradient)
return {};
if (is<SVG::SVGGradientElement>(*gradient))

View File

@ -442,7 +442,7 @@ WebIDL::ExceptionOr<String> URL::hash() const
auto& vm = realm().vm();
// 1. If thiss URLs fragment is either null or the empty string, then return the empty string.
if (m_url.fragment().is_null() || m_url.fragment().is_empty())
if (!m_url.fragment().has_value() || m_url.fragment()->is_empty())
return String {};
// 2. Return U+0023 (#), followed by thiss URLs fragment.
@ -469,7 +469,7 @@ void URL::set_hash(String const& hash)
// 3. Set thiss URLs fragment to the empty string.
auto url = m_url; // We copy the URL here to follow other browser's behavior of reverting the hash change if the parse failed.
url.set_fragment(DeprecatedString::empty());
url.set_fragment(String {});
// 4. Basic URL parse input with thiss URL as url and fragment state as state override.
auto result_url = URLParser::basic_parse(input, {}, move(url), URLParser::State::Fragment);

View File

@ -79,7 +79,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<WebSocket>> WebSocket::construct_impl(JS::R
return WebIDL::SyntaxError::create(realm, "Invalid protocol"sv);
// 7. If urlRecords fragment is non-null, then throw a "SyntaxError" DOMException.
if (!url_record.fragment().is_empty())
if (url_record.fragment().has_value())
return WebIDL::SyntaxError::create(realm, "Presence of URL fragment is invalid"sv);
Vector<String> protocols_sequence;

View File

@ -357,12 +357,12 @@ bool Launcher::open_file_url(const URL& url)
if (S_ISDIR(st.st_mode)) {
Vector<DeprecatedString> fm_arguments;
if (url.fragment().is_empty()) {
if (!url.fragment().has_value() || url.fragment()->is_empty()) {
fm_arguments.append(file_path);
} else {
fm_arguments.append("-s");
fm_arguments.append("-r");
fm_arguments.append(DeprecatedString::formatted("{}/{}", file_path, url.fragment()));
fm_arguments.append(DeprecatedString::formatted("{}/{}", file_path, *url.fragment()));
}
auto handler_optional = m_file_handlers.get("directory");