Commit Graph

85 Commits

Author SHA1 Message Date
Andreas Kling
072a3bdb90 RequestServer: Add diagnostic wire-activity logging
Per-request and per-connection logging that surfaces enough detail
to diagnose where time goes when a page load misbehaves. Gated by a
new REQUESTSERVER_WIRE_DEBUG cmakedefine.

Documentation/RequestServerWireLogging.md describes each label
(wire/wire+/wire++/wire^, wire-batch, wire-stall, wire-burst,
wire-pipe-pressure, LibDNS wire-dns, UI wire-cookie) and how to read
them.
2026-04-26 17:59:52 +02:00
Aliaksandr Kalenik
8c4870f207 RequestServer: Disable curl socket notifiers when no longer needed
When curl invokes the socket callback to tell us it only wants one
polling direction (e.g. CURL_POLL_IN without CURL_POLL_OUT, or vice
versa), we previously had no way to disable the other direction's
notifier. Once created, a notifier stayed enabled and kept firing
curl_multi_socket_action() for events curl was no longer interested in.

Merge the read and write branches into a single helper that also
disables the notifier for a direction when its CURL_POLL_* flag is
absent from the mask. This measurably improves performance by avoiding
redundant curl_multi_socket_action() calls on sockets curl has asked
us to stop watching in a given direction.
2026-04-21 15:45:41 +02:00
Timothy Flynn
4ad800b594 RequestServer: Use correct request map for stale-while-revalidate cookie
When we request the HTTP cookie for a SWR request, we were providing the
cookie to the standard request corresponding to the SWR request's ID.
This had two effects:

1. The SWR request would never finish.
2. If the corresponding standard request happened to be a connect-only
   request, this would result in a crash as we were expecting it to have
   gone through the normal fetch process.

This was seen on some articles on news.google.com.
2026-04-13 19:43:13 -04:00
Timothy Flynn
09e8299721 RequestServer: Move Request::Type enum to its own file
This will make it a bit easier to transfer over IPC.
2026-04-13 19:43:13 -04:00
Sam Atkins
22d7138c8d RequestServer: Don't create already-expired WebSockets in DNS callback
This prevents a race condition:
1. Try to connect a websocket
2. DNS lookup starts
3. JS causes the websocket to no longer be alive, and it is GCed
4. websocket_close() is called, but it doesn't find a websocket with
   that websocket_id, so nothing happens
5. DNS lookup completes, and opens the websocket
6. This websocket never gets closed

By separately tracking which websockets we are trying to connect, we can
record the fact we tried to close it, and then the DNS lookup callback
can skip creating the now-unwanted websocket.
2026-04-01 19:36:47 +01:00
Aliaksandr Kalenik
19627bba54 LibIPC: Return TransportHandle directly from create_paired()
Previously, `create_paired()` returned two full Transport objects, and
callers would immediately call `from_transport()` on the remote side to
extract its underlying fd. This wasted resources: the remote
Transport's IO thread, wakeup pipes, and send queue were initialized
only to be torn down without ever sending or receiving a message.

Now `create_paired()` returns `{Transport, TransportHandle}` — the
remote side is born as a lightweight handle containing just the raw fd,
skipping all unnecessary initialization.

Also replace `release_underlying_transport_for_transfer()` (which
returned a raw int fd) with `release_for_transfer()` (which returns a
TransportHandle directly), hiding the socket implementation detail
from callers including MessagePort.
2026-03-14 18:25:18 +01:00
Aliaksandr Kalenik
3bea3908b2 LibIPC+LibWeb+LibWebView+Services: Add IPC::TransportHandle
Add IPC::TransportHandle as an abstraction for passing IPC
transports through .ipc messages. This replaces IPC::File at
all sites where a transport (not a generic file) is being
transferred between processes.

