mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:28:10 +00:00
LibWeb: Implement Web::URL::url_encode closer to spec
This commit is contained in:
parent
799c79cc5a
commit
55d59636ef
4 changed files with 45 additions and 23 deletions
|
@ -233,14 +233,14 @@ WebIDL::ExceptionOr<void> HTMLFormElement::submit_form(JS::NonnullGCPtr<HTMLElem
|
||||||
|
|
||||||
if (scheme.is_one_of("http"sv, "https"sv)) {
|
if (scheme.is_one_of("http"sv, "https"sv)) {
|
||||||
if (method == MethodAttributeState::GET)
|
if (method == MethodAttributeState::GET)
|
||||||
TRY_OR_THROW_OOM(vm, mutate_action_url(move(parsed_action), move(entry_list), *target_navigable, history_handling));
|
TRY_OR_THROW_OOM(vm, mutate_action_url(move(parsed_action), move(entry_list), move(encoding), *target_navigable, history_handling));
|
||||||
else
|
else
|
||||||
TRY_OR_THROW_OOM(vm, submit_as_entity_body(move(parsed_action), move(entry_list), encoding_type, move(encoding), *target_navigable, history_handling));
|
TRY_OR_THROW_OOM(vm, submit_as_entity_body(move(parsed_action), move(entry_list), encoding_type, move(encoding), *target_navigable, history_handling));
|
||||||
} else if (scheme.is_one_of("ftp"sv, "javascript"sv)) {
|
} else if (scheme.is_one_of("ftp"sv, "javascript"sv)) {
|
||||||
get_action_url(move(parsed_action), *target_navigable, history_handling);
|
get_action_url(move(parsed_action), *target_navigable, history_handling);
|
||||||
} else if (scheme == "data"sv) {
|
} else if (scheme == "data"sv) {
|
||||||
if (method == MethodAttributeState::GET)
|
if (method == MethodAttributeState::GET)
|
||||||
TRY_OR_THROW_OOM(vm, mutate_action_url(move(parsed_action), move(entry_list), *target_navigable, history_handling));
|
TRY_OR_THROW_OOM(vm, mutate_action_url(move(parsed_action), move(entry_list), move(encoding), *target_navigable, history_handling));
|
||||||
else
|
else
|
||||||
get_action_url(move(parsed_action), *target_navigable, history_handling);
|
get_action_url(move(parsed_action), *target_navigable, history_handling);
|
||||||
} else if (scheme == "mailto"sv) {
|
} else if (scheme == "mailto"sv) {
|
||||||
|
@ -609,14 +609,13 @@ static ErrorOr<String> plain_text_encode(Vector<URL::QueryParam> const& pairs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submit-mutate-action
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#submit-mutate-action
|
||||||
ErrorOr<void> HTMLFormElement::mutate_action_url(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling)
|
ErrorOr<void> HTMLFormElement::mutate_action_url(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, String encoding, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling)
|
||||||
{
|
{
|
||||||
// 1. Let pairs be the result of converting to a list of name-value pairs with entry list.
|
// 1. Let pairs be the result of converting to a list of name-value pairs with entry list.
|
||||||
auto pairs = TRY(convert_to_list_of_name_value_pairs(entry_list));
|
auto pairs = TRY(convert_to_list_of_name_value_pairs(entry_list));
|
||||||
|
|
||||||
// 2. Let query be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
// 2. Let query be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
||||||
// FIXME: Pass in encoding.
|
auto query = TRY(url_encode(pairs, encoding));
|
||||||
auto query = TRY(url_encode(pairs, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
|
|
||||||
|
|
||||||
// 3. Set parsed action's query component to query.
|
// 3. Set parsed action's query component to query.
|
||||||
parsed_action.set_query(query.to_deprecated_string());
|
parsed_action.set_query(query.to_deprecated_string());
|
||||||
|
@ -642,8 +641,7 @@ ErrorOr<void> HTMLFormElement::submit_as_entity_body(AK::URL parsed_action, Vect
|
||||||
auto pairs = TRY(convert_to_list_of_name_value_pairs(entry_list));
|
auto pairs = TRY(convert_to_list_of_name_value_pairs(entry_list));
|
||||||
|
|
||||||
// 2. Let body be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
// 2. Let body be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
||||||
// FIXME: Pass in encoding.
|
body = TRY(ByteBuffer::copy(TRY(url_encode(pairs, encoding)).bytes()));
|
||||||
body = TRY(ByteBuffer::copy(TRY(url_encode(pairs, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded)).bytes()));
|
|
||||||
|
|
||||||
// 3. Set body to the result of encoding body.
|
// 3. Set body to the result of encoding body.
|
||||||
// NOTE: `encoding` refers to `UTF-8 encode`, which body already is encoded as because it uses AK::String.
|
// NOTE: `encoding` refers to `UTF-8 encode`, which body already is encoded as because it uses AK::String.
|
||||||
|
@ -713,8 +711,7 @@ ErrorOr<void> HTMLFormElement::mail_with_headers(AK::URL parsed_action, Vector<X
|
||||||
auto pairs = TRY(convert_to_list_of_name_value_pairs(entry_list));
|
auto pairs = TRY(convert_to_list_of_name_value_pairs(entry_list));
|
||||||
|
|
||||||
// 2. Let headers be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
// 2. Let headers be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
||||||
// FIXME: Pass in encoding.
|
auto headers = TRY(url_encode(pairs, encoding));
|
||||||
auto headers = TRY(url_encode(pairs, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
|
|
||||||
|
|
||||||
// 3. Replace occurrences of U+002B PLUS SIGN characters (+) in headers with the string "%20".
|
// 3. Replace occurrences of U+002B PLUS SIGN characters (+) in headers with the string "%20".
|
||||||
TRY(headers.replace("+"sv, "%20"sv, ReplaceMode::All));
|
TRY(headers.replace("+"sv, "%20"sv, ReplaceMode::All));
|
||||||
|
@ -751,8 +748,7 @@ ErrorOr<void> HTMLFormElement::mail_as_body(AK::URL parsed_action, Vector<XHR::F
|
||||||
default:
|
default:
|
||||||
// -> Otherwise
|
// -> Otherwise
|
||||||
// Let body be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
// Let body be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
||||||
// FIXME: Pass in encoding.
|
body = TRY(url_encode(pairs, encoding));
|
||||||
body = TRY(url_encode(pairs, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,7 @@ private:
|
||||||
|
|
||||||
ErrorOr<String> pick_an_encoding() const;
|
ErrorOr<String> pick_an_encoding() const;
|
||||||
|
|
||||||
ErrorOr<void> mutate_action_url(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
ErrorOr<void> mutate_action_url(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, String encoding, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
||||||
ErrorOr<void> submit_as_entity_body(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, EncodingTypeAttributeState encoding_type, String encoding, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
ErrorOr<void> submit_as_entity_body(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, EncodingTypeAttributeState encoding_type, String encoding, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
||||||
void get_action_url(AK::URL parsed_action, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
void get_action_url(AK::URL parsed_action, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
||||||
ErrorOr<void> mail_with_headers(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, String encoding, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
ErrorOr<void> mail_with_headers(AK::URL parsed_action, Vector<XHR::FormDataEntry> entry_list, String encoding, JS::NonnullGCPtr<AbstractBrowsingContext> target_navigable, HistoryHandlingBehavior history_handling);
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
* Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org>
|
||||||
|
* Copyright (c) 2023, Shannon Booth <shannon.ml.booth@gmail.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/QuickSort.h>
|
#include <AK/QuickSort.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
|
#include <AK/URLParser.h>
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
|
#include <LibTextCodec/Decoder.h>
|
||||||
#include <LibWeb/Bindings/ExceptionOrUtils.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>
|
||||||
|
@ -36,17 +39,40 @@ void URLSearchParams::visit_edges(Cell::Visitor& visitor)
|
||||||
visitor.visit(m_url);
|
visitor.visit(m_url);
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<String> url_encode(Vector<QueryParam> const& pairs, AK::URL::PercentEncodeSet percent_encode_set)
|
// https://url.spec.whatwg.org/#concept-urlencoded-serializer
|
||||||
|
// The application/x-www-form-urlencoded serializer takes a list of name-value tuples tuples, with an optional encoding encoding (default UTF-8), and then runs these steps. They return an ASCII string.
|
||||||
|
ErrorOr<String> url_encode(Vector<QueryParam> const& tuples, StringView encoding)
|
||||||
{
|
{
|
||||||
StringBuilder builder;
|
// 1. Set encoding to the result of getting an output encoding from encoding.
|
||||||
for (size_t i = 0; i < pairs.size(); ++i) {
|
encoding = TextCodec::get_output_encoding(encoding);
|
||||||
TRY(builder.try_append(AK::URL::percent_encode(pairs[i].name, percent_encode_set, AK::URL::SpaceAsPlus::Yes)));
|
|
||||||
TRY(builder.try_append('='));
|
// 2. Let output be the empty string.
|
||||||
TRY(builder.try_append(AK::URL::percent_encode(pairs[i].value, percent_encode_set, AK::URL::SpaceAsPlus::Yes)));
|
StringBuilder output;
|
||||||
if (i != pairs.size() - 1)
|
|
||||||
TRY(builder.try_append('&'));
|
// 3. For each tuple of tuples:
|
||||||
|
for (auto const& tuple : tuples) {
|
||||||
|
// 1. Assert: tuple’s name and tuple’s value are scalar value strings.
|
||||||
|
|
||||||
|
// 2. Let name be the result of running percent-encode after encoding with encoding, tuple’s name, the application/x-www-form-urlencoded percent-encode set, and true.
|
||||||
|
// FIXME: URLParser does not currently implement encoding.
|
||||||
|
auto name = AK::URLParser::percent_encode_after_encoding(tuple.name, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded, true);
|
||||||
|
|
||||||
|
// 3. Let value be the result of running percent-encode after encoding with encoding, tuple’s value, the application/x-www-form-urlencoded percent-encode set, and true.
|
||||||
|
// FIXME: URLParser does not currently implement encoding.
|
||||||
|
auto value = AK::URLParser::percent_encode_after_encoding(tuple.value, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded, true);
|
||||||
|
|
||||||
|
// 4. If output is not the empty string, then append U+0026 (&) to output.
|
||||||
|
if (!output.is_empty())
|
||||||
|
TRY(output.try_append('&'));
|
||||||
|
|
||||||
|
// 5. Append name, followed by U+003D (=), followed by value, to output.
|
||||||
|
TRY(output.try_append(name));
|
||||||
|
TRY(output.try_append('='));
|
||||||
|
TRY(output.try_append(value));
|
||||||
}
|
}
|
||||||
return builder.to_string();
|
|
||||||
|
// 4. Return output.
|
||||||
|
return output.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#concept-urlencoded-parser
|
// https://url.spec.whatwg.org/#concept-urlencoded-parser
|
||||||
|
@ -292,7 +318,7 @@ WebIDL::ExceptionOr<String> URLSearchParams::to_string() const
|
||||||
auto& vm = realm().vm();
|
auto& vm = realm().vm();
|
||||||
|
|
||||||
// return the serialization of this’s list.
|
// return the serialization of this’s list.
|
||||||
return TRY_OR_THROW_OOM(vm, url_encode(m_list, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
|
return TRY_OR_THROW_OOM(vm, url_encode(m_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::ThrowCompletionOr<void> URLSearchParams::for_each(ForEachCallback callback)
|
JS::ThrowCompletionOr<void> URLSearchParams::for_each(ForEachCallback callback)
|
||||||
|
|
|
@ -16,7 +16,7 @@ struct QueryParam {
|
||||||
String name;
|
String name;
|
||||||
String value;
|
String value;
|
||||||
};
|
};
|
||||||
ErrorOr<String> url_encode(Vector<QueryParam> const&, AK::URL::PercentEncodeSet);
|
ErrorOr<String> url_encode(Vector<QueryParam> const&, StringView encoding = "UTF-8"sv);
|
||||||
ErrorOr<Vector<QueryParam>> url_decode(StringView);
|
ErrorOr<Vector<QueryParam>> url_decode(StringView);
|
||||||
|
|
||||||
class URLSearchParams : public Bindings::PlatformObject {
|
class URLSearchParams : public Bindings::PlatformObject {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue