Commit Graph
118 Commits
Author SHA1 Message Date
Halil Durak 0a6d43c2bb HttpClient.isAdBlocked should just delegate Adblocker.isBlocked 2026-09-07 11:00:47 +03:00
Halil Durak 486c888080 drop is_subframe and notification 2026-09-07 11:00:47 +03:00
Halil Durak e696a29da7 metrics: make adblocker verdicts measurable 2026-09-07 11:00:05 +03:00
Halil Durak b60f790a03 Adblocker: changes on request construction & tokenization
* Engine.Request.fromHttp(req, source_url, buffers) now builds the adblock request straight from HttpClient.Request.
* The URL is tokenized once per request (hashed into the Request, shared by all engines); capped at 128 tokens (same as adblock-rust).
* Document hostname longer than 253 bytes now skips adblocking.
2026-09-07 10:57:36 +03:00
Halil Durak 6a85b1f386 handle all switch cases (emerged after rebase to main) 2026-09-07 10:57:36 +03:00
Halil Durak 8aa0dda4b3 integrate request engine to Adblocker, apply changes required for filter list in HttpClient 2026-09-07 10:57:35 +03:00
Muki Kiboigo 34b743fbd6 origin is tainted on cross origin redirects 2026-09-04 07:02:01 -07:00
Muki Kiboigo 54518383c0 enforce cors response on redirects as well 2026-09-04 07:00:03 -07:00
Muki Kiboigo 0610d5ecd1 collapse isCrossOriginModeAllowed check in pipeline 2026-09-04 07:00:02 -07:00
Muki Kiboigo 0aeba826b4 use credentials_mode instead of cookie bool 2026-09-04 07:00:02 -07:00
Muki Kiboigo 827d0f0598 only check cross origin mode on obey cors 2026-09-04 07:00:02 -07:00
Muki Kiboigo 8a8bb3814f fix test running 2026-09-04 07:00:01 -07:00
Muki Kiboigo 15d27902ba use experimental features flag instead of obey cors 2026-09-04 07:00:01 -07:00
Muki Kiboigo 1fe8456cbd add modes to the tests 2026-09-04 07:00:01 -07:00
Muki Kiboigo 12ed38dfdd better no cors opaque behavior 2026-09-04 07:00:00 -07:00
Muki Kiboigo d1f4605459 non-default credentials and request mode 2026-09-04 07:00:00 -07:00
Muki Kiboigo feebb889ad cors check before cache check 2026-09-04 06:59:40 -07:00
Muki Kiboigo d3c0291bd1 add request mode for Fetch 2026-09-04 06:59:39 -07:00
Muki Kiboigo ddfa034310 add credentials_mode for proper CORS credentials handling 2026-09-04 06:59:39 -07:00
Muki Kiboigo f31b32ac4e don't store network in CorsGate 2026-09-04 06:59:38 -07:00
Muki Kiboigo cf37a94f16 get rid of blocked on CorsGate check result 2026-09-04 06:59:38 -07:00
Muki Kiboigo 4e79f24814 basic validation without preflighting 2026-09-04 06:59:38 -07:00
Muki Kiboigo ec45dccacf add obey_cors option 2026-09-04 06:59:38 -07:00
Muki Kiboigo 212c806be5 add basic CorsGate scaffold 2026-09-04 06:59:37 -07:00
Muki Kiboigo b114382c44 add origin field to HttpClient Request 2026-09-04 06:59:37 -07:00
Karl Seguin 396cffa1c1 Merge pull request #3391 from lightpanda-io/resource-timing
webapi: resource-timing
2026-09-04 18:03:17 +08:00
Karl Seguin 1d66b2fbc8 Merge pull request #3398 from lightpanda-io/link-ownership
chore: Move ownership of the Inbox from HttpClient to WebSocker Driver
2026-09-04 03:04:57 +08:00
Karl Seguin 87320a506d chore: Move ownership of the Inbox from HttpClient to WebSocker Driver
Currently, the HttpClient owns the inbox and its borrowed by the Link. This is
a bit backwards, but it also means that we can't eagerly create a Link: the
Link needs the inbox, so it needs the HttpClient, which is created by the
Browser (which creates an Isolate).

Remember, the Inbox is one of the few things shared between the main thread
and the worker, so either end can own it and the other can borrow it.

This switches the ownership so that the HttpClient now borrows the Inbox from
the Server's side of the Link (the WebSocket).

The main goal of this change is to prepare for more advanced HTTP WebDriver
flows. The more we can create _without_ a Browser, the fewer edge cases we have
to deal with (Browser because it's expensive and has to be created on the
Worker thread due to how V8::Isolate works).
2026-09-03 16:51:12 +08:00
Karl Seguin 872fd7d5ff webapi: resource-timing
Adds resource timing, e.g. `performance.getEntriesByType("resource")`.

The `resource-timing` WPT category is currently at 4.6%, and this is a first
step at improving it. It also hopefully fixes https://github.com/lightpanda-io/browser/issues/3359

This is more complicated than I thought because there's a "Timing-Allow-Origin"
header that a server can include which hides some of the data if the request
doesn't come from the listed origin. And that, of course, interacts with
redirects.

(The DOMException change is seemingly random, but it came up in one of the WPT
cases I was looking at).
2026-09-02 20:39:51 +08:00
Karl Seguin 7d39a4fbaf http: handle redirects better
Our redirect handling was "optimized" to re-use the same easy connection, at the
cost of circumventing the entire pipeline. A redirect would not check the new
target's robots.txt, rate limit, CORS, Web Auth, ...

The new code simply restarts the pipeline (with a discriminator tag so that
things like CDP can tell the difference between a redirected request and a new
one).
2026-09-02 12:41:53 +08:00
Karl Seguin 2474a2c2bc Merge pull request #3368 from lightpanda-io/window-stop
webapi: window.stop()
2026-09-02 09:06:07 +08:00
Karl Seguin ed88bd763f complete merge 2026-09-02 08:17:15 +08:00
Karl Seguin e25d2da0c0 chore: Simplify making HTTP requests.
If you look at https://github.com/lightpanda-io/browser/pull/3293, you'll see
a relatively contained change that has to touch over 20 files. The issue is that
every HttpClient.newRequest needs to provide a lot of data. But `newRequest`
takes a 2nd parameter: the HttpClient.Owner. If we make that Owner a little
smarter, we can start to remove some of the individual fields needed in
newRequest. For example, we can still allow a callsite to pass frame_id but,
by default, we can use the owner's frame_id (which is what we want in most
cases).
2026-09-02 07:55:53 +08:00
Halil Durak 87308b5e23 compute site-for-cookies from ancestor chain of a Frame
The site for cookies were computed from the immediate parent `Frame`, which would allow sending a cookie that's `SameSite=Strict` from 2 levels deep under. Directly from RFC6265bis, this PR essentially implements (except for step 4, we skip host-less ancestors):

   Given a Document (document), the following algorithm returns its
   "site for cookies":

   1.  Let top-document be the active document in document's navigable's
       top-level traversable.

   2.  Let top-origin be the origin of top-document's URI if top-
       document's sandboxed origin browsing context flag is set, and
       top-document's origin otherwise.

   3.  Let documents be a list consisting of the active documents of
       document's inclusive ancestor navigables.

   4.  For each item in documents:

       1.  Let origin be the origin of item's URI if item's sandboxed
           origin browsing context flag is set, and item's origin
           otherwise.

       2.  If origin is not same-site with top-origin, return an origin
           set to an opaque origin.

   5.  Return top-origin.
2026-09-02 07:19:35 +08:00
Karl Seguin 76c8f4bb6e webapi: window.stop()
window.stop() is less destructive than other mechanisms we have. For one, it
seems largely isolated to pending or inflight HTTP requests. For anther, it
keeps the page intact.

To achieve this, HttpClient gains an `cancelRequests` which is a gentler version
of `abortOwner`. It cancels inflight/pending HTTP requests, which results in
error callbacks (not shutdown callbacks) firing.

Just like https://github.com/lightpanda-io/browser/pull/3189 I ran into the
problem that I couldn't distinguish between an HTTP request that was canceled
because of user-action (e.g. calling window.stop(), or xhr.abort()) and an HTTP
request that was internally aborted. These now have distinct errors/flows so
that we can present the correct state. Most places that aborted now all
transfer.cancel() which results in a distinct `error.TransferCanceled` (some
places still abort -> `error.Abort`). It should be possible to revisit 3189 now.

The CDP "Page.stopLoading" now hooks into this new behavior. Fixes
https://github.com/lightpanda-io/browser/issues/3351
2026-09-01 14:55:19 +08:00
Karl Seguin a68697921e cdp: remove race between terminate/disconnect
A client that disconnects might get treated as a harsher terminate failure (e.g.
watchdog). This doesn't have a huge impact, but it makes the CI flaky and it
produces more logs than is necessary.

