Commit Graph
9542 Commits
Author SHA1 Message Date
Karl Seguin 8bea867e5f Merge pull request #2406 from navidemad/parser-defer-rawtext-merge
parser: defer raw-text merge to bound memory growth
2026-05-11 21:05:39 +08:00
Karl Seguin 258003ca90 ArrayListUnmanaged (deprecated name) -> ArrayList 2026-05-11 20:42:11 +08:00
Navid EMAD a470f6b686 parser: lift merge buffer onto Parser and lazy-buffer single-chunk runs
Addresses follow-up review from karlseguin on #2406.

The pending-text merge buffer is now a single ArrayList on the Parser,
reused across runs via clearRetainingCapacity. In the streaming-parser
case (Document.write), parser.arena is the page-lifetime frame.arena, so
the previous per-PendingText buf.deinit was a no-op and growth artifacts
accumulated. With one shared buffer, total dead memory is bounded to one
peak-run-sized allocation regardless of how many text runs the parse
contains.

Single-chunk text runs no longer touch the buffer. The first chunk lives
only on CData._data via createTextNode; the buffer is seeded from
text_node.getData().str() only when a second chunk arrives at the same
parent and last_child. flushPendingText is a no-op when the buffer is
empty. Restores the common-case allocation count to 1 (matching main),
vs 3 in the previous PR head.

Benchmark deltas (ReleaseFast, peak RSS, 5-run median):
- 10K-paragraph synthetic page: 39 MB -> 37 MB
- 20K single-chunk script synthetic: 56 MB -> 54 MB
- 100 x 48 KB multi-chunk scripts: within noise (~46 MB)
- apple.com US iPhone live page: within JS-driven noise (~92 MB)

Refs #2397
2026-05-11 14:36:40 +02:00
Karl Seguin cfcfe4ee29 Merge pull request #2417 from lightpanda-io/nikneym/dummy-set-resource-timing-buffer-size
`Performance`: add dummy `setResourceTimingBufferSize`
2026-05-11 20:31:17 +08:00
Halil Durak 5faaf3dc15 --inject-script: testable injected scripts 2026-05-11 15:24:28 +03:00
Halil Durak 3c7c08f822 --inject-script: don't error out if script execution fails 2026-05-11 15:24:08 +03:00
Halil Durak 19401dc950 Config: update --inject-script documentation 2026-05-11 15:15:36 +03:00
Halil Durak d97081d71f --inject-script: execute injected scripts if encountered <head> tag
This now backs itself against html5ever to find <head>; the spec explicitly bans double-appearance of <head> tag and html5ever is aware of it.
2026-05-11 15:15:36 +03:00
Halil Durak 60d721caa2 Config: increase read file size for --inject-script-file 2026-05-11 15:15:36 +03:00
Halil Durak 246f91d1f8 --inject-script: prefer splice bytes into <head> directly 2026-05-11 15:15:35 +03:00
Halil Durak c566d0c41c introduce --inject-script and --inject-script-file
* Prefer `--inject-*` prefix.
* Support injecting multiple scripts (also allows using both variants together).
* Instead of executing scripts in JS context, actually insert them to `<head>` for correct dump output.
2026-05-11 15:15:35 +03:00
Halil Durak 39f12a5669 fetch: add support for --script option
Allows passing a JS file as an arg to be executed alongside other scripts.
2026-05-11 15:15:35 +03:00
Halil Durak 9d7eee211a Performance: fix zig fmt fail 2026-05-11 15:12:44 +03:00
Karl Seguin 08bc513fd9 Merge pull request #2416 from lightpanda-io/nikneym/link-crossorigin-getter-setter
`HTMLLinkElement`: `crossOrigin` -> `crossorigin` for attributes
2026-05-11 20:12:37 +08:00
Halil DurakandKarl Seguin 556cbc1c9f Update src/browser/webapi/Performance.zig
Co-authored-by: Karl Seguin <karlseguin@users.noreply.github.com>
2026-05-11 15:09:06 +03:00
Karl Seguin 5ba0928635 Merge pull request #2415 from lightpanda-io/nikneym/link-media-getter-setter
` HTMLLinkElement`: add `media` getter/setter
2026-05-11 20:00:09 +08:00
Halil Durak bcc82bff4a Performance: add dummy setResourceTimingBufferSize 2026-05-11 14:47:40 +03:00
Halil Durak 4e4e68e51c HTMLLinkElement: update tests 2026-05-11 14:40:40 +03:00
Halil Durak 3c8c849947 HTMLLinkElement: crossOrigin -> crossorigin for attributes 2026-05-11 14:40:26 +03:00
Halil Durak 20c7bc14d2 HTMLLinkElement: update tests 2026-05-11 14:35:41 +03:00
Halil Durak 55a42fe5c6 HTMLLinkElement: add media getter/setter 2026-05-11 14:35:30 +03:00
Navid EMAD 60219e69e9 parser: address review findings for raw-text merge
- Flush pending text in _removeFromParentCallback and
  _reparentChildrenCallback. Without these, html5ever can detach or
  reparent the pending text node mid-parse and a later flush would write
  accumulated bytes onto a node no longer in the tree (or to the wrong
  parent).

