Commit Graph
510 Commits
Author SHA1 Message Date
Karl Seguin 71cc6f93e5 fix robots log message length 2026-09-23 11:20:42 +08:00
Adrià Arrufat 728f61a80d log: check the message rules at comptime
logToErased asserts that a log message is at most 30 characters of
plain text, but only in a debug build and only once the line actually
runs. A message on a rare path therefore ships fine and then panics on
whoever first reaches it: `serve --host 0.0.0.0` without
--advertise-host crashed on startup in every debug build, because
"advertising loopback for wildcard bind" is 38 characters.

Every message is a literal, so make the six wrappers take a comptime
msg and apply the same two rules through @compileError. The runtime
check stays as the backstop for the paths the compiler does not
analyse for the current target, and now reads the same constant.

Eleven messages were over the limit; shorten them. The detail already
lives in the kv pairs in each case. renderFailed takes its message as
comptime now, the only call site that passed a runtime one.

Note the check only covers code analysed for the target being built:
the two in Certificates.zig sit in an OS switch prong that Linux never
compiles, and were found by scanning the source rather than by the
compiler.
2026-09-23 11:20:42 +08:00
Karl Seguin 4a7590691d Merge pull request #3546 from lightpanda-io/robots-limit-entries
Robot Limit Entries
2026-09-23 07:31:30 +08:00
Muki Kiboigo 8682cca571 remove inaccurate Robots comment 2026-09-22 12:55:27 -07:00
Muki Kiboigo be60d51990 add caching option for settle in RobotsGate 2026-09-22 12:55:27 -07:00
Muki Kiboigo d16091a403 0 for robot entry limit means no limit 2026-09-22 12:55:26 -07:00
Karl Seguin 0b66a5ed05 http: dont' re-use connections which are likely in a bad state.
Some status-codes should never have a body except for a single trailing blank
line. If we don't handle these, then we end up with a dirty connection in our
connection pool:

1 - read the header, but not the body
2 - put the connection back in the pool
3 - try to read the header, but actually get the body from #1

WPT /fetch/api/basic/response-null-body.any.html exercises this path and is
flaky (because it depends whether the request goes back out on a keep-alive
connection)..but for a given run,you'll almost always get 1-3 failures.

This commit processes the request, but tells libcurl not to re-use the
connection.
2026-09-22 10:08:41 +08:00
Muki Kiboigo 74789d3af0 use ClockCache as the map in RobotStore 2026-09-21 07:07:08 -07:00
Karl Seguin 7f3cf5793f cache use s-maxcache only to reduce total cache time
Tricky since we act as both the user agent and a shared cache. This is the
safest of the two.
2026-09-21 18:52:13 +08:00
Karl Seguin 3213342055 http: improve caching
1 - Centralized cache-awareness into Cache and pulled header details out of
    SqliteCache and HttpClient

2 - Added support for expires header

3 - Support caching more status types (but not all, since HttpClient would need
    to be aware of what caching a 3xx/206 means)

4 - Revalidate cares about  "not specified" vs "no-store" vs "stale"
    (e.g. expires=0 means "stale", not fallthrough the last-modified logic)
2026-09-21 11:38:34 +08:00
Muki Kiboigo b55b8966fd use robots_url before releasing arena in all RobotGate paths 2026-09-18 09:16:16 -07:00
Muki Kiboigo 16153e73b1 dont store arena_pool in RobotsContext 2026-09-18 09:08:37 -07:00
Muki Kiboigo eb56ce87e4 resolve using owned Robots instead of checking store 2026-09-18 09:05:23 -07:00
Muki Kiboigo b8e2197b22 switch from LRU to Clock 2026-09-18 08:16:34 -07:00
Muki Kiboigo 5f04c699d5 add robots evicted metric 2026-09-17 23:03:19 -07:00
Karl Seguin f70705b2ce webapi: include Sec-Fetch-Site and Sec-Fetch-Mode headers 2026-09-18 12:34:19 +08:00
Muki Kiboigo 7e4f1dedc1 force min of 1 on robot entry limit 2026-09-17 20:36:31 -07:00
Muki Kiboigo c289b13dc2 rename EvictionQueue to LruCache 2026-09-17 20:24:58 -07:00
Muki Kiboigo 6ec287be35 properly use LRU EvictionQueue in Robots 2026-09-17 20:23:34 -07:00
Muki Kiboigo a8697b662b switch EvictionQueue to proper LRU 2026-09-17 20:23:21 -07:00
Muki Kiboigo 2f7a21974a get rid of count on EvictionQueue 2026-09-17 20:01:29 -07:00
Muki Kiboigo b9cd6f1d88 remove initCapacity on Robots 2026-09-17 20:00:58 -07:00
Muki Kiboigo 9fa9e5ae0d add robot store entry limit option 2026-09-17 20:00:09 -07:00
Muki Kiboigo 9510e1361c add an eviction system for RobotsStore 2026-09-17 20:00:06 -07:00
Karl Seguin 437a9c27d6 Merge pull request #3543 from lightpanda-io/fix-import-crash
crash: fix a rare import crash
2026-09-18 05:53:27 +08:00
Pierre Tachoire 66e15748a6 Merge pull request #3485 from lightpanda-io/fetch-referrer-policy
Fetch Referrer Policy + CorsGate referrer checking
2026-09-17 18:14:53 +02:00
Karl Seguin a4e1fa95b9 crash: fix a rare import crash
Currently, our waitForImport blocks the caller, but continues to process any
already-queued requests. This can result in new JavaScript running while v8
is linking modules and that JavaScript can itself import a module that is
part of the still-being-linked graph.

