Commit Graph

800 Commits

Author SHA1 Message Date
Adrià Arrufat
70cc8ff5f9 Merge branch 'main' into agent 2026-06-08 17:01:18 +02:00
Pierre Tachoire
3ec0c25dde Merge pull request #2665 from mvanhorn/fix/2610-axnode-password-input-textbox-role
fix: map password inputs to textbox accessibility role
2026-06-08 11:21:32 +02:00
Matt Van Horn
e7cce250d3 fix: map password inputs to textbox accessibility role 2026-06-07 23:45:20 -07:00
Pierre Tachoire
fdf6276f39 cdp: use Frame.mouse_button consts from cdp.input.zig 2026-06-08 08:42:54 +02:00
Rohit
e68def97b3 refactor(cdp): use named constants for mouse button values
Address review: replace the bare 0/1/2 button values in the
mousedown/release switch (Frame.zig) and the CDP button mapping
(input.zig) with named constants so the code self-documents.
2026-06-06 19:03:45 +05:30
Rohit
1776d0ea71 feat(cdp): support mouse button and clickCount in Input.dispatchMouseEvent
Input.dispatchMouseEvent ignored the button and clickCount params, and
mousePressed only fired a click event (never mousedown). Add them:

- mousePressed now fires mousedown carrying the pressed button.
- mouseReleased fires mouseup, then the button-appropriate activation
  event: click for the main button, auxclick for the auxiliary button,
  and contextmenu for the secondary (right) button.
- a clickCount of 2 additionally fires dblclick.

This unblocks right-click, middle-click and double-click interactions
for Playwright/Puppeteer scripts. Follows the mouse event work in
#2636, #2640 and #2641.
2026-06-05 20:08:46 +05:30
Adrià Arrufat
88c8828224 Merge branch 'main' into agent 2026-06-05 12:43:46 +02:00
Karl Seguin
0e12790397 Merge pull request #2635 from Ar-maan05/feat-implement-file-api
Implement input type=file support (FileList, input.files/value, DOM.setFileInputFiles)
2026-06-05 10:52:23 +08:00
Karl Seguin
129d014479 Make FileList iterable / indexable
Small formatting tweaks
2026-06-05 08:27:38 +08:00
Rohit
e05074dbf5 feat(cdp): fire wheel events on Input.dispatchMouseEvent mouseWheel
Wire the CDP Input.dispatchMouseEvent "mouseWheel" type to a new
Frame.triggerMouseWheel, which hit-tests the point via elementFromPoint
and dispatches a wheel event (with deltaX/deltaY) on the target. When
the wheel event is not cancelled, it applies the scroll offset and
fires a scroll event, mirroring the wheel handling in WebDriver.zig.

Previously mouseWheel was silently ignored. Follow-up to #2636.
2026-06-04 19:27:56 +05:30
Rohit
f697013540 feat(cdp): fire mouseup on Input.dispatchMouseEvent mouseReleased
Wire the CDP Input.dispatchMouseEvent "mouseReleased" type to a new
Frame.triggerMouseRelease, which hit-tests the point via
elementFromPoint and dispatches a mouseup event on the target,
mirroring triggerMouseClick / triggerMouseMove and the mouseup
semantics already used by WebDriver.zig.

Previously mouseReleased was silently ignored. Follow-up to #2636.
2026-06-04 16:39:25 +05:30
Armaan Sandhu
7524a75147 feat(webapi): back input.files with FileList and add DOM.setFileInputFiles
Populate FileList with real File objects and expose them on
  HTMLInputElement:
  - input.files returns a live, identity-stable FileList for type=file
    (null for other input types)
  - input.value returns the spec "C:\fakepath\<name>" string
  - required file inputs report value-missing only when empty

  Implement CDP DOM.setFileInputFiles: load files from disk into a file
  input (MIME sniffed by extension) and fire input + change events.

  File backing arenas are reference counted via their Blob proto, so the
  owning Frame now acquires/releases them and frees any still held at
  teardown, preventing an ArenaPool leak for CDP-set files never read
  from JS. A scoped errdefer frees partially-created files when one path
  in a multi-file set fails to load.
2026-06-04 15:59:59 +05:30
Rohit
b347f8b2e2 feat(cdp): fire hover events on Input.dispatchMouseEvent mouseMoved
Wire the CDP Input.dispatchMouseEvent "mouseMoved" type to a new
Frame.triggerMouseMove, which hit-tests the point via elementFromPoint
and dispatches mousemove, mouseover and mouseenter on the target,
mirroring the existing triggerMouseClick and the actions.zig hover()
event semantics.

Previously mouseMoved was silently ignored, so element.hover() over
Playwright/Puppeteer (CDP) fired no events. Addresses the hover gap
reported in #2043.
2026-06-04 14:07:34 +05:30
Adrià Arrufat
f7c2e0b886 Merge branch 'main' into agent 2026-06-04 08:34:10 +02:00
Pierre Tachoire
a0ecf9cb7c cookies: use an init for Cookie.PreparedUri 2026-06-03 16:48:55 +02:00
Pierre Tachoire
00a91c7dac cdp: fix network.getCookies url build
When getting cookies from CDP, we musn't apply specific cookies's
path/host extraction for the target URL, but use the simple URL rules.
2026-06-03 16:37:03 +02:00
Adrià Arrufat
393d26cd11 Merge branch 'main' into agent 2026-06-03 10:09:33 +02:00
Adrià Arrufat
4ff4da2ede Merge branch 'main' into agent 2026-06-03 08:35:33 +02:00
Karl Seguin
f7a32c05a8 Improve / fix InterceptLayer.intercepted count tracking
The intercept state is currently split and hard to keep consistent and even
just reason about. InterceptLayer keeps the `intercepted` count, but CDP's
`BrowserContext` has its intercepted lookup. This isn't a problem per se, but
you BrowserContext.deinit tries to decrement `InterceptLayer.intercepted` which
is only safe if we can guarantee that the two are in sync. Which we can't.

This commit simplifies the upkeep of `InterceptLayer.intercepted` and uses the
Transfer's state on unpark/deinit to decrement it. The CDP layer no longer
cares about / has to maintain the count.

Driven by this crash report:

BrowserContext.deinit.intercepted
---
value: 0
/home/runner/work/browser/browser/src/lightpanda.zig:279:25: 0x2871842 in deinit (lightpanda)
/home/runner/work/browser/browser/src/cdp/CDP.zig:127:18: 0x28c3f45 in deinit (lightpanda)
/home/runner/work/browser/browser/src/Server.zig:186:21: 0x2827997 in handleConnection (lightpanda)
/home/runner/work/_temp/6dc322a8-c74f-4990-9660-4cc6dcfb9352/zig-x86_64-linux-0.15.2/lib/std/Thread.zig:509:13: 0x269c233 in entryFn (lightpanda)
???:?:?: 0x7fce7ccabd57 in ??? (libc.so.6)
Unwind information for `libc.so.6:0x7fce7ccabd57` was not available, trace may be incomplete

on 1.0.0-nightly.6542+94ba0791
2026-06-03 08:24:47 +08:00
Adrià Arrufat
818b225d99 Merge branch 'main' into agent 2026-06-02 08:12:26 +02:00
Karl Seguin
a7355a5762 Less arena-reuse (retain) in Debug
Arena reuse/retain can hide UAF issues, often resulting in a crash that is more
symptom than cause (far from where the error actually is). Removing this, lets
us better utilize the DebugAllocator's UAF-detection.

Also, when running WPT tests (-Dwpt_extensions) limit console logging to 100
values (a few tests writer millions of values, which is annoying and just
destroys the terminal).
2026-06-02 13:00:17 +08:00
Karl Seguin
94ba07913c Merge pull request #2584 from lightpanda-io/request_callback_terminate
Improve forced terminate on CDP client disconnect.
2026-06-02 11:10:57 +08:00
Karl Seguin
79cdbd285d Improve forced terminate on CDP client disconnect.
Depends on https://github.com/lightpanda-io/zig-v8-fork/pull/179

An improvement to https://github.com/lightpanda-io/browser/pull/2515 to prevent
a v8 assertion if we terminate as an inspector dispatch is happening.

The problem is that if we just immediately terminate, we aren't sure what the
worker thread is doing, and, apparently, if we terminate then dispatch a message
to the inspector, we fail an assertion.

With the way the code was, the only safe solution would be to hold a mutex
over the session dispatch, but that could block the network thread.

So instead of terminating from the network thread, we now ask v8 to execute
a callback. This gets executed on the worker thread, which can then terminate
the execution.

The initial version of 2515 delayed the termination from the network thread.
It's possible that solution would "solve" the issue, simply because it's very
unlikely that a worker would be "stuck" for 5 seconds and then get unstuck.
More likely that it exits immediately, or is stuck in an endless loop. But
that would still leave a window where we could terminate in network and then
dispatch in the worker. Less likely, but still possible. Hopefully this new
mechanism eliminates this from being a problem in all circumstances.
2026-06-02 08:27:49 +08:00
Karl Seguin
37a846d91d remove unused imports 2026-06-01 22:42:39 +08:00
Adrià Arrufat
204e3aa31b Merge branch 'main' into agent 2026-06-01 08:04:44 +02:00
Karl Seguin
14f1ef35f1 URL.isHTTPs -> URL.isSecure and consider wss://
Use conn.setCookie in websocket
2026-06-01 08:35:19 +08:00
Adrià Arrufat
c9c962ec74 Merge branch 'main' into agent 2026-05-30 22:05:01 +02:00
Karl Seguin
87c6d52abc Cleaner cookie ownership
Previously, Cookie.Jar.add would only conditionally take over the cookie. The
caller had no way to know whether or not to deinit it. This could result in
a double-free on certain error paths.

Cookie.Jar.add now unconditionally takes ownership of the cookie.
2026-05-29 09:32:03 +08:00
Adrià Arrufat
d0a48131da Merge branch 'main' into agent 2026-05-28 11:53:47 +02:00
Karl Seguin
05daa4a6dc This is a very small / mechanical change.
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
2026-05-28 08:23:35 +08:00
Adrià Arrufat
a3559a4f60 Merge branch 'main' into agent 2026-05-26 19:48:18 +02:00
Matt Van Horn
e361540c2d chore: fix three typos in comments and error message
- src/cdp/CDP.zig L1029 (was L780 in previous scan): "we dont' want" -> "we don't want"
- src/storage/sqlite/Pool.zig L101: test comment "single connetion" -> "single connection"
- src/storage/sqlite/Sqlite.zig L201: @compileError message "unsupport column type" -> "unsupported column type"

Comment / compile-time string only; no runtime behavior change.
2026-05-26 00:48:52 -07:00
Pierre Tachoire
63a8e6dd52 Merge pull request #2539 from lightpanda-io/accname_content_for_name
Accessibility: use content for name for specific role
2026-05-26 09:34:51 +02:00
Muki Kiboigo
a295a7a21a various changes to properly track next ticked transfers 2026-05-25 10:06:50 -07:00
Adrià Arrufat
9b4a48e07f Merge branch 'main' into agent 2026-05-25 18:18:55 +02:00
Karl Seguin
8472d21c59 Accessibility: use content for name for specific role
For typically name-less elements, check the "role" attribute to see if we should
fallback to the content.

Improves a handful of WPT tests, e.g.: /accname/name/comp_text_node.html

(It seems impossible to get 100% on these tests without knowing what is and
isn't a block-level element which would require more knowledge in the
StyleManager).
2026-05-25 12:46:20 +08:00
Adrià Arrufat
525c3e467c input: centralize password value redaction
Introduces `Input.getRedactedValue` to mask password values in
LLM-facing dumps (semantic tree, forms, AXNode) instead of
exposing raw values or using ad-hoc checks.
2026-05-24 08:36:23 +02:00
Navid EMAD
6df1dfe238 Replace active page on synthetic root navigation (about:blank, blob:)
Page.navigate("about:blank") (and blob:) issued against a non-blank tab
routed through Session.initiateRootNavigation, which always allocated a
pending Page. A pending Page is promoted to active only by
frameHeaderDoneCallback when HTTP response headers arrive — but synthetic
navigations ZIGFLAGS= make no HTTP request, so the pending Page was never committed
and the previous document stayed active (window.location.href, document.URL
and Page.getFrameTree all kept reporting the old page).

Route synthetic URLs through the existing immediate-swap path
(replaceRootImmediate) from initiateRootNavigation, mirroring what
processRootQueuedNavigation already does for JS-initiated synthetic
navigations. replaceRootImmediate now takes (frame_id, url, opts) so both
call sites share it.

