Commit Graph

5008 Commits

Author SHA1 Message Date
Muki Kiboigo
ee4ae77a71 add HttpClient.waitFor 2026-05-25 12:02:46 -07:00
Karl Seguin
9dc81f129c Merge pull request #2538 from lightpanda-io/feat-implement-file-api
Feat implement file api
2026-05-25 12:10:41 +08:00
Karl Seguin
d3c5c31a93 deduplicate File and Blob init 2026-05-25 11:36:17 +08:00
Karl Seguin
dc4218159a Merge pull request #2523 from navidemad/fix/2363-about-blank-replaces-document
Replace active page on synthetic root navigation (about:blank, blob:)
2026-05-25 09:19:30 +08:00
Karl Seguin
43a592d2fc small dedupe for arena release 2026-05-25 09:05:37 +08:00
Karl Seguin
43102317aa Merge pull request #2524 from willmafh/auth_challenge_parse_bugfix
bugfix: get scheme correctly when there is any leading whitespace
2026-05-24 16:44:00 +08:00
Armaan Sandhu
a7e3bea672 feat(webapi): implement W3C File API 2026-05-24 13:04:33 +05:30
willmafh
2d48926f1e bugfix: get scheme correctly when there is any leading whitespace 2026-05-23 12:39:34 +08: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
Karl Seguin
aeba861d69 Add WebDriver getComputedLabel
Used by https://github.com/lightpanda-io/wpt/pull/68

Helps many /accname/ WPT tests pass
2026-05-22 20:16:09 +08:00
Karl Seguin
9d6dcb71ab Merge pull request #2521 from lightpanda-io/multi_remove_assert_attributes
Add more attributes to multi_remove assertion failure
2026-05-22 20:12:53 +08:00
Pierre Tachoire
8b2a79d93a Merge pull request #2515 from lightpanda-io/cdp_watchdog 2026-05-22 13:19:48 +02:00
Karl Seguin
38a4a334fd Add more attributes to multi_remove assertion failure
Saw this assertion catch for the first time today. Hoping the extra data will
help identity the issue. No URL or other identifiable data is logged.
2026-05-22 16:10:11 +08:00
Karl Seguin
9621db2e5e Merge pull request #2514 from lightpanda-io/worker_performance
Performance WebAPI on Worker
2026-05-22 12:39:23 +08:00
Karl Seguin
0c9b07ab0f Add exposed option to bridge functions/accessors
While both Window and WorkerGlobalState expose the same "Performance" object,
some getters are window specific (e.g. eventCounts). I thought the same object
would always have the same shape and, when not possible, they'd be different
types (e.g. Location vs WorkerLocation). But that isn't always the case. So
.exposed = .window (or .worker, defaulting to .both) can not be defined on the
bridge mapping.
2026-05-22 11:32:37 +08:00
Karl Seguin
4b5d0109c5 Merge pull request #2513 from lightpanda-io/syncRequest_uaf
Protect against dangling pointer in syncRequest
2026-05-22 11:02:49 +08:00
Karl Seguin
05a373dccc zig fmt 2026-05-22 09:40:06 +08:00
Karl Seguin
5c20a79c08 improve comments 2026-05-22 09:38:58 +08:00
Karl Seguin
c0c1ae286f Merge pull request #2512 from lightpanda-io/about_blank_frame_visibility
Ensure about:blank frame visibility
2026-05-22 09:30:56 +08:00
Karl Seguin
f713d9561b Handle potentially unsorted frames pre-navigate 2026-05-22 08:48:52 +08:00
Karl Seguin
0f11736d3a Update src/browser/Frame.zig
Co-authored-by: Pierre Tachoire <pierre@lightpanda.io>
2026-05-22 08:39:06 +08: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
Navid EMAD
64a6e40121 network: advance shutdownCdpLinks iterator before dropCdp 2026-05-21 15:56:22 +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
3bfc434b3b network: fix typo in shutdown comment (Idempotent) 2026-05-21 12:40:48 +02: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
972be65db7 Merge pull request #2505 from lightpanda-io/transfer_state
Cleanup Transfer flag
2026-05-21 17:42:00 +08:00
Karl Seguin
24cc29ee79 Performance WebAPI on Worker
This includes EventCounts and PerformanceObserver. This change is like any
other WebAPI on Worker change (e.g. Frame -> js.Execution), but we need the
performance observer hooks in addition to that. Thankfully, every Frame/Worker
only has 1 Performance instance, so we can move the observers and delivery
from the Frame to the Performance instance so that both Frame and WGS gain the
behavior.
2026-05-21 16:17:21 +08:00
Karl Seguin
f3421466cd Protect against dangling pointer in UAF
syncRequest creates a context that lives on the function's stack. This "works"
because the transfer is only expected to live during the call to syncRequest
(this is the entire premise of syncRequest). But if self.tick returns an error,
the function returns, potentially with transfer.req.ctx still pointing to the
stack value.

This change captures a tick error and, if the sync request is still in_progress,
aborts the transfer. There's maybe a world where the error is recoverable and
the request could continue, but that seems error prone. AND, the most likely
non-transfer error that tick would return are pretty "serious", e.g. OOM or
client disconnected.
2026-05-21 14:23:58 +08:00
Karl Seguin
ca0eaa5f1e Ensure about:blank frame visibility
Our navigate on about:blank short-circuits most of the complex logic and loads
the content then and there, not asynchronously. This results in notifications
for the frame navigation/creation that happen immediately. With the current
code ordering though, the frame isn't entered in child_frames until AFTER
navigation, resulting in these events trigger on a frame which can't be found
via Session.findFrameByFrameId

This code adds the frame to child_frames BEFORE navigate (and removes it on
error).