waitForImport now works like a syncRequest. While HttpClient will continue to
make progress on all transfers, all other transfers will gate behind the waiting
one (using the same infrastructure that exists for syncRequest).

This crash was seen on an unknown srape URL.
2026-09-17 08:17:13 +08:00
Karl Seguin ddf0fa2ce9 Merge pull request #3538 from lightpanda-io/webdriver-navigate
WebDriver: add navigate
2026-09-17 07:37:36 +08:00
Karl Seguin bc5f0777fb Merge pull request #3540 from lightpanda-io/cors-redirect-credentials
webapi: limit redirect with credentials
2026-09-17 07:24:18 +08:00
Karl Seguin b15707973b webapi: limit redirect with credentials
A cors request with credentials can only follow redirects when staying on the
same origin. WPT cors-redirect-credentials
2026-09-16 17:41:32 +08:00
Karl Seguin afbc8378b1 Merge pull request #3522 from lightpanda-io/regex-shared
`Regex`: share the PCRE2 wrapper; `findElement` matches names by `/regex/`
2026-09-16 16:55:40 +08:00
Adrià Arrufat 35dbda3686 Regex: compile through the context
The context is what a pattern is compiled against, so `compile` reads
better as its method than as a free function taking it first.
2026-09-16 09:28:45 +02:00
Karl Seguin 7ecefa9e92 WebDriver: add navigate
This feature is significant because it adds support for processing an HTTP
request via the worker. It requires parking the connection and then having the
worker notify the loop when the response is ready. A lot of this was already
in-place (e.g. worker -> loop notification) but not quite do this extent.
2026-09-16 14:05:49 +08:00
Muki Kiboigo bf9ca09e33 dont dupe referer 2026-09-15 22:56:37 -07:00
Scott Taylor 8339361043 http: drop request-body headers when redirects rewrite the method
A multipart form POST followed by a 302 changed to GET and lost its body,
but retained Content-Type: multipart/form-data. Servers could then try to
parse an absent multipart body and return 400. This was reproduced on a
local redirect server and a storefront localization flow.

Delete Fetch's request-body header names when rewriting to GET. Preserve
method and body on 307/308, rewrite only POST on 301/302, and preserve GET
and HEAD on 303 rather than rewriting every request indiscriminately.

Test method/header transitions and header handling through the existing
CDP fulfilled-redirect path.
2026-09-15 07:48:18 -04:00
Adrià Arrufat d2f72a9fa9 Regex: share the PCRE2 wrapper beyond adblock
Compiled patterns are useful anywhere someone else writes the pattern:
the adblock lists today, agent tool arguments next. The wrapper moves
out of the adblock directory and gains an options struct (case, UTF-8
subjects) and a compile diagnostic the caller can log or show. The App
owns the one context every consumer compiles through, the blocker
included.
2026-09-15 09:33:39 +02:00
Halil Durak 93381010f1 Merge branch 'main' into nikneym/lax-exception-RFC6265bis 2026-09-14 14:27:55 +03:00
Muki Kiboigo 00c98313c2 use curl no body option for head requests 2026-09-14 07:58:56 +08:00
Muki Kiboigo afb98388cb add referrer handling to CorsGate 2026-09-13 14:22:42 -07:00
Adrià Arrufat db9779a654 Enable CURLOPT_PIPEWAIT on every easy handle
Requests issued to an origin while its first connection is still
handshaking each opened their own socket, up to --http-max-host-open,
because curl only learns from ALPN whether the origin multiplexes. With
pipewait they wait for that answer and share one h2 connection.

Fixture: 12 fetch() calls to a fresh cdnjs (h2) origin, release build.

  new TCP+TLS connections   6 -> 1
  in-page time to last resp ~285 ms -> ~105-135 ms

