Commit Graph

8321 Commits

Author SHA1 Message Date
Karl Seguin
0cb9c3aebb dedupe check and centralize it in HttpClient's tickSync 2026-07-22 16:41:33 +08:00
Karl Seguin
5b12c42df2 cdp: Sanitize non-UTF 8 values
Builds on https://github.com/lightpanda-io/browser/pull/2972 in order to fix
https://github.com/lightpanda-io/browser/issues/2992

I couldn't think of a generic way to fix this. Created a SafeString which
wraps a `[]const u8` with a custom jsonStringify function. This is now applied
to both header names and values.

The existing latin1 to utf8 conversion is now extracted into string.js and used
in Frame for the filename. This was moved to Frame because the same issue
could cause issues trying to save the file.
2026-07-22 14:59:33 +08:00
Karl Seguin
0871b6a8da disable Zig 0.16 signal_stack_size
Make sure jemallocator is disabled in Release builds (we only use it in Debug
builds to collect metrics. Supposedly something changed in our 0.16 build that
causes it to be initialized even though it isn't used. Not sure, for this, I'm
just doing what Claude tell me, but disabling something in Release that I know
we aren't using sounds ok).
2026-07-22 13:26:06 +08:00
Karl Seguin
92537df123 Raise memory limit regression to 29MB
We've been climbing the last couple weeks, and Zig 0.16 appears to have added
~400KB. I'll try to go hunt it, but I don't want this to delay the merge.

(Pierre agrees)
2026-07-22 13:26:06 +08:00
Karl Seguin
802862120f update zenai dep (zig 0.16) 2026-07-22 13:26:06 +08:00
Karl Seguin
df7bde233d Fix linux build
Try to fix CI (this is what claude came up with, I have no idea why CI is
failing).
2026-07-22 13:26:06 +08:00
Karl Seguin
8e42d63c1c zig: Zig 0.16
Built against https://github.com/lightpanda-io/zig-v8-fork/tree/zig-0.16 but
it doesn't require a new v8 build.

Built against https://github.com/lightpanda-io/boringssl-zig/tree/zig-0.16
since the current fork we point to isn't updated.

A global std.Io instance, lp.io. Way easier this way and requires 0 changes to
our libcurl integration / event loop.

Network code uses a new layer that does what Zig 0.15's posix package used to
do. Again, quicker migration that way. But, as long as we have the global IO,
and given the half-baked nature of networking in std.Io 0.16, this just makes
sense. Things can be migrated as needed.

The std.time.* -> std.Io.Timestamp/Clock/Duration resulted in _a lot_ of
changes. ArrayList = .{} -> ArrayList -> .empty also resulted in a lot of
changes, but that's obviously superficial. As is the trimLeft/trimRight ->
trimStart/trimEnd rename.

Locking adopt the `Uncancelable` variants, e.g. mutex.lockUncancelable() to
preserve the error-free signature (and, because cancellation would be something
we'd have to put more thought into).

std.json.ObjectMap is now unmanaged, so the allocator had to be passed along.
However, there's still a deprecated managed variant of MemoryPool, so I switched
to it (we can do a small follow up PR to move to the unmanaged after).

I tried use_llvm = false, but it locks my computer, consuming RAM until MacOS
gives me a popup I've never seen before, begging me to start killing processes.

Agent and the networking stuff saw the most significant changes.
2026-07-22 13:26:03 +08:00
Karl Seguin
8a3ef296c0 Merge pull request #3011 from lightpanda-io/rc-overflow
overflow: Make RC a u32
2026-07-22 13:19:59 +08:00
Karl Seguin
a100c49cee overflow: Make RC a u32
Remove the RC(T) generic, make the counter always a u32. We've now seen two
u8 overflow cases. Time to eliminate them all.
2026-07-22 09:39:54 +08:00
Scott Taylor
a12032cd0e Interrupt nested script waits during teardown
Assisted-By: devx/8bea7794-aef3-4ef5-a06d-fd1f1f3aafd0
2026-07-21 18:07:15 -04:00
Karl Seguin
90db5d7f69 Merge pull request #3005 from lightpanda-io/reduce-gc-hint-frequency
perf, v8: reduce gc hint frequency
2026-07-21 18:44:19 +08:00
Karl Seguin
ea13c57dcd Merge pull request #3006 from lightpanda-io/wpt-adjust
wpt: adjust concurrency
2026-07-21 18:00:31 +08:00
Pierre Tachoire
fd35c0d01a wpt: adjust concurrency 2026-07-21 11:38:27 +02:00
Pierre Tachoire
ea2008334f Merge pull request #2990 from staylor/scott/http-cache-interception
Add per-CDP control for Network.setCacheDisabled
2026-07-21 10:06:54 +02:00
Karl Seguin
69b3424b9c Revert "experiment: On session teardown, use less aggressive v8 GC hint"
This reverts commit aa4323f72b.
2026-07-21 10:34:01 +08:00
Karl Seguin
aa4323f72b experiment: On session teardown, use less aggressive v8 GC hint
critical -> moderate
2026-07-21 10:06:42 +08:00
Karl Seguin
eca8baf8ed v8, perf: Reduce v8 GC hint frequency.
We currently send a memoryPressureNotification every second during a run. This
can put too much pressure on v8, manifesting as high CPU usage particularly on
complex pages. This commit changes it to every 5 seconds.

Also, remove unused lowMemoryNotification.v8, perf: Reduce v8 GC hint frequency.
2026-07-21 08:58:42 +08:00
Scott Taylor
c7850a4012 Add per-CDP cache disable configuration
Assisted-By: devx/2fa2960e-76f4-4b6e-b6e6-1419f108f12b
2026-07-20 14:02:55 -04:00
Pierre Tachoire
cd9492f29c Merge pull request #3003 from lightpanda-io/script-error-window-reportError
webapi: On script error, trigger window.reportError
2026-07-20 17:53:06 +02:00
Pierre Tachoire
a5ee29d99d Merge pull request #2985 from Totara-thib/plumber-ci
ci: add plumber to watch workflow security
2026-07-20 17:27:22 +02:00
Karl Seguin
6c5bde28df webapi: On script error, trigger window.reportError
Besides this being correct, it should improve WPT stalls by triggering the
window.onerror which the WPT harness hooks into to stop tests.
2026-07-20 21:50:50 +08:00
Thibaud-Vdb
e25ea46cd8 chore(readme): remove plumber badge
Co-authored-by: Pierre Tachoire <pierre@tch.re>
2026-07-20 15:33:28 +02:00
Thibaud-Vdb
1d553ff5ee ci: add plumber to watch workflow security
Runs on pushes to main and on pull requests. The config starts from
the generated defaults and is scoped to this repo: the few controls
that are off carry a note explaining why and what would let them
come back on.

Reports are uploaded to code scanning, except on PRs from forks
where the token cannot write security events. Each run on main also
publishes the score through OIDC, which feeds the live badge added
to the README next to the existing ones.
2026-07-20 15:12:58 +02:00
Pierre Tachoire
32479b1299 Merge pull request #2984 from Totara-thib/pin-actions
ci: pin github actions to commit shas
2026-07-20 15:12:03 +02:00
Thibaud-Vdb
cca00c022e ci: pin github actions to commit shas
Mutable tags like @v6 can be re-pointed by whoever controls the action,
so the next run executes code nobody here reviewed, with the job's
token and secrets. Pinning to the full commit sha freezes what runs.
Version tags are kept as comments so renovate or dependabot can still
track updates.

dtolnay/rust-toolchain is pinned to a master commit with the toolchain
moved to an explicit input, as its readme recommends for sha pinning.
2026-07-20 14:56:59 +02:00
Karl Seguin
1ded9da773 Merge pull request #2995 from lightpanda-io/cookie-store
Cookie store
2026-07-20 20:16:29 +08:00
Karl Seguin
795c1a96bb Merge pull request #2988 from lightpanda-io/iframe-invalid-url
iframe: load about:blank on un-parsable URL
2026-07-20 18:50:07 +08:00
Karl Seguin
42f089780c move stripFragment to URL.zig 2026-07-20 18:47:00 +08:00
Karl Seguin
3d59f0eec2 uaf: Fix potential UAF from js-created CookieChangeEvent
Add WebDriver.getNamedCookie to give WPT access to http-only cookie.
2026-07-20 18:47:00 +08:00
Karl Seguin
4cdf8b441e webapi: Support max-age for CookieStore
Normalize get name so that it matches the normalize stored cookie name.

Don't queue cookie change event if there's no listener. This one's a bit tricky
since we do this check inside the callback already. But that means a listener
added after the event is created (but before it's delivered) gets a change
event it should not. So we need to check it both at event-creation time and
at delivery time.
2026-07-20 18:47:00 +08:00
Karl Seguin
9090869420 Merge pull request #2991 from lightpanda-io/blob-origin
webapi: Blob shared per origin
2026-07-20 18:46:34 +08:00
Karl Seguin
5736be9740 Merge pull request #2997 from lightpanda-io/robots-fix
robots.txt: Improve robots.txt correctness.
2026-07-20 18:41:23 +08:00
Karl Seguin
7a9b93becc robots.txt: Improve robots.txt correctness.
This applies two individual fixes to our robots.txt parser. The first is that
instead of doing an exact match with the User-Agent, it extracts the
"productToken". A UA of Lightpanda/1.0, should match "Lightpanda". The second is
that an empty directive matches.

Given:

User-agent: Lightpanda
Disallow:

User-agent: *
Disallow: /

We would have failed for 2 reasons. Fix #1 is necessary, otherwise
"Lightpanda" != "Lightpanda/1.0". Fix #2 is necessary  because this robots.txt
does _not_ disallow Lightpanda from anything (e.g. the fallback doesn't apply
to us).
2026-07-20 15:00:04 +08:00
Karl Seguin
0cffa933d4 Merge pull request #2996 from lightpanda-io/root-page-no-cache
cache: Never cache the top-level root page
2026-07-20 14:58:52 +08:00
Pierre Tachoire
9e1e045458 Merge pull request #2998 from lightpanda-io/wpt-change
wpt: set a memory limit per browser instead of per process
2026-07-20 08:58:09 +02:00
Pierre Tachoire
af3a552af7 wpt: set a memory limit per browser instead of per process 2026-07-20 08:29:44 +02:00
Karl Seguin
299eb2c5f9 Merge pull request #2989 from lightpanda-io/http-client-no-poll-after-dispatch
perf: If a message is dispatched, don't poll
2026-07-19 08:37:42 +08:00
Karl Seguin
996815d570 zig fmt 2026-07-18 17:19:02 +08:00
Karl Seguin
86bf28216a webapi: Blob shared per origin
This reworks blob URLs from being owned by the Frame to being owned by the Page
and shared / protected by origin. This allows, for example, a worker/popup/
iframe from accessing blobs created by its page, provided they share the same
origin.

This was already working on a small (but common) set of cases, but has now been
reworked (by moving the blob registry up to the Page, where it can be shared) to
cover every case.
2026-07-18 14:24:39 +08:00
Karl Seguin
20cde7a6f5 perf: If a message is dispatched, don't poll
Polling delays processing of messages. So don't poll after we know we've
dispatched. Largely impacts CDP which is more likely to poll (for data on the
CDP connection).
2026-07-18 09:54:41 +08:00
Adrià Arrufat
fc461e05a9 Merge pull request #2920 from lightpanda-io/run-command
cli: add `run` command for script replay
2026-07-17 23:59:23 +02:00
Adrià Arrufat
805b60d626 Merge branch 'main' into run-command
# Conflicts:
#	src/Config.zig
#	src/help.zon
2026-07-17 22:46:47 +02:00
Pierre Tachoire
ac0e6c86a9 Merge pull request #2970 from lightpanda-io/navigation-dispose-event
Dispose Event for `NavigationHistoryEntry`
2026-07-17 15:31:06 +02:00
Karl Seguin
6b6b17240e iframe: load about:blank on un-parsable URL
Spec says this is what we should do and it's apparently used a part of bot
detections (because bots don't load about:blank and thus the iframe's state
can easily be checked to be invalid, I guess).
2026-07-17 20:45:24 +08:00
Karl Seguin
11f9777282 cache: Never cache the top-level root page
The idea is that, for most cases, the top level page isn't revisited, so
caching is just overhead + wasted space. Plus, if someone does revisit it,
chances are they want a fresh copy.

Imagine someone scraping a typical ecommerce site. Sure, they want to cache
the .js files which get re-used from product to product. But do they want to
cache each individual product page?
2026-07-17 18:55:31 +08:00
Pierre Tachoire
d4ea815369 Merge pull request #2981 from lightpanda-io/help-pager
cli: page help output through $PAGER when stdout is a tty
0.3.5
2026-07-17 12:06:30 +02:00
Pierre Tachoire
8b110ff5c5 fire dispose even when currententrychange dispatch fails
The disposed entries are already out of _entries, so an error during
the currententrychange dispatch leaked their _on_dispose callbacks
(onRemoveFrame only walks _entries). Fire dispose in a defer and log
per-entry failures instead of propagating them.
2026-07-17 12:04:19 +02:00
Karl Seguin
6352863d6e css: Respect @layer priority
Builds ontop of https://github.com/lightpanda-io/browser/pull/2719 and adds
the missing layer-priority.

This can be broken down into two parts. The first is the hot read path. This
code is unchanged...same buckets and same u64 priority comparison.

What has changed is the build/rebuild step and how / what the
VisibilityRule.priority means. priority used to be 32bits for specificity and
32bits for doc order (specificity tie-breaker). Priority is now 12bits for
layer rank, 30bits for specificity and 22bits for doc order. Specificity was
only using 30bits, and the smaller doc order means we can now only represent
4 million rules (Facebook, which has _a lot_ of rules, has ~50K and like 95% of
those are not visibility rules..so we have plenty of space still).

But layer ordering is complicated because you need to parse everything before
you know the final order. So our build now accumulates intermediary results and
does a final iteration through the VisibilityRule to |= the rank_layer bits of
their priority. This is no-op if there are no layers (common case for now).
Because of this intermediary work, I've added a build_arena that is build/
rebuild specific. Possibly overkill since we don't expect sites to have
thousands of layers, but it's cheap to add (except now you need to think: should
I use the build_arena or self.arena).
2026-07-17 17:54:40 +08:00
Adrià Arrufat
f02fba40cd cli: drop redundant SIGPIPE ignore in the help pager
std.start.maybeIgnoreSigpipe() already installs a noop SIGPIPE handler
at startup (std.options.keep_sigpipe defaults to false), so a write to
a dead pager returns error.BrokenPipe — which the existing catch
handles — instead of killing the process. The manual SIG_IGN was also
the disposition std deliberately avoids, since ignored dispositions
survive exec and would leak to child processes.
2026-07-17 11:50:51 +02:00
Pierre Tachoire
4a995f9544 fire dispose after currententrychange per spec 2026-07-17 11:38:11 +02:00