mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 08:08:12 +00:00
LibWeb: Port URL and URLSearchParams to new String
This commit is contained in:
parent
843c9d6cd7
commit
9da09e4fd3
12 changed files with 229 additions and 157 deletions
|
@ -90,7 +90,8 @@ WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm& realm,
|
||||||
},
|
},
|
||||||
[&](JS::Handle<URL::URLSearchParams> const& url_search_params) -> WebIDL::ExceptionOr<void> {
|
[&](JS::Handle<URL::URLSearchParams> const& url_search_params) -> WebIDL::ExceptionOr<void> {
|
||||||
// Set source to the result of running the application/x-www-form-urlencoded serializer with object’s list.
|
// Set source to the result of running the application/x-www-form-urlencoded serializer with object’s list.
|
||||||
source = url_search_params->to_deprecated_string().to_byte_buffer();
|
auto search_params_bytes = TRY(url_search_params->to_string()).bytes();
|
||||||
|
source = TRY_OR_THROW_OOM(vm, ByteBuffer::copy(search_params_bytes));
|
||||||
// Set type to `application/x-www-form-urlencoded;charset=UTF-8`.
|
// Set type to `application/x-www-form-urlencoded;charset=UTF-8`.
|
||||||
type = TRY_OR_THROW_OOM(vm, ByteBuffer::copy("application/x-www-form-urlencoded;charset=UTF-8"sv.bytes()));
|
type = TRY_OR_THROW_OOM(vm, ByteBuffer::copy("application/x-www-form-urlencoded;charset=UTF-8"sv.bytes()));
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -32,7 +32,7 @@ HTMLButtonElement::HTMLButtonElement(DOM::Document& document, DOM::QualifiedName
|
||||||
case TypeAttributeState::Submit:
|
case TypeAttributeState::Submit:
|
||||||
// Submit Button
|
// Submit Button
|
||||||
// Submit element's form owner from element.
|
// Submit element's form owner from element.
|
||||||
form()->submit_form(this);
|
form()->submit_form(this).release_value_but_fixme_should_propagate_errors();
|
||||||
break;
|
break;
|
||||||
case TypeAttributeState::Reset:
|
case TypeAttributeState::Reset:
|
||||||
// Reset Button
|
// Reset Button
|
||||||
|
|
|
@ -47,21 +47,21 @@ void HTMLFormElement::visit_edges(Cell::Visitor& visitor)
|
||||||
visitor.visit(element.ptr());
|
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())
|
if (cannot_navigate())
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
if (action().is_null()) {
|
if (action().is_null()) {
|
||||||
dbgln("Unsupported form action ''");
|
dbgln("Unsupported form action ''");
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto effective_method = method().to_lowercase();
|
auto effective_method = method().to_lowercase();
|
||||||
|
|
||||||
if (effective_method == "dialog") {
|
if (effective_method == "dialog") {
|
||||||
dbgln("Failed to submit form: Unsupported form method '{}'", method());
|
dbgln("Failed to submit form: Unsupported form method '{}'", method());
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (effective_method != "get" && effective_method != "post") {
|
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 (!from_submit_binding) {
|
||||||
if (m_firing_submission_events)
|
if (m_firing_submission_events)
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
m_firing_submission_events = true;
|
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;
|
m_firing_submission_events = false;
|
||||||
|
|
||||||
if (!continue_)
|
if (!continue_)
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
// This is checked again because arbitrary JS may have run when handling submit,
|
// This is checked again because arbitrary JS may have run when handling submit,
|
||||||
// which may have changed the result.
|
// which may have changed the result.
|
||||||
if (cannot_navigate())
|
if (cannot_navigate())
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
AK::URL url(document().parse_url(action()));
|
AK::URL url(document().parse_url(action()));
|
||||||
|
|
||||||
if (!url.is_valid()) {
|
if (!url.is_valid()) {
|
||||||
dbgln("Failed to submit form: Invalid URL: {}", action());
|
dbgln("Failed to submit form: Invalid URL: {}", action());
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (url.scheme() == "file") {
|
if (url.scheme() == "file") {
|
||||||
if (document().url().scheme() != "file") {
|
if (document().url().scheme() != "file") {
|
||||||
dbgln("Failed to submit form: Security violation: {} may not submit to {}", document().url(), url);
|
dbgln("Failed to submit form: Security violation: {} may not submit to {}", document().url(), url);
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
if (effective_method != "get") {
|
if (effective_method != "get") {
|
||||||
dbgln("Failed to submit form: Unsupported form method '{}' for URL: {}", method(), url);
|
dbgln("Failed to submit form: Unsupported form method '{}' for URL: {}", method(), url);
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
} else if (url.scheme() != "http" && url.scheme() != "https") {
|
} else if (url.scheme() != "http" && url.scheme() != "https") {
|
||||||
dbgln("Failed to submit form: Unsupported protocol for URL: {}", url);
|
dbgln("Failed to submit form: Unsupported protocol for URL: {}", url);
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<URL::QueryParam> parameters;
|
Vector<URL::QueryParam> parameters;
|
||||||
|
|
||||||
for_each_in_inclusive_subtree_of_type<HTMLInputElement>([&](auto& input) {
|
for_each_in_inclusive_subtree_of_type<HTMLInputElement>([&](auto& input) {
|
||||||
if (!input.name().is_null() && (input.type() != "submit" || &input == submitter))
|
if (!input.name().is_null() && (input.type() != "submit" || &input == submitter)) {
|
||||||
parameters.append({ input.name(), input.value() });
|
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;
|
return IterationDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (effective_method == "get") {
|
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());
|
LoadRequest request = LoadRequest::create_for_url_on_page(url, document().page());
|
||||||
|
|
||||||
if (effective_method == "post") {
|
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_method("POST");
|
||||||
request.set_header("Content-Type", "application/x-www-form-urlencoded");
|
request.set_header("Content-Type", "application/x-www-form-urlencoded");
|
||||||
request.set_body(move(body));
|
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())
|
if (auto* page = document().page())
|
||||||
page->load(request);
|
page->load(request);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#resetting-a-form
|
// 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
|
// https://html.spec.whatwg.org/multipage/forms.html#dom-form-reset
|
||||||
|
|
|
@ -22,12 +22,12 @@ public:
|
||||||
DeprecatedString action() const;
|
DeprecatedString action() const;
|
||||||
DeprecatedString method() const { return attribute(HTML::AttributeNames::method); }
|
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();
|
void reset_form();
|
||||||
|
|
||||||
// NOTE: This is for the JS bindings. Use submit_form instead.
|
// 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.
|
// NOTE: This is for the JS bindings. Use submit_form instead.
|
||||||
void reset();
|
void reset();
|
||||||
|
|
|
@ -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.
|
// 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.
|
// 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
|
// 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) {
|
if (type_state() == TypeAttributeState::Checkbox || type_state() == TypeAttributeState::RadioButton) {
|
||||||
// 1. If the element is not connected, then return.
|
// 1. If the element is not connected, then return.
|
||||||
if (!is_connected())
|
if (!is_connected())
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
// 2. Fire an event named input at the element with the bubbles and composed attributes initialized to true.
|
// 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();
|
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;
|
JS::GCPtr<HTMLFormElement> form;
|
||||||
// 1. If the element does not have a form owner, then return.
|
// 1. If the element does not have a form owner, then return.
|
||||||
if (!(form = this->form()))
|
if (!(form = this->form()))
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
// 2. If the element's node document is not fully active, then return.
|
// 2. If the element's node document is not fully active, then return.
|
||||||
if (!document().is_fully_active())
|
if (!document().is_fully_active())
|
||||||
return;
|
return {};
|
||||||
|
|
||||||
// 3. Submit the form owner from the element.
|
// 3. Submit the form owner from the element.
|
||||||
form->submit_form(this);
|
TRY(form->submit_form(this));
|
||||||
} else if (type_state() == TypeAttributeState::FileUpload) {
|
} else if (type_state() == TypeAttributeState::FileUpload) {
|
||||||
show_the_picker_if_applicable(*this);
|
show_the_picker_if_applicable(*this);
|
||||||
} else {
|
} else {
|
||||||
dispatch_event(DOM::Event::create(realm(), EventNames::change).release_value_but_fixme_should_propagate_errors());
|
dispatch_event(DOM::Event::create(realm(), EventNames::change).release_value_but_fixme_should_propagate_errors());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
|
void HTMLInputElement::did_edit_text_node(Badge<BrowsingContext>)
|
||||||
|
|
|
@ -139,7 +139,7 @@ private:
|
||||||
|
|
||||||
static TypeAttributeState parse_type_attribute(StringView);
|
static TypeAttributeState parse_type_attribute(StringView);
|
||||||
void create_shadow_tree_if_needed();
|
void create_shadow_tree_if_needed();
|
||||||
void run_input_activation_behavior();
|
ErrorOr<void> run_input_activation_behavior();
|
||||||
void set_checked_within_group();
|
void set_checked_within_group();
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm
|
// https://html.spec.whatwg.org/multipage/input.html#value-sanitization-algorithm
|
||||||
|
|
|
@ -18,14 +18,16 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> URL::create(JS::Realm& realm, AK::URL
|
||||||
return MUST_OR_THROW_OOM(realm.heap().allocate<URL>(realm, realm, move(url), move(query)));
|
return MUST_OR_THROW_OOM(realm.heap().allocate<URL>(realm, realm, move(url), move(query)));
|
||||||
}
|
}
|
||||||
|
|
||||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> URL::construct_impl(JS::Realm& realm, DeprecatedString const& url, DeprecatedString const& base)
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> URL::construct_impl(JS::Realm& realm, String const& url, Optional<String> const& base)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm.vm();
|
||||||
|
|
||||||
// 1. Let parsedBase be null.
|
// 1. Let parsedBase be null.
|
||||||
Optional<AK::URL> parsed_base;
|
Optional<AK::URL> parsed_base;
|
||||||
// 2. If base is given, then:
|
// 2. If base is given, then:
|
||||||
if (!base.is_null()) {
|
if (base.has_value()) {
|
||||||
// 1. Let parsedBase be the result of running the basic URL parser on base.
|
// 1. Let parsedBase be the result of running the basic URL parser on base.
|
||||||
parsed_base = base;
|
parsed_base = base.value();
|
||||||
// 2. If parsedBase is failure, then throw a TypeError.
|
// 2. If parsedBase is failure, then throw a TypeError.
|
||||||
if (!parsed_base->is_valid())
|
if (!parsed_base->is_valid())
|
||||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid base URL"sv };
|
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid base URL"sv };
|
||||||
|
@ -40,7 +42,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> URL::construct_impl(JS::Realm& realm,
|
||||||
if (!parsed_url.is_valid())
|
if (!parsed_url.is_valid())
|
||||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid URL"sv };
|
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, "Invalid URL"sv };
|
||||||
// 5. Let query be parsedURL’s query, if that is non-null, and the empty string otherwise.
|
// 5. Let query be parsedURL’s query, if that is non-null, and the empty string otherwise.
|
||||||
auto& query = parsed_url.query().is_null() ? DeprecatedString::empty() : parsed_url.query();
|
auto query = parsed_url.query().is_null() ? String {} : TRY_OR_THROW_OOM(vm, String::from_deprecated_string(parsed_url.query()));
|
||||||
// 6. Set this’s URL to parsedURL.
|
// 6. Set this’s URL to parsedURL.
|
||||||
// 7. Set this’s query object to a new URLSearchParams object.
|
// 7. Set this’s query object to a new URLSearchParams object.
|
||||||
auto query_object = MUST(URLSearchParams::construct_impl(realm, query));
|
auto query_object = MUST(URLSearchParams::construct_impl(realm, query));
|
||||||
|
@ -75,20 +77,26 @@ void URL::visit_edges(Cell::Visitor& visitor)
|
||||||
visitor.visit(m_query.ptr());
|
visitor.visit(m_query.ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::href() const
|
WebIDL::ExceptionOr<String> URL::href() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return the serialization of this’s URL.
|
// return the serialization of this’s URL.
|
||||||
return m_url.serialize();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.serialize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::to_json() const
|
WebIDL::ExceptionOr<String> URL::to_json() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return the serialization of this’s URL.
|
// return the serialization of this’s URL.
|
||||||
return m_url.serialize();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.serialize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
WebIDL::ExceptionOr<void> URL::set_href(DeprecatedString const& href)
|
WebIDL::ExceptionOr<void> URL::set_href(String const& href)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. Let parsedURL be the result of running the basic URL parser on the given value.
|
// 1. Let parsedURL be the result of running the basic URL parser on the given value.
|
||||||
AK::URL parsed_url = href;
|
AK::URL parsed_url = href;
|
||||||
// 2. If parsedURL is failure, then throw a TypeError.
|
// 2. If parsedURL is failure, then throw a TypeError.
|
||||||
|
@ -102,37 +110,46 @@ WebIDL::ExceptionOr<void> URL::set_href(DeprecatedString const& href)
|
||||||
auto& query = m_url.query();
|
auto& query = m_url.query();
|
||||||
// 6. If query is non-null, then set this’s query object’s list to the result of parsing query.
|
// 6. If query is non-null, then set this’s query object’s list to the result of parsing query.
|
||||||
if (!query.is_null())
|
if (!query.is_null())
|
||||||
m_query->m_list = url_decode(query);
|
m_query->m_list = TRY_OR_THROW_OOM(vm, url_decode(query));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::origin() const
|
WebIDL::ExceptionOr<String> URL::origin() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return the serialization of this’s URL’s origin.
|
// return the serialization of this’s URL’s origin.
|
||||||
return m_url.serialize_origin();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.serialize_origin()));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::protocol() const
|
WebIDL::ExceptionOr<String> URL::protocol() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return this’s URL’s scheme, followed by U+003A (:).
|
// return this’s URL’s scheme, followed by U+003A (:).
|
||||||
return DeprecatedString::formatted("{}:", m_url.scheme());
|
return TRY_OR_THROW_OOM(vm, String::formatted("{}:", m_url.scheme()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_protocol(DeprecatedString const& protocol)
|
WebIDL::ExceptionOr<void> URL::set_protocol(String const& protocol)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// basic URL parse the given value, followed by U+003A (:), with this’s URL as url and scheme start state as state override.
|
// basic URL parse the given value, followed by U+003A (:), with this’s URL as url and scheme start state as state override.
|
||||||
auto result_url = URLParser::parse(DeprecatedString::formatted("{}:", protocol), nullptr, m_url, URLParser::State::SchemeStart);
|
auto result_url = URLParser::parse(TRY_OR_THROW_OOM(vm, String::formatted("{}:", protocol)), nullptr, m_url, URLParser::State::SchemeStart);
|
||||||
if (result_url.is_valid())
|
if (result_url.is_valid())
|
||||||
m_url = move(result_url);
|
m_url = move(result_url);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::username() const
|
WebIDL::ExceptionOr<String> URL::username() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return this’s URL’s username.
|
// return this’s URL’s username.
|
||||||
return m_url.username();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.username()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_username(DeprecatedString const& username)
|
void URL::set_username(String const& username)
|
||||||
{
|
{
|
||||||
// 1. If this’s URL cannot have a username/password/port, then return.
|
// 1. If this’s URL cannot have a username/password/port, then return.
|
||||||
if (m_url.cannot_have_a_username_or_password_or_port())
|
if (m_url.cannot_have_a_username_or_password_or_port())
|
||||||
|
@ -141,13 +158,15 @@ void URL::set_username(DeprecatedString const& username)
|
||||||
m_url.set_username(AK::URL::percent_encode(username, AK::URL::PercentEncodeSet::Userinfo));
|
m_url.set_username(AK::URL::percent_encode(username, AK::URL::PercentEncodeSet::Userinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::password() const
|
WebIDL::ExceptionOr<String> URL::password() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return this’s URL’s password.
|
// return this’s URL’s password.
|
||||||
return m_url.password();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.password()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_password(DeprecatedString const& password)
|
void URL::set_password(String const& password)
|
||||||
{
|
{
|
||||||
// 1. If this’s URL cannot have a username/password/port, then return.
|
// 1. If this’s URL cannot have a username/password/port, then return.
|
||||||
if (m_url.cannot_have_a_username_or_password_or_port())
|
if (m_url.cannot_have_a_username_or_password_or_port())
|
||||||
|
@ -156,21 +175,23 @@ void URL::set_password(DeprecatedString const& password)
|
||||||
m_url.set_password(AK::URL::percent_encode(password, AK::URL::PercentEncodeSet::Userinfo));
|
m_url.set_password(AK::URL::percent_encode(password, AK::URL::PercentEncodeSet::Userinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::host() const
|
WebIDL::ExceptionOr<String> URL::host() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. Let url be this’s URL.
|
// 1. Let url be this’s URL.
|
||||||
auto& url = m_url;
|
auto& url = m_url;
|
||||||
// 2. If url’s host is null, then return the empty string.
|
// 2. If url’s host is null, then return the empty string.
|
||||||
if (url.host().is_null())
|
if (url.host().is_null())
|
||||||
return DeprecatedString::empty();
|
return String {};
|
||||||
// 3. If url’s port is null, return url’s host, serialized.
|
// 3. If url’s port is null, return url’s host, serialized.
|
||||||
if (!url.port().has_value())
|
if (!url.port().has_value())
|
||||||
return url.host();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(url.host()));
|
||||||
// 4. Return url’s host, serialized, followed by U+003A (:) and url’s port, serialized.
|
// 4. Return url’s host, serialized, followed by U+003A (:) and url’s port, serialized.
|
||||||
return DeprecatedString::formatted("{}:{}", url.host(), *url.port());
|
return TRY_OR_THROW_OOM(vm, String::formatted("{}:{}", url.host(), *url.port()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_host(DeprecatedString const& host)
|
void URL::set_host(String const& host)
|
||||||
{
|
{
|
||||||
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return.
|
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return.
|
||||||
if (m_url.cannot_be_a_base_url())
|
if (m_url.cannot_be_a_base_url())
|
||||||
|
@ -181,16 +202,18 @@ void URL::set_host(DeprecatedString const& host)
|
||||||
m_url = move(result_url);
|
m_url = move(result_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::hostname() const
|
WebIDL::ExceptionOr<String> URL::hostname() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. If this’s URL’s host is null, then return the empty string.
|
// 1. If this’s URL’s host is null, then return the empty string.
|
||||||
if (m_url.host().is_null())
|
if (m_url.host().is_null())
|
||||||
return DeprecatedString::empty();
|
return String {};
|
||||||
// 2. Return this’s URL’s host, serialized.
|
// 2. Return this’s URL’s host, serialized.
|
||||||
return m_url.host();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.host()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_hostname(DeprecatedString const& hostname)
|
void URL::set_hostname(String const& hostname)
|
||||||
{
|
{
|
||||||
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return.
|
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return.
|
||||||
if (m_url.cannot_be_a_base_url())
|
if (m_url.cannot_be_a_base_url())
|
||||||
|
@ -201,17 +224,19 @@ void URL::set_hostname(DeprecatedString const& hostname)
|
||||||
m_url = move(result_url);
|
m_url = move(result_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::port() const
|
WebIDL::ExceptionOr<String> URL::port() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. If this’s URL’s port is null, then return the empty string.
|
// 1. If this’s URL’s port is null, then return the empty string.
|
||||||
if (!m_url.port().has_value())
|
if (!m_url.port().has_value())
|
||||||
return {};
|
return String {};
|
||||||
|
|
||||||
// 2. Return this’s URL’s port, serialized.
|
// 2. Return this’s URL’s port, serialized.
|
||||||
return DeprecatedString::formatted("{}", *m_url.port());
|
return TRY_OR_THROW_OOM(vm, String::formatted("{}", *m_url.port()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_port(DeprecatedString const& port)
|
void URL::set_port(String const& port)
|
||||||
{
|
{
|
||||||
// 1. If this’s URL cannot have a username/password/port, then return.
|
// 1. If this’s URL cannot have a username/password/port, then return.
|
||||||
if (m_url.cannot_have_a_username_or_password_or_port())
|
if (m_url.cannot_have_a_username_or_password_or_port())
|
||||||
|
@ -229,15 +254,17 @@ void URL::set_port(DeprecatedString const& port)
|
||||||
m_url = move(result_url);
|
m_url = move(result_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::pathname() const
|
WebIDL::ExceptionOr<String> URL::pathname() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return this’s URL’s path[0].
|
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return this’s URL’s path[0].
|
||||||
// 2. If this’s URL’s path is empty, then return the empty string.
|
// 2. If this’s URL’s path is empty, then return the empty string.
|
||||||
// 3. Return U+002F (/), followed by the strings in this’s URL’s path (including empty strings), if any, separated from each other by U+002F (/).
|
// 3. Return U+002F (/), followed by the strings in this’s URL’s path (including empty strings), if any, separated from each other by U+002F (/).
|
||||||
return m_url.path();
|
return TRY_OR_THROW_OOM(vm, String::from_deprecated_string(m_url.path()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_pathname(DeprecatedString const& pathname)
|
void URL::set_pathname(String const& pathname)
|
||||||
{
|
{
|
||||||
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return.
|
// 1. If this’s URL’s cannot-be-a-base-URL is true, then return.
|
||||||
if (m_url.cannot_be_a_base_url())
|
if (m_url.cannot_be_a_base_url())
|
||||||
|
@ -251,27 +278,32 @@ void URL::set_pathname(DeprecatedString const& pathname)
|
||||||
m_url = move(result_url);
|
m_url = move(result_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::search() const
|
WebIDL::ExceptionOr<String> URL::search() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. If this’s URL’s query is either null or the empty string, then return the empty string.
|
// 1. If this’s URL’s 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().is_null() || m_url.query().is_empty())
|
||||||
return DeprecatedString::empty();
|
return String {};
|
||||||
// 2. Return U+003F (?), followed by this’s URL’s query.
|
// 2. Return U+003F (?), followed by this’s URL’s query.
|
||||||
return DeprecatedString::formatted("?{}", m_url.query());
|
return TRY_OR_THROW_OOM(vm, String::formatted("?{}", m_url.query()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_search(DeprecatedString const& search)
|
WebIDL::ExceptionOr<void> URL::set_search(String const& search)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. Let url be this’s URL.
|
// 1. Let url be this’s URL.
|
||||||
auto& url = m_url;
|
auto& url = m_url;
|
||||||
// If the given value is the empty string, set url’s query to null, empty this’s query object’s list, and then return.
|
// If the given value is the empty string, set url’s query to null, empty this’s query object’s list, and then return.
|
||||||
if (search.is_empty()) {
|
if (search.is_empty()) {
|
||||||
url.set_query({});
|
url.set_query({});
|
||||||
m_query->m_list.clear();
|
m_query->m_list.clear();
|
||||||
return;
|
return {};
|
||||||
}
|
}
|
||||||
// 2. Let input be the given value with a single leading U+003F (?) removed, if any.
|
// 2. Let input be the given value with a single leading U+003F (?) removed, if any.
|
||||||
auto input = search.substring_view(search.starts_with('?'));
|
auto search_as_string_view = search.bytes_as_string_view();
|
||||||
|
auto input = search_as_string_view.substring_view(search_as_string_view.starts_with('?'));
|
||||||
// 3. Set url’s query to the empty string.
|
// 3. Set url’s query to the empty string.
|
||||||
auto url_copy = url; // We copy the URL here to follow other browser's behaviour of reverting the search change if the parse failed.
|
auto url_copy = url; // We copy the URL here to follow other browser's behaviour of reverting the search change if the parse failed.
|
||||||
url_copy.set_query(DeprecatedString::empty());
|
url_copy.set_query(DeprecatedString::empty());
|
||||||
|
@ -280,8 +312,10 @@ void URL::set_search(DeprecatedString const& search)
|
||||||
if (result_url.is_valid()) {
|
if (result_url.is_valid()) {
|
||||||
m_url = move(result_url);
|
m_url = move(result_url);
|
||||||
// 5. Set this’s query object’s list to the result of parsing input.
|
// 5. Set this’s query object’s list to the result of parsing input.
|
||||||
m_query->m_list = url_decode(input);
|
m_query->m_list = TRY_OR_THROW_OOM(vm, url_decode(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
URLSearchParams const* URL::search_params() const
|
URLSearchParams const* URL::search_params() const
|
||||||
|
@ -289,16 +323,18 @@ URLSearchParams const* URL::search_params() const
|
||||||
return m_query;
|
return m_query;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URL::hash() const
|
WebIDL::ExceptionOr<String> URL::hash() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. If this’s URL’s fragment is either null or the empty string, then return the empty string.
|
// 1. If this’s URL’s 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().is_null() || m_url.fragment().is_empty())
|
||||||
return DeprecatedString::empty();
|
return String {};
|
||||||
// 2. Return U+0023 (#), followed by this’s URL’s fragment.
|
// 2. Return U+0023 (#), followed by this’s URL’s fragment.
|
||||||
return DeprecatedString::formatted("#{}", m_url.fragment());
|
return TRY_OR_THROW_OOM(vm, String::formatted("#{}", m_url.fragment()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void URL::set_hash(DeprecatedString const& hash)
|
void URL::set_hash(String const& hash)
|
||||||
{
|
{
|
||||||
// 1. If the given value is the empty string, then set this’s URL’s fragment to null and return.
|
// 1. If the given value is the empty string, then set this’s URL’s fragment to null and return.
|
||||||
if (hash.is_empty()) {
|
if (hash.is_empty()) {
|
||||||
|
@ -306,7 +342,8 @@ void URL::set_hash(DeprecatedString const& hash)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 2. Let input be the given value with a single leading U+0023 (#) removed, if any.
|
// 2. Let input be the given value with a single leading U+0023 (#) removed, if any.
|
||||||
auto input = hash.substring_view(hash.starts_with('#'));
|
auto hash_as_string_view = hash.bytes_as_string_view();
|
||||||
|
auto input = hash_as_string_view.substring_view(hash_as_string_view.starts_with('#'));
|
||||||
// 3. Set this’s URL’s fragment to the empty string.
|
// 3. Set this’s URL’s fragment to the empty string.
|
||||||
auto url = m_url; // We copy the URL here to follow other browser's behaviour of reverting the hash change if the parse failed.
|
auto url = m_url; // We copy the URL here to follow other browser's behaviour of reverting the hash change if the parse failed.
|
||||||
url.set_fragment(DeprecatedString::empty());
|
url.set_fragment(DeprecatedString::empty());
|
||||||
|
|
|
@ -20,47 +20,47 @@ class URL : public Bindings::PlatformObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> create(JS::Realm&, AK::URL url, JS::NonnullGCPtr<URLSearchParams> query);
|
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> create(JS::Realm&, AK::URL url, JS::NonnullGCPtr<URLSearchParams> query);
|
||||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> construct_impl(JS::Realm&, DeprecatedString const& url, DeprecatedString const& base);
|
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URL>> construct_impl(JS::Realm&, String const& url, Optional<String> const& base = {});
|
||||||
|
|
||||||
virtual ~URL() override;
|
virtual ~URL() override;
|
||||||
|
|
||||||
DeprecatedString href() const;
|
WebIDL::ExceptionOr<String> href() const;
|
||||||
WebIDL::ExceptionOr<void> set_href(DeprecatedString const&);
|
WebIDL::ExceptionOr<void> set_href(String const&);
|
||||||
|
|
||||||
DeprecatedString origin() const;
|
WebIDL::ExceptionOr<String> origin() const;
|
||||||
|
|
||||||
DeprecatedString protocol() const;
|
WebIDL::ExceptionOr<String> protocol() const;
|
||||||
void set_protocol(DeprecatedString const&);
|
WebIDL::ExceptionOr<void> set_protocol(String const&);
|
||||||
|
|
||||||
DeprecatedString username() const;
|
WebIDL::ExceptionOr<String> username() const;
|
||||||
void set_username(DeprecatedString const&);
|
void set_username(String const&);
|
||||||
|
|
||||||
DeprecatedString password() const;
|
WebIDL::ExceptionOr<String> password() const;
|
||||||
void set_password(DeprecatedString const&);
|
void set_password(String const&);
|
||||||
|
|
||||||
DeprecatedString host() const;
|
WebIDL::ExceptionOr<String> host() const;
|
||||||
void set_host(DeprecatedString const&);
|
void set_host(String const&);
|
||||||
|
|
||||||
DeprecatedString hostname() const;
|
WebIDL::ExceptionOr<String> hostname() const;
|
||||||
void set_hostname(DeprecatedString const&);
|
void set_hostname(String const&);
|
||||||
|
|
||||||
DeprecatedString port() const;
|
WebIDL::ExceptionOr<String> port() const;
|
||||||
void set_port(DeprecatedString const&);
|
void set_port(String const&);
|
||||||
|
|
||||||
DeprecatedString pathname() const;
|
WebIDL::ExceptionOr<String> pathname() const;
|
||||||
void set_pathname(DeprecatedString const&);
|
void set_pathname(String const&);
|
||||||
|
|
||||||
DeprecatedString search() const;
|
WebIDL::ExceptionOr<String> search() const;
|
||||||
void set_search(DeprecatedString const&);
|
WebIDL::ExceptionOr<void> set_search(String const&);
|
||||||
|
|
||||||
URLSearchParams const* search_params() const;
|
URLSearchParams const* search_params() const;
|
||||||
|
|
||||||
DeprecatedString hash() const;
|
WebIDL::ExceptionOr<String> hash() const;
|
||||||
void set_hash(DeprecatedString const&);
|
void set_hash(String const&);
|
||||||
|
|
||||||
DeprecatedString to_json() const;
|
WebIDL::ExceptionOr<String> to_json() const;
|
||||||
|
|
||||||
void set_query(Badge<URLSearchParams>, DeprecatedString query) { m_url.set_query(move(query)); }
|
void set_query(Badge<URLSearchParams>, String query) { m_url.set_query(query.to_deprecated_string()); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
URL(JS::Realm&, AK::URL, JS::NonnullGCPtr<URLSearchParams> query);
|
URL(JS::Realm&, AK::URL, JS::NonnullGCPtr<URLSearchParams> query);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#import <URL/URLSearchParams.idl>
|
#import <URL/URLSearchParams.idl>
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#url
|
// https://url.spec.whatwg.org/#url
|
||||||
[Exposed=*, LegacyWindowAlias=webkitURL]
|
[Exposed=*, LegacyWindowAlias=webkitURL, UseNewAKString]
|
||||||
interface URL {
|
interface URL {
|
||||||
constructor(USVString url, optional USVString base);
|
constructor(USVString url, optional USVString base);
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <AK/QuickSort.h>
|
#include <AK/QuickSort.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
|
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||||
#include <LibWeb/Bindings/Intrinsics.h>
|
#include <LibWeb/Bindings/Intrinsics.h>
|
||||||
#include <LibWeb/URL/URL.h>
|
#include <LibWeb/URL/URL.h>
|
||||||
#include <LibWeb/URL/URLSearchParams.h>
|
#include <LibWeb/URL/URLSearchParams.h>
|
||||||
|
@ -35,20 +36,20 @@ void URLSearchParams::visit_edges(Cell::Visitor& visitor)
|
||||||
visitor.visit(m_url);
|
visitor.visit(m_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString url_encode(Vector<QueryParam> const& pairs, AK::URL::PercentEncodeSet percent_encode_set)
|
ErrorOr<String> url_encode(Vector<QueryParam> const& pairs, AK::URL::PercentEncodeSet percent_encode_set)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
for (size_t i = 0; i < pairs.size(); ++i) {
|
for (size_t i = 0; i < pairs.size(); ++i) {
|
||||||
builder.append(AK::URL::percent_encode(pairs[i].name, percent_encode_set, AK::URL::SpaceAsPlus::Yes));
|
TRY(builder.try_append(AK::URL::percent_encode(pairs[i].name, percent_encode_set, AK::URL::SpaceAsPlus::Yes)));
|
||||||
builder.append('=');
|
TRY(builder.try_append('='));
|
||||||
builder.append(AK::URL::percent_encode(pairs[i].value, percent_encode_set, AK::URL::SpaceAsPlus::Yes));
|
TRY(builder.try_append(AK::URL::percent_encode(pairs[i].value, percent_encode_set, AK::URL::SpaceAsPlus::Yes)));
|
||||||
if (i != pairs.size() - 1)
|
if (i != pairs.size() - 1)
|
||||||
builder.append('&');
|
TRY(builder.try_append('&'));
|
||||||
}
|
}
|
||||||
return builder.to_deprecated_string();
|
return builder.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<QueryParam> url_decode(StringView input)
|
ErrorOr<Vector<QueryParam>> url_decode(StringView input)
|
||||||
{
|
{
|
||||||
// 1. Let sequences be the result of splitting input on 0x26 (&).
|
// 1. Let sequences be the result of splitting input on 0x26 (&).
|
||||||
auto sequences = input.split_view('&');
|
auto sequences = input.split_view('&');
|
||||||
|
@ -80,10 +81,10 @@ Vector<QueryParam> url_decode(StringView input)
|
||||||
auto space_decoded_name = name.replace("+"sv, " "sv, ReplaceMode::All);
|
auto space_decoded_name = name.replace("+"sv, " "sv, ReplaceMode::All);
|
||||||
|
|
||||||
// 5. Let nameString and valueString be the result of running UTF-8 decode without BOM on the percent-decoding of name and value, respectively.
|
// 5. Let nameString and valueString be the result of running UTF-8 decode without BOM on the percent-decoding of name and value, respectively.
|
||||||
auto name_string = AK::URL::percent_decode(space_decoded_name);
|
auto name_string = TRY(String::from_deprecated_string(AK::URL::percent_decode(space_decoded_name)));
|
||||||
auto value_string = AK::URL::percent_decode(value);
|
auto value_string = TRY(String::from_deprecated_string(AK::URL::percent_decode(value)));
|
||||||
|
|
||||||
output.empend(move(name_string), move(value_string));
|
TRY(output.try_empend(move(name_string), move(value_string)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
@ -96,8 +97,10 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::create(J
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
|
// https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
|
||||||
// https://url.spec.whatwg.org/#urlsearchparams-initialize
|
// https://url.spec.whatwg.org/#urlsearchparams-initialize
|
||||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::construct_impl(JS::Realm& realm, Variant<Vector<Vector<DeprecatedString>>, OrderedHashMap<DeprecatedString, DeprecatedString>, DeprecatedString> const& init)
|
WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::construct_impl(JS::Realm& realm, Variant<Vector<Vector<String>>, OrderedHashMap<String, String>, String> const& init)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm.vm();
|
||||||
|
|
||||||
// 1. If init is a string and starts with U+003F (?), then remove the first code point from init.
|
// 1. If init is a string and starts with U+003F (?), then remove the first code point from init.
|
||||||
// NOTE: We do this when we know that it's a string on step 3 of initialization.
|
// NOTE: We do this when we know that it's a string on step 3 of initialization.
|
||||||
|
|
||||||
|
@ -106,8 +109,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::construc
|
||||||
// URLSearchParams init from this point forward
|
// URLSearchParams init from this point forward
|
||||||
|
|
||||||
// 1. If init is a sequence, then for each pair in init:
|
// 1. If init is a sequence, then for each pair in init:
|
||||||
if (init.has<Vector<Vector<DeprecatedString>>>()) {
|
if (init.has<Vector<Vector<String>>>()) {
|
||||||
auto const& init_sequence = init.get<Vector<Vector<DeprecatedString>>>();
|
auto const& init_sequence = init.get<Vector<Vector<String>>>();
|
||||||
|
|
||||||
Vector<QueryParam> list;
|
Vector<QueryParam> list;
|
||||||
list.ensure_capacity(init_sequence.size());
|
list.ensure_capacity(init_sequence.size());
|
||||||
|
@ -125,8 +128,8 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::construc
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2. Otherwise, if init is a record, then for each name → value of init, append a new name-value pair whose name is name and value is value, to query’s list.
|
// 2. Otherwise, if init is a record, then for each name → value of init, append a new name-value pair whose name is name and value is value, to query’s list.
|
||||||
if (init.has<OrderedHashMap<DeprecatedString, DeprecatedString>>()) {
|
if (init.has<OrderedHashMap<String, String>>()) {
|
||||||
auto const& init_record = init.get<OrderedHashMap<DeprecatedString, DeprecatedString>>();
|
auto const& init_record = init.get<OrderedHashMap<String, String>>();
|
||||||
|
|
||||||
Vector<QueryParam> list;
|
Vector<QueryParam> list;
|
||||||
list.ensure_capacity(init_record.size());
|
list.ensure_capacity(init_record.size());
|
||||||
|
@ -140,13 +143,14 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::construc
|
||||||
// 3. Otherwise:
|
// 3. Otherwise:
|
||||||
// a. Assert: init is a string.
|
// a. Assert: init is a string.
|
||||||
// NOTE: `get` performs `VERIFY(has<T>())`
|
// NOTE: `get` performs `VERIFY(has<T>())`
|
||||||
auto const& init_string = init.get<DeprecatedString>();
|
auto const& init_string = init.get<String>();
|
||||||
|
|
||||||
// See NOTE at the start of this function.
|
// See NOTE at the start of this function.
|
||||||
StringView stripped_init = init_string.substring_view(init_string.starts_with('?'));
|
auto init_string_view = init_string.bytes_as_string_view();
|
||||||
|
auto stripped_init = init_string_view.substring_view(init_string_view.starts_with('?'));
|
||||||
|
|
||||||
// b. Set query’s list to the result of parsing init.
|
// b. Set query’s list to the result of parsing init.
|
||||||
return URLSearchParams::create(realm, url_decode(stripped_init));
|
return URLSearchParams::create(realm, TRY_OR_THROW_OOM(vm, url_decode(stripped_init)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#dom-urlsearchparams-size
|
// https://url.spec.whatwg.org/#dom-urlsearchparams-size
|
||||||
|
@ -156,39 +160,47 @@ size_t URLSearchParams::size() const
|
||||||
return m_list.size();
|
return m_list.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void URLSearchParams::append(DeprecatedString const& name, DeprecatedString const& value)
|
WebIDL::ExceptionOr<void> URLSearchParams::append(String const& name, String const& value)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. Append a new name-value pair whose name is name and value is value, to list.
|
// 1. Append a new name-value pair whose name is name and value is value, to list.
|
||||||
m_list.empend(name, value);
|
TRY_OR_THROW_OOM(vm, m_list.try_empend(name, value));
|
||||||
// 2. Update this.
|
// 2. Update this.
|
||||||
update();
|
TRY(update());
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void URLSearchParams::update()
|
WebIDL::ExceptionOr<void> URLSearchParams::update()
|
||||||
{
|
{
|
||||||
// 1. If query’s URL object is null, then return.
|
// 1. If query’s URL object is null, then return.
|
||||||
if (!m_url)
|
if (!m_url)
|
||||||
return;
|
return {};
|
||||||
// 2. Let serializedQuery be the serialization of query’s list.
|
// 2. Let serializedQuery be the serialization of query’s list.
|
||||||
auto serialized_query = to_deprecated_string();
|
auto serialized_query = TRY(to_string());
|
||||||
// 3. If serializedQuery is the empty string, then set serializedQuery to null.
|
// 3. If serializedQuery is the empty string, then set serializedQuery to null.
|
||||||
if (serialized_query.is_empty())
|
if (serialized_query.is_empty())
|
||||||
serialized_query = {};
|
serialized_query = {};
|
||||||
// 4. Set query’s URL object’s URL’s query to serializedQuery.
|
// 4. Set query’s URL object’s URL’s query to serializedQuery.
|
||||||
m_url->set_query({}, move(serialized_query));
|
m_url->set_query({}, move(serialized_query));
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void URLSearchParams::delete_(DeprecatedString const& name)
|
WebIDL::ExceptionOr<void> URLSearchParams::delete_(String const& name)
|
||||||
{
|
{
|
||||||
// 1. Remove all name-value pairs whose name is name from list.
|
// 1. Remove all name-value pairs whose name is name from list.
|
||||||
m_list.remove_all_matching([&name](auto& entry) {
|
m_list.remove_all_matching([&name](auto& entry) {
|
||||||
return entry.name == name;
|
return entry.name == name;
|
||||||
});
|
});
|
||||||
// 2. Update this.
|
// 2. Update this.
|
||||||
update();
|
TRY(update());
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URLSearchParams::get(DeprecatedString const& name)
|
Optional<String> URLSearchParams::get(String const& name)
|
||||||
{
|
{
|
||||||
// return the value of the first name-value pair whose name is name in this’s list, if there is such a pair, and null otherwise.
|
// return the value of the first name-value pair whose name is name in this’s list, if there is such a pair, and null otherwise.
|
||||||
auto result = m_list.find_if([&name](auto& entry) {
|
auto result = m_list.find_if([&name](auto& entry) {
|
||||||
|
@ -200,18 +212,20 @@ DeprecatedString URLSearchParams::get(DeprecatedString const& name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#dom-urlsearchparams-getall
|
// https://url.spec.whatwg.org/#dom-urlsearchparams-getall
|
||||||
Vector<DeprecatedString> URLSearchParams::get_all(DeprecatedString const& name)
|
WebIDL::ExceptionOr<Vector<String>> URLSearchParams::get_all(String const& name)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return the values of all name-value pairs whose name is name, in this’s list, in list order, and the empty sequence otherwise.
|
// return the values of all name-value pairs whose name is name, in this’s list, in list order, and the empty sequence otherwise.
|
||||||
Vector<DeprecatedString> values;
|
Vector<String> values;
|
||||||
for (auto& entry : m_list) {
|
for (auto& entry : m_list) {
|
||||||
if (entry.name == name)
|
if (entry.name == name)
|
||||||
values.append(entry.value);
|
TRY_OR_THROW_OOM(vm, values.try_append(entry.value));
|
||||||
}
|
}
|
||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool URLSearchParams::has(DeprecatedString const& name)
|
bool URLSearchParams::has(String const& name)
|
||||||
{
|
{
|
||||||
// return true if there is a name-value pair whose name is name in this’s list, and false otherwise.
|
// return true if there is a name-value pair whose name is name in this’s list, and false otherwise.
|
||||||
return !m_list.find_if([&name](auto& entry) {
|
return !m_list.find_if([&name](auto& entry) {
|
||||||
|
@ -220,8 +234,10 @@ bool URLSearchParams::has(DeprecatedString const& name)
|
||||||
.is_end();
|
.is_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
void URLSearchParams::set(DeprecatedString const& name, DeprecatedString const& value)
|
WebIDL::ExceptionOr<void> URLSearchParams::set(String const& name, String const& value)
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// 1. If this’s list contains any name-value pairs whose name is name, then set the value of the first such name-value pair to value and remove the others.
|
// 1. If this’s list contains any name-value pairs whose name is name, then set the value of the first such name-value pair to value and remove the others.
|
||||||
auto existing = m_list.find_if([&name](auto& entry) {
|
auto existing = m_list.find_if([&name](auto& entry) {
|
||||||
return entry.name == name;
|
return entry.name == name;
|
||||||
|
@ -234,13 +250,15 @@ void URLSearchParams::set(DeprecatedString const& name, DeprecatedString const&
|
||||||
}
|
}
|
||||||
// 2. Otherwise, append a new name-value pair whose name is name and value is value, to this’s list.
|
// 2. Otherwise, append a new name-value pair whose name is name and value is value, to this’s list.
|
||||||
else {
|
else {
|
||||||
m_list.empend(name, value);
|
TRY_OR_THROW_OOM(vm, m_list.try_empend(name, value));
|
||||||
}
|
}
|
||||||
// 3. Update this.
|
// 3. Update this.
|
||||||
update();
|
TRY(update());
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void URLSearchParams::sort()
|
WebIDL::ExceptionOr<void> URLSearchParams::sort()
|
||||||
{
|
{
|
||||||
// 1. Sort all name-value pairs, if any, by their names. Sorting must be done by comparison of code units. The relative order between name-value pairs with equal names must be preserved.
|
// 1. Sort all name-value pairs, if any, by their names. Sorting must be done by comparison of code units. The relative order between name-value pairs with equal names must be preserved.
|
||||||
quick_sort(m_list.begin(), m_list.end(), [](auto& a, auto& b) {
|
quick_sort(m_list.begin(), m_list.end(), [](auto& a, auto& b) {
|
||||||
|
@ -266,13 +284,17 @@ void URLSearchParams::sort()
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
});
|
});
|
||||||
// 2. Update this.
|
// 2. Update this.
|
||||||
update();
|
TRY(update());
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
DeprecatedString URLSearchParams::to_deprecated_string() const
|
WebIDL::ExceptionOr<String> URLSearchParams::to_string() const
|
||||||
{
|
{
|
||||||
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return the serialization of this’s list.
|
// return the serialization of this’s list.
|
||||||
return url_encode(m_list, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded);
|
return TRY_OR_THROW_OOM(vm, url_encode(m_list, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::ThrowCompletionOr<void> URLSearchParams::for_each(ForEachCallback callback)
|
JS::ThrowCompletionOr<void> URLSearchParams::for_each(ForEachCallback callback)
|
||||||
|
|
|
@ -13,34 +13,34 @@
|
||||||
namespace Web::URL {
|
namespace Web::URL {
|
||||||
|
|
||||||
struct QueryParam {
|
struct QueryParam {
|
||||||
DeprecatedString name;
|
String name;
|
||||||
DeprecatedString value;
|
String value;
|
||||||
};
|
};
|
||||||
DeprecatedString url_encode(Vector<QueryParam> const&, AK::URL::PercentEncodeSet);
|
ErrorOr<String> url_encode(Vector<QueryParam> const&, AK::URL::PercentEncodeSet);
|
||||||
Vector<QueryParam> url_decode(StringView);
|
ErrorOr<Vector<QueryParam>> url_decode(StringView);
|
||||||
|
|
||||||
class URLSearchParams : public Bindings::PlatformObject {
|
class URLSearchParams : public Bindings::PlatformObject {
|
||||||
WEB_PLATFORM_OBJECT(URLSearchParams, Bindings::PlatformObject);
|
WEB_PLATFORM_OBJECT(URLSearchParams, Bindings::PlatformObject);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> create(JS::Realm&, Vector<QueryParam> list);
|
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> create(JS::Realm&, Vector<QueryParam> list);
|
||||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> construct_impl(JS::Realm&, Variant<Vector<Vector<DeprecatedString>>, OrderedHashMap<DeprecatedString, DeprecatedString>, DeprecatedString> const& init);
|
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> construct_impl(JS::Realm&, Variant<Vector<Vector<String>>, OrderedHashMap<String, String>, String> const& init);
|
||||||
|
|
||||||
virtual ~URLSearchParams() override;
|
virtual ~URLSearchParams() override;
|
||||||
|
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
void append(DeprecatedString const& name, DeprecatedString const& value);
|
WebIDL::ExceptionOr<void> append(String const& name, String const& value);
|
||||||
void delete_(DeprecatedString const& name);
|
WebIDL::ExceptionOr<void> delete_(String const& name);
|
||||||
DeprecatedString get(DeprecatedString const& name);
|
Optional<String> get(String const& name);
|
||||||
Vector<DeprecatedString> get_all(DeprecatedString const& name);
|
WebIDL::ExceptionOr<Vector<String>> get_all(String const& name);
|
||||||
bool has(DeprecatedString const& name);
|
bool has(String const& name);
|
||||||
void set(DeprecatedString const& name, DeprecatedString const& value);
|
WebIDL::ExceptionOr<void> set(String const& name, String const& value);
|
||||||
|
|
||||||
void sort();
|
WebIDL::ExceptionOr<void> sort();
|
||||||
|
|
||||||
DeprecatedString to_deprecated_string() const;
|
WebIDL::ExceptionOr<String> to_string() const;
|
||||||
|
|
||||||
using ForEachCallback = Function<JS::ThrowCompletionOr<void>(DeprecatedString const&, DeprecatedString const&)>;
|
using ForEachCallback = Function<JS::ThrowCompletionOr<void>(String const&, String const&)>;
|
||||||
JS::ThrowCompletionOr<void> for_each(ForEachCallback);
|
JS::ThrowCompletionOr<void> for_each(ForEachCallback);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -52,7 +52,7 @@ private:
|
||||||
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
|
||||||
void update();
|
WebIDL::ExceptionOr<void> update();
|
||||||
|
|
||||||
Vector<QueryParam> m_list;
|
Vector<QueryParam> m_list;
|
||||||
JS::GCPtr<URL> m_url;
|
JS::GCPtr<URL> m_url;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
// https://url.spec.whatwg.org/#urlsearchparams
|
// https://url.spec.whatwg.org/#urlsearchparams
|
||||||
[Exposed=*]
|
[Exposed=*, UseNewAKString]
|
||||||
interface URLSearchParams {
|
interface URLSearchParams {
|
||||||
|
|
||||||
constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = "");
|
constructor(optional (sequence<sequence<USVString>> or record<USVString, USVString> or USVString) init = "");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue