mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-04-21 20:15:17 +00:00
LibWeb: Use create_entry when constructing FormData entry list
When constructing an entry list, XHR::FormDataEntry is created manually and appended to the entry list instead of using the spec-defined method of creating an entry.
This commit is contained in:
parent
036327332f
commit
66bdb825c8
Notes:
github-actions[bot]
2025-02-20 03:25:57 +00:00
Author: https://github.com/AppleFlavored 🔰 Commit: https://github.com/LadybirdBrowser/ladybird/commit/66bdb825c86 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3623 Reviewed-by: https://github.com/gmta Reviewed-by: https://github.com/tcl3 ✅
3 changed files with 165 additions and 9 deletions
|
@ -121,10 +121,10 @@ WebIDL::ExceptionOr<Optional<Vector<XHR::FormDataEntry>>> construct_entry_list(J
|
|||
auto [x, y] = input_element->selected_coordinate();
|
||||
|
||||
// 6. Create an entry with namex and x, and append it to entry list.
|
||||
entry_list.append(XHR::FormDataEntry { .name = move(name_x), .value = String::number(x) });
|
||||
entry_list.append(TRY(create_entry(realm, name_x, String::number(x))));
|
||||
|
||||
// 7. Create an entry with namey and y, and append it to entry list.
|
||||
entry_list.append(XHR::FormDataEntry { .name = move(name_y), .value = String::number(y) });
|
||||
entry_list.append(TRY(create_entry(realm, name_y, String::number(y))));
|
||||
|
||||
// 8. Continue.
|
||||
continue;
|
||||
|
@ -143,7 +143,7 @@ WebIDL::ExceptionOr<Optional<Vector<XHR::FormDataEntry>>> construct_entry_list(J
|
|||
if (auto* select_element = dynamic_cast<HTML::HTMLSelectElement*>(control.ptr())) {
|
||||
for (auto const& option_element : select_element->list_of_options()) {
|
||||
if (option_element->selected() && !option_element->disabled()) {
|
||||
entry_list.append(XHR::FormDataEntry { .name = name.to_string(), .value = option_element->value() });
|
||||
entry_list.append(TRY(create_entry(realm, name.to_string(), option_element->value())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ WebIDL::ExceptionOr<Optional<Vector<XHR::FormDataEntry>>> construct_entry_list(J
|
|||
|
||||
// 2. Create an entry with name and value, and append it to entry list.
|
||||
auto checkbox_or_radio_element_name = checkbox_or_radio_element->name();
|
||||
entry_list.append(XHR::FormDataEntry { .name = checkbox_or_radio_element_name->to_string(), .value = move(value) });
|
||||
entry_list.append(TRY(create_entry(realm, checkbox_or_radio_element_name->to_string(), value)));
|
||||
}
|
||||
// 8. Otherwise, if the field element is an input element whose type attribute is in the File Upload state, then:
|
||||
else if (auto* file_element = dynamic_cast<HTML::HTMLInputElement*>(control.ptr()); file_element && file_element->type_state() == HTMLInputElement::TypeAttributeState::FileUpload) {
|
||||
|
@ -165,13 +165,13 @@ WebIDL::ExceptionOr<Optional<Vector<XHR::FormDataEntry>>> construct_entry_list(J
|
|||
FileAPI::FilePropertyBag options {};
|
||||
options.type = "application/octet-stream"_string;
|
||||
auto file = TRY(FileAPI::File::create(realm, {}, String {}, options));
|
||||
entry_list.append(XHR::FormDataEntry { .name = name.to_string(), .value = GC::make_root(file) });
|
||||
entry_list.append(TRY(create_entry(realm, name.to_string(), GC::Ref<FileAPI::Blob> { file })));
|
||||
}
|
||||
// 2. Otherwise, for each file in selected files, create an entry with name and a File object representing the file, and append it to entry list.
|
||||
else {
|
||||
for (size_t i = 0; i < file_element->files()->length(); i++) {
|
||||
auto file = GC::Ref { *file_element->files()->item(i) };
|
||||
entry_list.append(XHR::FormDataEntry { .name = name.to_string(), .value = GC::make_root(file) });
|
||||
entry_list.append(TRY(create_entry(realm, name.to_string(), GC::Ref<FileAPI::Blob> { file })));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,11 +181,11 @@ WebIDL::ExceptionOr<Optional<Vector<XHR::FormDataEntry>>> construct_entry_list(J
|
|||
auto charset = encoding.has_value() ? encoding.value() : "UTF-8"_string;
|
||||
|
||||
// 2. Create an entry with name and charset, and append it to entry list.
|
||||
entry_list.append(XHR::FormDataEntry { .name = name.to_string(), .value = move(charset) });
|
||||
entry_list.append(TRY(create_entry(realm, name.to_string(), charset)));
|
||||
}
|
||||
// 10. Otherwise, create an entry with name and the value of the field element, and append it to entry list.
|
||||
else {
|
||||
entry_list.append(XHR::FormDataEntry { .name = name.to_string(), .value = control_as_form_associated_element->value() });
|
||||
entry_list.append(TRY(create_entry(realm, name.to_string(), control_as_form_associated_element->value())));
|
||||
}
|
||||
|
||||
// 11. If the element has a dirname attribute, and that attribute's value is not the empty string, then:
|
||||
|
@ -197,7 +197,7 @@ WebIDL::ExceptionOr<Optional<Vector<XHR::FormDataEntry>>> construct_entry_list(J
|
|||
String dir = MUST((control->directionality() == DOM::Element::Directionality::Ltr) ? String::from_utf8("ltr"sv) : String::from_utf8("rtl"sv));
|
||||
|
||||
// 3. Create an entry with dirname and dir, and append it to entry list.
|
||||
entry_list.append(XHR::FormDataEntry { .name = dirname, .value = dir });
|
||||
entry_list.append(TRY(create_entry(realm, dirname, dir)));
|
||||
}
|
||||
}
|
||||
// 6. Let form data be a new FormData object associated with entry list.
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 1 tests
|
||||
|
||||
1 Pass
|
||||
Pass test that FormData is correctly constructed from the form data set
|
|
@ -0,0 +1,150 @@
|
|||
<!DOCTYPE html>
|
||||
<title>FormData: constructor (with form element)</title>
|
||||
<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
|
||||
<link rel="help" href="https://xhr.spec.whatwg.org/#dom-formdata">
|
||||
<link rel="help" href="https://html.spec.whatwg.org/multipage/#constructing-form-data-set">
|
||||
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
|
||||
<form>
|
||||
<output name="do-not-submit-me-1"></output>
|
||||
|
||||
<datalist>
|
||||
<input type="text" name="do-not-submit-me-2" value="bad">
|
||||
<select name="do-not-submit-me-3">
|
||||
<option value="bad" selected></option>
|
||||
</select>
|
||||
<input type="checkbox" name="do-not-submit-me-4" checked>
|
||||
</datalist>
|
||||
|
||||
<input type="text" name="do-not-submit-me-5" disabled value="bad">
|
||||
<fieldset disabled>
|
||||
<input type="text" name="do-not-submit-me-6" value="bad">
|
||||
</fieldset>
|
||||
|
||||
<button name="do-not-submit-me-7">bad</button>
|
||||
<input type="submit" name="do-not-submit-me-8" value="bad">
|
||||
<input type="reset" name="do-not-submit-me-9" value="bad">
|
||||
<input type="image" name="do-not-submit-me-10" value="bad">
|
||||
|
||||
<input type="checkbox" name="do-not-submit-me-11">
|
||||
<input type="radio" name="do-not-submit-me-12">
|
||||
|
||||
<input type="text" value="do-not-submit-me-13">
|
||||
<input type="text" name="" value="do-not-submit-me-14">
|
||||
|
||||
<object name="do-not-submit-me-15"></object>
|
||||
|
||||
<select name="select-1">
|
||||
<option disabled value="do-not-submit-me-16"></option>
|
||||
<option value="do-not-submit-me-17"></option>
|
||||
<option disabled value="do-not-submit-me-18" selected></option>
|
||||
</select>
|
||||
|
||||
<select name="select-2">
|
||||
<option value="do-not-submit-me-19"></option>
|
||||
<option value="submit-me-1" selected></option>
|
||||
</select>
|
||||
|
||||
<select name="select-3" multiple>
|
||||
<option value="do-not-submit-me-20"></option>
|
||||
<option value="submit-me-2" selected></option>
|
||||
<option value="do-not-submit-me-21"></option>
|
||||
<option value="submit-me-3" selected></option>
|
||||
</select>
|
||||
|
||||
<input type="checkbox" name="submit-me-4" value="checkbox-1" checked>
|
||||
<input type="checkbox" name="submit-me-5" checked>
|
||||
|
||||
<input type="radio" name="submit-me-6" value="radio-1" checked>
|
||||
<input type="radio" name="submit-me-7" checked>
|
||||
|
||||
<!-- not tested: <input type="file"> with selected files -->
|
||||
|
||||
<input type="file" name="file-1">
|
||||
|
||||
<!-- not tested: <object>s that allow form submission -->
|
||||
|
||||
<input type="text" name="submit-me-8" value="text-1">
|
||||
<input type="text" name="submit-me-8" value="text-2">
|
||||
<input type="search" name="submit-me-9" value="search-1">
|
||||
<input type="url" name="submit-me-10" value="url-1">
|
||||
<input type="hidden" name="submit-me-11" value="hidden-1">
|
||||
<input type="password" name="submit-me-12" value="password-1">
|
||||
<input type="number" name="submit-me-13" value="11">
|
||||
<input type="range" name="submit-me-14" value="11">
|
||||
<input type="color" name="submit-me-15" value="#123456">
|
||||
|
||||
<textarea name="submit-me-16">textarea value
|
||||
with linebreaks set to LF</textarea>
|
||||
|
||||
<!-- this generates two form data entries! -->
|
||||
<input type="text" name="dirname-is-special" dirname="submit-me-17" value="dirname-value">
|
||||
|
||||
<input type="text" name="submit-me-21">
|
||||
</form>
|
||||
|
||||
<script>
|
||||
"use strict";
|
||||
|
||||
test(() => {
|
||||
|
||||
const form = document.querySelector("form");
|
||||
|
||||
const input = document.createElement("input");
|
||||
input.name = "submit-me-18-\uDC01";
|
||||
input.value = "value-\uDC01";
|
||||
assert_equals(input.name, "submit-me-18-\uDC01", "input.name accepts unpaired surrogates");
|
||||
assert_equals(input.value, "value-\uDC01", "input.value accepts unpaired surrogates");
|
||||
form.appendChild(input);
|
||||
|
||||
const input2 = document.createElement("input");
|
||||
input2.name = "submit-me-\r19\n";
|
||||
input2.value = "value\n\r";
|
||||
assert_equals(input2.name, "submit-me-\r19\n", "input.name accepts \\r and \\n");
|
||||
assert_equals(input2.value, "value", "input.value when type=text should not contain newlines");
|
||||
form.appendChild(input2);
|
||||
|
||||
const formData = new FormData(form);
|
||||
|
||||
const expected = [
|
||||
["select-2", "submit-me-1"],
|
||||
["select-3", ["submit-me-2", "submit-me-3"]],
|
||||
["submit-me-4", "checkbox-1"],
|
||||
["submit-me-5", "on"],
|
||||
["submit-me-6", "radio-1"],
|
||||
["submit-me-7", "on"],
|
||||
["submit-me-8", ["text-1", "text-2"]],
|
||||
["submit-me-9", "search-1"],
|
||||
["submit-me-10", "url-1"],
|
||||
["submit-me-11", "hidden-1"],
|
||||
["submit-me-12", "password-1"],
|
||||
["submit-me-13", "11"],
|
||||
["submit-me-14", "11"],
|
||||
["submit-me-15", "#123456"],
|
||||
["submit-me-16", "textarea value\nwith linebreaks set to LF"],
|
||||
["dirname-is-special", "dirname-value"],
|
||||
["submit-me-17", "ltr"],
|
||||
["submit-me-18-\uFFFD", "value-\uFFFD"],
|
||||
["submit-me-\r19\n", "value"],
|
||||
["submit-me-21", ""]
|
||||
];
|
||||
|
||||
for (const t of expected) {
|
||||
const field = t[0];
|
||||
const valueOrValues = t[1];
|
||||
const values = Array.isArray(valueOrValues) ? valueOrValues : [valueOrValues];
|
||||
assert_array_equals(formData.getAll(field), values, field);
|
||||
}
|
||||
|
||||
const fileEntry = formData.getAll("file-1");
|
||||
assert_equals(fileEntry.length, 1);
|
||||
assert_equals(fileEntry[0], formData.get("file-1"));
|
||||
assert_equals(fileEntry[0].constructor, File);
|
||||
assert_equals(fileEntry[0].size, 0);
|
||||
assert_equals(fileEntry[0].name, "");
|
||||
assert_equals(fileEntry[0].type, "application/octet-stream");
|
||||
|
||||
}, "test that FormData is correctly constructed from the form data set");
|
||||
</script>
|
Loading…
Add table
Reference in a new issue