forms: add enctype + 5 submitter form-* IDL accessors#2450
Merged
Conversation
Six form-submission IDL accessors were missing from the JsApi blocks of HTMLFormElement, HTMLButtonElement, and HTMLInputElement, so reads produced undefined instead of the spec-mandated string/boolean. The content-attribute path (clicking a submit button honoring formaction / formmethod / formenctype) was wired up in lightpanda-io#2279; this commit adds the matching IDL-property accessors per WHATWG HTML §4.10.18.6 and §4.10.21.5. - Form.enctype: limited to known values, missing+invalid both default to application/x-www-form-urlencoded (mirrors getMethod's shape). - Button/Input formAction: returns frame.url when missing/empty, else the resolved URL (mirrors Form.getAction). - Button/Input formEnctype, formMethod: limited to known values with no missing-value default ("" when missing, canonical invalid-value default application/x-www-form-urlencoded / get when invalid). - Button/Input formTarget: plain reflection, defaults to "". - Button/Input formNoValidate: boolean reflection of formnovalidate. Closes lightpanda-io#2449
The "limited to only known values" canonicalization (per WHATWG HTML
§2.2.2) was duplicated five times: Form.getMethod + Form.getEnctype +
{Button,Input}.{getFormMethod,getFormEnctype}. Each callsite differed
only in the missing-value default ("" for submitter overrides, "get" /
"application/x-www-form-urlencoded" for the form-side).
Extract into two pub helpers on Form.zig taking the attribute slice +
the missing-value default. The five callers collapse to one-liners.
Behavior-preserving: existing form.html / button.html / input-attrs.html
fixtures all pass unchanged; full suite 637/637 green.
Net: -36 LOC.
Closing the divergence introduced by the new IDL accessors: `submitter.formEnctype`
(and `form.enctype`) now return "text/plain" for that attribute value per WHATWG
HTML §4.10.21.5, but `Frame.submitForm` previously fell back to urlencoded with
a `.not_implemented` log when it saw the same value on the submission path.
Implement the spec's text/plain encoding algorithm (HTML §4.10.21.8):
- FormData.EncType gains a `.plaintext` variant.
- FormData.plaintextEncode writes "name=value CRLF" per entry, no URL-encoding,
no escaping — the spec accepts that text/plain is a lossy, human-readable
encoding (values containing "=" or CRLF produce an ambiguous wire format
by design).
- Frame.submitForm recognizes "text/plain" before the urlencoded fallback and
sets the Content-Type header to "text/plain; charset=<form-charset>", per
spec step 21.4.
Two new Zig unit tests cover encoding output (`FormData: plaintext write`,
`FormData: plaintext empty body`). Full suite 639/639 green.
This is bundled with the IDL accessor commits because returning "text/plain"
from the IDL while the submission silently re-encodes as urlencoded is a
spec-internal inconsistency the IDL change itself introduces. Reviewers who'd
prefer to land just the read-only accessors first should feel free to ask for
a split — this commit is self-contained and reverts cleanly.
…nctype The submitForm encoding path was the last duplicate of the "limited to only known values" canonicalization the previous commit consolidated for the IDL getters. Now it consumes the same Form.normalizeMethod / Form.normalizeEnctype helpers, so a single function owns the canonical mapping (`""` / unknown -> spec default, recognized values pass through unchanged). Side effect of routing through the helper: the `log.warn(.not_implemented, "FormData.encoding", ...)` branch falls out. After commit 4b693db added `text/plain`, the only attribute values that still reach the urlencoded fallback are spec-invalid ones, which per HTML §4.10.21.5 silently canonicalize to `application/x-www-form-urlencoded`. The warning was firing for valid spec behavior — Chrome doesn't log either. Behavior-preserving on all observable surfaces: full suite 639/639 green; existing form-submission integration tests (multipart, urlencoded, text/plain, GET-ignores-enctype) all pass unchanged.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds six missing form-submission IDL accessors so reads of
form.enctypeandsubmitter.{formAction, formEnctype, formMethod, formNoValidate, formTarget}return the spec-mandated string or boolean instead ofundefined. Companion to #2279 (which wired up the content-attribute submission path for the same set of attributes) — same WHATWG sections, same canonicalization rules, just the JS-property side that downstream CDP clients read.Also bundled: support for
enctype="text/plain"form submissions per HTML §4.10.21.8. Before this PR the IDL accessor and the submission path silently agreed (both ignoredtext/plain). With the IDL accessor now returning"text/plain"per spec, the submission path was the next link in the chain — left untouched it would have re-encoded as urlencoded with a.not_implementedwarning. Reviewers preferring to land just the read-only IDL accessors first can ask to drop commits4b693db4..f0cce427; both are self-contained and revert cleanly.Closes #2449.
Root cause
The accessors were absent from the
JsApiblocks ofForm.zig,Button.zig, andInput.zig. Readingform.enctypefrom JS resolved through V8 to "property not on the prototype" →undefined.Runtime.evaluatereturnedresult.value === undefined. CDP clients that then call.toLowerCase()on the return crash withTypeError: Cannot read properties of undefined.flowchart LR A[Runtime.evaluate form.enctype] --> B[no accessor on HTMLFormElement.prototype] B --> C[returns undefined, TypeError downstream] style B fill:#fdd style C fill:#fddFix
Commit
2fdc82aa— IDL accessors:src/browser/webapi/element/html/Form.zig— addgetEnctype/setEnctypemirroring the existinggetMethod/setMethod(limited-to-known-values pattern), registerenctypeinJsApi.src/browser/webapi/element/html/Button.zig— add five getter/setter pairs (getFormAction,getFormEnctype,getFormMethod,getFormNoValidate,getFormTarget) and register them inJsApi. URL-resolvinggetFormActionmirrorsForm.getAction.src/browser/webapi/element/html/Input.zig— same five accessors registered alongside the existingformaccessor.Commit
cedfdba0— IDL DRY pass:Form.normalizeMethod/Form.normalizeEnctypehelpers; the five IDL callsites (existingForm.getMethod+ four new accessors) collapse to one-liners. Net -36 LOC.Commit
4b693db4—text/plainsubmission:src/browser/webapi/net/FormData.zig—EncTypegains a.plaintextvariant;plaintextEncodewritesname=value\r\nper entry per HTML §4.10.21.8.src/browser/Frame.zig—submitFormrecognizestext/plainbefore the urlencoded fallback, setsContent-Type: text/plain; charset=<form-charset>per spec step 21.4.Commit
f0cce427— submission-path DRY:src/browser/Frame.zig—submitFormnow consumesForm.normalizeMethod/Form.normalizeEnctypeinstead of inlining theeqlIgnoreCasechain a sixth time. Single function owns the canonical mapping for both IDL reads and the submission path. Drops thelog.warn(.not_implemented, "FormData.encoding", ...)branch — aftertext/plainlands, the only values still reaching the urlencoded fallback are spec-invalid ones, which per §4.10.21.5 silently canonicalize (Chrome doesn't log either).Defaults follow WHATWG HTML strictly:
form.enctypeapplication/x-www-form-urlencodedapplication/x-www-form-urlencodedsubmitter.formEnctype""application/x-www-form-urlencodedsubmitter.formMethod""getsubmitter.formActionframe.url)submitter.formTarget""submitter.formNoValidatefalsetrue(boolean attribute reflection)flowchart LR A[Runtime.evaluate form.enctype] --> B[Form.getEnctype reads attribute, normalizes] B --> C[returns application/x-www-form-urlencoded] style B fill:#dfd style C fill:#dfdTest
src/browser/tests/element/html/:form.html— three new<script>blocks coveringenctypeinitial / set / normalization.button.html— eleven new<script>blocks covering all five submitter overrides (initial / set / invalid-value / normalization).input-attrs.html— eight new<script>blocks mirroring the button coverage on<input type=submit>.src/browser/webapi/net/FormData.zig:FormData: plaintext write— three entries including one with embedded=and CRLF; asserts the spec's verbatim-write semantics.FormData: plaintext empty body— empty entry list → empty output.TEST_FILTER='WebApi: HTML.Form','WebApi: HTML.Button','WebApi: HTML.Input','FormData: plaintext'. Fullzig build testclean (639/639).FormData.zigwhile keepingFrame.zigcauses a compile failure on the new.plaintextvariant (proves the production code routes through it); reverting all threewebapi/element/html/*.zigproduction files while keeping the HTML fixtures causes the three runners to fail (proves the fixtures exercise the new accessors).repro.shexits 1 against installed nightly (1.0.0-nightly.6198+2e159aaf— all 11 IDL reads returnundefined) and exits 0 against a local debug build off this branch (all 11 reads return spec-typed values, includingformActionresolving to the document URL when missing).Notes
formActiongetter intentionally diverges from thesubmitter.X || form.Xshort-circuit some downstream JS uses: per HTML §4.10.21.6 it MUST return the document URL when the attribute is missing, not"". Callers that want fall-through to the form's value should checksubmitter.hasAttribute("formaction")first (matches Chrome behavior).Network.requestWillBeSentpayloads for submitter-triggered submissions are unaffected (those were addressed by forms: honor formaction / formmethod / formenctype on submit button #2279).