Note: about:blank iframe navigation is more common than you probably think. As
soon as a frame is [dynamically] created, it navigates to about:blank, e.g.:

let iframe = document.createElement('iframe');
// IMPLICIT navigation to about:blank happens here

// and this will be another navigation event
iframe.src = "keemun.php";
2026-05-21 12:33:50 +08:00
Karl Seguin
666ff0b670 Remove unused intercept_response ParkedBy
Add comment about how unpark is meant (and not meant) to be used.
2026-05-21 11:50:25 +08:00
Karl Seguin
88b98e705f Capture disconnect/close in Worker
Currently, if a disconnect/close is captured in a worker during a syncRequest,
that specific request is terminated, but the error doesn't bubble up. The worker
remains alive and will subsequently block in a perform, with no connection alive
to wake it up.

In this commit, when disconnect/close is received, inbox.terminate is set to
true. This flag is checked (in syncRequest and http_client.tick) and
error.ClientDisconnected is returned.

(Also, on network shutdown, always broadcast the cdp_unregister since there's
no harm in sending an extra signal even if nothing was removed).
2026-05-21 10:38:52 +08: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
Karl Seguin
4c454cff71 Merge pull request #2509 from navidemad/fix/network-pollfds-clobbers-cdp-sockets
Fix CDP server stall/SIGTERM hang in optimized builds (Network drops CDP sockets from poll set)
2026-05-21 06:56:46 +08:00
Navid EMAD
bdf28c51cd network: terminate live CDP connections on shutdown
The CDP server ignored a single SIGTERM while a connection was live: the
process only exited if the socket was closed before the signal, or after a
third signal. A conventional one-shot graceful stop (SIGTERM then waitpid)
hung.

On shutdown the sighandler runs Network.stop (which sets `shutdown` and lets
the run loop exit) before Server.shutdown. A live CDP worker parks in
curl_multi_poll and is woken ONLY by the Network thread via
dropCdp -> handles.wakeup(). Once the run loop exits with links still live,
nothing can wake those workers, so Server.deinit()'s
`while (active_threads > 0)` loop spins forever.

Drop every still-live CDP link from the run loop when `shutdown` is set,
reusing the existing peer-EOF path: dropCdp(notify=true) pushes a .disconnect
into the worker's inbox and wakes it, so cdp.tick() returns false and the
worker exits before the loop breaks.
2026-05-20 21:01:51 +02:00
Navid EMAD
e1e49c8a2e Fix Network dropping CDP sockets from its poll set once a multi exists
preparePollFds cleared and rebuilt the curl portion of `pollfds` every
loop iteration, but sliced `pollfds[PSEUDO_POLLFDS..]` — all the way to
the end of the array. That range also covers the CDP socket region
`[cdp_start..]`, which prepareCdpPollFds owns and only rebuilds when
`cdp_dirty` is set (a steady-state optimization). So the @memset wiped
every live CDP socket fd to -1 on each iteration.

This only bites once Network owns a curl multi handle, which is created
solely by telemetry — and telemetry is disabled in Debug builds, which
is why it reproduced only in ReleaseFast/ReleaseSafe (and the nightly).
Regular HTTP/navigation runs on the worker's own handles, not Network's
multi, so it never triggered the path in Debug.

Once the CDP sockets are dropped from the poll set, the Network thread
stops reading client messages (#2508, hard stall after the first
command) and never observes peer EOF or `conn.shutdown`, so the worker
is never told to exit and SIGTERM is ignored after a connection (#2507).

Fix: slice only the curl region `[PSEUDO_POLLFDS..cdp_start]`.

Also harden the poll timeout: `curl_multi_timeout` returns -1 when curl
is idle, and `@min(250, -1)` is -1 (block forever), which starved
onTick (telemetry's periodic flush) and turned any missed wakeup into a
permanent hang rather than a <=250ms blip. Treat curl_timeout <= 0 as
"no deadline" and fall back to the 250ms cap.

Fixes #2507
Fixes #2508
2026-05-20 19:13:09 +02:00
Pierre Tachoire
5fce406a13 compact more help options 2026-05-20 16:09:16 +02:00
Pierre Tachoire
af6175cc56 rewrite help in a more compact way
Inspired by go help output
2026-05-20 16:05:17 +02:00
Francis Bouvier
dffa961f45 Remove options from main help 2026-05-20 16:05:13 +02:00
Karl Seguin
1cdd2bb324 Cleanup Transfer flag
Replaces 4 boolean flags with a state. Makes it easier to figure out what the
state of the transfer is, and removes the possibility of inconsistent flags
.e.g queued + loop_owned.

loop_owned -> state != .created
_queued -> state == .queued
_perform -> state == .completing
aborted -> state == .aborted
2026-05-20 20:37:21 +08:00
Pierre Tachoire
f1b0adf923 Merge pull request #2498 from navidemad/fix/author-display-rule-beats-ua-hidden
`StyleManager`: author `display` rule must beat UA `[hidden]` / `display:none`
2026-05-20 14:01:25 +02:00
Pierre Tachoire
bb2d62d189 Merge pull request #2500 from lightpanda-io/parseHtmlAsChildren_assertion
parseHtmlAsChildren handling for unexpected dom (custom element callb…
2026-05-20 14:00:58 +02: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
b6fd09c5ab Merge pull request #2502 from lightpanda-io/max-cdp-conn
by using httpClient, fetch generates a call to Config.maxConnections
2026-05-20 16:28:56 +08:00
Pierre Tachoire
639cb14cb3 Merge pull request #2494 from marchelbling/feat-fetch-json-option
feat: add --json to fetch command
2026-05-20 10:17:21 +02:00
Pierre Tachoire
6eb25d5c44 by using httpClient, fetch generates a call to Config.maxConnections 2026-05-20 10:14:17 +02:00