1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-05-31 13:38:11 +00:00

LibWeb: Implement Web::URL::url_encode closer to spec

This commit is contained in:
Shannon Booth 2023-06-25 14:15:24 +12:00 committed by Andreas Kling
parent 799c79cc5a
commit 55d59636ef
4 changed files with 45 additions and 23 deletions

View file

@ -233,14 +233,14 @@ WebIDL::ExceptionOr<void> HTMLFormElement::submit_form(JS::NonnullGCPtr<HTMLElem
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), *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
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)) {
get_action_url(move(parsed_action), *target_navigable, history_handling);
} else if (scheme == "data"sv) {
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
get_action_url(move(parsed_action), *target_navigable, history_handling);
} 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
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.
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.
// FIXME: Pass in encoding.
auto query = TRY(url_encode(pairs, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
auto query = TRY(url_encode(pairs, encoding));
// 3. Set parsed action's query component to query.
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));
// 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, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded)).bytes()));
body = TRY(ByteBuffer::copy(TRY(url_encode(pairs, encoding)).bytes()));
// 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.
@ -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));
// 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, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
auto headers = TRY(url_encode(pairs, encoding));
// 3. Replace occurrences of U+002B PLUS SIGN characters (+) in headers with the string "%20".
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:
// -> Otherwise
// 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, AK::URL::PercentEncodeSet::ApplicationXWWWFormUrlencoded));
body = TRY(url_encode(pairs, encoding));
break;
}

View file

@ -96,7 +96,7 @@ private:
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);
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);

View file

@ -1,12 +1,15 @@
/*
* 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
*/
#include <AK/QuickSort.h>
#include <AK/StringBuilder.h>
#include <AK/URLParser.h>
#include <AK/Utf8View.h>
#include <LibTextCodec/Decoder.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/URL/URL.h>
@ -36,17 +39,40 @@ void URLSearchParams::visit_edges(Cell::Visitor& visitor)
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;
for (size_t i = 0; i < pairs.size(); ++i) {
TRY(builder.try_append(AK::URL::percent_encode(pairs[i].name, percent_encode_set, AK::URL::SpaceAsPlus::Yes)));
TRY(builder.try_append('='));
TRY(builder.try_append(AK::URL::percent_encode(pairs[i].value, percent_encode_set, AK::URL::SpaceAsPlus::Yes)));
if (i != pairs.size() - 1)
TRY(builder.try_append('&'));
// 1. Set encoding to the result of getting an output encoding from encoding.
encoding = TextCodec::get_output_encoding(encoding);
// 2. Let output be the empty string.
StringBuilder output;
// 3. For each tuple of tuples:
for (auto const& tuple : tuples) {
// 1. Assert: tuples name and tuples value are scalar value strings.
// 2. Let name be the result of running percent-encode after encoding with encoding, tuples 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, tuples 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
@ -292,7 +318,7 @@ WebIDL::ExceptionOr<String> URLSearchParams::to_string() const
auto& vm = realm().vm();
// return the serialization of thiss 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)

View file

@ -16,7 +16,7 @@ struct QueryParam {
String name;
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);
class URLSearchParams : public Bindings::PlatformObject {