TransportHandle provides from_transport(),
clone_from_transport(), and create_transport() methods that
encapsulate the fd-to-socket-to-transport conversion in one
place. This is preparatory work for Mach port support on
macOS -- when that lands, only TransportHandle's internals
need to change while all .ipc definitions and call sites
remain untouched.
2026-03-12 20:32:55 +01:00
Aliaksandr Kalenik
2e881978af LibIPC+LibWeb+LibWebView+Services: Add Transport::create_paired()
Consolidate the repeated socketpair + adopt + configure pattern from
4 call sites into a single Transport::create_paired() factory method.
This fixes inconsistent error handling and socket configuration across
call sites, and prepares for future mach port support on macOS.
2026-03-11 14:42:24 +01:00
Jelle Raaijmakers
2b78b84979 AK+Everywhere: Add and use weak_callback()
We have a common pattern of creating a `WeakPtr<T>` from a reference and
passing that into a lambda, to then take the strong ref when the lambda
is executed. Add `weak_callback(Weakable, lambda)` that returns a lambda
that only invokes the callback if a strong ref exists, and passes it as
the first argument.
2026-02-26 08:03:50 -05:00
Timothy Flynn
d215446e35 RequestServer: Store fewer objects globally
Especially for the disk cache, it always felt a bit sketchy to create
these objects on the global stack. We now create them in RequestServer's
main() where we can be more certain of destruction order, and pass them
to ConnectionFromClient instances.
2026-02-15 15:25:30 -05:00
Timothy Flynn
7d60d0bfb7 LibHTTP+LibWebView+RequestServer: Allow users to set disk cache limits
This adds a settings box to about:settings to allow users to limit the
disk cache size. This will override the default 5 GiB limit. We do not
automatically delete cache data if the new limit is suddenly less than
the used disk space; this will happen on the next request. This allows
multiple changes to the settings in a row without thrashing the cache.

In the future, we can add more toggles, such as disabling the disk
cache altogether.
2026-02-13 10:20:52 -05:00
Timothy Flynn
e6c008a269 LibWeb+RequestServer: Attach HTTP cookie headers from RequestServer
We currently attach HTTP cookie headers from LibWeb within Fetch. This
has the downside that the cookie IPC, and the infrastructure around it,
are all synchronous. This blocks the WebContent process entirely while
the cookie is being retrieved, for every request on a page.

We now attach cookie headers from RequestServer. The state machine in
RequestServer::Request allows us to easily do this work asynchronously.
We can also skip this work entirely when the response is served from
disk cache.

Note that we will continue to parse cookies in the WebContent process.
If something goes awry during parsing. we limit the damage to that
process, instead of the UI or RequestServer.

Also note that WebSocket requests still have cookie headers attached
attached from LibWeb. This will be handled in a future patch.

In the future, we may want to introduce a memory cache for cookies in
RequestServer to avoid IPC altogether as able.
2026-02-10 12:21:20 +01:00
Andreas Kling
22fedde7ef RequestServer: Fix crash during process exit
During process exit, static variables and thread-local variables are
destroyed in an unpredictable order. The connections HashMap was static,
so when destroyed during static destruction, it would destroy
ConnectionFromClient objects whose notifiers would try to unregister
from thread data that may have already been destroyed.

Fix this by moving the connections HashMap from static storage to stack
storage in ladybird_main(). This guarantees it will be destroyed before
the function returns, while the event loop and all thread data are still
fully alive.
2026-01-25 09:32:51 +01:00
Timothy Flynn
aa1517b727 LibHTTP+LibWeb+RequestServer: Handle the Fetch API's cache mode
If the cache mode is no-store, we must not interact with the cache at
all.

If the cache mode is reload, we must not use any cached response.

If the cache-mode is only-if-cached or force-cache, we are permitted
to respond with stale cache responses.

Note that we currently cannot test only-if-cached in test-web. Setting
this mode also requires setting the cors mode to same-origin, but our
http-test-server infra requires setting the cors mode to cors.
2026-01-22 07:05:06 -05:00
Timothy Flynn
0dff009b41 RequestServer: Move the Alt-Svc cache to the cache directory
We did not have a StandardPaths::cache_directory when this cache was
added. Now that we do, let's make use of it.
2025-12-22 13:33:13 +01:00
Timothy Flynn
add8402536 LibHTTP+RequestServer: Implement the stale-while-revalidate directive
This directive allows our disk cache to serve stale responses for a time
indicated by the directive itself, while we revalidate the response in
the background.

