mirror of
https://github.com/servo/servo
synced 2026-04-27 09:57:23 +02:00
script: Fix last remaining base element test (#42339)
This was the last failure in this directory. To fix it, I had to spelunk into a couple of places: 1. We shouldn't use the `base_element()` of the document, but select the first base element, regardless if it has an empty href or not 2. We didn't implement target checking for elements. Only some values are valid and an empty target (which the test also confusingly uses) is not valid. Hence, it should fallback to the base element 3. We weren't sanitizing the value in case it contains an ASCII tab or newline + U+003C. This is true for both the form target as well as for other link elements. All in all, added a lot more specification text to figure out what was going on. Signed-off-by: Tim van der Lippe <tvanderlippe@gmail.com>
This commit is contained in:
committed by
GitHub
parent
c6fbaf33e2
commit
cb37480071
@@ -83,7 +83,7 @@ use crate::dom::submitevent::SubmitEvent;
|
||||
use crate::dom::types::HTMLIFrameElement;
|
||||
use crate::dom::virtualmethods::VirtualMethods;
|
||||
use crate::dom::window::Window;
|
||||
use crate::links::{LinkRelations, get_element_target};
|
||||
use crate::links::{LinkRelations, get_element_target, valid_navigable_target_name_or_keyword};
|
||||
use crate::script_runtime::CanGc;
|
||||
use crate::script_thread::ScriptThread;
|
||||
|
||||
@@ -817,59 +817,73 @@ impl HTMLFormElement {
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Step 9
|
||||
// Step 9. If form cannot navigate, then return.
|
||||
if self.upcast::<Element>().cannot_navigate() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 10
|
||||
// Step 10. Let method be the submitter element's method.
|
||||
let method = submitter.method();
|
||||
// Step 11. If method is dialog, then:
|
||||
// TODO
|
||||
|
||||
// Step 12. Let action be the submitter element's action.
|
||||
let mut action = submitter.action();
|
||||
|
||||
// Step 11
|
||||
// Step 13. If action is the empty string, let action be the URL of the form document.
|
||||
if action.is_empty() {
|
||||
action = DOMString::from(base.as_str());
|
||||
}
|
||||
// Step 12-13
|
||||
// Step 14. Let parsed action be the result of encoding-parsing a URL given action, relative to submitter's node document.
|
||||
let action_components = match base.join(&action.str()) {
|
||||
Ok(url) => url,
|
||||
// Step 15. If parsed action is failure, then return.
|
||||
Err(_) => return,
|
||||
};
|
||||
// Step 14-16
|
||||
// Step 16. Let scheme be the scheme of parsed action.
|
||||
let scheme = action_components.scheme().to_owned();
|
||||
// Step 17. Let enctype be the submitter element's enctype.
|
||||
let enctype = submitter.enctype();
|
||||
let method = submitter.method();
|
||||
|
||||
// Step 17
|
||||
let target_attribute_value =
|
||||
if submitter.is_submit_button() && submitter.target() != DOMString::new() {
|
||||
Some(submitter.target())
|
||||
} else {
|
||||
let form_owner = submitter.form_owner();
|
||||
let form = form_owner.as_deref().unwrap_or(self);
|
||||
get_element_target(form.upcast::<Element>())
|
||||
};
|
||||
|
||||
// Step 18
|
||||
let noopener = self
|
||||
.relations
|
||||
.get()
|
||||
.get_element_noopener(target_attribute_value.as_ref());
|
||||
|
||||
// Step 19
|
||||
let source = doc.browsing_context().unwrap();
|
||||
let (maybe_chosen, _new) = source
|
||||
.choose_browsing_context(target_attribute_value.unwrap_or(DOMString::new()), noopener);
|
||||
|
||||
// Step 20
|
||||
let chosen = match maybe_chosen {
|
||||
Some(proxy) => proxy,
|
||||
None => return,
|
||||
// Step 19. If the submitter element is a submit button and it has a formtarget attribute,
|
||||
// then set formTarget to the formtarget attribute value.
|
||||
let form_target_attribute = submitter.target();
|
||||
let form_target = if submitter.is_submit_button() &&
|
||||
valid_navigable_target_name_or_keyword(&form_target_attribute)
|
||||
{
|
||||
Some(form_target_attribute)
|
||||
} else {
|
||||
// Step 18. Let formTarget be null.
|
||||
None
|
||||
};
|
||||
// Step 20. Let target be the result of getting an element's target given submitter's form owner and formTarget.
|
||||
let form_owner = submitter.form_owner();
|
||||
let form = form_owner.as_deref().unwrap_or(self);
|
||||
let target = get_element_target(form.upcast::<Element>(), form_target);
|
||||
|
||||
// Step 21. Let noopener be the result of getting an element's noopener with form, parsed action, and target.
|
||||
let noopener = self.relations.get().get_element_noopener(target.as_ref());
|
||||
|
||||
// Step 22. Let targetNavigable be the first return value of applying the rules for choosing a navigable given target,
|
||||
// form's node navigable, and noopener.
|
||||
let source = doc.browsing_context().unwrap();
|
||||
let (maybe_chosen, _new) =
|
||||
source.choose_browsing_context(target.unwrap_or_default(), noopener);
|
||||
|
||||
let Some(chosen) = maybe_chosen else {
|
||||
// Step 23. If targetNavigable is null, then return.
|
||||
return;
|
||||
};
|
||||
// Step 24. Let historyHandling be "auto".
|
||||
// TODO
|
||||
// Step 25. If form document equals targetNavigable's active document, and form document has not yet completely loaded,
|
||||
// then set historyHandling to "replace".
|
||||
// TODO
|
||||
|
||||
let target_document = match chosen.document() {
|
||||
Some(doc) => doc,
|
||||
None => return,
|
||||
};
|
||||
// Step 21
|
||||
let target_window = target_document.window();
|
||||
let mut load_data = LoadData::new(
|
||||
LoadOrigin::Script(doc.origin().snapshot()),
|
||||
@@ -884,7 +898,9 @@ impl HTMLFormElement {
|
||||
target_document.creation_sandboxing_flag_set_considering_parent_iframe(),
|
||||
);
|
||||
|
||||
// Step 22
|
||||
// Step 26. Select the appropriate row in the table below based on scheme as given by the first cell of each row.
|
||||
// Then, select the appropriate cell on that row based on method as given in the first cell of each column.
|
||||
// Then, jump to the steps named in that cell and defined below the table.
|
||||
match (&*scheme, method) {
|
||||
(_, FormMethod::Dialog) => {
|
||||
// TODO: Submit dialog
|
||||
|
||||
Reference in New Issue
Block a user