H1-only origins are unchanged in connection count; their first burst
waits one handshake before fanning out.
2026-09-13 22:09:36 +02:00
Karl Seguin 128233c4ff Merge pull request #3494 from lightpanda-io/robot-store-leak
mem: fix robot store leak
2026-09-13 08:29:51 +08:00
Karl Seguin 35c0a9aeda chore: dedupe HttpClient.Owner using new GlobalScope
https://github.com/lightpanda-io/browser/pull/3447 made better use of the
GlobalScope to simplify various callsites. This changes HttpClient.Owner to
contain the global_scope, rather than copying a handful of scope fields.
2026-09-12 12:09:56 +08:00
Karl Seguin 7a4e2f62bd mem: fix robot store key leak
The RobotStore is shared by all Browsers. While every browser has a single
flight to prevent duplicate requests to the same robots.txt, that's limited to
that specific browser. So, 2 browsers can ask for the same robots.txt and then
put try to store the result. The RobotStore _is_ thread safe, but it's a simple
last-one-wins which overrites the previous record, without freeing either the
key or value.

This replaces the last-write-wins with a first-write-wins, avoiding the leak.
2026-09-12 11:39:27 +08:00
Karl Seguin f81f6e4eb7 mem: reduce memory usage of cloned HTTP responses
ScriptManager, XMLHttpRequest.zig, Fetch, Workers, etc. all take ownership (aka
dupe) the HTTP response from HTTPClient. They all have a headerCallback that
does something like:

```zig
if (transfer.getContentLength()) |cl| {
  try self.body.ensureTotalCapacity(self.arena, cl);
}
```

But in all non-streaming cases (which is most cases),  the HttpClient buffers
the response and only calls the headerCallback _after_ the body has been
received. Rather than relying on "Content-Length" header, the body buffer can
be sized to the exact body length. Why does this matter? Because the
Content-Length is the length of the body on the wire, and if the body is
compressed (like almost all .js files are), it will under-report the final
body length AND, because most callers are using an arena, the buffer growth
will retain more memory than it should.

This adds a `transfer.bodyLen()` method. Callers which dupe the body now use
this rather than the Content-Length (Content-Length is still used, e.g. for
XHR progress report).
2026-09-11 11:50:30 +08:00
Karl Seguin 8ad9eaf48d webdriver: HTTP WebDriver session management
This is a small step towards WebDriver supports (non-bidi). It allows creating
and deleting a BiDi "Session" (e.g. a worker). It also allows attaching a BiDi
driver to an HTTP-created BiDi session (the typical selenium startup flow).

This change unblocks the most basic setup/teardown of Selenium, so it still
isn't enough to actually use a Selenium script as-is. But it's significant
because it models a worker (thread) that isn't tied to a WebSocket, something we
haven't had before.

A consequence of a pure HTTP Session is that we don't have a clear cleanup
signal. There is no "the socket is disconnected". There's a new HTTP reaper
which kills HTTP Sessions after --http-session-timeout. It's expected that
drivers properly DELETE /session/:id. I imagine we're going to run into
--cdp-max-connections limits and need to tweak this code. BUT, this entire flow
is only enabled with --protocol webdriver, so it won't impact exiting CDP users.
2026-09-11 05:11:26 +08:00
Karl Seguin 72165ef2a4 Merge pull request #3476 from lightpanda-io/make-private-if-private
chore: make declarations private if they don't need to be public
2026-09-11 05:09:17 +08:00
Adrià Arrufat d693f49872 Merge pull request #3463 from lightpanda-io/adblock-regex-pcre2
`AdBlocker`: run /regex/ filters with PCRE2
2026-09-10 14:04:14 +02:00
Adrià Arrufat aecb115771 Regex: a failed compile allocation is PCRE2_ERROR_HEAP_FAILED
Compile errors are reported as 100 plus the internal number, and the
one for a failed allocation has a public name.
2026-09-10 11:25:20 +02:00
Adrià Arrufat 06f7f6f295 Engine: look through an optional stretch when reading a branch's ends
An alternation or a repeat keeps only whether its text may start and
end with a token character, and read that off one marker. An optional
non-token stretch there (`\/?x`) was taken as a definite non-token,
so `\/ads(\/?x|\/y)` was filed under "ads" while `/adsx` carries no
such token. What follows the stretch answers now.
2026-09-10 11:25:20 +02:00
Karl Seguin 2e6999f20b chore: make declarations private if they don't need to be public
This change is 99%  s/pub//   + a handful of dead code removal.
2026-09-10 14:42:09 +08:00