Issuing requests that weren't initiated by a client is a new thing for
RequestServer. In this implementation, we associate the request with
the client that initiated the request to the stale cache entry. This
adds a "background request" mode to the Request object, to prevent us
from trying to send any of the revalidation response over IPC.
2025-12-13 13:07:02 -06:00
Timothy Flynn
a5bc2e96c3 RequestServer: Do not randomly assign preconnect request IDs
Let's avoid the possibility that we randomly generate a request ID that
already exists and is in use.
2025-12-12 10:54:33 -05:00
Timothy Flynn
624611aa3f LibRequests+RequestServer: Store request IDs as u64
Not super important, but this will match an upcoming ID for stale-while-
revalidate requests. It also would techinically be UB if this ID had
ever overflowed. Let's make it 64-bit while we are here to also avoid
the possibility that it ever will overflow.
2025-12-12 10:54:33 -05:00
Timothy Flynn
3a413d988b LibRequests+RequestServer: Store websocket IDs as u64
The bug fixed here is that in RequestServer's ConnectionFromClient, we
stored the websocket ID as i32, despite it being i64 everywhere else.
Let's make it unsigned while we are here to be consistent with how all
other RS-related IDs will be soon.
2025-12-12 10:54:33 -05:00
Timothy Flynn
674075f79e Everywhere: Remove LibCore/System.h includes from header files
This reduces the number of compilation jobs when System.h changes from
about 750 to 60. (There are still a large number of linker jobs.)
2025-12-04 15:40:46 +00:00
Timothy Flynn
21bbbacd07 LibHTTP+RequestServer: Move the HTTP cache implementation to LibHTTP
We currently have two ongoing implementations of RFC 9111, HTTP caching.
In order to consolidate these, this patch moves the implementation from
RequestServer to LibHTTP for re-use within LibWeb.
2025-11-29 08:35:02 -05:00
Timothy Flynn
9375660b64 LibHTTP+LibWeb+RequestServer: Move Fetch's HTTP header infra to LibHTTP
The end goal here is for LibHTTP to be the home of our RFC 9111 (HTTP
caching) implementation. We currently have one implementation in LibWeb
for our in-memory cache and another in RequestServer for our disk cache.

The implementations both largely revolve around interacting with HTTP
headers. But in LibWeb, we are using Fetch's header infra, and in RS we
are using are home-grown header infra from LibHTTP.

So to give these a common denominator, this patch replaces the LibHTTP
implementation with Fetch's infra. Our existing LibHTTP implementation
was not particularly compliant with any spec, so this at least gives us
a standards-based common implementation.

This migration also required moving a handful of other Fetch AOs over
to LibHTTP. (It turns out these AOs were all from the Fetch/Infra/HTTP
folder, so perhaps it makes sense for LibHTTP to be the implementation
of that entire set of facilities.)
2025-11-27 14:57:29 +01:00
Timothy Flynn
3f61f0f189 RequestServer: Add a time parameter to the clear cache endpoint
This allows removing cache entries last accessed since a provided
timestamp.
2025-11-12 09:06:21 -05:00
Timothy Flynn
ba49942b6d LibRequests+RequestServer: Add a method to estimate disk cache size
This allows estimating the cache size stored on disk since a provided
time stamp, and in total.
2025-11-12 09:06:21 -05:00
Timothy Flynn
822fcc39de RequestServer: Manage request lifetimes as a simple state machine
We currently manage request lifetime as both an ActiveRequest structure
and a series of lambda callbacks. In an upcoming patch, we will want to
"pause" a request to de-duplicate equivalent requests, such that only
one request goes over the network and saves its response to the disk
cache.

To make that easier to reason about, this adds a Request class to manage
the lifetime of a request via a state machine. We will now be able to
add a "waiting for disk cache" state to stop the request.
2025-10-28 11:52:51 +01:00
Timothy Flynn
1216a2f952 RequestServer: Move some cURL utilities to their own file
This will allow more easily using these from other files. This also lets
us hide the Windows.h header necessity in a single location, instead of
needing to remember to include it everywhre we would otherwise include
<curl/curl.h>.
2025-10-28 11:52:51 +01:00
Timothy Flynn
7450da5556 RequestServer: Move Resolver (and related structures) to its own file
In an upcoming commit to handle requests as a state machine, we will
need access to Resolver from outside of ConnectionFromClient..
2025-10-28 11:52:51 +01:00
ayeteadoe
997d6ee75a RequestServer: Support UDP default resolver on Windows 2025-10-28 11:52:51 +01:00
Timothy Flynn
9b8f6b8108 RequestServer: Issue a network request for failed cached responses
If transferring a cached response body fails for any reason, we will now
issue a network request instead of failing the request outright.

