1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 19:37:36 +00:00

LibWeb: Port URL and URLSearchParams to new String

This commit is contained in:
Kenneth Myhra 2023-03-01 20:10:01 +01:00 committed by Linus Groh
parent 843c9d6cd7
commit 9da09e4fd3
12 changed files with 229 additions and 157 deletions

View file

@ -32,7 +32,7 @@ HTMLButtonElement::HTMLButtonElement(DOM::Document& document, DOM::QualifiedName
case TypeAttributeState::Submit:
// Submit Button
// Submit element's form owner from element.
form()->submit_form(this);
form()->submit_form(this).release_value_but_fixme_should_propagate_errors();
break;
case TypeAttributeState::Reset:
// Reset Button

View file

@ -47,21 +47,21 @@ void HTMLFormElement::visit_edges(Cell::Visitor& visitor)
visitor.visit(element.ptr());
}
void HTMLFormElement::submit_form(JS::GCPtr<HTMLElement> submitter, bool from_submit_binding)
ErrorOr<void> HTMLFormElement::submit_form(JS::GCPtr<HTMLElement> submitter, bool from_submit_binding)
{
if (cannot_navigate())
return;
return {};
if (action().is_null()) {
dbgln("Unsupported form action ''");
return;
return {};
}
auto effective_method = method().to_lowercase();
if (effective_method == "dialog") {
dbgln("Failed to submit form: Unsupported form method '{}'", method());
return;
return {};
}
if (effective_method != "get" && effective_method != "post") {
@ -70,7 +70,7 @@ void HTMLFormElement::submit_form(JS::GCPtr<HTMLElement> submitter, bool from_su
if (!from_submit_binding) {
if (m_firing_submission_events)
return;
return {};
m_firing_submission_events = true;
@ -91,51 +91,56 @@ void HTMLFormElement::submit_form(JS::GCPtr<HTMLElement> submitter, bool from_su
m_firing_submission_events = false;
if (!continue_)
return;
return {};
// This is checked again because arbitrary JS may have run when handling submit,
// which may have changed the result.
if (cannot_navigate())
return;
return {};
}
AK::URL url(document().parse_url(action()));
if (!url.is_valid()) {
dbgln("Failed to submit form: Invalid URL: {}", action());
return;
return {};
}
if (url.scheme() == "file") {
if (document().url().scheme() != "file") {
dbgln("Failed to submit form: Security violation: {} may not submit to {}", document().url(), url);
return;
return {};
}
if (effective_method != "get") {
dbgln("Failed to submit form: Unsupported form method '{}' for URL: {}", method(), url);
return;
return {};
}
} else if (url.scheme() != "http" && url.scheme() != "https") {
dbgln("Failed to submit form: Unsupported protocol for URL: {}", url);
return;
return {};
}
Vector<URL::QueryParam> parameters;
for_each_in_inclusive_subtree_of_type<HTMLInputElement>([&](auto& input) {
if (!input.name().is_null() && (input.type() != "submit" || &input == submitter))
parameters.append({ input.name(), input.value() });
if (!input.name().is_null() && (input.type() != "submit" || &input == submitter)) {
auto name = String::from_deprecated_string(input.name()).release_value_but_fixme_should_propagate_errors();
auto value = String::from_deprecated_string(input.value()).release_value_but_fixme_should_propagate_errors();
parameters.append({ move(name), move(value) });
}
return IterationDecision::Continue;
});
if (effective_method == "get") {
url.set_query(url_encode(parameters, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
auto url_encoded_parameters = TRY(url_encode(parameters, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded)).to_deprecated_string();
url.set_query(move(url_encoded_parameters));
}
LoadRequest request = LoadRequest::create_for_url_on_page(url, document().page());
if (effective_method == "post") {
auto body = url_encode(parameters, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded).to_byte_buffer();
auto url_encoded_parameters_as_bytes = TRY(url_encode(parameters, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded)).bytes();
auto body = TRY(ByteBuffer::copy(url_encoded_parameters_as_bytes));
request.set_method("POST");
request.set_header("Content-Type", "application/x-www-form-urlencoded");
request.set_body(move(body));
@ -143,6 +148,8 @@ void HTMLFormElement::submit_form(JS::GCPtr<HTMLElement> submitter, bool from_su
if (auto* page = document().page())
page->load(request);
return {};
}
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#resetting-a-form
@ -166,9 +173,12 @@ void HTMLFormElement::reset_form()
}
}
void HTMLFormElement::submit()
WebIDL::ExceptionOr<void> HTMLFormElement::submit()
{
submit_form(this, true);
auto& vm = realm().vm();
TRY_OR_THROW_OOM(vm, submit_form(this, true));
return {};
}
// https://html.spec.whatwg.org/multipage/forms.html#dom-form-reset

View file

@ -22,12 +22,12 @@ public:
DeprecatedString action() const;
DeprecatedString method() const { return attribute(HTML::AttributeNames::method); }
void submit_form(JS::GCPtr<HTMLElement> submitter, bool from_submit_binding = false);
ErrorOr<void> submit_form(JS::GCPtr<HTMLElement> submitter, bool from_submit_binding = false);
void reset_form();
// NOTE: This is for the JS bindings. Use submit_form instead.
void submit();
WebIDL::ExceptionOr<void> submit();
// NOTE: This is for the JS bindings. Use submit_form instead.
void reset();

View file

@ -35,7 +35,7 @@ HTMLInputElement::HTMLInputElement(DOM::Document& document, DOM::QualifiedName q
// FIXME: 1. If this element is not mutable and is not in the Checkbox state and is not in the Radio state, then return.
// 2. Run this element's input activation behavior, if any, and do nothing otherwise.
run_input_activation_behavior();
run_input_activation_behavior().release_value_but_fixme_should_propagate_errors();
};
}
@ -217,12 +217,12 @@ WebIDL::ExceptionOr<void> HTMLInputElement::show_picker()
}
// https://html.spec.whatwg.org/multipage/input.html#input-activation-behavior
void HTMLInputElement::run_input_activation_behavior()
ErrorOr<void> HTMLInputElement::run_input_activation_behavior()
{
if (type_state() == TypeAttributeState::Checkbox || type_state() == TypeAttributeState::RadioButton) {
// 1. If the element is not connected, then return.
if (!is_connected())
return;
return {};
// 2. Fire an event named input at the element with the bubbles and composed attributes initialized to true.
auto input_event = DOM::Event::create(realm(), HTML::EventNames::input).release_value_but_fixme_should_propagate_errors();
@ -238,19 +238,21 @@ void HTMLInputElement::run_input_activation_behavior()
JS::GCPtr<HTMLFormElement> form;
// 1. If the element does not have a form owner, then return.
if (!(form = this->form()))
return;
return {};
// 2. If the element's node document is not fully active, then return.
if (!document().is_fully_active())
return;
return {};
// 3. Submit the form owner from the element.
form->submit_form(this);
TRY(form->submit_form(this));
} else if (type_state() == TypeAttributeState::FileUpload) {
show_the_picker_if_applicable(*this);
} else {
dispatch_event(DOM::Event::create(realm(), EventNames::change).release_value_but_fixme_should_propagate_errors());
}
return {};
}
void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)

View file

@ -139,7 +139,7 @@ private:
static TypeAttributeState parse_type_attribute(StringView);
void create_shadow_tree_if_needed();
void run_input_activation_behavior();
ErrorOr<void> run_input_activation_behavior();
void set_checked_within_group();
// https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm