Commit Graph

5839 Commits

Author SHA1 Message Date
Navid EMAD
46f1646cf0 forms: honor formaction / formmethod / formenctype on submit button
When a form is submitted via a click on a submit button (or
form.requestSubmit(button)), the HTML form-submission algorithm requires
the submitter's formaction / formmethod / formenctype attributes to
override the form's corresponding attributes when present. Frame.submitForm
was reading action / method / enctype only from the form element, so the
button-side overrides were silently ignored. The symmetrical lookup for
formtarget already exists upstream — this commit applies the same pattern
to the other three attributes.

Closes #2278
2026-04-28 00:12:22 +02:00
Karl Seguin
ef3305a713 Merge pull request #2271 from lightpanda-io/disable_webgl_canvas
return null on getContext('webgl') and getContext('experimental-webgl')
2026-04-27 22:00:05 +08:00
Karl Seguin
65f3f90cab Merge pull request #2270 from lightpanda-io/terminate_guard
Mutex for Isolate.Terminate
2026-04-27 21:49:22 +08:00
Karl Seguin
1e61c76009 Merge pull request #2251 from lightpanda-io/same_url_navigate
Fix same-url navigate
2026-04-27 21:49:08 +08:00
Karl Seguin
f515233b52 Merge pull request #2248 from lightpanda-io/blackhole_storage
Add and default to Blackhole storage
2026-04-27 21:48:54 +08:00
Karl Seguin
36f89f0071 Merge pull request #2272 from lightpanda-io/uievents
Improve WPT uievents/ tests
2026-04-27 21:48:36 +08:00
Karl Seguin
fcb9b00e09 Merge pull request #2243 from lightpanda-io/exit_on_cli_error
Propagate CLI parsing errors
2026-04-27 19:39:30 +08:00
Karl Seguin
cb0ff4d07c Merge pull request #2257 from navidemad/fix-a15-location-pathname-search-setters
browser: trigger navigation when Location.pathname or .search is assigned
2026-04-27 18:31:09 +08:00
Karl Seguin
0bcb0e4e6a Merge pull request #2265 from navidemad/fix-a16-redirect-fragment-inherit
http: inherit request URL fragment across fragment-less redirect
2026-04-27 18:15:16 +08:00
Karl Seguin
9441e4fec8 Improve WPT uievents/ tests
1. Add a bunch of initXYZEvent functions, and fix the overload of initTextEvent
2. Add a number of missing (mostly legacy) accessors, e.g. uievent.getWhich()
3. CompositionEvent inherits from UIEvent, not Event
4. Give every accessor get/set a name. E.g the "name" of script.src is
  "get script" and "set script".
2026-04-27 15:57:11 +08:00
Karl Seguin
a205bbbf7d return null on getContext('webgl') and getContext('experimental-webgl')
Currently, we return a dummy `WebGLRenderingContext`. But this type implements
virtually nothing. From MDN: "If the context identifier is not supported null is
returned."

Now, normally we like to move things along as much as we can. Returning
`WebGLRenderingContext` lets us know the next thing the code needs. But in this
case, it seems to be problematic. At least some code is defensive around a null
value from getContext('webgl'), but once we return an instance, it expects it
to work correctly. This is what causes https://github.com/features/copilot to
enter an endless JS loop.
2026-04-27 14:56:55 +08:00
Navid EMAD
00c42dec4e http: inherit request URL fragment across fragment-less redirect
Per RFC 7231 §7.1.2, when a 3xx response carries a Location header
without a fragment, the user agent must process the redirect as if
the value inherited the fragment of the request URL. URL.resolve
follows RFC 3986 §5.3 which drops the base fragment, so handleRedirect
now reattaches the original fragment when the resolved target has none.

Closes #2263
2026-04-27 08:04:47 +02:00
Karl Seguin
9fbade4573 Merge pull request #2253 from navidemad/fix-requestsubmit-default-submitter
Fix SubmitEvent.submitter for requestSubmit() with no argument
2026-04-27 12:20:36 +08:00
Karl Seguin
5dd1820f88 Merge pull request #2255 from navidemad/fix-network-cookies-empty-params-and-get-all
network: accept empty params on clearBrowserCookies, add getAllCookies
2026-04-27 12:15:58 +08:00
Navid EMAD
253efcae6e browser: trigger navigation when Location.pathname or .search is assigned
The JsApi binding for Location.prototype declared `pathname` and `search`
as read-only accessors (`null` setter), so assigning either had no
observable effect — the URL was never re-parsed and no navigation was
queued. Per HTML Living Standard §7.4.4.5.5/§7.4.4.5.6, both setters
must run the URL parser against a copy of the current URL and then
"Location-object navigate" to the result.

Add `setPathname` / `setSearch` member functions that mirror the
existing `setHash` shape: compute the new full URL via the matching
helper in `src/browser/URL.zig` and forward to `Frame.scheduleNavigation`
with `kind = .push` (matches Chrome's history-handling for these
setters). Wire them into the `pathname` / `search` accessors in place
of the previous `null` setters.

Closes #2256
2026-04-27 05:30:01 +02:00
Karl Seguin
6e729131ed Mutex for Isolate.Terminate
Improvement to https://github.com/lightpanda-io/browser/pull/2246

In that PR, the check for `v8__Isolate__IsExecutionTerminating` guarded
runMicrotasks from running when the execution was terminated, but what if
termination happens immediately after?  This adds a mutex to ensure that the
isolate cannot be terminated while microtasks are being processed.
2026-04-27 11:10:38 +08:00
Navid EMAD
53b41966fd network: send empty params test cases as raw JSON
The empty Zig anonymous struct `.{}` serializes to `[]` (tuple → JSON
array), not `{}`. The dispatch path's `InputParams.jsonParse` requires
the params field to begin with `object_begin`, so the previous test
fixtures hit `error.UnexpectedToken` → `error.InvalidJSON` instead of
exercising the production code paths.

Switch the two empty-params test cases to raw JSON string literals,
which the testing helper passes through unchanged (string literals are
pointer types and skip `std.json.Stringify.valueAlloc`). The production
code paths under test are unchanged.
2026-04-27 04:56:57 +02:00
Karl Seguin
e30658fae1 fix test 2026-04-27 10:50:48 +08:00
Navid EMAD
5fba50a8d0 network: accept empty params on clearBrowserCookies, add getAllCookies
`Network.clearBrowserCookies` had an inverted-logic guard that returned
`InvalidParams` whenever the caller included a `params: {}` field — which
most CDP libraries (chrome-remote-interface, chromedp, etc.) do
unconditionally. The CDP spec defines no parameters for the method, but
JSON-RPC convention is to silently accept extra ones; Chrome and the
sibling `Storage.clearCookies` handler already do. Drop the guard.

`Network.getAllCookies` was missing from the `Network` dispatch enum and
returned `UnknownMethod`. Add a small handler that returns the entire
cookie jar via the existing `CdpStorage.CookieWriter`, mirroring
`Storage.getCookies` minus the `browserContextId` filter (Network
commands are scoped to the current browser context already).

Closes #2254
2026-04-27 04:10:20 +02:00
Navid EMAD
746921b86d Fix SubmitEvent.submitter for requestSubmit() with no argument
When Form.requestSubmit() is called without a submitter argument, the
HTML spec defaults the internal submitter variable to the form element
itself (step 2). The subsequent "submit a form element" algorithm then
collapses submitter === form back to submitterButton = null before
constructing the SubmitEvent. We were skipping that collapse and using
the form as the SubmitEvent's submitter, which diverges from Chrome /
Firefox / WPT.

Frame.submitForm now coerces submitter_ to null when it equals the
form element, mirroring the spec algorithm. The form.html fixture
that previously asserted the wrong behavior is updated to assert
.submitter === null per spec.

https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#concept-form-submit

Closes #2252
2026-04-27 03:44:33 +02:00
Karl Seguin
a2f21ff463 Fix same-url navigate
Same-URL navigate should always cause a reload. The code that currently prevents
a navigate on fragment change is too loose and treats identical URLs as being
a fragment change..but for it to be considered a fragment change, the fragment
actually has to change.

This improves some WPT compat where tests do:

<iframe></iframe>  <--- loads "about:blank"

<script>
document.querySelector('iframe').src = "about:blank"; <--- should load it again
</script>
2026-04-27 09:27:30 +08:00
Karl Seguin
a578f4d6ad Merge pull request #2246 from lightpanda-io/terminate
Adds --terminate-ms command line argument + ctrl-c improvements in fetch
2026-04-27 08:57:45 +08:00
Karl Seguin
945e9597bf Propagate CLI parsing errors
Rather than continue on a failed argument parse, propagate the error so that
the program eventually exists.
2026-04-27 08:48:30 +08:00
Karl Seguin
e1e9a0d78c Merge pull request #2244 from navidemad/fix/get-element-by-id-from-node-recovery
Fix Frame.getElementByIdFromNode to recover from removed_ids
2026-04-27 08:46:05 +08:00
Karl Seguin
7819ee50fa Add and default to Blackhole storage
Tweak sqlite build to omit more features, hoping to shrink the size when sqlite
is used.
2026-04-26 09:04:33 +08:00
Karl Seguin
b3257754e0 Merge pull request #2245 from lightpanda-io/navigate_load_arena
Use an arena from the ArenaPool for the main page
2026-04-26 08:25:55 +08:00
Karl Seguin
fc636d4e36 Merge pull request #2247 from lightpanda-io/small_fixes
Various small fixes
2026-04-26 08:25:41 +08:00
Karl Seguin
ed5bc09951 Merge pull request #2241 from lightpanda-io/fix/bound-memory-growth-long-waits-main
browser: bound per-tick memory growth on JS-heavy pages
2026-04-25 14:53:10 +08:00
Adrià Arrufat
093555b374 browser: hint v8 gc during long waits
Runner._wait can iterate for the full opts.ms budget (up to 30s in
fetch, longer in agent tool-use loops). V8 was only nudged to GC on
session/page teardown (Browser.deinit, Page.deinit), so a page that
stays alive while running heavy JS accumulates wrappers and
external-ref'd Zig allocations V8 has no reason to drop. Fire
memoryPressureNotification(.moderate) once per second from the wait
loop.
2026-04-25 08:19:49 +02:00
Karl Seguin
8509b112b8 Various small fixes
Extracted from https://github.com/lightpanda-io/browser/pull/2242
2026-04-25 13:22:41 +08:00
Karl Seguin
12c2efb811 Adds --terminate-ms command line argument + ctrl-c improvements in fetch
The main.zig path for `fetch` now captures the *Browser so that
browser.env.terminate() can be called. This is a bit more complex than the serve
path because the Browser owns the Isolate and can't be moved from one thread to
another.

