Commit Graph

8347 Commits

Author SHA1 Message Date
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
Karl Seguin
3430bbddd8 postMessage / MessageEvent now allow / track MessagePost
Navigator properties moved from data properties to real accessors. This impact
how they're seen (and potentially treated) by JS code.

These change result in https://www.browserscan.net/bot-detection correctly
rendering. When paired with https://github.com/lightpanda-io/browser/pull/2561
we now render that page correctly (still detected as a bot, but we no longer
fail to render)
2026-05-28 08:13:21 +08:00
Karl Seguin
4e2f21990c Merge pull request #2560 from lightpanda-io/capture_401_407
Capture 401 and 407 bodies
2026-05-28 06:57:21 +08:00
Karl Seguin
15a7a66003 Make various Window/Worker accessors settable
window.console (and many others) should be settable. This is the [Replaceable]
WebIDL attribute.

This improves loading of https://www.browserscan.net/bot-detection which would
immediately break/fail because we would throw on window.console setting.

This appears to come from obfuscator.io's disableConsoleOutput flag, so the
issue might be relatively common.
2026-05-27 21:41:40 +08:00
Karl Seguin
f614d898aa Capture 401 and 407 bodies
We currently skip capturing 401 and 407 bodies. This appears to be an
optimization with the intent that it won't be needed. While that might be true
in some cases (though, not sure when), it isn't always true. A page.navigate
to a 401 should display the content.

(Also, tried to silence meaningless BrokenPipe noise in tests).
2026-05-27 19:34:39 +08:00
Karl Seguin
13547c0ff8 Add declarative shadow dom (DSD)
Normally, a shadow dom is attached to an element via `el.attachShadow(mode)`.
With DSD, the shadow dom is attached during parsing. Essentially, when we see:

<template shadowrootmode="open">...</template>

it has the end result of calling attachShadow on the parent element. This is
used increasingly by a number of frameworks, though normally with backwards
compatibility that fallbacks to doing it in JavaScript.

DSD happens during parsing and document.write, but not via innerHTML = ''.
However, both Element and DocumentFragment gain a `setHTMLUnsafe` which is like
innerHTML WITH DSD.

I initially thought this feature could be implement exactly like I describe:
when the parser adds a template, check for a `shadowrootmode` attribute and
call attachShadow...except..you need to call attachShadow on the parent, which
the parser hasn't popped yet, and it alters where the children are added.
Thankfully, html5ever has a boolean to enable/disable dsd..hence the html5ever
binding changes to (a) enable / disable this featuer and (b) the new callback.
2026-05-27 19:11:43 +08:00
Karl Seguin
158dffd543 In debug, try to capture a module evaluation stack
This requires setting SetCaptureStackTraceForUncaughtExceptions on the isolate,
so for now, I've only enabled it in debug.
2026-05-27 19:10:25 +08:00
Pierre Tachoire
7743e68c58 Merge pull request #2558 from lightpanda-io/session_deinit_memory_notification 2026-05-27 13:08:26 +02:00
Karl Seguin
930ffb5581 Notify v8 of memory pressure on session.deinit
https://github.com/lightpanda-io/browser/pull/2548 removed the _need_ to call
v8::Isolate::MemoryPressureNotification on Session.deinit and actually removed
the call.

But [my theory] is that this causes our peak memory to be higher. So, I'm
adding it back.

The point of #2548 was to open the door for improving the memory signals to v8
by removing the _need_ for this specific signal. That PR made it so that, for
correctness (UAF) we no longer _had_ to call it. The point of the PR wasn't
to necessarily improve the signals, so I don't feel too bad about putting this
back in.
2026-05-27 18:35:40 +08:00
Karl Seguin
c04c6b3827 Use Node's own frame when executing on nodeIsReady
When nodeIsReady is called from a dynamic (JS) insertion, execute any code
on the node's frame, not the frame that did the insertion.

The code is a bit uglier than it has to be, because getting the node's frame
isn't free, and we only execute code for a few types (scripts, links, ...) so
we only get the owning frame when we're sure it's needed (thus the duplication)
2026-05-27 18:13:01 +08:00
Karl Seguin
4735126507 Merge pull request #2553 from lightpanda-io/remove_legacy_test
Remove legacy test
2026-05-27 15:23:51 +08:00
Karl Seguin
ff6743af88 Merge pull request #2554 from lightpanda-io/StaticRange
Add StaticRange
2026-05-27 15:23:33 +08:00
Karl Seguin
f80a5ce3b2 Merge pull request #2555 from lightpanda-io/markdown-shadow-piercing
Add shadow dom piercing to markdown dump
2026-05-27 15:18:55 +08:00
Karl Seguin
014b8e12eb Add shadow dom piercing to markdown dump
The markdown renderer currently ignores shadow-dom. It doesn't "pierce" it, so
it'll render the light-dom (which is the template / fallback), which won't be
right.