- Streaming.done now nulls self.handle right after html5ever_finish,
  before flushPendingText. If the flush errors the handle is already
  cleared, so dropping the Streaming can't double-free.

- Document.close uses a defer to clear _script_created_parser even when
  done() returns an error. Document.write's parser-panic path now
  attempts a final flush before dropping the streaming parser, so
  whatever bytes html5ever fed before the panic still land on their
  text node.

- raw_text_chunked.html: larger raw-text bodies and exact byte counts
  per element. Catches future deferred-merge regressions that drop or
  duplicate a chunk; the memory bound itself is verified out-of-band
  via the live reproducer in the PR description.

Refs #2397
2026-05-11 13:22:29 +02:00
Navid EMAD 15101f12e4 parser: defer raw-text merge to bound memory growth
Frame.appendNew did String.concat(arena, [existing, txt]) every time
html5ever flushed a script-data/rawtext chunk on a '<' token, allocating
O(N) on the page-lifetime arena per chunk. Total bytes ~= N^2/(2*c). On
apple.com US iPhone pages a 347 KB inline JSON literal with embedded
HTML strings ballooned the parse to 3.5 GB peak RSS.

Move the merge into the parser. Same-parent text chunks accumulate in a
std.ArrayListUnmanaged on the per-parse arena; one String.dupe lands the
final value on the frame arena. Flush points are the natural ends of a
text run: a non-text child appended, a foster/before-sibling insertion,
the parent element popping, or the parse call returning.

Frame.appendNew now takes *Node directly; it had no non-parser callers.
Streaming.done returns !void to propagate the final flush.

Refs #2397
2026-05-11 13:22:29 +02:00
Adrià Arrufat b5777ce35c agent: support listing LP_* variables in getEnv 2026-05-11 12:34:36 +02:00
Adrià Arrufat ecfb404af4 agent: require ALL CAPS for commands 2026-05-11 11:41:04 +02:00
Pierre Tachoire d2151b6ffd Merge pull request #2305 from navidemad/feat/xpath-1.0-evaluator
xpath: implement XPath 1.0 (Document.evaluate, XPathResult, DOM.performSearch)
2026-05-11 10:01:28 +02:00
Adrià Arrufat 3273898e97 browser.tools: reduce eval branch quota in minify 2026-05-11 09:18:09 +02:00
Adrià Arrufat 0ffabdd278 browser.tools: simplify minify function logic 2026-05-11 09:13:55 +02:00
Adrià Arrufat 1423cbe1d1 refactor: optimize agent memory and browser tools
- Rebuild `message_arena` during self-heal to prevent memory accumulation.
- Optimize `minify` comptime performance by avoiding string concatenation.
- Update `extractText` to use `runEval` and sentinels for better reliability.
- Add logging for long environment variable names in `lookupLpEnv`.
2026-05-11 09:07:27 +02:00
Adrià Arrufat 0338bf71af refactor: simplify mcp communication and tool dispatching 2026-05-11 08:57:36 +02:00
Karl Seguin c16c15bedf Various small DOM fixes, WPT driven
1. Implement document.adoptNode (we were removing from the existing document,
   but not adding to the new document)

