mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-01 05:39:11 +00:00
LibWeb: Don't propogate small OOMs from URLSearchParams
Made easier now that URL percent encode after encoding is also not throwing any errors. This simplfies a bunch of error handling.
This commit is contained in:
parent
4bb211ba88
commit
df4739d7ce
Notes:
github-actions[bot]
2024-08-12 22:02:35 +00:00
Author: https://github.com/shannonbooth
Commit: df4739d7ce
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1033
Reviewed-by: https://github.com/tcl3 ✅
7 changed files with 59 additions and 77 deletions
|
@ -59,7 +59,7 @@ JS::NonnullGCPtr<DOMURL> DOMURL::initialize_a_url(JS::Realm& realm, URL::URL con
|
|||
|
||||
// 2. Set url’s URL to urlRecord.
|
||||
// 3. Set url’s query object to a new URLSearchParams object.
|
||||
auto query_object = MUST(URLSearchParams::create(realm, query));
|
||||
auto query_object = URLSearchParams::create(realm, query);
|
||||
|
||||
// 4. Initialize url’s query object with query.
|
||||
auto result_url = DOMURL::create(realm, url_record, move(query_object));
|
||||
|
@ -190,8 +190,6 @@ WebIDL::ExceptionOr<String> DOMURL::to_json() const
|
|||
// https://url.spec.whatwg.org/#ref-for-dom-url-href②
|
||||
WebIDL::ExceptionOr<void> DOMURL::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.
|
||||
URL::URL parsed_url = href;
|
||||
|
||||
|
@ -210,7 +208,7 @@ WebIDL::ExceptionOr<void> DOMURL::set_href(String const& href)
|
|||
|
||||
// 6. If query is non-null, then set this’s query object’s list to the result of parsing query.
|
||||
if (query.has_value())
|
||||
m_query->m_list = TRY_OR_THROW_OOM(vm, url_decode(*query));
|
||||
m_query->m_list = url_decode(*query);
|
||||
return {};
|
||||
}
|
||||
|
||||
|
@ -411,10 +409,8 @@ WebIDL::ExceptionOr<String> DOMURL::search() const
|
|||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#ref-for-dom-url-search%E2%91%A0
|
||||
WebIDL::ExceptionOr<void> DOMURL::set_search(String const& search)
|
||||
void DOMURL::set_search(String const& search)
|
||||
{
|
||||
auto& vm = realm().vm();
|
||||
|
||||
// 1. Let url be this’s URL.
|
||||
auto& url = m_url;
|
||||
|
||||
|
@ -430,7 +426,7 @@ WebIDL::ExceptionOr<void> DOMURL::set_search(String const& search)
|
|||
strip_trailing_spaces_from_an_opaque_path(*this);
|
||||
|
||||
// 4. Return.
|
||||
return {};
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Let input be the given value with a single leading U+003F (?) removed, if any.
|
||||
|
@ -447,10 +443,8 @@ WebIDL::ExceptionOr<void> DOMURL::set_search(String const& search)
|
|||
m_url = move(result_url);
|
||||
|
||||
// 6. Set this’s query object’s list to the result of parsing input.
|
||||
m_query->m_list = TRY_OR_THROW_OOM(vm, url_decode(input));
|
||||
m_query->m_list = url_decode(input);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#dom-url-searchparams
|
||||
|
|
|
@ -68,7 +68,7 @@ public:
|
|||
bool cannot_be_a_base_url() const { return m_url.cannot_be_a_base_url(); }
|
||||
|
||||
WebIDL::ExceptionOr<String> search() const;
|
||||
WebIDL::ExceptionOr<void> set_search(String const&);
|
||||
void set_search(String const&);
|
||||
|
||||
JS::NonnullGCPtr<URLSearchParams const> search_params() const;
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ void URLSearchParams::visit_edges(Cell::Visitor& visitor)
|
|||
|
||||
// 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)
|
||||
String url_encode(Vector<QueryParam> const& tuples, StringView encoding)
|
||||
{
|
||||
// 1. Set encoding to the result of getting an output encoding from encoding.
|
||||
encoding = TextCodec::get_output_encoding(encoding);
|
||||
|
@ -69,21 +69,21 @@ ErrorOr<String> url_encode(Vector<QueryParam> const& tuples, StringView encoding
|
|||
|
||||
// 4. If output is not the empty string, then append U+0026 (&) to output.
|
||||
if (!output.is_empty())
|
||||
TRY(output.try_append('&'));
|
||||
output.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));
|
||||
output.append(name);
|
||||
output.append('=');
|
||||
output.append(value);
|
||||
}
|
||||
|
||||
// 4. Return output.
|
||||
return output.to_string();
|
||||
return MUST(output.to_string());
|
||||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#concept-urlencoded-parser
|
||||
// The application/x-www-form-urlencoded parser takes a byte sequence input, and then runs these steps:
|
||||
ErrorOr<Vector<QueryParam>> url_decode(StringView input)
|
||||
Vector<QueryParam> url_decode(StringView input)
|
||||
{
|
||||
// 1. Let sequences be the result of splitting input on 0x26 (&).
|
||||
auto sequences = input.split_view('&');
|
||||
|
@ -119,23 +119,23 @@ ErrorOr<Vector<QueryParam>> url_decode(StringView input)
|
|||
auto name_string = String::from_utf8_with_replacement_character(URL::percent_decode(space_decoded_name), String::WithBOMHandling::No);
|
||||
auto value_string = String::from_utf8_with_replacement_character(URL::percent_decode(space_decoded_value), String::WithBOMHandling::No);
|
||||
|
||||
TRY(output.try_empend(move(name_string), move(value_string)));
|
||||
output.empend(move(name_string), move(value_string));
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::create(JS::Realm& realm, Vector<QueryParam> list)
|
||||
JS::NonnullGCPtr<URLSearchParams> URLSearchParams::create(JS::Realm& realm, Vector<QueryParam> list)
|
||||
{
|
||||
return realm.heap().allocate<URLSearchParams>(realm, realm, move(list));
|
||||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#urlsearchparams-initialize
|
||||
WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> URLSearchParams::create(JS::Realm& realm, StringView init)
|
||||
JS::NonnullGCPtr<URLSearchParams> URLSearchParams::create(JS::Realm& realm, StringView init)
|
||||
{
|
||||
// NOTE: We skip the other steps since we know it is a string at this point.
|
||||
// b. Set query’s list to the result of parsing init.
|
||||
return URLSearchParams::create(realm, MUST(url_decode(init)));
|
||||
return URLSearchParams::create(realm, url_decode(init));
|
||||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#dom-urlsearchparams-urlsearchparams
|
||||
|
@ -203,36 +203,35 @@ size_t URLSearchParams::size() const
|
|||
return m_list.size();
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> URLSearchParams::append(String const& name, String const& value)
|
||||
// https://url.spec.whatwg.org/#dom-urlsearchparams-append
|
||||
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.
|
||||
TRY_OR_THROW_OOM(vm, m_list.try_empend(name, value));
|
||||
// 2. Update this.
|
||||
TRY(update());
|
||||
m_list.empend(name, value);
|
||||
|
||||
return {};
|
||||
// 2. Update this.
|
||||
update();
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> URLSearchParams::update()
|
||||
void URLSearchParams::update()
|
||||
{
|
||||
// 1. If query’s URL object is null, then return.
|
||||
if (!m_url)
|
||||
return {};
|
||||
return;
|
||||
|
||||
// 2. Let serializedQuery be the serialization of query’s list.
|
||||
auto serialized_query = TRY(to_string());
|
||||
auto serialized_query = to_string();
|
||||
|
||||
// 3. If serializedQuery is the empty string, then set serializedQuery to null.
|
||||
if (serialized_query.is_empty())
|
||||
serialized_query = {};
|
||||
|
||||
// 4. Set query’s URL object’s URL’s query to serializedQuery.
|
||||
m_url->set_query({}, move(serialized_query));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#dom-urlsearchparams-delete
|
||||
WebIDL::ExceptionOr<void> URLSearchParams::delete_(String const& name, Optional<String> const& value)
|
||||
void URLSearchParams::delete_(String const& name, Optional<String> const& value)
|
||||
{
|
||||
// 1. If value is given, then remove all tuples whose name is name and value is value from this’s list.
|
||||
if (value.has_value()) {
|
||||
|
@ -248,9 +247,7 @@ WebIDL::ExceptionOr<void> URLSearchParams::delete_(String const& name, Optional<
|
|||
}
|
||||
|
||||
// 2. Update this.
|
||||
TRY(update());
|
||||
|
||||
return {};
|
||||
update();
|
||||
}
|
||||
|
||||
Optional<String> URLSearchParams::get(String const& name)
|
||||
|
@ -265,15 +262,13 @@ Optional<String> URLSearchParams::get(String const& name)
|
|||
}
|
||||
|
||||
// https://url.spec.whatwg.org/#dom-urlsearchparams-getall
|
||||
WebIDL::ExceptionOr<Vector<String>> URLSearchParams::get_all(String const& name)
|
||||
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.
|
||||
Vector<String> values;
|
||||
for (auto& entry : m_list) {
|
||||
if (entry.name == name)
|
||||
TRY_OR_THROW_OOM(vm, values.try_append(entry.value));
|
||||
values.append(entry.value);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
@ -304,10 +299,8 @@ bool URLSearchParams::has(String const& name, Optional<String> const& value)
|
|||
return false;
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> URLSearchParams::set(String const& name, String const& value)
|
||||
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.
|
||||
auto existing = m_list.find_if([&name](auto& entry) {
|
||||
return entry.name == name;
|
||||
|
@ -320,15 +313,14 @@ WebIDL::ExceptionOr<void> URLSearchParams::set(String const& name, String const&
|
|||
}
|
||||
// 2. Otherwise, append a new name-value pair whose name is name and value is value, to this’s list.
|
||||
else {
|
||||
TRY_OR_THROW_OOM(vm, m_list.try_empend(name, value));
|
||||
m_list.empend(name, value);
|
||||
}
|
||||
|
||||
// 3. Update this.
|
||||
TRY(update());
|
||||
|
||||
return {};
|
||||
update();
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<void> URLSearchParams::sort()
|
||||
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.
|
||||
quick_sort(m_list.begin(), m_list.end(), [](auto& a, auto& b) {
|
||||
|
@ -349,18 +341,15 @@ WebIDL::ExceptionOr<void> URLSearchParams::sort()
|
|||
}
|
||||
VERIFY_NOT_REACHED();
|
||||
});
|
||||
// 2. Update this.
|
||||
TRY(update());
|
||||
|
||||
return {};
|
||||
// 2. Update this.
|
||||
update();
|
||||
}
|
||||
|
||||
WebIDL::ExceptionOr<String> URLSearchParams::to_string() const
|
||||
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));
|
||||
return url_encode(m_list);
|
||||
}
|
||||
|
||||
JS::ThrowCompletionOr<void> URLSearchParams::for_each(ForEachCallback callback)
|
||||
|
|
|
@ -16,31 +16,31 @@ struct QueryParam {
|
|||
String name;
|
||||
String value;
|
||||
};
|
||||
ErrorOr<String> url_encode(Vector<QueryParam> const&, StringView encoding = "UTF-8"sv);
|
||||
ErrorOr<Vector<QueryParam>> url_decode(StringView);
|
||||
String url_encode(Vector<QueryParam> const&, StringView encoding = "UTF-8"sv);
|
||||
Vector<QueryParam> url_decode(StringView);
|
||||
|
||||
class URLSearchParams : public Bindings::PlatformObject {
|
||||
WEB_PLATFORM_OBJECT(URLSearchParams, Bindings::PlatformObject);
|
||||
JS_DECLARE_ALLOCATOR(URLSearchParams);
|
||||
|
||||
public:
|
||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> create(JS::Realm&, StringView);
|
||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> create(JS::Realm&, Vector<QueryParam> list);
|
||||
static JS::NonnullGCPtr<URLSearchParams> create(JS::Realm&, StringView);
|
||||
static JS::NonnullGCPtr<URLSearchParams> create(JS::Realm&, Vector<QueryParam> list);
|
||||
static WebIDL::ExceptionOr<JS::NonnullGCPtr<URLSearchParams>> construct_impl(JS::Realm&, Variant<Vector<Vector<String>>, OrderedHashMap<String, String>, String> const& init);
|
||||
|
||||
virtual ~URLSearchParams() override;
|
||||
|
||||
size_t size() const;
|
||||
WebIDL::ExceptionOr<void> append(String const& name, String const& value);
|
||||
WebIDL::ExceptionOr<void> delete_(String const& name, Optional<String> const& value = {});
|
||||
void append(String const& name, String const& value);
|
||||
void delete_(String const& name, Optional<String> const& value = {});
|
||||
Optional<String> get(String const& name);
|
||||
WebIDL::ExceptionOr<Vector<String>> get_all(String const& name);
|
||||
Vector<String> get_all(String const& name);
|
||||
bool has(String const& name, Optional<String> const& value = {});
|
||||
WebIDL::ExceptionOr<void> set(String const& name, String const& value);
|
||||
void set(String const& name, String const& value);
|
||||
|
||||
WebIDL::ExceptionOr<void> sort();
|
||||
void sort();
|
||||
|
||||
WebIDL::ExceptionOr<String> to_string() const;
|
||||
String to_string() const;
|
||||
|
||||
using ForEachCallback = Function<JS::ThrowCompletionOr<void>(String const&, String const&)>;
|
||||
JS::ThrowCompletionOr<void> for_each(ForEachCallback);
|
||||
|
@ -54,7 +54,7 @@ private:
|
|||
virtual void initialize(JS::Realm&) override;
|
||||
virtual void visit_edges(Cell::Visitor&) override;
|
||||
|
||||
WebIDL::ExceptionOr<void> update();
|
||||
void update();
|
||||
|
||||
Vector<QueryParam> m_list;
|
||||
JS::GCPtr<DOMURL> m_url;
|
||||
|
|
|
@ -149,11 +149,10 @@ WebIDL::ExceptionOr<JS::Value> package_data(JS::Realm& realm, ByteBuffer bytes,
|
|||
auto entries = DOMURL::url_decode(StringView { bytes });
|
||||
|
||||
// 2. If entries is failure, then throw a TypeError.
|
||||
if (entries.is_error())
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, entries.error().string_literal() };
|
||||
// FIXME: Spec bug? It doesn't seem possible to throw an error here.
|
||||
|
||||
// 3. Return a new FormData object whose entry list is entries.
|
||||
return TRY(XHR::FormData::create(realm, entries.release_value()));
|
||||
return TRY(XHR::FormData::create(realm, entries));
|
||||
}
|
||||
// Otherwise, throw a TypeError.
|
||||
else {
|
||||
|
|
|
@ -108,7 +108,7 @@ WebIDL::ExceptionOr<Infrastructure::BodyWithType> extract_body(JS::Realm& realm,
|
|||
},
|
||||
[&](JS::Handle<DOMURL::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.
|
||||
auto search_params_string = TRY(url_search_params->to_string());
|
||||
auto search_params_string = url_search_params->to_string();
|
||||
source = MUST(ByteBuffer::copy(search_params_string.bytes()));
|
||||
// Set type to `application/x-www-form-urlencoded;charset=UTF-8`.
|
||||
type = MUST(ByteBuffer::copy("application/x-www-form-urlencoded;charset=UTF-8"sv.bytes()));
|
||||
|
|
|
@ -731,7 +731,7 @@ ErrorOr<void> HTMLFormElement::mutate_action_url(URL::URL parsed_action, Vector<
|
|||
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.
|
||||
auto query = TRY(url_encode(pairs, encoding));
|
||||
auto query = url_encode(pairs, encoding);
|
||||
|
||||
// 3. Set parsed action's query component to query.
|
||||
parsed_action.set_query(query);
|
||||
|
@ -757,7 +757,7 @@ ErrorOr<void> HTMLFormElement::submit_as_entity_body(URL::URL parsed_action, Vec
|
|||
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.
|
||||
body = TRY(ByteBuffer::copy(TRY(url_encode(pairs, encoding)).bytes()));
|
||||
body = TRY(ByteBuffer::copy(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.
|
||||
|
@ -815,7 +815,7 @@ ErrorOr<void> HTMLFormElement::mail_with_headers(URL::URL parsed_action, Vector<
|
|||
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.
|
||||
auto headers = TRY(url_encode(pairs, encoding));
|
||||
auto headers = 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));
|
||||
|
@ -851,7 +851,7 @@ ErrorOr<void> HTMLFormElement::mail_as_body(URL::URL parsed_action, Vector<XHR::
|
|||
default:
|
||||
// -> Otherwise
|
||||
// Let body be the result of running the application/x-www-form-urlencoded serializer with pairs and encoding.
|
||||
body = TRY(url_encode(pairs, encoding));
|
||||
body = url_encode(pairs, encoding);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue