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>
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>
Puppeteer's page.setCookie() internally calls Network.deleteCookies twice
before setting a cookie. The second call includes a partitionKey field for
CHIPS (partitioned cookies), which caused Lightpanda to return NotImplemented.
Since Lightpanda doesn't support partitioned cookies, we now silently ignore
the partitionKey parameter and proceed with the cookie operation based on
name/domain/path matching.
This change affects:
- Network.deleteCookies: no longer rejects requests with partitionKey
- Network.setCookie (via setCdpCookie): no longer rejects cookies with partitionKey
Fixes#1818
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The reallocation_count counter was being incremented regardless of whether
the resize/remap operations succeeded. This led to inaccurate memory
allocation statistics.
- resize: Only increment when rawResize returns true (success)
- remap: Only increment when rawRemap returns non-null (success)
This fixes the TODO comments that were present in the code.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 - When Target.setAutoAttach is called, send the `Target.attachedToTarget`
event before sending the response. This matches Chrome's behavior and
it stops playwright from thinking there's no target and making extra calls,
e.g. to Target.attachedToTarget.
2 - Use the same dummy frameId for all startup messages. I'm not sure why we
have STARTUP-P and STARTUP-B. Using the same frame (a) makes more sense to
me (b) doesn't break any existing integration tests, and (c) improves this
scenario: https://github.com/lightpanda-io/browser/issues/1800
Dynamic scripts have script.async == true by default (we handled this correctly
in the ScriptManager, but we didn't return the right value when .async was
accessed).
Inline scripts only consider direct children, not the entire tree.
Empty inline scripts are executed at a later time if text is inserted into them
Loading `sub 1.html` has a side effect - it increments window.top..sub1_count).
So it should be used careful. It was being used in `about_blank_renavigate` as
a placeholder which _should_ not get navigated, but there's no strict guarantee
about when it gets canceled.