Add the deprecated-but-widely-used window.event property that returns
the Event currently being handled. Returns undefined when no event is
being dispatched.
Implementation saves and restores window._current_event around handler
invocation in both dispatchDirect and dispatchNode, supporting nested
event dispatch correctly.
Fixes#1770
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This may be a stopgap.
Our identity model assumes that v8 won't allow cross-origin access. It turns out
that with CDP and Inspector, this isn't true. Inspectors can break / violate
cross-origin restrictions. The result is that 2 origins can see the same zig
instance, which causes 2 v8::Objects to reference the same Zig instance.
This likely causes some consistency issue. Like, if you take mo in 1 context,
and write an arbitrary property, mo.hack = true, you won't observe that in the
2nd context (because it's a different v8::Object). But, it _is_ the same Zig
instance, so if you set a known/real property, it will be updated.
That's probably a pretty minor issue. The bigger issue is that it can result in
a use-after-free when using explicit strong/weak ref:
1 - Mutation observer is created in Origin1
2 - It's automatically set to weak
3 - Something is observed, the reference is made strong
4 - The MO is accessed from Origin2
5 - Creates a new v8::Object
6 - Sets it to weak
7 - Object goes out of scope in Origin2
8 - Finalizer is called <- free
9 - MO is manipulated in Origin 1 <- use after free
Maybe the right option is to have a single shared identity map. I need to think
about it. As a stopgap, switching to reference counting (which we already
support) shold prevent the use-after free. While we'll still create 2
v8::Objects, they'll each acquireRef (_rc = 2) and thus it won't be freed until
they both release i
Maybe the right option is to have a single shared identity map. I need to think
about it. As a stopgap, switching to reference counting (which we already
support) shold prevent the use-after free. While we'll still create 2
v8::Objects, they'll each acquireRef (_rc = 2) and thus it won't be freed until
they both release it.
Small follow up to https://github.com/lightpanda-io/browser/pull/1837 If we
sniff the content type from the byte order mark (BOM), then we should set the
charset. This has higher precedence than sniffing the content type from the
content of the document (e.g. meta tags)
The getMessage() fallback returned raw tag names like
"wrong_document_error" instead of human-readable messages.
Fill in all 18 error codes with messages based on the
WebIDL spec error descriptions.
Closes#82
Signed-off-by: JiangNan <1394485448@qq.com>
- Use std.ascii.eqlIgnoreCase instead of custom asciiEqlIgnoreCase
- Fix infinite loop in findAttrValue when attribute has no '=' sign
(e.g. self-closing <meta foo="bar"/>)
- Add is_default_charset flag to Mime struct so prescan only overrides
charset when Content-Type header didn't set one explicitly
- Add regression test for the self-closing meta loop case
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The CDP timeout handler in httpLoop had two compounding bugs:
1. Unit mismatch: timestamp(.monotonic) returns seconds, but
ms_remaining is in milliseconds. The comparison and subtraction
mixed units.
2. Double-counting: In the .done branch, elapsed was computed as
absolute time since last_message, but last_message was never
updated in this branch. Each iteration subtracted the growing
total elapsed seconds from an already-decremented ms_remaining.
During complex page loads, Session._wait() returns .done rapidly
(due to JS macrotask execution, background tasks, or errors). Each
rapid .done return subtracted the growing elapsed (seconds) from
ms_remaining (milliseconds), draining it to zero in ~2 seconds
instead of the configured 10-second timeout.
Fix: use milliTimestamp() for consistent units, update last_message
in the .done branch for incremental elapsed tracking, and use >= for
correct boundary comparison.
Fixes#1849
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
https://github.com/lightpanda-io/browser/pull/1775 made blobs finalizable and
https://github.com/lightpanda-io/browser/pull/1795 made it possible to navigate
from blobs (important for WPT tests). This fixes a number of issues related to
both.
First, weak/strong ref'ing a value now uses the resolved value. When registering
a finalizer, we use the resolved value (the most specific type in the prototype
chain). For this reason, when toggling a weak/strong ref, we have to use the
same resolved value. This solves a segfault where a File is created, but
extended as a Blob (e.g. in createObjectURL).
Next, two issues were fixed when navigating to an invalid blob. First, the frame
is properly removed from the parent list on frame navigation error. Second,
on frame navigation error, we don't stop _all_ other navigations, we just log
the error and move on to the next frame.
processMessage no longer returns Zig errors when dispatchCommand fails —
it sends a CDP error response and continues. Update all expectError calls
to use processMessage + expectSentError instead.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Origins were introduced to group memory/data that can be owned by multiple
frames (on the same origin). There's a general idea that the initial "opaque"
origin is very transient and should get replaced before any actual JavaScript
is executed (because the real origin is setup as soon as we get the header from
the response, long before we execute any script).
But...with CDP, this guarantee doesn't hold There's nothing stop a CDP script
from executing javascript at any point, including while the main page is still
being loaded. This can result on allocations made on the opaque origin which
is promptly discarded.
To solve this, this commit introduced origin takeover. Rather than just
transferring any data from one origin (the opaque) to the new one and then
deinit' the opaque one (which is what results in user-after-free), the new
origin simply maintains a list of opaque origins it has "taken-over"and is
responsible for freeing it (in its own deinit). This ensures that any allocation
made in the opaque origin remain valid.
When a CDP command with an unrecognized domain (e.g. `NonExistent.method`)
was sent, the error response was correctly returned but the connection
died immediately after. This happened because dispatch() re-returned the
error after sending the error response, which propagated up through
processMessage() → handleMessage() where `catch return false` closed
the WebSocket connection.
Now the error is only propagated if sendError itself fails (e.g. broken
pipe). Otherwise dispatch() returns normally and the read loop continues.
Fixes#1843
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>