From 22a7cd9700be7f1043fb99059912420a5706f3fe Mon Sep 17 00:00:00 2001 From: Shannon Booth Date: Thu, 23 Jan 2025 19:40:57 +1300 Subject: [PATCH] LibWeb: Port Document encoding_parse_url and parse_url to Optional This ports two more APIs away from URL::is_valid. --- Libraries/LibWeb/CSS/SelectorEngine.cpp | 13 ++++++--- Libraries/LibWeb/CSS/StyleComputer.cpp | 2 +- Libraries/LibWeb/DOM/Document.cpp | 16 +++++----- Libraries/LibWeb/DOM/Document.h | 4 +-- Libraries/LibWeb/HTML/HTMLBodyElement.cpp | 13 +++++---- Libraries/LibWeb/HTML/HTMLFormElement.cpp | 18 ++++++------ .../LibWeb/HTML/HTMLHyperlinkElementUtils.cpp | 4 +-- Libraries/LibWeb/HTML/HTMLImageElement.cpp | 22 +++++++------- Libraries/LibWeb/HTML/HTMLInputElement.cpp | 4 +-- Libraries/LibWeb/HTML/HTMLLinkElement.cpp | 27 ++++++++++------- Libraries/LibWeb/HTML/HTMLMediaElement.cpp | 14 ++++----- Libraries/LibWeb/HTML/HTMLObjectElement.cpp | 20 +++++++++---- Libraries/LibWeb/HTML/HTMLScriptElement.cpp | 8 ++--- .../LibWeb/HTML/HTMLTableCellElement.cpp | 4 +-- Libraries/LibWeb/HTML/HTMLTableElement.cpp | 4 +-- Libraries/LibWeb/HTML/HTMLTableRowElement.cpp | 4 +-- .../LibWeb/HTML/HTMLTableSectionElement.cpp | 4 +-- Libraries/LibWeb/HTML/HTMLVideoElement.cpp | 4 +-- Libraries/LibWeb/HTML/NavigableContainer.cpp | 4 +-- Libraries/LibWeb/HTML/Window.cpp | 2 +- Libraries/LibWeb/Page/EventHandler.cpp | 29 ++++++++++--------- Libraries/LibWeb/SVG/SVGGradientElement.cpp | 4 ++- Libraries/LibWeb/SVG/SVGImageElement.cpp | 5 ++-- Libraries/LibWeb/SVG/SVGImageElement.h | 2 +- Libraries/LibWeb/SVG/SVGScriptElement.cpp | 5 ++-- Services/WebContent/ConnectionFromClient.cpp | 6 ++-- 26 files changed, 135 insertions(+), 107 deletions(-) diff --git a/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Libraries/LibWeb/CSS/SelectorEngine.cpp index 1998df0e738..4d891894a82 100644 --- a/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -466,10 +466,15 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla if (!matches_link_pseudo_class(element)) return false; auto document_url = element.document().url(); - URL::URL target_url = element.document().encoding_parse_url(element.attribute(HTML::AttributeNames::href).value_or({})); - if (target_url.fragment().has_value()) - return document_url.equals(target_url, URL::ExcludeFragment::No); - return document_url.equals(target_url, URL::ExcludeFragment::Yes); + auto maybe_href = element.attribute(HTML::AttributeNames::href); + if (!maybe_href.has_value()) + return false; + auto target_url = element.document().encoding_parse_url(*maybe_href); + if (!target_url.has_value()) + return false; + if (target_url->fragment().has_value()) + return document_url.equals(*target_url, URL::ExcludeFragment::No); + return document_url.equals(*target_url, URL::ExcludeFragment::Yes); } case CSS::PseudoClass::Visited: // FIXME: Maybe match this selector sometimes? diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index 6ff9054a417..7fa6fe2c23b 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -2923,7 +2923,7 @@ Optional StyleComputer::load_font_face(ParsedFontFace const& font_f for (auto const& source : font_face.sources()) { // FIXME: These should be loaded relative to the stylesheet URL instead of the document URL. if (source.local_or_url.has()) - urls.append(m_document->encoding_parse_url(source.local_or_url.get().to_string())); + urls.append(*m_document->encoding_parse_url(source.local_or_url.get().to_string())); // FIXME: Handle local() } diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 4e8c8e4e738..ec1307337b7 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1122,17 +1122,17 @@ URL::URL Document::base_url() const } // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#parse-a-url -URL::URL Document::parse_url(StringView url) const +Optional Document::parse_url(StringView url) const { // 1. Let baseURL be environment's base URL, if environment is a Document object; otherwise environment's API base URL. auto base_url = this->base_url(); // 2. Return the result of applying the URL parser to url, with baseURL. - return DOMURL::parse(url, base_url).value_or(URL::URL {}); + return DOMURL::parse(url, base_url); } // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#encoding-parsing-a-url -URL::URL Document::encoding_parse_url(StringView url) const +Optional Document::encoding_parse_url(StringView url) const { // 1. Let encoding be UTF-8. // 2. If environment is a Document object, then set encoding to environment's character encoding. @@ -1145,7 +1145,7 @@ URL::URL Document::encoding_parse_url(StringView url) const auto base_url = this->base_url(); // 5. Return the result of applying the URL parser to url, with baseURL and encoding. - return DOMURL::parse(url, base_url, encoding).value_or(URL::URL {}); + return DOMURL::parse(url, base_url, encoding); } // https://html.spec.whatwg.org/multipage/urls-and-fetching.html#encoding-parsing-and-serializing-a-url @@ -1155,11 +1155,11 @@ Optional Document::encoding_parse_and_serialize_url(StringView url) cons auto parsed_url = encoding_parse_url(url); // 2. If url is failure, then return failure. - if (!parsed_url.is_valid()) + if (!parsed_url.has_value()) return {}; // 3. Return the result of applying the URL serializer to url. - return parsed_url.serialize(); + return parsed_url->serialize(); } void Document::set_needs_layout() @@ -4752,10 +4752,10 @@ void Document::shared_declarative_refresh_steps(StringView input, GC::Ptr parse_url(StringView) const; + Optional encoding_parse_url(StringView) const; Optional encoding_parse_and_serialize_url(StringView) const; CSS::StyleComputer& style_computer() { return *m_style_computer; } diff --git a/Libraries/LibWeb/HTML/HTMLBodyElement.cpp b/Libraries/LibWeb/HTML/HTMLBodyElement.cpp index e490a5afb02..4f8bac83c43 100644 --- a/Libraries/LibWeb/HTML/HTMLBodyElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLBodyElement.cpp @@ -125,12 +125,13 @@ void HTMLBodyElement::attribute_changed(FlyString const& name, Optional document().set_visited_link_color(color.value()); } else if (name.equals_ignoring_ascii_case("background"sv)) { // https://html.spec.whatwg.org/multipage/rendering.html#the-page:attr-background - m_background_style_value = CSS::ImageStyleValue::create(document().encoding_parse_url(value.value_or(String {}))); - m_background_style_value->on_animate = [this] { - if (paintable()) { - paintable()->set_needs_display(); - } - }; + if (auto maybe_background_url = document().encoding_parse_url(value.value_or(String {})); maybe_background_url.has_value()) { + m_background_style_value = CSS::ImageStyleValue::create(maybe_background_url.value()); + m_background_style_value->on_animate = [this] { + if (paintable()) + paintable()->set_needs_display(); + }; + } } #undef __ENUMERATE diff --git a/Libraries/LibWeb/HTML/HTMLFormElement.cpp b/Libraries/LibWeb/HTML/HTMLFormElement.cpp index 389cebedf49..78db49abf13 100644 --- a/Libraries/LibWeb/HTML/HTMLFormElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLFormElement.cpp @@ -223,13 +223,13 @@ WebIDL::ExceptionOr HTMLFormElement::submit_form(GC::Ref subm // 14. Parse a URL given action, relative to the submitter element's node document. If this fails, return. // 15. Let parsed action be the resulting URL record. auto parsed_action = submitter->document().parse_url(action); - if (!parsed_action.is_valid()) { + if (!parsed_action.has_value()) { dbgln("Failed to submit form: Invalid URL: {}", action); return {}; } // 16. Let scheme be the scheme of parsed action. - auto const& scheme = parsed_action.scheme(); + auto const& scheme = parsed_action->scheme(); // 17. Let enctype be the submitter element's enctype. auto encoding_type = encoding_type_state_from_form_element(submitter); @@ -282,21 +282,21 @@ WebIDL::ExceptionOr HTMLFormElement::submit_form(GC::Ref subm if (scheme.is_one_of("http"sv, "https"sv)) { if (method == MethodAttributeState::GET) - TRY_OR_THROW_OOM(vm, mutate_action_url(move(parsed_action), move(entry_list), move(encoding), *target_navigable, history_handling, options.user_involvement)); + TRY_OR_THROW_OOM(vm, mutate_action_url(parsed_action.release_value(), move(entry_list), move(encoding), *target_navigable, history_handling, options.user_involvement)); else - TRY_OR_THROW_OOM(vm, submit_as_entity_body(move(parsed_action), move(entry_list), encoding_type, move(encoding), *target_navigable, history_handling, options.user_involvement)); + TRY_OR_THROW_OOM(vm, submit_as_entity_body(parsed_action.release_value(), move(entry_list), encoding_type, move(encoding), *target_navigable, history_handling, options.user_involvement)); } else if (scheme.is_one_of("ftp"sv, "javascript"sv)) { - get_action_url(move(parsed_action), *target_navigable, history_handling, options.user_involvement); + get_action_url(parsed_action.release_value(), *target_navigable, history_handling, options.user_involvement); } else if (scheme.is_one_of("data"sv, "file"sv)) { if (method == MethodAttributeState::GET) - TRY_OR_THROW_OOM(vm, mutate_action_url(move(parsed_action), move(entry_list), move(encoding), *target_navigable, history_handling, options.user_involvement)); + TRY_OR_THROW_OOM(vm, mutate_action_url(parsed_action.release_value(), move(entry_list), move(encoding), *target_navigable, history_handling, options.user_involvement)); else - get_action_url(move(parsed_action), *target_navigable, history_handling, options.user_involvement); + get_action_url(parsed_action.release_value(), *target_navigable, history_handling, options.user_involvement); } else if (scheme == "mailto"sv) { if (method == MethodAttributeState::GET) - TRY_OR_THROW_OOM(vm, mail_with_headers(move(parsed_action), move(entry_list), move(encoding), *target_navigable, history_handling, options.user_involvement)); + TRY_OR_THROW_OOM(vm, mail_with_headers(parsed_action.release_value(), move(entry_list), move(encoding), *target_navigable, history_handling, options.user_involvement)); else - TRY_OR_THROW_OOM(vm, mail_as_body(move(parsed_action), move(entry_list), encoding_type, move(encoding), *target_navigable, history_handling, options.user_involvement)); + TRY_OR_THROW_OOM(vm, mail_as_body(parsed_action.release_value(), move(entry_list), encoding_type, move(encoding), *target_navigable, history_handling, options.user_involvement)); } else { dbgln("Failed to submit form: Unknown scheme: {}", scheme); return {}; diff --git a/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp b/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp index 3b9905ac5ea..62e41e47f91 100644 --- a/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp +++ b/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp @@ -47,8 +47,8 @@ void HTMLHyperlinkElementUtils::set_the_url() auto url = hyperlink_element_utils_document().encoding_parse_url(*href_content_attribute); // 4. If url is not failure, then set this element's url to url. - if (url.is_valid()) - m_url = move(url); + if (url.has_value()) + m_url = url.release_value(); } // https://html.spec.whatwg.org/multipage/links.html#dom-hyperlink-origin diff --git a/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Libraries/LibWeb/HTML/HTMLImageElement.cpp index e265630f4a8..406ef67749b 100644 --- a/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -522,13 +522,13 @@ ErrorOr HTMLImageElement::update_the_image_data(bool restart_animations, b // If that is not successful, then abort this inner set of steps. // Otherwise, let urlString be the resulting URL string. auto url_string = document().parse_url(selected_source.value()); - if (!url_string.is_valid()) + if (!url_string.has_value()) goto after_step_7; // 2. Let key be a tuple consisting of urlString, the img element's crossorigin attribute's mode, // and, if that mode is not No CORS, the node document's origin. ListOfAvailableImages::Key key; - key.url = url_string; + key.url = url_string.value(); key.mode = m_cors_setting; key.origin = document().origin(); @@ -564,7 +564,7 @@ ErrorOr HTMLImageElement::update_the_image_data(bool restart_animations, b restart_the_animation(); // 2. Set current request's current URL to urlString. - m_current_request->set_current_url(realm(), url_string); + m_current_request->set_current_url(realm(), *url_string); // 3. If maybe omit events is not set or previousURL is not equal to urlString, then fire an event named load at the img element. if (!maybe_omit_events || previous_url != url_string) @@ -622,7 +622,7 @@ after_step_7: // 12. Parse selected source, relative to the element's node document, and let urlString be the resulting URL string. auto url_string = document().parse_url(selected_source.value().url.to_byte_string()); // If that is not successful, then: - if (!url_string.is_valid()) { + if (!url_string.has_value()) { // 1. Abort the image request for the current request and the pending request. abort_the_image_request(realm(), m_current_request); abort_the_image_request(realm(), m_pending_request); @@ -673,7 +673,7 @@ after_step_7: // 16. Set image request to a new image request whose current URL is urlString. auto image_request = ImageRequest::create(realm(), document().page()); - image_request->set_current_url(realm(), url_string); + image_request->set_current_url(realm(), *url_string); // 17. If current request's state is unavailable or broken, then set the current request to image request. // Otherwise, set the pending request to image request. @@ -690,7 +690,7 @@ after_step_7: if (delay_load_event) m_load_event_delayer.emplace(document()); - add_callbacks_to_image_request(*image_request, maybe_omit_events, url_string, previous_url); + add_callbacks_to_image_request(*image_request, maybe_omit_events, *url_string, previous_url); // AD-HOC: If the image request is already available or fetching, no need to start another fetch. if (image_request->is_available() || image_request->is_fetching()) @@ -698,7 +698,7 @@ after_step_7: // 18. Let request be the result of creating a potential-CORS request given urlString, "image", // and the current state of the element's crossorigin content attribute. - auto request = create_potential_CORS_request(vm(), url_string, Fetch::Infrastructure::Request::Destination::Image, m_cors_setting); + auto request = create_potential_CORS_request(vm(), *url_string, Fetch::Infrastructure::Request::Destination::Image, m_cors_setting); // 19. Set request's client to the element's node document's relevant settings object. request->set_client(&document().relevant_settings_object()); @@ -848,7 +848,7 @@ void HTMLImageElement::react_to_changes_in_the_environment() // 6. ⌛ Parse selected source, relative to the element's node document, // and let urlString be the resulting URL string. If that is not successful, then return. auto url_string = document().parse_url(selected_source.value()); - if (!url_string.is_valid()) + if (!url_string.has_value()) return; // 7. ⌛ Let corsAttributeState be the state of the element's crossorigin content attribute. @@ -862,14 +862,14 @@ void HTMLImageElement::react_to_changes_in_the_environment() // 10. ⌛ Let key be a tuple consisting of urlString, corsAttributeState, and, if corsAttributeState is not No CORS, origin. ListOfAvailableImages::Key key; - key.url = url_string; + key.url = *url_string; key.mode = m_cors_setting; if (cors_attribute_state != CORSSettingAttribute::NoCORS) key.origin = document().origin(); // 11. ⌛ Let image request be a new image request whose current URL is urlString auto image_request = ImageRequest::create(realm(), document().page()); - image_request->set_current_url(realm(), url_string); + image_request->set_current_url(realm(), *url_string); // 12. ⌛ Let the element's pending request be image request. m_pending_request = image_request; @@ -917,7 +917,7 @@ void HTMLImageElement::react_to_changes_in_the_environment() // Otherwise: else { // 1. Let request be the result of creating a potential-CORS request given urlString, "image", and corsAttributeState. - auto request = create_potential_CORS_request(vm(), url_string, Fetch::Infrastructure::Request::Destination::Image, m_cors_setting); + auto request = create_potential_CORS_request(vm(), *url_string, Fetch::Infrastructure::Request::Destination::Image, m_cors_setting); // 2. Set request's client to client, initiator to "imageset", and set request's synchronous flag. request->set_client(&client); diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 3c6456857bb..e4bfe296f1f 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -1385,14 +1385,14 @@ WebIDL::ExceptionOr HTMLInputElement::handle_src_attribute(String const& v auto url = document().encoding_parse_url(value); // 2. If url is failure, then return. - if (!url.is_valid()) + if (!url.has_value()) return {}; // 3. Let request be a new request whose URL is url, client is the element's node document's relevant settings // object, destination is "image", initiator type is "input", credentials mode is "include", and whose // use-URL-credentials flag is set. auto request = Fetch::Infrastructure::Request::create(vm); - request->set_url(move(url)); + request->set_url(url.release_value()); request->set_client(&document().relevant_settings_object()); request->set_destination(Fetch::Infrastructure::Request::Destination::Image); request->set_initiator_type(Fetch::Infrastructure::Request::InitiatorType::Input); diff --git a/Libraries/LibWeb/HTML/HTMLLinkElement.cpp b/Libraries/LibWeb/HTML/HTMLLinkElement.cpp index c9840ba6fc8..ae0826c1fcf 100644 --- a/Libraries/LibWeb/HTML/HTMLLinkElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLLinkElement.cpp @@ -77,18 +77,25 @@ void HTMLLinkElement::inserted() // FIXME: Follow spec for fetching and processing these attributes as well if (m_relationship & Relationship::Preload) { - // FIXME: Respect the "as" attribute. - LoadRequest request; - request.set_url(document().encoding_parse_url(get_attribute_value(HTML::AttributeNames::href))); - set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request)); + if (auto maybe_href = document().encoding_parse_url(get_attribute_value(HTML::AttributeNames::href)); maybe_href.has_value()) { + // FIXME: Respect the "as" attribute. + LoadRequest request; + request.set_url(maybe_href.value()); + set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, request)); + } } else if (m_relationship & Relationship::DNSPrefetch) { - ResourceLoader::the().prefetch_dns(document().encoding_parse_url(get_attribute_value(HTML::AttributeNames::href))); + if (auto dns_prefetch_url = document().encoding_parse_url(get_attribute_value(HTML::AttributeNames::href)); dns_prefetch_url.has_value()) { + ResourceLoader::the().prefetch_dns(dns_prefetch_url.value()); + } } else if (m_relationship & Relationship::Preconnect) { - ResourceLoader::the().preconnect(document().encoding_parse_url(get_attribute_value(HTML::AttributeNames::href))); + if (auto maybe_href = document().encoding_parse_url(get_attribute_value(HTML::AttributeNames::href)); maybe_href.has_value()) { + ResourceLoader::the().preconnect(maybe_href.value()); + } } else if (m_relationship & Relationship::Icon) { - auto favicon_url = document().encoding_parse_url(href()); - auto favicon_request = LoadRequest::create_for_url_on_page(favicon_url, &document().page()); - set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, favicon_request)); + if (auto favicon_url = document().encoding_parse_url(href()); favicon_url.has_value()) { + auto favicon_request = LoadRequest::create_for_url_on_page(favicon_url.value(), &document().page()); + set_resource(ResourceLoader::the().load_resource(Resource::Type::Generic, favicon_request)); + } } } @@ -572,7 +579,7 @@ WebIDL::ExceptionOr HTMLLinkElement::load_fallback_favicon_if_needed(GC::R // synchronous flag is set, credentials mode is "include", and whose use-URL-credentials flag is set. // NOTE: Fetch requests no longer have a synchronous flag, see https://github.com/whatwg/fetch/pull/1165 auto request = Fetch::Infrastructure::Request::create(vm); - request->set_url(document->parse_url("/favicon.ico"sv)); + request->set_url(*document->parse_url("/favicon.ico"sv)); request->set_client(&document->relevant_settings_object()); request->set_destination(Fetch::Infrastructure::Request::Destination::Image); request->set_credentials_mode(Fetch::Infrastructure::Request::CredentialsMode::Include); diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index badd035b165..20387f4d2e5 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -625,14 +625,14 @@ public: // would have resulted from parsing the URL specified by candidate's src attribute's value relative to the // candidate's node document when the src attribute was last changed. auto url_record = m_candidate->document().parse_url(candiate_src); - auto url_string = url_record.to_string(); // 4. ⌛ If urlString was not obtained successfully, then end the synchronous section, and jump down to the failed // with elements step below. - if (!url_record.is_valid()) { + if (!url_record.has_value()) { TRY(failed_with_elements()); return {}; } + auto url_string = url_record->to_string(); // FIXME: 5. ⌛ If candidate has a type attribute whose value, when parsed as a MIME type (including any codecs described // by the codecs parameter, for types that define that parameter), represents a type that the user agent knows @@ -645,7 +645,7 @@ public: // 8. Run the resource fetch algorithm with urlRecord. If that algorithm returns without aborting this one, then // the load failed. - TRY(m_media_element->fetch_resource(url_record, [this](auto) { + TRY(m_media_element->fetch_resource(*url_record, [this](auto) { failed_with_elements().release_value_but_fixme_should_propagate_errors(); })); @@ -871,15 +871,15 @@ WebIDL::ExceptionOr HTMLMediaElement::select_resource() auto url_record = document().parse_url(source); // 3. ⌛ If urlString was obtained successfully, set the currentSrc attribute to urlString. - if (url_record.is_valid()) - m_current_src = url_record.to_string(); + if (url_record.has_value()) + m_current_src = url_record->to_string(); // 4. End the synchronous section, continuing the remaining steps in parallel. // 5. If urlRecord was obtained successfully, run the resource fetch algorithm with urlRecord. If that algorithm returns without aborting this one, // then the load failed. - if (url_record.is_valid()) { - TRY(fetch_resource(url_record, move(failed_with_attribute))); + if (url_record.has_value()) { + TRY(fetch_resource(*url_record, move(failed_with_attribute))); return {}; } diff --git a/Libraries/LibWeb/HTML/HTMLObjectElement.cpp b/Libraries/LibWeb/HTML/HTMLObjectElement.cpp index 9d288232739..22c23f4e834 100644 --- a/Libraries/LibWeb/HTML/HTMLObjectElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLObjectElement.cpp @@ -169,7 +169,11 @@ String HTMLObjectElement::data() const if (!data.has_value()) return {}; - return document().encoding_parse_url(*data).to_string(); + auto maybe_url = document().encoding_parse_url(*data); + if (!maybe_url.has_value()) + return {}; + + return maybe_url->to_string(); } GC::Ptr HTMLObjectElement::create_layout_node(GC::Ref style) @@ -257,7 +261,7 @@ void HTMLObjectElement::queue_element_task_to_run_object_representation_steps() auto url = document().encoding_parse_url(*data); // 3. If url is failure, then fire an event named error at the element and jump to the step below labeled fallback. - if (!url.is_valid()) { + if (!url.has_value()) { dispatch_event(DOM::Event::create(realm, HTML::EventNames::error)); run_object_representation_fallback_steps(); return; @@ -267,7 +271,7 @@ void HTMLObjectElement::queue_element_task_to_run_object_representation_steps() // object, destination is "object", credentials mode is "include", mode is "navigate", initiator type is // "object", and whose use-URL-credentials flag is set. auto request = Fetch::Infrastructure::Request::create(vm); - request->set_url(move(url)); + request->set_url(url.release_value()); request->set_client(&document().relevant_settings_object()); request->set_destination(Fetch::Infrastructure::Request::Destination::Object); request->set_credentials_mode(Fetch::Infrastructure::Request::CredentialsMode::Include); @@ -512,7 +516,13 @@ void HTMLObjectElement::load_image() // FIXME: This currently reloads the image instead of reusing the resource we've already downloaded. auto data = get_attribute_value(HTML::AttributeNames::data); auto url = document().encoding_parse_url(data); - m_resource_request = HTML::SharedResourceRequest::get_or_create(realm(), document().page(), url); + + if (!url.has_value()) { + run_object_representation_fallback_steps(); + return; + } + + m_resource_request = HTML::SharedResourceRequest::get_or_create(realm(), document().page(), *url); m_resource_request->add_callbacks( [this] { run_object_representation_completed_steps(Representation::Image); @@ -522,7 +532,7 @@ void HTMLObjectElement::load_image() }); if (m_resource_request->needs_fetching()) { - auto request = HTML::create_potential_CORS_request(vm(), url, Fetch::Infrastructure::Request::Destination::Image, HTML::CORSSettingAttribute::NoCORS); + auto request = HTML::create_potential_CORS_request(vm(), *url, Fetch::Infrastructure::Request::Destination::Image, HTML::CORSSettingAttribute::NoCORS); request->set_client(&document().relevant_settings_object()); m_resource_request->fetch_resource(realm(), request); } diff --git a/Libraries/LibWeb/HTML/HTMLScriptElement.cpp b/Libraries/LibWeb/HTML/HTMLScriptElement.cpp index f442326d4a5..55b4d03f5d5 100644 --- a/Libraries/LibWeb/HTML/HTMLScriptElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLScriptElement.cpp @@ -385,7 +385,7 @@ void HTMLScriptElement::prepare_script() auto url = document().parse_url(src); // 6. If the previous step failed, then queue an element task on the DOM manipulation task source given el to fire an event named error at el, and return. Otherwise, let url be the resulting URL record. - if (!url.is_valid()) { + if (!url.has_value()) { dbgln("HTMLScriptElement: Refusing to run script because the src URL '{}' is invalid.", url); queue_an_element_task(HTML::Task::Source::DOMManipulation, [this] { dispatch_event(DOM::Event::create(realm(), HTML::EventNames::error)); @@ -413,16 +413,16 @@ void HTMLScriptElement::prepare_script() // -> "classic" if (m_script_type == ScriptType::Classic) { // Fetch a classic script given url, settings object, options, classic script CORS setting, encoding, and onComplete. - fetch_classic_script(*this, url, settings_object, move(options), classic_script_cors_setting, encoding.release_value(), on_complete).release_value_but_fixme_should_propagate_errors(); + fetch_classic_script(*this, *url, settings_object, move(options), classic_script_cors_setting, encoding.release_value(), on_complete).release_value_but_fixme_should_propagate_errors(); } // -> "module" else if (m_script_type == ScriptType::Module) { // If el does not have an integrity attribute, then set options's integrity metadata to the result of resolving a module integrity metadata with url and settings object. if (!has_attribute(HTML::AttributeNames::integrity)) - options.integrity_metadata = resolve_a_module_integrity_metadata(url, settings_object); + options.integrity_metadata = resolve_a_module_integrity_metadata(*url, settings_object); // Fetch an external module script graph given url, settings object, options, and onComplete. - fetch_external_module_script_graph(realm(), url, settings_object, options, on_complete); + fetch_external_module_script_graph(realm(), *url, settings_object, options, on_complete); } } diff --git a/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp b/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp index 4cf419f0f2e..c3e2c7f59c0 100644 --- a/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTableCellElement.cpp @@ -89,8 +89,8 @@ void HTMLTableCellElement::apply_presentational_hints(GC::Refset_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(parsed_value)); + if (auto parsed_value = document().encoding_parse_url(value); parsed_value.has_value()) + cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(*parsed_value)); return; } }); diff --git a/Libraries/LibWeb/HTML/HTMLTableElement.cpp b/Libraries/LibWeb/HTML/HTMLTableElement.cpp index 190f6bd1a8b..ba2b57b971f 100644 --- a/Libraries/LibWeb/HTML/HTMLTableElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTableElement.cpp @@ -91,8 +91,8 @@ void HTMLTableElement::apply_presentational_hints(GC::Refset_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(parsed_value)); + if (auto parsed_value = document().encoding_parse_url(value); parsed_value.has_value()) + cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(*parsed_value)); return; } if (name == HTML::AttributeNames::bgcolor) { diff --git a/Libraries/LibWeb/HTML/HTMLTableRowElement.cpp b/Libraries/LibWeb/HTML/HTMLTableRowElement.cpp index 6887e8e7e28..5bf2abfcac7 100644 --- a/Libraries/LibWeb/HTML/HTMLTableRowElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTableRowElement.cpp @@ -62,8 +62,8 @@ void HTMLTableRowElement::apply_presentational_hints(GC::Refset_property_from_presentational_hint(CSS::PropertyID::BackgroundColor, CSS::CSSColorValue::create_from_color(color.value())); } else if (name == HTML::AttributeNames::background) { // https://html.spec.whatwg.org/multipage/rendering.html#tables-2:encoding-parsing-and-serializing-a-url - if (auto parsed_value = document().encoding_parse_url(value); parsed_value.is_valid()) - cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(parsed_value)); + if (auto parsed_value = document().encoding_parse_url(value); parsed_value.has_value()) + cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(*parsed_value)); } else if (name == HTML::AttributeNames::height) { if (auto parsed_value = parse_dimension_value(value)) cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::Height, *parsed_value); diff --git a/Libraries/LibWeb/HTML/HTMLTableSectionElement.cpp b/Libraries/LibWeb/HTML/HTMLTableSectionElement.cpp index e92c94eb799..7db36930493 100644 --- a/Libraries/LibWeb/HTML/HTMLTableSectionElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTableSectionElement.cpp @@ -115,8 +115,8 @@ void HTMLTableSectionElement::apply_presentational_hints(GC::Refset_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(parsed_value)); + if (auto parsed_value = document().encoding_parse_url(value); parsed_value.has_value()) + cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::BackgroundImage, CSS::ImageStyleValue::create(*parsed_value)); } // https://html.spec.whatwg.org/multipage/rendering.html#tables-2:rules-for-parsing-a-legacy-colour-value else if (name == HTML::AttributeNames::bgcolor) { diff --git a/Libraries/LibWeb/HTML/HTMLVideoElement.cpp b/Libraries/LibWeb/HTML/HTMLVideoElement.cpp index b96f7e16ee2..4a31f6914da 100644 --- a/Libraries/LibWeb/HTML/HTMLVideoElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLVideoElement.cpp @@ -164,14 +164,14 @@ WebIDL::ExceptionOr HTMLVideoElement::determine_element_poster_frame(Optio // 3. Parse the poster attribute's value relative to the element's node document. If this fails, then there is no // poster frame; return. auto url_record = document().parse_url(*poster); - if (!url_record.is_valid()) + if (!url_record.has_value()) return {}; // 4. Let request be a new request whose URL is the resulting URL record, client is the element's node document's // relevant settings object, destination is "image", initiator type is "video", credentials mode is "include", // and whose use-URL-credentials flag is set. auto request = Fetch::Infrastructure::Request::create(vm); - request->set_url(move(url_record)); + request->set_url(url_record.release_value()); request->set_client(&document().relevant_settings_object()); request->set_destination(Fetch::Infrastructure::Request::Destination::Image); request->set_initiator_type(Fetch::Infrastructure::Request::InitiatorType::Video); diff --git a/Libraries/LibWeb/HTML/NavigableContainer.cpp b/Libraries/LibWeb/HTML/NavigableContainer.cpp index 4796e2b0f45..faa536bc2bc 100644 --- a/Libraries/LibWeb/HTML/NavigableContainer.cpp +++ b/Libraries/LibWeb/HTML/NavigableContainer.cpp @@ -208,8 +208,8 @@ Optional NavigableContainer::shared_attribute_processing_steps_for_ifr auto src_attribute_value = get_attribute_value(HTML::AttributeNames::src); if (!src_attribute_value.is_empty()) { auto parsed_src = document().parse_url(src_attribute_value); - if (parsed_src.is_valid()) - url = parsed_src; + if (parsed_src.has_value()) + url = parsed_src.release_value(); } // 3. If the inclusive ancestor navigables of element's node navigable contains a navigable diff --git a/Libraries/LibWeb/HTML/Window.cpp b/Libraries/LibWeb/HTML/Window.cpp index 06b718e2bf9..4b216266da7 100644 --- a/Libraries/LibWeb/HTML/Window.cpp +++ b/Libraries/LibWeb/HTML/Window.cpp @@ -202,7 +202,7 @@ WebIDL::ExceptionOr Window::window_open_steps_internal(Str url_record = source_document.encoding_parse_url(url); // 2. If urlRecord is failure, then throw a "SyntaxError" DOMException. - if (!url_record->is_valid()) + if (!url_record.has_value()) return WebIDL::SyntaxError::create(realm(), MUST(String::formatted("Invalid URL '{}'", url))); } diff --git a/Libraries/LibWeb/Page/EventHandler.cpp b/Libraries/LibWeb/Page/EventHandler.cpp index 182c864c1f0..d25f436e09c 100644 --- a/Libraries/LibWeb/Page/EventHandler.cpp +++ b/Libraries/LibWeb/Page/EventHandler.cpp @@ -497,28 +497,31 @@ EventResult EventHandler::handle_mouseup(CSSPixelPoint viewport_position, CSSPix GC::Ref document = *m_navigable->active_document(); auto href = link->href(); auto url = document->encoding_parse_url(href); - - if (button == UIEvents::MouseButton::Primary && (modifiers & UIEvents::Mod_PlatformCtrl) != 0) { - m_navigable->page().client().page_did_click_link(url, link->target().to_byte_string(), modifiers); - } else if (button == UIEvents::MouseButton::Middle) { - m_navigable->page().client().page_did_middle_click_link(url, link->target().to_byte_string(), modifiers); - } else if (button == UIEvents::MouseButton::Secondary) { - m_navigable->page().client().page_did_request_link_context_menu(top_level_viewport_position, url, link->target().to_byte_string(), modifiers); + if (url.has_value()) { + if (button == UIEvents::MouseButton::Primary && (modifiers & UIEvents::Mod_PlatformCtrl) != 0) { + m_navigable->page().client().page_did_click_link(*url, link->target().to_byte_string(), modifiers); + } else if (button == UIEvents::MouseButton::Middle) { + m_navigable->page().client().page_did_middle_click_link(*url, link->target().to_byte_string(), modifiers); + } else if (button == UIEvents::MouseButton::Secondary) { + m_navigable->page().client().page_did_request_link_context_menu(top_level_viewport_position, *url, link->target().to_byte_string(), modifiers); + } } } else if (button == UIEvents::MouseButton::Secondary) { if (is(*node)) { auto& image_element = as(*node); auto image_url = image_element.document().encoding_parse_url(image_element.src()); - Optional bitmap; - if (image_element.immutable_bitmap()) - bitmap = image_element.immutable_bitmap()->bitmap(); + if (image_url.has_value()) { + Optional bitmap; + if (image_element.immutable_bitmap()) + bitmap = image_element.immutable_bitmap()->bitmap(); - m_navigable->page().client().page_did_request_image_context_menu(top_level_viewport_position, image_url, "", modifiers, bitmap); + m_navigable->page().client().page_did_request_image_context_menu(top_level_viewport_position, *image_url, "", modifiers, bitmap); + } } else if (is(*node)) { auto& media_element = as(*node); Page::MediaContextMenu menu { - .media_url = media_element.document().encoding_parse_url(media_element.current_src()), + .media_url = *media_element.document().encoding_parse_url(media_element.current_src()), .is_video = is(*node), .is_playing = media_element.potentially_playing(), .is_muted = media_element.muted(), @@ -811,7 +814,7 @@ EventResult EventHandler::handle_mousemove(CSSPixelPoint viewport_position, CSSP if (is_hovering_link) { page.set_is_hovering_link(true); - page.client().page_did_hover_link(document.encoding_parse_url(hovered_link_element->href())); + page.client().page_did_hover_link(*document.encoding_parse_url(hovered_link_element->href())); } else if (page.is_hovering_link()) { page.set_is_hovering_link(false); page.client().page_did_unhover_link(); diff --git a/Libraries/LibWeb/SVG/SVGGradientElement.cpp b/Libraries/LibWeb/SVG/SVGGradientElement.cpp index c333f87c2e1..47a365ab26c 100644 --- a/Libraries/LibWeb/SVG/SVGGradientElement.cpp +++ b/Libraries/LibWeb/SVG/SVGGradientElement.cpp @@ -129,7 +129,9 @@ GC::Ptr SVGGradientElement::linked_gradient(HashTable< auto link = has_attribute(AttributeNames::href) ? get_attribute(AttributeNames::href) : get_attribute("xlink:href"_fly_string); if (auto href = link; href.has_value() && !link->is_empty()) { auto url = document().encoding_parse_url(*href); - auto id = url.fragment(); + if (!url.has_value()) + return {}; + auto id = url->fragment(); if (!id.has_value() || id->is_empty()) return {}; auto element = document().get_element_by_id(id.value()); diff --git a/Libraries/LibWeb/SVG/SVGImageElement.cpp b/Libraries/LibWeb/SVG/SVGImageElement.cpp index c13967b89cf..f7d9a8a2958 100644 --- a/Libraries/LibWeb/SVG/SVGImageElement.cpp +++ b/Libraries/LibWeb/SVG/SVGImageElement.cpp @@ -146,11 +146,10 @@ void SVGImageElement::process_the_url(Optional const& href) } m_href = document().parse_url(*href); - - if (!m_href.is_valid()) + if (!m_href.has_value()) return; - fetch_the_document(m_href); + fetch_the_document(*m_href); } // https://svgwg.org/svg2-draft/linking.html#processingURL-fetch diff --git a/Libraries/LibWeb/SVG/SVGImageElement.h b/Libraries/LibWeb/SVG/SVGImageElement.h index fd674d8a28d..b7b4a014e26 100644 --- a/Libraries/LibWeb/SVG/SVGImageElement.h +++ b/Libraries/LibWeb/SVG/SVGImageElement.h @@ -60,7 +60,7 @@ private: size_t m_current_frame_index { 0 }; size_t m_loops_completed { 0 }; - URL::URL m_href; + Optional m_href; GC::Ptr m_resource_request; Optional m_load_event_delayer; diff --git a/Libraries/LibWeb/SVG/SVGScriptElement.cpp b/Libraries/LibWeb/SVG/SVGScriptElement.cpp index 8b869140654..718de002a10 100644 --- a/Libraries/LibWeb/SVG/SVGScriptElement.cpp +++ b/Libraries/LibWeb/SVG/SVGScriptElement.cpp @@ -53,11 +53,12 @@ void SVGScriptElement::process_the_script_element() if (has_attribute(SVG::AttributeNames::href) || has_attribute_ns(Namespace::XLink.to_string(), SVG::AttributeNames::href)) { auto href_value = href()->base_val(); - script_url = document().parse_url(href_value); - if (!script_url.is_valid()) { + auto maybe_script_url = document().parse_url(href_value); + if (!maybe_script_url.has_value()) { dbgln("Invalid script URL: {}", href_value); return; } + script_url = maybe_script_url.release_value(); auto& vm = realm().vm(); auto request = Fetch::Infrastructure::Request::create(vm); diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index 325664aee16..3f71114e32e 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -433,14 +433,14 @@ void ConnectionFromClient::debug_request(u64 page_id, ByteString const& request, } else { auto link = maybe_link.release_value(); auto url = document->encoding_parse_url(link->get_attribute_value(Web::HTML::AttributeNames::href)); - if (url.query().has_value() && !url.query()->is_empty()) { + if (url->query().has_value() && !url->query()->is_empty()) { load_html(page_id, "

Invalid ref test link - query string must be empty

"); return; } if (has_mismatch_selector) - url.set_query("mismatch"_string); + url->set_query("mismatch"_string); - load_url(page_id, url); + load_url(page_id, *url); } } return;