Engine-only changes pulled out of the WPT conformance branch. The
tests, runner, and harness vendoring that drove these have moved to a
separate benchmark repo (obscura-bench).
Real bug fixes:
- Tree::insert_before created a self-cycle when the inserted node was
its own reference (the spec-conformant `child.after(x)` path that
the testharness's ChildNode helpers exercise). The fixup wrote
node.prev_sibling = node.next_sibling = own id; every subsequent
childNodes / querySelectorAll walk then looped forever and obscura
burned RAM until OOM. Per spec the op is a no-op; we now early-return.
- Tree::text_content extended to return own data for direct
CharacterData access (Text / Comment / ProcessingInstruction).
- Element.namespaceURI now reflects the namespace passed to
createElementNS instead of collapsing every non-svg namespace to
xhtml. Without this, code that creates elements in MathML, custom
XML namespaces, or the empty namespace gets misclassified as HTML.
- AbortController / AbortSignal: the previous shim was a plain object
whose addEventListener was a no-op, so listeners for 'abort'
silently never fired and any AbortSignal.timeout / AbortSignal.any
chains broke. New impl tracks aborted/reason, has a real
addEventListener / removeEventListener / dispatchEvent surface,
honors `once`, and implements the static abort / timeout / any
factories crawlers use for budgeted fetches.
- StorageEvent class added. localStorage / sessionStorage mutations
now dispatch 'storage' events on the parent window and every iframe
window so cross-frame onstorage listeners fire.
- ProcessingInstruction (nodeType 7) and DocumentType (nodeType 10)
constructors plus document.createProcessingInstruction and
document.implementation.createDocumentType. textContent returns
null for Document and DocumentType per spec.
- insertAdjacentText / insertAdjacentElement on Element. Without
these the testharness output renderer threw in a forEach without
try/catch, breaking the completion callback chain for every test
with subtests.
- Window + Node addEventListener filter non-callable listeners,
accept the EventListenerObject shape (object with handleEvent),
dedupe by (type, callback, capture), honor the `once` option, and
snapshot the listener list before dispatch so a `once: true`
removal mid-iteration doesn't corrupt the loop.
- Iframe HTML loader now extracts head <script> blocks and body
on-handler attributes (`<body onstorage=...>`), evals scripts in
the parent realm after the iframe window is built, re-attaches
handlers as window listeners. Same iframe element reusing its src
no longer double-registers in the iframe registry.
- ops.rs validate_fetch_url honors the OBSCURA_ALLOW_PRIVATE_NETWORK
env var, and the CLI --allow-private-network flag mirrors itself
into that env so the js-side fetch gate matches the http_client
gate. Without this, iframe loads of 127.0.0.1 resources were
blocked even with the flag set.
- ops.rs: create_processing_instruction, create_doctype, pi_target,
doctype_name, doctype_public_id ops added; set_text_content extended
to handle PI nodes.