mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 09:35:59 -04:00
Merge pull request #2279 from navidemad/fix-a20-form-attrs-on-submitter
forms: honor formaction / formmethod / formenctype on submit button
This commit is contained in:
@@ -3753,7 +3753,16 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For
|
||||
const arena = try self._session.getArena(.medium, "submitForm");
|
||||
errdefer self._session.releaseArena(arena);
|
||||
|
||||
const enctype = form_element.getAttributeSafe(comptime .wrap("enctype"));
|
||||
// Per HTML spec form-submission algorithm, when the submitter is a submit
|
||||
// button, its formaction/formmethod/formenctype attributes override the
|
||||
// form's corresponding attributes (matching how formtarget is honored above).
|
||||
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-submit
|
||||
const enctype = blk: {
|
||||
if (submitter_) |s| {
|
||||
if (s.getAttributeSafe(comptime .wrap("formenctype"))) |fe| break :blk fe;
|
||||
}
|
||||
break :blk form_element.getAttributeSafe(comptime .wrap("enctype"));
|
||||
};
|
||||
|
||||
// Get charset from accept-charset attribute or fall back to document charset
|
||||
const charset: []const u8 = blk: {
|
||||
@@ -3770,8 +3779,18 @@ pub fn submitForm(self: *Frame, submitter_: ?*Element, form_: ?*Element.Html.For
|
||||
var buf = std.Io.Writer.Allocating.init(arena);
|
||||
try form_data.write(.{ .enctype = enctype, .charset = charset, .allocator = arena }, &buf.writer);
|
||||
|
||||
const method = form_element.getAttributeSafe(comptime .wrap("method")) orelse "";
|
||||
var action = form_element.getAttributeSafe(comptime .wrap("action")) orelse self.url;
|
||||
const method = blk: {
|
||||
if (submitter_) |s| {
|
||||
if (s.getAttributeSafe(comptime .wrap("formmethod"))) |fm| break :blk fm;
|
||||
}
|
||||
break :blk form_element.getAttributeSafe(comptime .wrap("method")) orelse "";
|
||||
};
|
||||
var action = blk: {
|
||||
if (submitter_) |s| {
|
||||
if (s.getAttributeSafe(comptime .wrap("formaction"))) |fa| break :blk fa;
|
||||
}
|
||||
break :blk form_element.getAttributeSafe(comptime .wrap("action")) orelse self.url;
|
||||
};
|
||||
|
||||
var opts = NavigateOpts{
|
||||
.reason = .form,
|
||||
|
||||
@@ -56,3 +56,73 @@
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Per HTML spec, formaction on the submit button overrides the form's action.
|
||||
https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-submit -->
|
||||
<iframe name=frame4 id=f4></iframe>
|
||||
<form target="frame4" action="support/should-not-load.html">
|
||||
<input type=submit id=submit_formaction formaction="support/page.html">
|
||||
</form>
|
||||
|
||||
<script id=formaction type=module>
|
||||
{
|
||||
const state = await testing.async();
|
||||
$('#submit_formaction').click();
|
||||
$('#f4').onload = () => {
|
||||
state.resolve();
|
||||
};
|
||||
|
||||
await state.done(() => {
|
||||
testing.expectEqual('a-page\n', $('#f4').contentDocument.body.textContent);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Per HTML spec, formmethod on the submit button overrides the form's method.
|
||||
A form with method=GET would append the FormData as ?x=probe to the action;
|
||||
formmethod=POST should suppress that and send the values in the request body.
|
||||
We verify the override by asserting the loaded iframe URL has no query string. -->
|
||||
<iframe name=frame5 id=f5></iframe>
|
||||
<form target="frame5" method="GET" action="support/page.html">
|
||||
<input name="x" value="probe">
|
||||
<input type=submit id=submit_formmethod formmethod="POST">
|
||||
</form>
|
||||
|
||||
<script id=formmethod type=module>
|
||||
{
|
||||
const state = await testing.async();
|
||||
$('#submit_formmethod').click();
|
||||
$('#f5').onload = () => {
|
||||
state.resolve();
|
||||
};
|
||||
|
||||
await state.done(() => {
|
||||
// formmethod=POST overrode form's GET, so the FormData entry was NOT
|
||||
// appended to the action URL as a query string.
|
||||
testing.expectEqual(false, $('#f5').contentDocument.URL.includes('?'));
|
||||
testing.expectEqual('a-page\n', $('#f5').contentDocument.body.textContent);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Combined: formaction + formmethod on the same submit button. -->
|
||||
<iframe name=frame6 id=f6></iframe>
|
||||
<form target="frame6" method="GET" action="support/should-not-load.html">
|
||||
<input name="x" value="probe">
|
||||
<input type=submit id=submit_form_both formaction="support/page.html" formmethod="POST">
|
||||
</form>
|
||||
|
||||
<script id=formaction_and_formmethod type=module>
|
||||
{
|
||||
const state = await testing.async();
|
||||
$('#submit_form_both').click();
|
||||
$('#f6').onload = () => {
|
||||
state.resolve();
|
||||
};
|
||||
|
||||
await state.done(() => {
|
||||
testing.expectEqual(false, $('#f6').contentDocument.URL.includes('?'));
|
||||
testing.expectEqual('a-page\n', $('#f6').contentDocument.body.textContent);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user