In a terminate state, the driver will now check its inbox to see if this is a
client disconnection.
2026-09-01 12:11:07 +08:00
Karl Seguin 7c51dfff05 bidi: add skeleton for bidi
1. Abstract "Driver". Non-CDP things that referenced *CDP now reference a Driver
2. Move the NodeRegistry out of CDP. This created an artificial link between
   agent / mcp and CDP
3. Add BiDi driver with enough to navigate to a page
2026-08-31 22:44:59 +08:00
Karl Seguin 7dd4496b0f cli: add --http-version 1.1 / auto flag
https://github.com/lightpanda-io/browser/issues/3348

When set to 1.1, libcurl is configured to only offer HTTP 1.1. By default, or
when set to "auto", it's up to libcurl to decide how to connect. This maps to
libcurl's CURL_HTTP_VERSION_1_1 and CURL_HTTP_VERSION_NONE.

LP.configureCDP now takes an `httpVersion` field which can be "1.1" or "auto"
to control that specific browser session. Ideally this is called prior to any
navigation.
2026-08-31 16:16:47 +08:00
muki 57b86112b3 Merge pull request #3240 from lightpanda-io/xhr-async-flag
XHR Sync Request
2026-08-26 17:11:48 -07:00
Karl Seguin fce38a1aa8 Merge pull request #3289 from lightpanda-io/fix-double-releases
fix: Fix double-release and other (edge-case) memory issues
2026-08-27 07:34:45 +08:00
Karl Seguin cfd921ecab fix: Fix double-release and other (edge-case) memory issues
Our `Arena` from the `ArenaPool` now tracks if it's already been released. On
a subsequent release, it panics then and there. Without this, the code will
almost certainly panic anyways, but it will panic in a seemingly unrelated
place. Hopefully this makes identifying future cases of this easier (since we'll
get the stack trace of the re-releaser).

Fix 3 separate memory issues, all edge cases.

1 - an XHR error handler that re-open/sends would incorrectly null the new
    transfer (maybe this isn't that odd, maybe it's a common retry-on-error).

2 - On a curl_easy_pause error (from WebSocket.zig) we now unqueue the just-
    queued message, because the error will errdefer the message arena to be
    cleaned up.

3 - ScriptManager now cleans up after itself on a failure prior to submit()
    being called.
2026-08-26 18:24:12 +08:00
Pierre Tachoire 467167d6e6 http: strip Authorization on cross-origin redirects 2026-08-26 10:00:11 +02:00
Muki Kiboigo 234d47d0e2 syncRequest -> submitSync on Transfer 2026-08-25 17:43:03 -07:00
Halil Durak 87a87ba62e HttpClient: remove pending_low_queue, separate keys for headers_only in cache, more eager connection reuse 2026-08-25 14:20:38 +03:00
Halil Durak c1079444c4 addHeader -> setHeader + enable low prio for images 2026-08-25 14:18:46 +03:00
Halil Durak e58f99da18 add --load-resources CLI arg, supporting image param 2026-08-25 14:18:45 +03:00
Karl Seguin a6618fff63 http: Guarantee Transfer contract of single outcome callback
HttpClient guarantees that only one of done/error/shtudown callback will be
called. But that guarantee had a hole when a done/error callback would trigger
JS that caused an HttpClient.abort (e.g. by scheduling a navigation).

So far, this isn't a problem. fetch/XHR guard against this themselves, and
ScriptManager doesn't care of it happens.

But https://github.com/lightpanda-io/browser/pull/3230 doesn't guard against it
and would crash if it happens: its doneCallback frees `self` but can re-enter
shutdown which needs `self`. While 3230 could fix this issue, I'd prefer to
bake this contract into the HttpClient. Transfers now have an
`_outcome_delivered: bool` which guarantees that only one of done/error/shutdown
is called.
2026-08-22 11:09:52 +08:00
Karl Seguin 57bcdfed10 chore: Simplify Network and HttpClient init
Remove app field from Network
2026-08-22 07:05:05 +08:00
Karl Seguin decedca6e7 chore: Network cleanup
Network has accumulated a bit of bagged. It knows a lot about certificates, it
knows a lot of the cache. I have plans to expand Network, and wanted to clean it
up.

1 - certificate logic moved to dedicated Certificates.zig
2 - Removed CurlDebugAllocator
    - this makes setup easier, to Updater can just init libcurl directly
3 - Change Updater to be a single function
4 - Cache initialization is don in the Cache
5 - ?Cache => Cache{.kind = .noop}
2026-08-22 07:04:58 +08:00
Karl Seguin 9f4b39d723 Merge pull request #3239 from lightpanda-io/ratelimiter
http: Add optional rate limit
2026-08-22 06:58:52 +08:00