Quellcode durchsuchen

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

Shannon Booth vor 2 Jahren
Ursprung
Commit
55d59636ef

+ 7 - 11
Userland/Libraries/LibWeb/HTML/HTMLFormElement.cpp

@@ -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;
     }
 

+ 1 - 1
Userland/Libraries/LibWeb/HTML/HTMLFormElement.h

@@ -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);

+ 36 - 10
Userland/Libraries/LibWeb/URL/URLSearchParams.cpp

@@ -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: 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
@@ -292,7 +318,7 @@ WebIDL::ExceptionOr<String> URLSearchParams::to_string() const
     auto& vm = realm().vm();
 
     // 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)

+ 1 - 1
Userland/Libraries/LibWeb/URL/URLSearchParams.h

@@ -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 {