2. Document.url should use the document's frame, falling back to the execution
   frame

3. Move HTMLDocument.location to Document.location

4. DOMImplementation.createDocument uses a more appropriate default namespace
   (xml -> null)

5. Map querySelector functions to DOMException-safe errors. The Selector returns
   specific errors, but for the DOM apis (document.querySelector,
   df.querySelectorAll, elem.matches, etc...) these largely all map to
   SyntaxError
2026-05-11 14:29:47 +08:00
Adrià Arrufat ecc68f8780 Merge branch 'main' into agent 2026-05-11 08:03:35 +02:00
Karl Seguin 8d5eef44c8 Improve events
1 - Expose various event types for Workers
2 - Listen to the removed listener flag in more places. We delay removing the
    listener (to keep the list intact) via a flag, but need to consider that
    flag in all places, e.g. when checking for duplicates when adding a listener
3 - Enforce passive flag. We have this flag, but weren't using it to block
    calls to preventDefault returnValue (which a passive listener should not
    call)
2026-05-11 12:34:52 +08:00
Karl Seguin a5aa302e65 Fix HTMLCollection
For any unknown string keys, it should return error.NotHandled (which tells
v8 that we did not service the request).
2026-05-11 11:42:04 +08:00
Karl Seguin c90e47646e add AbortSignal.any static + AbortSignal reason can be a DOMException 2026-05-11 11:38:06 +08:00
Karl Seguin efbf1db87c Merge pull request #2410 from lightpanda-io/fix_merge
Try to fix a bad merge
2026-05-11 11:37:28 +08:00
Karl Seguin 0bbddb3179 Try to fix a bad merge
https://github.com/lightpanda-io/browser/pull/2289
and
https://github.com/lightpanda-io/browser/pull/2297
2026-05-11 11:25:40 +08:00
Karl Seguin 1bfefa3d58 Merge pull request #2289 from navidemad/fix-b2-page-navigation-history
page: implement Page.getNavigationHistory and Page.navigateToHistoryEntry
2026-05-11 09:29:43 +08:00
Adrià Arrufat aae699e3b5 refactor: simplify MCP tool results and optimize slash command
Consolidates MCP tool listing and result sending. Optimizes buffer
allocation in SlashCommand.stripQuotes.
2026-05-10 17:22:33 +02:00
Adrià Arrufat 10f7478099 refactor: unify tool arg parsing and simplify string formatting 2026-05-10 17:07:57 +02:00
Karl Seguin 92d617d649 Merge pull request #2404 from navidemad/fix-fetch-double-free-on-sync-error
Fix double-free in fetch when http_client.request fails synchronously
2026-05-10 12:03:07 +08:00
Karl Seguin 520d968840 Merge pull request #2398 from staylor/fix/worker-importscripts-segfault
Defer page teardown while worker scripts are evaluating
2026-05-10 11:08:49 +08:00
Karl Seguin 261059acbe Merge pull request #2393 from lightpanda-io/scheduler_timeslice
Add timeslice to scheduler
2026-05-10 10:33:21 +08:00
Adrià Arrufat e7d6597e08 refactor: unify URL handling and clean up agent logic 2026-05-10 00:04:51 +02:00
Scott Taylor 92607ad765 Defer page teardown while worker scripts are evaluating
Worker scripts can call importScripts(), which performs a synchronous
HTTP request via HttpClient.syncRequest. To stay responsive during a
long fetch, syncRequest pumps the CDP socket (cdp.blocking_read) while
waiting. If a CDP message such as Target.closeTarget arrives on that
socket mid-fetch, the previous code path tore down the page
immediately:

    Worker JS -> importScripts -> syncRequest -> blocking_read
      -> CDP dispatch -> Target.closeTarget
      -> Session.removePage -> Page.deinit -> Frame.deinit
      -> Worker.deinit (frees worker arena + identity_map)