This largely mimics the existing logic in dump.
2026-05-27 13:20:14 +08:00
Karl Seguin
7cb7d01d97 Add StaticRange
This doesn't solve anything, but I was looking at /input-events/ WPT tests and
many are stuck with due to this type not existing. I don't expect this to fix
any of those tests, but it does move them along a bit further (the /input-events
test are all based on editing capabilities that we don't have).

We already had a // todo StaticRange in AbstractRange, and since it's very
simple, why not.
2026-05-27 10:40:52 +08:00
Karl Seguin
479c29816a Remove legacy test
AFAIK, these aren't being used and I've personally not have reason to reference
/ look at them for months.

I have no issues though if we want to keep them in.
2026-05-27 08:55:04 +08:00
Karl Seguin
81c1ae7392 Merge pull request #2546 from lightpanda-io/unified_data_urls
Unify Data URLs
2026-05-27 08:33:22 +08:00
Adrià Arrufat
a3559a4f60 Merge branch 'main' into agent 2026-05-26 19:48:18 +02:00
Adrià Arrufat
1e5bc2a1ba Merge pull request #2552 from lightpanda-io/agent-token-optimization
browser: support markdown scoping and truncation
2026-05-26 19:47:49 +02:00
Adrià Arrufat
0b931690b0 agent: clarify guidance and tool descriptions
Updates the `maxBytes` tool description to specify UTF-8 truncation,
and refines the driver guidance for `tree` and `html` tools.
2026-05-26 19:25:23 +02:00
Adrià Arrufat
b4d55eb863 string: extract truncateUtf8 helper
Moves the UTF-8 truncation logic from Spinner's `utf8FloorTo` to a
shared `truncateUtf8` function in `string.zig`. Reuses it in both
Spinner and markdown rendering, and adds comprehensive tests.
2026-05-26 16:52:09 +02:00
Karl Seguin
85d84c296e Merge pull request #2551 from lightpanda-io/fix-appcodename
Navigator.appCodeName returns `Mozilla`
0.3.1
2026-05-26 22:37:41 +08:00
Adrià Arrufat
693db15281 browser: support markdown scoping and truncation
Adds `selector`, `backendNodeId`, and `maxBytes` options to the
`markdown` tool. This allows rendering specific subtrees and capping
large outputs. Also updates the agent guidance to prefer scoped reads.
2026-05-26 16:06:42 +02:00
Karl Seguin
5056c7ad2a Merge pull request #2548 from lightpanda-io/browser_finalizer_callback_identity
Move FinalizerCallbackIdentity lifetime from Session to Browser
2026-05-26 22:00:02 +08:00
Karl Seguin
2225a6ad29 Merge pull request #2429 from lightpanda-io/custom-element-reactions-v2
Custom element reactions v2
2026-05-26 21:59:28 +08:00
Karl Seguin
2ec8906339 Merge pull request #2549 from lightpanda-io/recursive_submit
Protect against recursive form submits
2026-05-26 21:58:40 +08:00
Pierre Tachoire
eb194627d4 Navigator.appCodeName returns Mozilla
https://developer.mozilla.org/en-US/docs/Web/API/Navigator/appCodeName
2026-05-26 15:57:20 +02:00
Karl Seguin
38cdf6c4e4 Merge pull request #2542 from lightpanda-io/post_load_inline_deferred_scripts
Immediately run deferred inline scripts after "load" is fired
2026-05-26 17:57:35 +08:00
Karl Seguin
ed92ea1a5f Merge pull request #2543 from lightpanda-io/frame_document_write
Improve document.write within an iframe
2026-05-26 17:32:49 +08:00
Karl Seguin
72ad189785 Protect against recursive form submits
Fixes WPT crash /html/semantics/forms/form-submission-0/form-submission-algorithm.html

This fixes two separate possible recursive entries in the form submission
process. Both fixes are spec-accurate (hence the WPT test that specifically
tries it).

In short, the issues are  the submit -> submit -> repeat and
formdata -> submit -> formdata -> submit -> repeat.

So two guards are added to track "I'm submitting" and "I'm building the form
data".
2026-05-26 17:27:32 +08:00
Pierre Tachoire
398d9a5c39 Merge pull request #2545 from lightpanda-io/response_request_tweaks
Tweak Response and Request
2026-05-26 10:54:10 +02:00
Karl Seguin
01b8bb305b Move FinalizerCallbackIdentity lifetime from Session to Browser
A v8 Finalizer can fire at any point, including after the underlying Zig object
has been freed. Even after the corresponding Frame and Page have been freed.

To deal with this, v8 Finalizers are tied to a special
FinalizerCallback.Identity (fci) which tracks whether the underlying Page still
exists (fci.done == true). This ensures that, if v8 calls an finalizer much
later, we don't UAF. All we have to do is cleanup the fci itself and exit -
everything else is already gone.

The problem is, we tied the fci's to the session, but the v8 Finalizer can
outlive the Session (which is meaningful to v8). We made this work by trying
to force the isolate to reclaim memory on session deinit. The problem with this
is that it still isn't guaranteed to work (though, practically speaking, if
this _has_ resulted in any UAF, it's been rare). PLUS it puts load on the v8
worker threads that can compound over short-lived sessions.

The fix is to move the fci to the browser. This is safe because Browser ==
Env == Isolate, so when the browser is torn down, the isolate is torn down, and
at THAT point, we're sure no Finalizers can fire.

With this change, the call to `memoryPressureNotification(.critical)` in
Session.deinit has been removed.
2026-05-26 16:43:28 +08:00
Pierre Tachoire
cccf461a0e Merge pull request #2547 from mvanhorn/osc/fix-comment-typos
chore: fix three typos in comments and error message
2026-05-26 10:31:00 +02:00
Pierre Tachoire
c15cd46c85 Merge pull request #2541 from lightpanda-io/import_meta.resolve
implement import.meta.resolve
2026-05-26 10:04:00 +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
e7cb9253a6 Merge pull request #2540 from lightpanda-io/websocket_worker
make websocket work in worker
2026-05-26 09:37:16 +02: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
Karl Seguin
02df0dc287 Unify Data URLs
Previously, the logic for data/blob URLs were spread out at every http_client
caller. fetch/XHR/ScriptManager all had their own "if this is a data url, ..."
logic.

This causes two issues.
1 - Duplication, particularly as we try to cover more edge cases that need to
    be handled in all places.

2 - Correctness because data/blob URLs are still URLs and still need to be
    "fetched" (from memory). They should still fire with the same timing as any
    other URL. That means that for fetch/XHR, they should fire asynchronously
    (i.e. on the next tick). And for ScriptManager they should fire depending
    on the type of script (normal/defer/async).

This PR relies on the infrastructure added to:
https://github.com/lightpanda-io/browser/pull/2506 in order to fulfilled a
synthetic response on the next tick.

Frame.navigate is excluded from this refactor. For one, about:blank must be
special-cased and run synchronously (one of the few places where this is
strictly required) and even blob URLs are a bit different: the blob URL list
is the parent frame, not self, and there's more we need to do (set origin).
Potentially there _is_ some improvement here, but it's both less significant
and less simple.
2026-05-26 13:41:03 +08:00
Karl Seguin
c846fa2faf Tweak Response and Request
Implement `bodyUsed` getter for both types. With this implemented, correctly
reject requests when `bodyUsed == true`.

Expand Response to use BodyInit (Request was already using it).

Expand BodyInit to discriminate between a TypedArray/BufferArray and a string,
which allows us to capture the correct content type.

Add Request.priority and in Request/Response body getters, strip BOM as needed.
2026-05-26 10:01:55 +08:00
Karl Seguin
9fb631bd4d Merge pull request #2506 from lightpanda-io/next-tick-client
Serve Cache from Next Client Tick
2026-05-26 08:42:52 +08:00
Muki Kiboigo
2043f3e3b1 use next_tick_count to limit drain count 2026-05-25 17:13:16 -07:00
Muki Kiboigo
17e166c35f assert that next_tick_count is 0 after abort 2026-05-25 17:12:40 -07:00
Muki Kiboigo
c927fc927d decrement next_tick_count when canceled 2026-05-25 17:05:48 -07:00
Karl Seguin
228fdafa11 Merge pull request #2544 from lightpanda-io/cache-evict
Cache Eviction
2026-05-26 07:38:12 +08:00
Muki Kiboigo
f0bc85f117 add Cache Eviction 2026-05-25 11:23:25 -07:00
Adrià Arrufat
7149bf3f5f Schema: reject duplicate fields in buildValue 2026-05-25 20:22:44 +02:00
Muki Kiboigo
a4c535370b add optional Abort handler to runNextTick 2026-05-25 11:05:11 -07:00
Muki Kiboigo
aa90575f82 iterate through NextTickQueue without popFirst 2026-05-25 10:52:52 -07:00
Muki Kiboigo
00ccb5ed52 NextTickNode is owned by Transfer 2026-05-25 10:52:51 -07:00
Adrià Arrufat
c59872bfb9 eval: isolate scripts and support top-level return
Wrap eval scripts in block scope to prevent let/const leaks. If a
top-level return error occurs, retry execution inside an IIFE.
2026-05-25 19:49:43 +02:00