With main having access to the browser, two things are now possible:
1 - We can support a --terminate-ms flag (https://github.com/lightpanda-io/browser/issues/2206)
2 - ctrl-c can correctly stop blocked JavaScript processes

1 is implemented via setitimer to set a timer for SIGALRM, avoiding the need to
add another "watcher" thread, or putting a timer in Network.run.
2026-04-25 12:34:06 +08:00
Karl Seguin
d02674f365 Use an arena from the ArenaPool for the main page
Was previously using page.arena, but there's no reason to hold this beyond the
point where the page is parsed, and the page can live for quite some time after
the initial load.
2026-04-25 10:49:27 +08:00
Karl Seguin
25cec9bd82 Merge pull request #2233 from lightpanda-io/custom_elements
Custom elements
2026-04-25 10:12:09 +08:00
Navid EMAD
3761d2a32f Fix querySelector('#id') vs getElementById('id') disagreement
Frame.getElementByIdFromNode is the selector engine's fast path for
`#id` queries. It only consulted `_elements_by_id`, while
Document.getElementById and ShadowRoot.getElementById both fall back
to `_removed_ids` + TreeWalker to recover a surviving duplicate after
the first has been removed.

The two APIs could disagree after DOM manipulation that removes a
duplicate-ID element (e.g. Turbo Drive's PageRenderer.replaceBody
doing innerHTML + replaceWith):

  document.querySelector('#page-title')  => null
  document.getElementById('page-title')  => <h1>

Dispatch to the existing canonical getElementById on the scope
(ShadowRoot or Document) instead of keeping a third, map-only copy
of the lookup. The two APIs now agree by construction.
2026-04-25 04:04:14 +02:00
Karl Seguin
5ec7c660da update v8 dep 2026-04-25 09:51:58 +08:00
Karl Seguin
3cdb7ee91c Merge pull request #2239 from lightpanda-io/test_only_use_after_free
Fix a test-only use-after-free
2026-04-25 07:41:17 +08:00
Karl Seguin
8a08d1b407 Fix a test-only use-after-free
Only surfaced if an individual test was ran. When running multiple tests, the
bucket reuse of the underlying arena hides the issue.
2026-04-24 21:51:50 +08:00
Pierre Tachoire
b2b1302fa2 Merge pull request #2234 from lightpanda-io/empty_redirect_user_after_free
Fix a use-after-free on an empty (and invalid) location
0.2.9
2026-04-24 14:52:07 +02:00
Pierre Tachoire
d2fc963640 Merge pull request #2231 from lightpanda-io/pkg
ci: refacto release workflow and add Arch linux package build
2026-04-24 14:50:55 +02:00
Nikolay Govorov
8b2b5ddff4 Merge pull request #2226 from lightpanda-io/wp/mrdimidium/fix-timeout
Setup timeout via tcp keepalive
2026-04-24 13:21:13 +01:00
Nikolay Govorov
999f57b729 Remove timeout flag 2026-04-24 12:40:25 +01:00
Karl Seguin
87a99749b7 Use TCP_KEEPALIVE instead of TCP_KEEPIDLE on MacOS
See: https://github.com/nginx/nginx/issues/336
2026-04-24 12:40:24 +01:00
Nikolay Govorov
c7d004fefb Setup timeout via tcp keepalive 2026-04-24 12:40:21 +01:00
Adrià Arrufat
46f8fc5a13 Merge pull request #2236 from lightpanda-io/fix/optional-positional-args
cli: allow optional positional arguments in command builder
2026-04-24 13:36:38 +02:00
Pierre Tachoire
5b9c05753c Merge pull request #2232 from lightpanda-io/axtree-nodeid-string 2026-04-24 13:22:37 +02:00
Adrià Arrufat
6a65801527 cli: allow optional positional arguments in command builder 2026-04-24 13:08:40 +02:00
Karl Seguin
7b50dff956 Fix a user-after-free on an empty (and invalid) empty location
Improves WPT: /fetch/api/redirect/redirect-empty-location.any.html
2026-04-24 18:31:45 +08:00
Karl Seguin
957f2d9c92 Merge pull request #2229 from lightpanda-io/wpt_extensions_action
Update WebDriver to use Page
2026-04-24 18:21:57 +08:00
Pierre Tachoire
368bbc75e0 ci: refacto build step into 1 job per os + CPU matrix 2026-04-24 11:43:48 +02:00
Pierre Tachoire
ce541fbc63 ci: add arch linux package generation 2026-04-24 11:43:47 +02:00