The catch here is that we will have already transferred the response
code and headers to the client, and potentially some of the body. So we
attempt to only request the remaining data over the network using a
range request. This feels a bit sketchy, but this is also how Chromium
behaves.

However, the server may or may not support range requests. If they do,
we can expect an HTTP 206 response with the bytes we need. If not, we
will receive an HTTP 200 (assuming the request succeeded), along with
the entire object's body. In this case, we also behave like Chromium,
and internally drop number of bytes we had already transferred.
2025-10-16 09:06:48 -04:00
Timothy Flynn
163e8e5b44 LibWebView+RequestServer: Support clearing the HTTP disk cache
This is a bit of a blunt hammer, but this hooks an action to clear the
HTTP disk cache into the existing Clear Cache action. Upon invocation,
it stops all existing cache entries from making further progress, and
then deletes the entire cache index and all cache files.

In the future, we will of course want more fine-grained control over
cache deletion, e.g. via an about:history page.
2025-10-14 13:40:33 +02:00
Timothy Flynn
3516a2344f LibRequests+RequestServer: Begin implementing an HTTP disk cache
This adds a disk cache for HTTP responses received from the network. For
now, we take a rather conservative approach to caching. We don't cache a
response until we're 100% sure it is cacheable (there are heuristics we
can implement in the future based on the absence of specific headers).

The cache is broken into 2 categories of files:

1. An index file. This is a SQL database containing metadata about each
   cache entry (URL, timestamps, etc.).
2. Cache files. Each cached response is in its own file. The file is an
   amalgamation of all info needed to reconstruct an HTTP response. This
   includes the status code, headers, body, etc.

A cache entry is created once we receive the headers for a response. The
index, however, is not updated at this point. We stream the body into
the cache entry as it is received. Once we've successfully cached the
entire body, we create an index entry in the database. If any of these
steps failed along the way, the cache entry is removed and the index is
left untouched.

Subsequent requests are checked for cache hits from the index. If a hit
is found, we read just enough of the cache entry to inform WebContent of
the status code and headers. The body of the response is piped to WC via
syscalls, such that the transfer happens entirely in the kernel; no need
to allocate the memory for the body in userspace (WC still allocates a
buffer to hold the data, of course). If an error occurs while piping the
body, we currently error out the request. There is a FIXME to switch to
a network request.

Cache hits are also validated for freshness before they are used. If a
response has expired, we remove it and its index entry, and proceed with
a network request.
2025-10-14 13:40:33 +02:00
ayeteadoe
58be9e6400 RequestServer: Enable in Windows CI 2025-08-23 16:04:36 -06:00
Jelle Raaijmakers
9080af4085 RequestServer: Don't set CURLOPT_HTTPGET _and_ CURLOPT_CUSTOMREQUEST
We always set CURLOPT_CUSTOMREQUEST, so we can skip setting
CURLOPT_HTTPGET.
2025-08-13 10:30:04 -04:00
Jelle Raaijmakers
ed57d2de98 RequestServer: Don't return unused bool when setting curl options 2025-08-13 10:30:04 -04:00
Jelle Raaijmakers
da351ac468 RequestServer: Pass nullptr instead of an unused variable 2025-08-13 10:30:04 -04:00
Jelle Raaijmakers
585e4ed875 RequestServer: Add some useful dbgln_if()s
In trying to debug request handling, I've found these to help
understanding what's going on behind the scenes.
2025-08-13 10:30:04 -04:00
Jelle Raaijmakers
41cf150a5b LibDNS+RequestServer: Don't construct Vectors to validate DNS response
Instead of filling vectors and returning them just to invoke
`.is_empty()`, forward the calls to the underlying vectors directly.
2025-08-13 10:30:04 -04:00
rmg-x
d489e46448 RequestServer: Clarify comment for removing Content-Type header
This comment assumed that the reader knew how curl behaved with empty
header values.
2025-08-13 06:30:56 -04:00
rmg-x
d1db27dc42 RequestServer: Remove unused include of AK/Badge.h 2025-08-13 06:30:56 -04:00
Timothy Flynn
58f5fe7d79 RequestServer: Add an IPC method to reconnect N request clients
Similar to the same IPC on ImageDecoder, this just avoids IPC churn.
2025-08-10 11:02:50 +02:00
Luke Wilde
08a03534af Meta+RequestServer: Enable HTTP/3 for curl
This adds an overlay port for curl that adds the features required for
HTTP/3.