When control unwound back into the worker's eval, the next operation
that hit ctx.identity.identity_map.getOrPut dereferenced the freed
metadata pointer and segfaulted (sometimes immediately, sometimes a
few connections later as the arena got recycled).

Reproducer: any URL that loads dedicated workers calling importScripts
during initial eval, driven via puppeteer-core's connectOverCDP. The
allbirds.com product page (which loads ~8 web-pixel workers each
calling importScripts) reliably triggered it within ~10 connections.

Session.removePage already deferred when the frame's own
ScriptManager.is_evaluating was set; that guard never tripped because
worker scripts don't go through the frame's ScriptManager. Fix:

  * Worker.loadInitialScript now sets the worker's own
    _worker_scope._script_manager.is_evaluating around the eval, with
    save/restore so nested worker evals compose correctly.

  * WorkerGlobalScope.importScript also sets its own
    _script_manager.is_evaluating around the syncRequest +
    runMacrotasks. The typical caller (Worker.loadInitialScript)
    already sets this around its outer eval, so the outer guard
    usually covers us; the inner mark is defense-in-depth for callers
    that reach importScripts() from a setTimeout / microtask outside
    the loadInitialScript scope.

  * New Frame.anyScriptEvaluating method walks the frame tree (frame
    ScriptManager + every worker's ScriptManager + child frames) and
    returns true if any is mid-eval. Session.removePage and
    CDP.disposeBrowserContext use this in place of the frame-only
    check, deferring teardown until all evals unwind. Final cleanup
    happens at CDP.deinit on connection close, matching the existing
    deferred-teardown contract.

Verified by running the puppeteer-core repro back-to-back against a
single Lightpanda serve; all returned 200 with the right title, no
UAF crashes (was previously crashing within 1-10 runs). All 521 unit
tests still pass.

Note: a separate, pre-existing latent V8 issue surfaces under stress
on this same code path. After many iterations a Runtime.evaluate
promise tracked by V8's inspector PromiseHandlerTracker is discarded
during garbage collection's first-pass weak callbacks; the discard
sends a failure response which triggers v8::String::NewFromOneByte,
hitting the debug-only assertion AllowHeapAllocation::IsAllowed() in
heap-allocator-inl.h:79 (no allocations allowed during weak callbacks).
This reproduces on a baseline build of this PR commit and on a
baseline build of just the original two-line is_evaluating fix \u2014
i.e. it is not introduced by the deferral logic. The deferral makes
it more visible because inspector callbacks now live longer before
teardown, so they are more likely to be alive during a GC. Tracking
this as a follow-up; the fix here still resolves the UAF that was
crashing the server immediately.
2026-05-09 17:26:41 -04:00
Adrià Arrufat a5e7ec16be agent: unify interactive prompts and tool execution 2026-05-09 20:40:38 +02:00
Adrià Arrufat 1de98efbc4 agent: simplify model string ownership 2026-05-09 20:27:16 +02:00
Adrià Arrufat 5284abc3e7 agent: consolidate listModels logic into Agent.zig 2026-05-09 20:18:27 +02:00
Adrià Arrufat 938795ec8d agent: add --pick-model for interactive selection 2026-05-09 20:11:52 +02:00
Adrià Arrufat 16b83f5093 agent: add provider auto-detection and --no-llm flag 2026-05-09 19:52:42 +02:00