Fixes #2363
2026-05-22 15:41:15 +02:00
Pierre Tachoire
8b2a79d93a Merge pull request #2515 from lightpanda-io/cdp_watchdog 2026-05-22 13:19:48 +02:00
Karl Seguin
abdfd443e1 On CDP client disconnect, terminate Env
Protects against a stuck worker. This works even if the worker isn't currently
in JS but then enters JS.
2026-05-22 07:13:46 +08:00
Karl Seguin
3fc75dfe85 Revert "Add watchdog to Network thread for abandoned & stuck workers"
This reverts commit 8da7657d4c.
2026-05-22 07:09:57 +08:00
Pierre Tachoire
bc43d64324 Merge pull request #2511 from navidemad/fix-sigterm-live-cdp-connection
network: terminate live CDP connections on shutdown
2026-05-21 19:02:47 +02:00
Karl Seguin
8da7657d4c Add watchdog to Network thread for abandoned & stuck workers
If a worker is in some heavy JS e.g. `for(;;)` it will be stuck forever, even
if the peer closes the CDP connection.

With CDP reads now owned by the network thread, we now correctly detect the
disconnect and simply need to force the worker to shutdown. To achieve this,
on socket close, the CdpLink held by the network is given a terminate_ms (five
seconds from now) and added to a linked list. On every wakeup, the network
thread can check the list + timestamp and, if necessary, call Isolate::Terminate
(which is safe to call on a different thread).
2026-05-21 19:22:12 +08:00
Navid EMAD
baf1b20532 network: free request headers when syncRequest short-circuits on disconnect
syncRequest's `terminated` early return (added in 88b98e70) exits before request() takes ownership of req.headers, so the curl_slist leaked after a latched disconnect (any nested fetch / importScripts / external stylesheet). Free it in the early return, mirroring request()'s own failure paths.

Also adds a behavioral syncRequest-after-disconnect test. The leak itself isn't assertable here (curl_slist is C-allocated through the tracking allocator, outside the per-test leak check), so it's verified by the ownership contract rather than the suite.
2026-05-21 12:36:45 +02:00
Navid EMAD
901eece853 network: add regression test for the CDP disconnect latch (#2510)
Drives a .disconnect through the worker's inbox and asserts a second tick still returns error.ClientDisconnected once the inbox is empty. Fails against the pre-latch HttpClient (the worker would re-park in perform with no producer to wake it); passes with the latch.
2026-05-21 12:18:28 +02:00
Karl Seguin
e4171bc694 Merge pull request #2501 from lightpanda-io/remove_reentrency_teardown_protection
Remove reentrency teardown protection
2026-05-21 10:15:26 +08:00
Pierre Tachoire
6e6b3caf96 Merge pull request #2479 from navidemad/accessibility-query-ax-tree
Implement Accessibility.queryAXTree CDP method (and fix latent frame-binding bug)
2026-05-20 13:59:35 +02:00
Pierre Tachoire
2ad2c9d878 Merge pull request #2487 from navidemad/feat/external-stylesheets-flag
Add --enable-external-stylesheets flag with fetch + parse
2026-05-20 13:41:59 +02:00
Karl Seguin
a9cf87e0b0 Remove reentrency teardown protection
This largely reverts 92607ad765 (captured in PR:
https://github.com/lightpanda-io/browser/pull/2398).

https://github.com/lightpanda-io/browser/pull/2495 introduces protection against
execution arbitrary CDP command during JavaScript callbacks. Claude initially
made the case for keeping the existing code as a safety net, but sycophanted
when I pushed by.

My reason for removing it is that it isn't a low-maintenance guard. It's a flag
that serves a real purpose (ensuring 1 JS script is finished before executing
another one), that has been expended to solve these issues. It needs to be set
(and reverted) at every callsite that makes a blocking call, and it needs to be
checked (recursively across all frames) in any place that can teardown the page/
frame.

Claude called the allowlist "load-bearing in a non-obvious way", but I think
it's purpose built specifically for this case. Extended the comment atop
`allowDuringSyncWait` so that future-selves remember this.
2026-05-20 15:08:18 +08:00
Navid EMAD
814ca8ab3f accessibility: unify query+tree writers, route objectId via dom.getNode
Fold QueryWriter into Writer behind an Opts.filter. Tree mode is unchanged
(filter=null); query mode walks the full subtree (including AX-ignored
nodes per the queryAXTree spec) and emits the flat-match shape. Shared
resolveRole helper handles label-promotion for both paths so the two
can't drift.

Drop the "objectId not yet supported" carve-out: queryAXTree now reuses
dom.getNode, which already resolves nodeId/backendNodeId/objectId.
2026-05-19 20:43:54 +02:00