This is not quite compatible with the upstream vcpkg.json, because
enabling HTTP/2 makes it use the default SSL backend, which is
sectransp for macOS and schannel on Windows. These backends are not
compatible with ngtcp2. Additionally, we can not build curl with
multiple SSL backends when using ngtcp2.

I couldn't find a way to selectively disable/enable dependencies based
on what features are enabled, so I made HTTP/2 pick OpenSSL in our
overlay port. Upstream vcpkg will likely want to support wolfSSL and
GnuTLS backends for ngtcp2, so they'll be additional work to get this
into upstream.
2025-07-09 14:44:56 -06:00
Luke Wilde
05ee3f1876 RequestServer: Wait until initial connection is open for multiplexing
By default, if multiple requests start to a newly seen origin, curl
will not wait for a connection to open to figure out if the server
supports multiplexing and will instead open a new connection for each
request (including a new TLS session and such)

This is particularly an issue for initial page load, where a complex
website could, for example, request tens of items at once (e.g. a bunch
of scripts).

We can be kinder to servers that support multiplexing by telling curl
to wait till an initial connection is established to determine if
multiplexing is supported.

On my machine and internet connection, this reduces the amount of
connections to github.githubassets.com on initial load of
https://github.com/LadybirdBrowser/ladybird from 12 to 2.
2025-07-07 14:11:26 +02:00
Andrew Kaster
d9c85288d9 LibTLS: Remove blocking option and simplify Options struct
The complex macro for options with defaults doesn't make sense
now that there's only one option.
2025-06-23 17:49:21 +02:00
Luke Wilde
2dead9231d RequestServer: Handle client disappearance more gracefully
Without these fixes, RequestServer was likely to crash if the client
crashed (e.g. WebContent). This was because there was no error handling
for when writing to the client failed.

This is particularly an issue because RequestServer has shared
instances, so it would then crash every other client of RequestServer.
Then, because another RequestServer instance is not currently spun up,
it becomes impossible to start any clients that need a RequestServer
instance. Recreating a RequestServer should also be handled, but that's
not in the scope of this change.

We can tell curl that we failed to write data to the client and that
the request should be aborted by returning `CURL_WRITEFUNC_ERROR` from
the write callback.

It is also possible for requests to be destroyed with buffered data,
which is normal to happen if the client disappears
(i.e. ConnectionFromClient is destroyed) or the request is cancelled by
the client. We log a warning in case this is not expected, to assist
with debugging related issues.
2025-06-13 17:03:57 +02:00
Ali Mohammad Pur
4b5664f867 LibWebView+RequestSever: Wire up a validate-DNSSEC setting option to RS 2025-06-11 18:16:29 +02:00
Andreas Kling
e0e09f71be RequestServer: Don't try to self-destruct already-destroyed request 2025-05-29 03:46:49 +02:00
Aliaksandr Kalenik
ceaeea3c26 RequestServer: Use write notifier instead of busy waiting for socket
...to become writable.

Solves triangular deadlock problem that happened in the following case
(copied from https://github.com/LadybirdBrowser/ladybird/issues/1816):
- The WebContent process is spinning on
   `send_sync_but_allow_failure` waiting for the UI process to respond
- The UI process is spinning on `send_sync_but_allow_failure`, waiting
   for RequestServer to respond
- RequestServer is stuck in this loop, trying to write to the
  WebContent's socket file (when I attach to RS, we are always in the
  sched_yield call, so we're spinning on EAGAIN).

For me the issue was reliably reproducible on Google Maps and with this
change we no longer deadlock there.
2025-05-24 16:28:48 +03:00
Colin Reeder
5ac88e7726 RequestServer: Leave Accept-Encoding up to curl 2025-05-19 13:18:44 +02:00
Mohamed amine Bounya
b77643a2e8 RequestServer: Don't assert for socket fd not being CURL_SOCKET_BAD
The assertion in `WebSocketImplCurl::did_connect()` keeps failing for
multiple websockets when loading `https://www.speedtest.net/` since
commit 14ebcd4. This fixes that by checking and returning false if
something went wrong and letting the caller function handle it.
2025-04-30 18:20:26 -06:00
Ali Mohammad Pur
2c13504bfc LibWebView+RequestServer: Add some UI for DNS settings 2025-04-22 18:05:07 -04:00