Three changes:
- js.Execution now has a page (instead of calling exec.context.page)
- js.Execution now has a session (instead of calling exec.context.page.session)
- js.Execution.context renamed to .js to be consistent with Frame and WGS
We currently skip capturing 401 and 407 bodies. This appears to be an
optimization with the intent that it won't be needed. While that might be true
in some cases (though, not sure when), it isn't always true. A page.navigate
to a 401 should display the content.
(Also, tried to silence meaningless BrokenPipe noise in tests).
Normally, a shadow dom is attached to an element via `el.attachShadow(mode)`.
With DSD, the shadow dom is attached during parsing. Essentially, when we see:
<template shadowrootmode="open">...</template>
it has the end result of calling attachShadow on the parent element. This is
used increasingly by a number of frameworks, though normally with backwards
compatibility that fallbacks to doing it in JavaScript.
DSD happens during parsing and document.write, but not via innerHTML = ''.
However, both Element and DocumentFragment gain a `setHTMLUnsafe` which is like
innerHTML WITH DSD.
I initially thought this feature could be implement exactly like I describe:
when the parser adds a template, check for a `shadowrootmode` attribute and
call attachShadow...except..you need to call attachShadow on the parent, which
the parser hasn't popped yet, and it alters where the children are added.
Thankfully, html5ever has a boolean to enable/disable dsd..hence the html5ever
binding changes to (a) enable / disable this featuer and (b) the new callback.
https://github.com/lightpanda-io/browser/pull/2548 removed the _need_ to call
v8::Isolate::MemoryPressureNotification on Session.deinit and actually removed
the call.
But [my theory] is that this causes our peak memory to be higher. So, I'm
adding it back.
The point of #2548 was to open the door for improving the memory signals to v8
by removing the _need_ for this specific signal. That PR made it so that, for
correctness (UAF) we no longer _had_ to call it. The point of the PR wasn't
to necessarily improve the signals, so I don't feel too bad about putting this
back in.
The markdown renderer currently ignores shadow-dom. It doesn't "pierce" it, so
it'll render the light-dom (which is the template / fallback), which won't be
right.
This largely mimics the existing logic in dump.
This doesn't solve anything, but I was looking at /input-events/ WPT tests and
many are stuck with due to this type not existing. I don't expect this to fix
any of those tests, but it does move them along a bit further (the /input-events
test are all based on editing capabilities that we don't have).
We already had a // todo StaticRange in AbstractRange, and since it's very
simple, why not.
AFAIK, these aren't being used and I've personally not have reason to reference
/ look at them for months.
I have no issues though if we want to keep them in.
Fixes WPT crash /html/semantics/forms/form-submission-0/form-submission-algorithm.html
This fixes two separate possible recursive entries in the form submission
process. Both fixes are spec-accurate (hence the WPT test that specifically
tries it).
In short, the issues are the submit -> submit -> repeat and
formdata -> submit -> formdata -> submit -> repeat.
So two guards are added to track "I'm submitting" and "I'm building the form
data".
A v8 Finalizer can fire at any point, including after the underlying Zig object
has been freed. Even after the corresponding Frame and Page have been freed.
To deal with this, v8 Finalizers are tied to a special
FinalizerCallback.Identity (fci) which tracks whether the underlying Page still
exists (fci.done == true). This ensures that, if v8 calls an finalizer much
later, we don't UAF. All we have to do is cleanup the fci itself and exit -
everything else is already gone.
The problem is, we tied the fci's to the session, but the v8 Finalizer can
outlive the Session (which is meaningful to v8). We made this work by trying
to force the isolate to reclaim memory on session deinit. The problem with this
is that it still isn't guaranteed to work (though, practically speaking, if
this _has_ resulted in any UAF, it's been rare). PLUS it puts load on the v8
worker threads that can compound over short-lived sessions.
The fix is to move the fci to the browser. This is safe because Browser ==
Env == Isolate, so when the browser is torn down, the isolate is torn down, and
at THAT point, we're sure no Finalizers can fire.
With this change, the call to `memoryPressureNotification(.critical)` in
Session.deinit has been removed.
Previously, the logic for data/blob URLs were spread out at every http_client
caller. fetch/XHR/ScriptManager all had their own "if this is a data url, ..."
logic.
This causes two issues.
1 - Duplication, particularly as we try to cover more edge cases that need to
be handled in all places.
2 - Correctness because data/blob URLs are still URLs and still need to be
"fetched" (from memory). They should still fire with the same timing as any
other URL. That means that for fetch/XHR, they should fire asynchronously
(i.e. on the next tick). And for ScriptManager they should fire depending
on the type of script (normal/defer/async).
This PR relies on the infrastructure added to:
https://github.com/lightpanda-io/browser/pull/2506 in order to fulfilled a
synthetic response on the next tick.
Frame.navigate is excluded from this refactor. For one, about:blank must be
special-cased and run synchronously (one of the few places where this is
strictly required) and even blob URLs are a bit different: the blob URL list
is the parent frame, not self, and there's more we need to do (set origin).
Potentially there _is_ some improvement here, but it's both less significant
and less simple.
Implement `bodyUsed` getter for both types. With this implemented, correctly
reject requests when `bodyUsed == true`.
Expand Response to use BodyInit (Request was already using it).
Expand BodyInit to discriminate between a TypedArray/BufferArray and a string,
which allows us to capture the correct content type.
Add Request.priority and in Request/Response body getters, strip BOM as needed.
This fixes two things. First, it better tracks the calling context and the
target context, so that if a parent frame does a document.write within a child
frame, any JavaScript is executed in the child frame's context (previously, it
would be executed in the parent's context).
Second, it ensures that, on document.write, we force-execute any pending
scripts. This is related to https://github.com/lightpanda-io/browser/pull/2542
but applies specifically to document.write.
Currently, any inline deferred script, e.g:
<script type=module>
...
</script>
That happens AFTER load, never executes. Unclear how serious an issue this is,
but it _does_ cause problems for some WPT tests which use document.write to
inject a <script type="module">...</script> block after an iframe is loaded.