Commit graph

956 commits

Author SHA1 Message Date
Aliaksandr Kalenik
0a41859ae9 LibWeb+LibWebView: Feed async scroll deltas in device pixels
The synchronous wheel path treats wheel deltas as CSS-pixel scroll
distances, while the async compositor scroll tree mutates scroll state
stored in device pixels. Passing the same unscaled delta into the
compositor made async scrolling advance too little whenever
device pixels per CSSPixel was greater than 1, so scrolling felt slower
than with async scrolling disabled.

Convert wheel deltas before crossing the compositor boundary and make
the compositor IPC carry only the device-pixel position and delta it
needs. This keeps AsyncScrollTree device-pixel native and makes async
viewport scrolling match the synchronous path across high-DPI displays
and page zoom levels.
2026-05-12 22:35:54 +02:00
Andreas Kling
a031d00695 WebContent: Exit cleanly when browser IPC disconnects
Exit WebContent immediately when either browser-side IPC peer
disconnects. Plumb Unix process exit status through LibWebView so the
browser process can tell clean owner-driven shutdown apart from renderer
crashes.

This keeps nonzero exits and signal deaths reported as crashes, while
letting status 0 exits disappear without making test-web report the page
as crashed.
2026-05-12 20:57:08 +02:00
Andreas Kling
780083a0e2 LibWeb: Add compositor debug logging
Trace the compositor state transitions that matter once presentation and
async scrolling share one path: page registration, backing-store swaps,
did_paint delivery, ready_to_paint acknowledgements, wheel admission,
and deferred presents waiting for reusable bitmaps.

Keep the logs under COMPOSITOR_DEBUG and use the [Compositor] prefix
consistently. The trace is about ownership and backpressure instead of
dumping every wheel event detail, so stalls can be diagnosed without
reintroducing noisy async-scrolling-only logging.
2026-05-12 20:57:08 +02:00
Andreas Kling
5d4137173a LibWebView: Route wheel bypasses over Compositor IPC
Send the experimental UI-process wheel bypass to WebContent over the
Compositor IPC connection instead of adding a separate async scrolling
transport. This keeps bypass admission on the channel that owns bitmaps
and ready_to_paint acknowledgements.

If the compositor rejects the wheel, LibWebView falls back to regular
input delivery. If it accepts, mark the queued DOM event as having
already performed its default action so dispatch preserves ordering
without scrolling twice.
2026-05-12 20:57:08 +02:00
Andreas Kling
f07b55c2df LibWeb: Scroll the viewport on the compositor thread
Use the snapshot from the previous commit to let CompositorThread apply
experimental viewport wheel deltas when async scrolling is enabled. The
event handler first performs synchronous admission on the main thread,
then enqueues a compositor scroll command instead of mutating live
document scroll state directly.

Rasterize accepted scrolls through the same compositor presentation
path added earlier. The compositor stores the newest async viewport
offset so the next main-thread display-list recording can adopt it
before repainting, preventing older paints from snapping the visible
position backward.

Keep DOM wheel dispatch on the main thread. When the compositor already
performed the default action, dispatch the wheel as non-cancelable and
suppress a second default scroll. Non-viewport targets, nested
scrollers, and pages with blocking wheel listeners stay synchronous.
2026-05-12 20:57:08 +02:00
Andreas Kling
1b810a5e15 LibWeb: Present frames through Compositor IPC
Introduce a dedicated Compositor IPC channel between the UI process and
WebContent. Use it for backing-store setup, presented bitmap delivery,
and bitmap-specific ready_to_paint acknowledgements.

This makes CompositorThread the single owner of frame presentation
bookkeeping before async scrolling starts producing frames without the
main thread.

Remove old paint and backing-store messages from WebContentClient and
PageClient so the UI process no longer observes two presentation
protocols.
2026-05-12 20:57:08 +02:00
Andreas Kling
4ba14759dc LibGC: Move Web::WebDriver::HeapTimer to GC::Timer
Move HeapTimer out of LibWeb and into LibGC as GC::Timer, inheriting
from GC::Cell instead of JS::Cell. Add a finalize() override that
stops the timer, ensuring it is cleaned up during GC finalization.
2026-05-10 10:58:11 +02:00
Shannon Booth
5adfd1c43a LibWeb/Bindings: Generate struct definitions from IDL dictionaries
Previously we were inconsistent by generating code for enum definitions
but not generating code for dictionaries. With future changes to the
IDL generator to expose helpers to convert to and from IDL values
this produced circular depdendencies. To solve this problem, also
generate the dictionary definitions in bindings headers.
2026-05-09 10:49:49 +02:00
R-Goc
02bb892d7a LibThreading/LibSync: Split out sync primitives
This commit splits out synchronization primitives from LibThreading into
LibSync. This is because LibThreading depends on LibCore, while LibCore
needs the synchronization primitives from LibThreading. This worked
while they were header only, but when I tried to add an implementation
file it ran into the circular dependency. To abstract away the pthread
implementation using cpp files is necessary so the synchronization
primitives were moved to a separate library.
2026-05-08 18:58:35 -05:00
Timothy Flynn
b221d7fe8b LibWeb+LibWebView+WebContent+UI: Add an action to cut text 2026-05-07 09:13:06 -04:00
Aliaksandr Kalenik
568b7ce7ea LibWeb: Make Paintable tree ref-counted
The Paintable tree and its supplemental painting data structures were
GC allocated because that was the easiest way to manage it and avoid
leaks introduced by ref cycles. This included the Paintable subclasses
themselves plus StackingContext, ChromeWidget, Scrollbar, ResizeHandle,
and scroll-frame state.

We are now trying to reduce GC allocation churn on layout and painting
updates, so keeping this short-lived rendering tree outside the JS heap
is a better fit. Move Paintable to RefCountedTreeNode, make painting
helpers ref-counted or weakly reference Paintables, and update the
layout and event-handler call sites to use RefPtr/WeakPtr ownership.
2026-05-07 15:03:44 +02:00
Andreas Kling
c32b5a3f73 LibWeb+RequestServer: Send cached bytecode with responses
Attach cached JavaScript bytecode sidecars to HTTP response headers so
WebContent can materialize classic and module scripts directly from a
decoded cache blob on cache hits.

Carry the disk cache vary key with the sidecar and reuse it when storing
fresh bytecode, avoiding mismatches against the augmented network
request headers used to create the cache entry.

Keep CORS-filtered module responses intact for status, MIME, and script
creation checks. Read bytecode sidecar data only from the internal
response, and treat decode or materialization failure as a cache miss
that falls back to normal source compilation.
2026-05-06 08:20:06 +02:00
Andreas Kling
557191decb LibWeb+RequestServer: Cache bytecode after script handoff
Schedule JavaScript bytecode cache generation after downloaded classic
scripts and modules have been handed back to the main thread.

The cache job reparses and fully compiles on the thread pool,
serializes the bytecode blob, and stores it as HTTP cache sidecar data.
RequestServer finalizes the disk cache entry before notifying
WebContent, so the script fetcher can attach the sidecar immediately.
2026-05-06 08:20:06 +02:00
Andreas Kling
2c53432aa4 RequestServer: Expose cache sidecars over IPC
Add RequestServer messages and LibRequests helpers for storing and
retrieving HTTP cache sidecar data.

Transfer sidecar payloads as anonymous buffers so large JavaScript
bytecode blobs do not have to be serialized into IPC message bodies.
2026-05-06 08:20:06 +02:00
Jelle Raaijmakers
b488b7e7b1 LibWeb: Propagate line box borders debug toggle to child navigables
Only the top navigable received this setting; existing and new
descendant navigables never showed these debug boxes.
2026-05-05 23:47:23 +02:00
Undefine
b9fec5edbf Meta: Rename and merge some lagom_* and ladybird_*
We had both {lagom,ladybird}_test and {lagom,ladybird}_lib, now both
are just one helper. Also rename all other lagom_* helpers to be
ladybird_*.
2026-05-05 22:08:24 +02:00
Undefine
1d83e8c896 Meta: Move all remaining dependency checks to check_for_dependencies
This also allows us to get rid of a couple of files that were meant
for dependency specific checks.
2026-05-05 22:08:24 +02:00
Sam Atkins
48a0e9fef7 RequestServer: Queue websocket writes under curl backpressure
Add the same connect timeout used by regular requests to curl-backed
websockets, buffer unsent websocket bytes, and resume them from a write
notifier instead of retrying curl_easy_send() in a tight loop.

This prevents CPU spins on CURLE_AGAIN and keeps large websocket sends
from hanging when the peer applies backpressure.
2026-05-05 19:14:29 +02:00
Sam Atkins
1d7825f601 RequestServer: Terminate cancelled and failed websockets cleanly
Convert DNS failures and connecting-stage close requests into terminal
websocket state changes, and remove websocket entries once they close.

This keeps clients from getting stuck in CONNECTING and makes early
cancelled or failed websocket attempts terminate like the other close
paths.
2026-05-05 19:14:29 +02:00
Aliaksandr Kalenik
3d1140e998 WebContent: Schedule a frame when WebDriver waits for the next paint
The Take Screenshot and Take Element Screenshot endpoints add a callback
to the animation frame driver and rely on it firing to encode and return
the framebuffer. Since rendering updates moved to on-demand scheduling,
that callback never runs unless something else happens to request a
frame, so the WebDriver client times out waiting for the response.

Request a frame after registering the callback, matching what
Window::request_animation_frame() does for the JS-exposed API.
2026-04-30 21:14:03 +02:00
Andreas Kling
c919f1c28f LibWebView: Add style invalidation counter dump option
Add --dump-style-invalidation-counters=N to Ladybird and propagate it
to WebContent helper processes.

When enabled, WebContent dumps the current document style invalidation
counters with dbgln() after every N recorded style invalidations. This
makes it possible to collect the counters while browsing without adding
temporary C++ logging.
2026-04-30 00:24:04 +02:00
Aliaksandr Kalenik
f785e13ae9 LibWeb: Schedule rendering updates on demand
Previously a fixed-rate paint refresh timer kept queueing rendering
update tasks at the maximum configured frame rate, regardless of whether
anything had actually changed. This wasted CPU on idle pages, which
spend most of their time in a steady state where no style, layout, or
paint work is needed.

Replace the repeating timer with a single-shot frame timer driven by
PageClient::request_frame(). A rendering update is now scheduled only
when something requires one. The configured maximum frame rate is
preserved as a ceiling on how closely consecutive frames can follow each
other.
2026-04-29 20:54:53 +02:00
Aliaksandr Kalenik
737691c43a LibWeb: Keep worker startup reachable until script load completes
Fixes flakiness in worker tests that create a Worker or SharedWorker
with a missing script URL and only attach an error handler to it.
Once the test callback returns, nothing keeps the worker rooted from
JavaScript. If GC ran before the WebWorker process reported the
script fetch failure, the Worker/WorkerAgentParent cycle could be
collected and the error event never delivered, leaving the test hung
until timeout.

Hold startup-pending WorkerAgentParents from the outside
EnvironmentSettingsObject and release that edge once the script load
succeeds, fails, or the worker closes. The worker now survives long
enough to deliver its first script-load result.
2026-04-27 18:02:49 +02:00
Andreas Kling
03d1b37354 RequestServer: Pre-resolve preconnect handles via our DNS resolver
handle_connect_state (used by <link rel=preconnect>) attached easy
handles to the multi without setting CURLOPT_RESOLVE, so libcurl spawned
its own threaded resolver for them. When the system stub resolver was
slow, the thread got stuck and the next ~Request pthread_join'd it on
the main thread for many seconds.

Route Connect-mode requests through the same DNS + CURLOPT_RESOLVE path
that Fetch uses, so libcurl never spawns the thread.
2026-04-26 17:59:52 +02:00
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
Tim Ledbetter
884a0140aa LibCore: Allow zero-size AnonymousBuffer creation
Previously, `AnonymousBuffer::create_with_size(0)` returned an error
because POSIX `mmap` rejects a zero length with `EINVAL`, and Windows
`CreateFileMapping` rejects a zero maximum size for an anonymous
mapping. This caused a crash when using `--headless=text` with zero
size pages like `about:blank`.
2026-04-22 09:08:39 -04:00
Andreas Kling
f0765e80f3 RequestServer: Avoid O(N^2) copy when draining response buffer
write_queued_bytes_without_blocking() used to allocate a Vector sized
to the entire queued response buffer and memcpy every queued byte into
it, on every curl on_data_received callback. When the client pipe was
slower than the network, the buffer grew, and each arriving chunk
triggered a full copy of everything still queued. With enough pending
data this added up to tens of gigabytes of memcpy per request and
stalled RequestServer for tens of seconds.

Drain the stream in a loop using peek_some_contiguous() + send()
directly from the underlying chunk, and discard exactly what the
socket accepted. No intermediate buffer, no copy. The loop exits on
EAGAIN and enables the writer notifier, matching the previous
back-pressure behavior.
2026-04-22 13:32:07 +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
06796f5f7f LibURL+LibWeb+LibWebView: Convert about:version to a proper WebUI
Passing the browser command line and executable path to every WebContent
process just in case we load about:version always felt a bit weird. We
now use the WebUI framework to load this information on demand.
2026-04-21 06:59:11 -04:00
Shannon Booth
fd44da6829 LibWeb/Bindings: Emit one bindings header and cpp per IDL
Previously, the LibWeb bindings generator would output multiple per
interface files like Prototype/Constructor/Namespace/GlobalMixin
depending on the contents of that IDL file.

This complicates the build system as it means that it does not know
what files will be generated without knowledge of the contents of that
IDL file.

Instead, for each IDL file only generate a single Bindings/<IDLFile>.h
and Bindings/<IDLFile>.cpp.
2026-04-21 07:36:13 +02:00
Undefine
8cee6ba5a0 Meta: Remove a Qt option related from RequestServer's CMakeLists
Since those are no longer set in the top level CMake file this is no
longer necessary.
2026-04-20 16:41:29 -06:00
Undefine
e39a8719fd Meta: Move most dependency checks to check_for_dependencies.cmake
This file was here for quite a long while now. Let's finally move most
of the dependency checks to one centralized place.
2026-04-20 16:41:29 -06:00
Shannon Booth
de14978046 LibWeb: Implement cross process BroadcastChannel delivery
Route BroadcastChannel messages over IPC so matching channels can
receive them across WebContent and WebWorker processes, rather than only
within a single process.

Each channel now serializes its payload, sends it upward over IPC, and
receiving processes deliver it locally after matching by storage key and
channel name.
2026-04-14 18:43:28 +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
Timothy Flynn
79893b9cef LibWeb+LibWebView+WebContent: Add a setting to control autoscrolling 2026-04-13 13:01:45 -04:00
Andreas Kling
2ca7dfa649 LibJS: Move bytecode interpreter state to VM
The bytecode interpreter only needed the running execution context,
but still threaded a separate Interpreter object through both the C++
and asm entry points. Move that state and the bytecode execution
helpers onto VM instead, and teach the asm generator and slow paths to
use VM directly.
2026-04-13 18:29:43 +02:00
Aliaksandr Kalenik
75af441bff Everywhere: Replace SharedBackingStore with Gfx::SharedImage
Generalize the backing store sharing abstraction into SharedImage, which
represents shared GPU memory independently of Skia and can be used to
share memory between different processes or different GPU contexts.
2026-04-09 01:18:59 +02:00
Shannon Booth
57130908b3 LibJS+LibWeb: Make DOMException hold an [[ErrorData]] slot
Split JS::ErrorData out of JS::Error so that it can be used both
by JS::Error and WebIDL::DOMException. This adds support for
Error.isError to DOMException, also letting us report DOMException
stack information to the console.
2026-04-08 20:33:53 +02:00
Shannon Booth
a2e735b94c LibWeb: Fire unhandled dedicated worker exceptions on the parent global
When a dedicated worker has an unhandled exception, we should propogate
that exception to be fired at the parent global. Fixes a timeout
in the included WPT test.
2026-04-05 23:38:38 +02:00
Shannon Booth
bb0f244667 LibWeb: Remove ShadowRealm HTML integration 2026-04-05 13:57:58 +02:00
Glenn Skrzypczak
f1d3244b22 LibWeb: Support CSS modules
This adds support for importing CSS stylesheets from CSS files in
javascript.
2026-04-03 21:21:09 +02: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
Shannon Booth
0086a7899d LibWeb: Remove some uneeded navigation error propogation
We should not have any errors to propogate down these paths.
2026-04-01 04:41:11 +02:00
Aliaksandr Kalenik
2a69fd4c52 LibWeb: Replace spin_until in apply_the_history_step with state machine
Replace the blocking spin_processing_tasks_with_source_until calls
in apply_the_history_step_after_unload_check() with an event-driven
ApplyHistoryStepState GC cell that tracks 5 phases, following the
same pattern used by CheckUnloadingCanceledState.

Key changes:
- Introduce ApplyHistoryStepState with phases:
  WaitingForDocumentPopulation, ProcessingContinuations,
  WaitingForChangeJobCompletion, WaitingForNonChangingJobs and Completed
- Add on_complete callbacks to apply_the_push_or_replace_history_step,
  finalize_a_same_document_navigation,
  finalize_a_cross_document_navigation, and
  update_for_navigable_creation_or_destruction
- Remove spin_until from Document::open()
- Use null-document tasks for non-changing navigable updates and
  document unload/destroy to avoid stuck tasks when documents become
  non-fully-active
- Defer completely_finish_loading when document has no navigable yet,
  and re-trigger post-load steps in activate_history_entry for documents
  that completed loading before activation

Co-Authored-By: Shannon Booth <shannon@serenityos.org>
2026-03-31 09:47:59 +02:00
Luke Wilde
df32da5e86 LibWeb: Make every HTMLElement potentially form-associated
This can be the case for form-associated custom elements, where any
HTML element can be form-associated.
2026-03-25 13:18:15 +00:00
Luke Wilde
cfd795f907 LibWeb+IDLGenerators: Support nullable union types 2026-03-25 13:18:15 +00:00
Aliaksandr Kalenik
1d025620e3 Everywhere: Move Mach bootstrap listener into LibIPC
Move MachPortServer from LibWebView into LibIPC as MachBootstrapListener
and move the Mach message structs from MachMessageTypes.h into LibIPC.

These types are IPC infrastructure, not UI or platform concerns.
Consolidating them in LibIPC keeps the Mach bootstrap handshake
self-contained in a single library and removes LibWebView's dependency
on LibThreading.
2026-03-24 19:51:52 +01:00
Aliaksandr Kalenik
e47f4cf90f Everywhere: Simplify Mach bootstrap transport handshake
Previously, the bootstrap handshake used a two-state machine
(WaitingForPorts / WaitingForReplyPort) to handle a race: the parent
registering transport ports and the child sending a bootstrap request
could arrive in either order, so whichever came first stored its half
and the second completed the handshake.

Eliminate the race by holding a mutex across spawn() and
register_child_transport(). Since the child cannot send a bootstrap
request before it exists, and the lock isn't released until its
transport is registered, handle_bootstrap_request() is guaranteed to
find the entry. This reduces the pending map to a simple pid-to-ports
lookup and collapses the two-variant state into two straightforward
branches: known child, or on-demand (non-child) caller like WebDriver.
2026-03-24 19:51:52 +01:00
Timothy Flynn
58791db818 AK+LibWeb: Move generation of random UUIDs into AK
This will let us use this more outside of LibWeb more easily.

Stop handling tiny OOM while we are here.
2026-03-24 12:04:50 -04:00
Aliaksandr Kalenik
3cb644500e Everywhere: Send IOSurface backing stores via main IPC route on macOS
Now that LibIPC uses Mach ports for transport on macOS, IOSurface port
rights can be sent as regular IPC message attachments instead of through
a separate ad-hoc Mach message side-channel. Introduce
Web::SharedBackingStore that wraps either a MachPort (macOS) or
ShareableBitmap (other platforms) with IPC encode/decode support,
unifying backing store allocation into the existing
did_allocate_backing_stores IPC message.
2026-03-23 23:22:38 +01:00
Aliaksandr Kalenik
c6d740ea41 Everywhere: Remove dynamic Mach bootstrap registration on macOS
Registering multiple Mach port names with the bootstrap server at
runtime is not how macOS expects it to be used — the bootstrap server
is meant for static services, and the only reason we used it originally
was so child processes could reach back to the UI process.

Remove bootstrap_transport_over_socket(), which had both sides register
dynamic names with the bootstrap server and exchange them over a socket.
Instead, WebDriver and BrowserProcess connections now go through
MachPortServer instances directly. When a non-child process contacts a
MachPortServer, the server creates a port pair on demand (detected via
sysctl ppid check) and returns the local half immediately. This keeps
bootstrap server usage limited to the one original case: child processes
looking up their parent's MachPortServer.

WebDriver Session now runs its own MachPortServer per session.
--webdriver-content-path becomes --webdriver-mach-server-name on macOS.
Spare WebContent launches are skipped when a WebDriver session is active
to avoid bootstrap races.
2026-03-23 18:50:48 +01:00
Aliaksandr Kalenik
4ea4d63008 Everywhere: Replace Unix socket IPC transport with Mach ports on macOS
On macOS, use Mach port messaging instead of Unix domain sockets for
all IPC transport. This makes the transport capable of carrying Mach
port rights as message attachments, which is a prerequisite for sending
IOSurface handles over the main IPC channel (currently sent via a
separate out-of-band path). It also avoids the need for the FD
acknowledgement protocol that TransportSocket requires, since Mach port
right transfers are atomic in the kernel.

Three connection establishment patterns:

- Spawned helper processes (WebContent, RequestServer, etc.) use the
  existing MachPortServer: the child sends its task port with a reply
  port, and the parent responds with a pre-created port pair.

- Socket-bootstrapped connections (WebDriver, BrowserProcess) exchange
  Mach port names over the socket, then drop the socket.

- Pre-created pairs for IPC tests and in-message transport transfer.

Attachment on macOS now wraps a MachPort instead of a file descriptor,
converting between the two via fileport_makeport()/fileport_makefd().

The LibIPC socket transport tests are disabled on macOS since they are
socket-specific.
2026-03-23 18:50:48 +01:00
Tim Ledbetter
26389363ad LibGfx+LibWeb: Move Skia backend context to process level singleton
Previously, this was attached to the traversable navigable. Using a
singleton instead allows us to use the context for detached documents.
2026-03-19 13:35:16 +01:00
Zaggy1024
2e54c18fb3 LibWeb: Use a queue to process fullscreen request completions
Instead of immediately firing fullscreenchange, defer that until
WebContent's client has confirmed that it is in fullscreen for the
content. The fullscreenchange is fired by the viewport change, so in
cases where the fullscreen transition is instantaneous (i.e. the
fullscreen state is entered at the exact moment the viewport expands),
the resize event should precede the fullscreenchange event, as the spec
requires.

This fixes the WPT element-request-fullscreen-timing.html test, which
was previously succeeding by accident because we were immediately
fullscreenchange upon requestFullscreen() being called, instead of
following spec and doing the viewport (window) resize in parallel. The
WPT test was actually initially intended to assert that the
fullscreenchange event follows the resize event, but the WPT runner
didn't actually have a different resolution for normal vs fullscreen
viewports, so the resize event doesn't actually fire in their setup. In
our headless mode, the default viewport is 800x600, and the fullscreen
viewport is 1920x1080, so we do fire a resize event when entering
fullscreen. Therefore, that imported test is reverted to assert that
the resize precedes the fullscreenchange.
2026-03-17 18:58:37 -05:00
Zaggy1024
ac69815740 Everywhere: Add an is_fullscreen parameter to set_viewport
This will be used by the UIs to notify WebContent when fullscreen for
content is entered or exited.
2026-03-17 18:58:37 -05:00
Zaggy1024
d0a38bd046 WebContent: Remove the sync result from did_request_fullscreen_window
This was unused.
2026-03-17 18:58:37 -05:00
Zaggy1024
44ed698d4f LibWeb: Separate the active element and the element being activated
We were conflating elements being the active element and elements being
activated. The :active pseudo class is supposed to be based on whether
an element will have its activation behavior run upon a button being
released.

Store whether an element is being activated as a flag that is set/reset
by EventHandler.

Doing this allows label elements to visually activate their control
without doing a weird paintable hack, so the Labelable classes have
been yeeted.
2026-03-17 04:01:29 -05:00
Andreas Kling
669bc04295 RequestServer: Increase RequestPipe socket buffer sizes
The RequestPipe uses a socketpair for streaming response body data
from RequestServer to WebContent. On macOS, the default socket buffer
size for AF_LOCAL sockets is only ~8KB, which meant every read/write
syscall could only transfer ~8KB at a time. For large responses, this
resulted in thousands of tiny reads with significant per-read overhead.

Increase the send and receive buffer sizes to 512KB, matching the
approach already used by IPC::TransportSocket. This dramatically
improves throughput for large response bodies -- for example, fetching
a 25MB file from localhost went from ~850ms to ~25ms in testing.
2026-03-15 09:06:06 -04:00
Zaggy1024
e4a8fc4b7b WebContent: Exit after the crash signal handler dumps a backtrace
I'm unsure exactly why this is possible, but using a freed GC pointer
on macOS was causing a segmentation violation to reach our signal
handler, but instead of exiting, the process would get stuck.

To solve this, when terminal signals are received, just exit() instead
of trying to let it get to the default handler. This allows test-web to
get unstuck in cases like this, and instead of timing out and leaving a
zombie, count the test as a crash.

In particular, the issue was caused by calling top_level_traversable()
on a null Navigable. Since GC::Ptr's null checks are debug-only, it was
trying to access garbage m_parent fields. With or without the signal
handlers, this would result in an (unsurprising) EXC_BAD_ACCESS, as
observed by attaching lldb. Regardless of debuggers being attached, or
signal handlers being enabled, after the signal, the process would get
stuck and refuse to exit, even after a SIGKILL. Sampling the stuck
processes didn't seem to indicate that the program counter was moving
in this state, so I'm unsure what causes it to get stuck.
2026-03-15 11:10:05 +01:00
Zaggy1024
0b2a654703 WebContent: Silence a clang-tidy warning in the signal handler 2026-03-15 11:10:05 +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
Shannon Booth
c4c0afe4d7 LibWebSocket+RequestServer: Handle connection drop during closing
This fixes a race condition where a WebSocket would report a fatal
connection error instead of a clean close when the server dropped the
underlying connection immediately after sending a Close frame.

This fixes various timeouts in WPT, such as in:

https://wpt.live/websockets/Send-null.any.worker.html?wss
2026-03-13 17:28:06 +01:00
Aliaksandr Kalenik
429847e843 LibWeb+LibWebView+WebWorker: Send service sockets to workers over IPC
Instead of passing RequestServer and ImageDecoder socket FDs as
command-line arguments to WebWorker, send them over the main IPC channel
after launch. The worker-agent handoff now carries all three transport
handles (worker, RequestServer, ImageDecoder) so the connection path
matches WebContent.
2026-03-12 20:32:55 +01:00
Aliaksandr Kalenik
ff95e47802 LibWeb+LibWebView+WebContent: Send service sockets over IPC channel
Instead of passing RequestServer and ImageDecoder socket FDs as
command-line arguments to WebContent, send them over the main IPC
channel after launch. This unifies initial connection and reconnection
into a single code path.
2026-03-12 20:32:55 +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
Jelle Raaijmakers
d1f98d596d RequestServer: Check for curl errors before sending headers
I noticed TLS errors only being dumped to stderr, but not shown on our
regular error page. This restores that behavior and adds a regression
test.
2026-03-12 13:17:18 -04:00
sideshowbarker
e38adbc31b LibWeb: Enable crash backtraces from WPT runner
When a WebContent process receives a fatal signal, print a backtrace to
stderr before re-raising the signal. The backtrace is captured by
the test runner and written to a .stderr.html file.

Uses SA_RESETHAND so the handler runs only once, then resets to the
default disposition and re-raises the signal for normal crash behavior.
2026-03-12 17:10:51 +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
Shannon Booth
1ca68af702 LibWeb: Fire error event at Worker when script loading fails
This fixes a whole bunch of WPT timeouts for Workers which wait
for this event to arrive.
2026-03-08 12:18:21 +00:00
Christian Frey
deda42ea94 WebContent: Enable IOSurfaces on Intel macOS
Without IOSurface, the Metal rendering path introduced in #7956 hits a
VERIFY(iosurface_ref) failure and crashes on launch on Intel Macs.
The FIXME stated that the implementation of IOSurface does not work on
Intel macOS, but testing confirms it now works correctly.
2026-03-05 09:28:36 -05:00
Zaggy1024
1c7aca7e07 LibThreading: Simplify BackgroundAction callback invocation
Using a Promise in BackgroundAction was not doing anything since the
change to use a weak reference to the event loop, so let's just drop
that.

The thread will now always move itself (and therefore its callbacks)
over to the originating thread before completing, regardless of the
presence of callbacks. This ensures that ref counting remains on the
main thread.

In addition, BackgroundAction's completion callback can no longer
return errors. This functionality wasn't actually used anywhere, it was
a holdover from the behavior of Core::Promise.
2026-03-02 17:06:39 -06:00
Timothy Flynn
1aed4d624d WebContent: Implement WebDriver's fullscreen endpoint according to spec
Use the Fullscreen API rather than invoking the fullscreen IPC directly.
2026-03-02 15:49:13 -05:00
Timothy Flynn
44b9199de1 WebContent: Implement steps to fully exit fullscreen in WebDriver 2026-03-02 15:49:13 -05:00
Timothy Flynn
ae8181b467 LibWeb+LibWebView+UI: Add a context menu item to toggle fullscreen state 2026-03-01 15:41:43 -06:00
Shannon Booth
1ca2b052a0 WebContent: Make more use of Value::as_if 2026-02-28 10:24:37 -05:00
Andreas Kling
b20d14970f LibWeb: Flatten Platform::FontPlugin by merging WebView::FontPlugin
WebView::FontPlugin was the only implementation of the abstract
FontPlugin base class. Its dependencies (LibGfx, LibCore) are
already visible to LibWeb.

Remove the virtual dispatch by making FontPlugin concrete and
absorbing the WebView::FontPlugin implementation directly.
2026-02-28 15:32:14 +01:00
Andreas Kling
3cfc7aa629 LibWeb: Flatten Platform::EventLoopPlugin by merging Serenity impl
EventLoopPluginSerenity was the only implementation of the abstract
EventLoopPlugin base class. Its methods simply wrapped Core::EventLoop
calls with GC function unwrapping.

Remove the virtual dispatch by making EventLoopPlugin concrete and
absorbing the EventLoopPluginSerenity implementation directly.
2026-02-28 15:32:14 +01:00
Jonathan Gamble
152758f5a6 ImageDecoder: Disconnect client on duplicate request id
Request ids from a client connection must never be reused. This is also
enforced in the LibImageDecoderClient library by main thread asserts
around a monotonically increasing request id counter.
2026-02-28 00:04:06 -06:00
Jonathan Gamble
7d902c2a89 LibImageDecoderClient: Remove sync id fetch from async decode request 2026-02-28 00:04:06 -06:00
Shannon Booth
74109d2f6b RequestServer: Only trim HTTP whitespace from response headers
The Fetch spec defines HTTP whitespace as tab, LF, CR, and space.
Previously, trim_whitespace was also stripping vertical tab (U+000B)
and form feed (U+000C), which are not HTTP whitespace characters.
Switch to HTTP::normalize_header_value which matches the fetch
definition.

Fixes 4 subtests for WPT test:

https://wpt.live/cors/origin.htm
2026-02-26 20:01:13 +01:00
Timothy Flynn
9bd0a50a01 RequestServer: Capture async references to Request objects weakly
It's possible for the client (WebContent) to stop a request while the
request is waiting for an async callback to be invoked. So we cannot
assume the request itself will still be alive once these callbacks are
finally invoked.
2026-02-26 15:36:38 +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
Jelle Raaijmakers
90a211bf47 LibWeb: Use device-pixel coordinates in display list and AVC
Stop converting between CSS and device pixels as part of rendering - the
display list should be as simple as possible, so convert to DevicePixels
once when constructing the display list.
2026-02-26 07:43:00 +01:00
Shannon Booth
9e7aa878bc LibWeb: Properly determine if running in SecureContext for Workers
Fixes the included imported test. Note that this required a minor
edit of the WPT import to work with our test harness setup to
try and create a non secure context setup as both file:// and
localhost are considered secure contexts.
2026-02-26 07:22:50 +01:00
Simon Farre
04d1e2bf3d LibWeb: Implement exitFullscreen algorithm
Exiting fullscreen from the UI will be added in future commits.
2026-02-23 18:44:26 +00:00
Simon Farre
bc17805b2b LibWeb: Implement requestFullscreen algorithm
The required functionality to exit fullscreen will be in a followup
commit.
2026-02-23 18:44:26 +00:00
Simon Farre
44e0735d9b LibWebView+UI/Qt: Allow WebContent to enter/exit the fullscreen UI
These IPC methods should be expanded in the future to allow WebContent
to specify what UI elements should be kept/removed, for example, the
navigation UI.
2026-02-23 18:44:26 +00:00
Jelle Raaijmakers
1cc29c669a WebContent: Combine viewport size and DPR into a single IPC message
The set_viewport_size and set_device_pixel_ratio IPC messages were sent
separately, potentially causing a race condition when the DPR changes
(e.g. moving a window between screens): the DPR message would arrive
and use a stale viewport size, computing a temporarily wrong CSS
viewport. Combine both into a single set_viewport IPC that updates the
device viewport size and DPR together.
2026-02-23 15:22:12 +01:00
Shannon Booth
665654a1c4 LibWeb: Begin serializing global object as part of serialized ESO
Instead of passing through window's associated document's URL as
an extra argument to starting up a worker. This will allow for
improving the representation of 'outside settings' when setting
up a Worker.
2026-02-23 11:42:20 +01:00
Shannon Booth
1be69479a6 LibURL+Elsewhere: Consider file:// origins opaque by default
This aligns our behaviour closer to other browsers, which
_mostly_ consider file scheme URLs as opaque. For test
purposes, allow overriding this behaviour with a commandline
flag.
2026-02-21 23:00:57 +01:00
Jelle Raaijmakers
46459ec876 WebContent: Update traversable's viewport size on DPR change
We were effectively copying the logic from .set_viewport_size() into
PageClient, but we forgot to actually update the viewport size on device
pixel ratio changes.
2026-02-19 21:31:21 +01:00
Timothy Flynn
8ad1c72ed3 LibWeb+LibWebView+Services: Add a flag to enable experimental interfaces
This adds the --expose-experimental-interfaces command line flag to
enable experimental IDL interfaces. Any IDL interface with Experimental
in its exposed attributes will be disabled by default.

The problem is that by stubbing out or partially implementing interfaces
in LibWeb, we actually make some sites behave worse. For example, the
OffscreenCanvas interface being exposed makes sites believe we fully
support it, even though we don't. If the interface was not exposed,
these sites may fall back to ordinary canvas objects. Similarly, to
use YouTube, we currently have to patch out MSE interfaces.

This flag will allow developers to iteratively work on features,
without breaking such sites. We enable experimental interfaces during
tests.
2026-02-17 22:17:50 +01:00
Timothy Flynn
b357d3c3c8 LibWebView+WebContent: Move test-mode special handling to the UI process
We will need to propagate test mode behavior to both the WebContent and
WebWorker processes. By moving this handling to the UI process, we will
only need to update one location.
2026-02-17 22:17:50 +01: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
Tim Ledbetter
e0cb38f544 WebContent: Remove unused get_window_handle() IPC method
This is no longer used.
2026-02-15 08:21:41 -05:00
Tim Ledbetter
cb803899c2 WebDriver: Send window handle asynchronously after WebContent connects
This prevents a potential deadlock when tests open many popup windows
in quick succession.
2026-02-15 08:21:41 -05:00
Luke Wilde
10b5ccc931 WebContent+LibWebView: Add endpoint to request top level closure
This will allow the UI to request WebContent to properly close the top
level traversable when closing a tab. For example, this allows the site
to ask if the user is sure they want to leave, closes WebSocket
connections and more.
2026-02-14 23:26:10 +00:00
Andreas Kling
a4f126554d ImageDecoder: Add streaming animation decode sessions
Add IPC messages and server-side implementation for streaming
animated image decode. Instead of decoding all frames upfront,
only decode an initial batch and keep the decoder alive for
on-demand frame requests.

New IPC messages:
- request_animation_frames: request decode of a batch of frames
- stop_animation_decode: clean up a decode session
- did_decode_animation_frames: deliver decoded frames to client
- did_fail_animation_decode: report decode errors

The existing did_decode_image message gains a session_id parameter
(0 for single-shot decode, non-zero for streaming sessions).
2026-02-13 18:34:24 +01: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
Andreas Kling
9e8e568b43 LibWeb: Use structural sharing for CSS custom properties
Replace per-element OrderedHashMap storage for custom properties with
a RefCounted chain (CustomPropertyData) that enables structural
sharing. Each chain node stores only the properties declared directly
on its element, with a parent pointer to the inherited chain.

Elements that don't override any custom properties share the parent's
data directly (just a RefPtr copy). During cascade, only entries that
actually differ from the parent are stored in own_values - the rest
are inherited through the chain. During var() resolution, resolved
values are compared against the parent's and matching entries are
dropped, enabling further sharing.

The chain uses a depth limit (max 32) with flattening, plus
absorption of small parent nodes (threshold 8) to keep lookups fast.

This reduces custom property memory from ~79 MB to ~5.7 MB on
cloudflare.com.
2026-02-13 14:57:15 +01:00
Andreas Kling
89f4fdb9d3 RequestServer+LibWeb: Fix resource substitution for cross-origin scripts
Substituted responses were missing the Access-Control-Allow-Origin
header, causing the CORS check to fail and the script to be treated as
a network error.

Fix this by adding `Access-Control-Allow-Origin: *` to all substituted
responses.

Also include the script's src attribute in the error message when a
script element's result is null, to make debugging easier.
2026-02-12 16:59:47 +01:00
Aliaksandr Kalenik
30e4779acb AK+LibWeb: Reduce recompilation impact of DOM/Node.h
Remove includes from Node.h that are only needed for forward
declarations (AccessibilityTreeNode.h, XMLSerializer.h,
JsonObjectSerializer.h). Extract StyleInvalidationReason and
FragmentSerializationMode enums into standalone lightweight
headers so downstream headers (CSSStyleSheet.h, CSSStyleProperties.h,
HTMLParser.h) can include just the enum they need instead of all of
Node.h. Replace Node.h with forward declarations in headers that only
use Node by pointer/reference.

This breaks the circular dependency between Node.h and
AccessibilityTreeNode.h, reducing AccessibilityTreeNode.h's
recompilation footprint from ~1399 to ~25 files.
2026-02-11 20:02:28 +01:00
Aliaksandr Kalenik
901cc28272 LibWeb: Reduce recompilation impact of DOM/Document.h
Remove 11 heavy includes from Document.h that were only needed for
pointer/reference types (already forward-declared in Forward.h), and
extract the nested ViewportClient interface to a standalone header.

This reduces Document.h's recompilation cascade from ~1228 files to
~717 files (42% reduction). Headers like BrowsingContext.h that were
previously transitively included see even larger improvements (from
~1228 down to ~73 dependents).
2026-02-11 20:02:28 +01:00
Timothy Flynn
d97a3d9b5a LibHTTP+RequestServer: Send revalidation attributes without parsing
The caching RFC is quite strict about the format of date strings. If we
received a revalidation attribute with an invalid date string, we would
previously fail a runtime assertion. This was because to start a
revalidation request, we would simply check for the presence of any
revalidation header; but then when we issued the request, we would fail
to parse the header, and end up with all attributes being null.

We now don't parse the revalidation attributes at all. Whatever we
receive in the Last-Modified response header is what we will send in the
If-Modified-Since request header, verbatim. For better or worse, this is
how other browsers behave. So if the server sends us an invalid date
string, it can receive its own date format for revalidation.
2026-02-10 09:09:53 -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
Timothy Flynn
8d97389038 LibHTTP+Everywhere: Move the cookie implementation to LibHTTP
This will allow parsing cookies outside of LibWeb.

LibHTTP is basically becoming the home of HTTP WG specs.
2026-02-10 12:21:20 +01:00
Aliaksandr Kalenik
b41ed92505 LibWeb: Remove Document.h include from Layout/Viewport.h
Move the inline dom_node() method to Viewport.cpp so the header no
longer needs the full Document definition. Add explicit includes to
files that relied on the transitive dependency.
2026-02-08 18:51:13 +01:00
Adam Colvin
2df5a7bb31 LibJS: Add source locations to console.trace()
LibJS+DevTools: Implement console.trace() with source locations

- Add Console::TraceFrame struct with source location data
- Implement Console::trace() to gather stack information
- Add WebView::StackFrame and ConsoleTrace for IPC
- Implement DevToolsConsoleClient::printer() for traces
- Update FrameActor to format traces for DevTools
- Update WorkerDebugConsoleClient trace handling
- Update ReplConsoleClient to format trace output
2026-02-06 11:58:07 +00:00
Jelle Raaijmakers
c56c933014 LibWeb+WebContent: Instantly update DPI for painting and media queries
If our UI informed the page of a DPI change, we would store the new
device pixel ratio and leave it at that. It would take a layout/style
update (e.g. by clicking the page) to actually render the page using the
new DPI. This is very visible on macOS when moving the Ladybird window
from a 1x resolution monitor to a HiDPI 2x monitor.

We now instantly update the backing stores and mark media queries for
reevaluation. Moving the Ladybird window on macOS now immediately
updates the page when dragging it to a HiDPI monitor.
2026-02-06 09:01:26 +01:00
Timothy Flynn
0482b6bb57 LibWeb+LibWebView+WebContent: Implement versioning for document cookies
This patch introduces a cookie cache in the WebContent process to reduce
blocking IPC calls when JS accesses document.cookie. The UI process now
maintains a cookie version counter per-domain in shared memory. When JS
reads document.cookie, we check whether we have a valid cached cookie by
comparing the current shared version to the last used version. If they
match, the cached cookie is returned without IPC.

This optimization is based on Chromium's shared versioning, in which it
was observed that 87% of document.cookie accesses were redundant. See:
https://blog.chromium.org/2024/06/introducing-shared-memory-versioning-to.html

Note that this cache only supports document.cookie, not HTTP Cookie
headers. HTTP cookies are attached to requests with varying URLs and
paths. The cookies that match the document URL might not match the
request URL, which we wouldn't know from WebContent. So attaching the
cached document cookie would be incorrect.

On https://twinings.co.uk, we see approximately 600 document.cookie
requests while the page loads. This patch reduces the time spent in
the document.cookie getter from ~45ms to 2-3ms.
2026-02-05 07:28:07 -05:00
R-Goc
853526200a RequestServer: Don't register signals handlers on Windows
This change makes it so that signal handlers aren't registered on
windows. The reason for that is that the aim of these handlers was to
catch signals that came from another process, but the windows signal
implementation doesn't actually support signaling another process. So we
will need to use a different mechanism for this.
2026-02-02 10:35:11 +01:00
Andreas Kling
34ae80d602 WebContent+LibWebView: Send GC graphs etc over IPC as shared memory
These can get very large, exceeding the new IPC message size limits.
Instead of serializing them into messages (which was silly anyway)
we now send them as Core::AnonymousBuffer which uses shared memory.
2026-02-01 22:46:09 +01:00
Timothy Flynn
76eb5b2fa6 LibWeb+LibWebView+WebContent: Perform cookie URL filtering in the UI
When cookies change or expire, we currently send a list of all changed
cookies to all WebContent processes. We then filter that list in the
WebContent process for cookies that match the page's URL before sending
out cookie change events to JS.

We now perform this filtering in the UI process, so each WebContent
process only receives the cookies it would be interested in, if any.
This serves two purposes:

1. Less IPC chatter.
2. This will let each ViewImplementation know that its cookie value has
   actually changed.

(2) is for an upcoming change that will introduce a cookie cache, and
will allow each view to know it should bust that cache.

Note that for this filtering to work, we must iterate ViewImplementation
instances rather than WebContentClient in order to have the view's URL.
We must then associate the IPC with the view's page ID.

No changes to the /cookiestore WPT subtests.
2026-02-01 08:31:58 -05:00
Tim Ledbetter
7bfbeb8a25 WebDriver: Fix use-after-return in client death callback 2026-02-01 11:41:57 +01:00
CountBleck
6a109c5c57 LibWeb: Allow workers to be spawned by other workers
This commit provides IPC endpoint to WebWorker processes that allows new
WebWorker processes to be requested (just like what WebContent has).
This is implemented by proxying the request_worker_agent call from
WebWorker through WebContent to LibWebView. This allows the WPT test...
http://wpt.live/referrer-policy/gen/worker-classic.http-rp/unsafe-url/worker-classic.http.html
...to pass, and the same is likely true for similar tests.
2026-01-31 22:45:08 +01:00
CountBleck
625926bdeb LibWeb: Set the creation_url of worker environment settings objects
This originally was part of a FIXME in step 5 of "setup a worker
environment settings object". After this change, all the WPT subtests in
https://wpt.live/referrer-policy/gen/worker-classic.http-rp/no-referrer-when-downgrade/fetch.http.html
will pass!
2026-01-31 22:45:08 +01:00
CountBleck
2f96ef33fe LibWeb: Ensure that worker script fetches set the correct referrer
The fetch requests for web worker scripts should be treated as if they
occurred in the caller global scope (which may be a Window) and not the
new worker's global scope. The referrer-policy/4K WPT subtests,
specifically those that test worker subresources, depend on this
behavior to work correctly. This commit fixes many of these subtests,
albeit via a hack where the serialized ESO's creation url is set to
the caller's document URL.
2026-01-31 22:45:08 +01:00
Andreas Kling
cc8eedd8c5 WebContent: Replace WeakPtr/Weakable with GC::Ptr for console client
WebContentConsoleClient is a GC::Cell, so PageClient (also a Cell)
should use GC::Ptr instead of WeakPtr to reference it. Visit it in
visit_edges instead.

Also remove unused GC::Root<JS::GlobalObject> member.
2026-01-30 20:57:42 +01:00
Zaggy1024
b37f42a887 RequestServer: Ignore SIGPIPE for the entire service process
We don't want to be terminated when we write to a pipe that's closed,
so set SIGPIPE to be ignored in main. We already pass MSG_NOSIGNAL when
sending over our socket in RequestPipe, so this is a secondary measure.

However, cURL assumes by default that SIGPIPE is unhandled, so before
any operations that interact with pipes, they set their own handler,
interact with the pipe, then restore the original handler. Since we now
ignore the signal, we can just tell cURL not to do this extra work.
2026-01-29 05:22:27 -06:00
Timothy Flynn
46cd83c405 RequestServer: Honor the only-if-cached Cache-Control request directive
The only-if-cached directive currently behaves differently in the HTTP
Caching RFC compared to the Fetch spec. In the former, we must return
an HTTP 504 response if we do not find a cache entry. In the latter, we
must return a network error.

Note that similar to commit aa1517b727, we
cannot test the only-if-cached directive. We implement a same-origin
restriction aligned with the Fetch API that prevents our test infra from
excercising this directive.
2026-01-28 11:31:04 -05:00
Timothy Flynn
6840571cb3 RequestServer: Store the HTTP status code as an optional
Rather than using 0 as a nominal value. This just feels a bit better in
an upcoming commit that makes further use of it.
2026-01-28 11:31:04 -05: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
54c2ecedca RequestServer: Do not flush the disk cache for unsuccessful requests
If a request failed, or was stopped, do not attempt to write the cache
entry footer to disk. Note that at this point, the cache index will not
have been created, thus this entry will not be used in the future. We do
still delete any partial file on disk.

This serves as a more general fix for the issue addressed in commit
9f2ac14521.
2026-01-23 14:24:20 +01:00
Timothy Flynn
d3041dc054 LibHTTP+LibWeb: Support the HTTP Vary response header
We now partition the HTTP disk cache based on the Vary response header.
If a cached response contains a Vary header, we look for each of the
header names in the outgoing HTTP request. The outgoing request must
match every header value in the original request for the cache entry
to be used; otherwise, a new request will be issued, and a separate
cache entry will be created.

Note that we must now defer creating the disk cache file itself until we
have received the response headers. The Vary key is computed from these
headers, and affects the partitioned disk cache file name.

There are further optimizations we can make here. If we have a Vary
mismatch, we could find the best candidate cached response and issue a
conditional HTTP request. The content server may then respond with an
HTTP 304 if the mismatched request headers are actually okay. But for
now, if we have a Vary mismatch, we issue an unconditional request as
a purely correctness-oriented patch.
2026-01-22 08:54:49 -05:00
Timothy Flynn
36a826815d LibHTTP+LibWeb+RequestServer: Store request headers in the HTTP caches
We need to store request headers in order to handle Vary mismatches.

(Note we should also be using BLOB for header storage in sqlite, as they
are not necessarily UTF-8.)
2026-01-22 08:54:49 -05: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
6120b3b918 LibWeb+LibWebView+WebWorker: Enable the HTTP memory cache in workers
This is expected by WPT. For this to work, we must be able to determine
the network partition key for shared worker environments. So we now set
a top-level origin for these environments, with a FIXME to implement it
in accordance with the Client-Side Storage Partitioning spec.
2026-01-22 07:05:06 -05:00
Shannon Booth
c6fab541b7 LibWeb: Fix storage set broadcast event never broadcasting old value
We had skipped some steps in the spec and were:
 * Always broadcasting an old value of null, instead of what it
   actually was previously.
 * Still broadcasting a storage event even if the value had
   not changed in storage compared to the last value.

Fix both issues by returning what the old value is in the setter and
implementing the missing logic.
2026-01-21 22:27:59 +01:00
Sam Atkins
3c1d6dd38f LibWeb/HTML: Expose whether we're running in test mode 2026-01-20 06:58:16 -05:00
Sam Atkins
cdf55ea371 WebContent+LibWebView: Rename --layout-test-mode flag to --test-mode
This name has been outdated for a while, as it's enabled when running
any kind of test, not just layout tests.
2026-01-20 06:58:16 -05:00
Timothy Flynn
bc1cafc716 LibHTTP+LibWebView+RequestServer: Allow using the disk cache during WPT
We currently disable the disk cache because the WPT runner will run more
than one RequestServer process at a time. The SQLite database does not
handle this concurrent read/write access well.

We will now enable the disk cache with a per-process database. This is
needed to ensure that WPT Fetch cache tests are sufficiently handled by
RequestServer.
2026-01-19 08:02:14 -05:00
Zaggy1024
84c0eb3dbf LibCore+LibHTTP+RequestServer: Send data via sockets instead of pipes
This brings the implementation on Unix in line with Windows, so we can
drop a few ifdefs.
2026-01-19 06:53:29 -05:00
Zaggy1024
8eda26c5cf LibCore+Everywhere: Make Windows's System::ioctl consistent with POSIX
Passing the option by value on Windows where it's a pointer on all
other platforms seems like it may cause some unnecessary ifdef soup.
2026-01-19 06:53:29 -05:00
Andreas Kling
18aee32084 RequestServer: Add --resource-map option for URL-to-file substitution
This adds support for intercepting network requests and serving local
file content instead. When a URL matches an entry in the substitution
map, the local file is served while preserving the original URL's
origin for cross-origin checks.

Usage:
    Ladybird --resource-map=/path/to/map.json

The JSON file format is:
    {
      "substitutions": [
        {
          "url": "https://example.com/script.js",
          "file": "/path/to/local/script.js",
          "content_type": "application/javascript",
          "status_code": 200
        }
      ]
    }

Fields:
  - url (required): Exact URL to intercept (query string and fragment
    are stripped before matching)
  - file (required): Absolute path to local file to serve
  - content_type (optional): Override Content-Type header (defaults to
    guessing from filename)
  - status_code (optional): HTTP status code (defaults to 200)

This is incredibly useful for debugging production websites: you can
intercept any script, stylesheet, or other resource and replace it with
a local copy containing your own debug instrumentation, console.log
statements, or experimental fixes - all without modifying the actual
site or setting up a local dev server.
2026-01-19 10:23:26 +01:00
Adam Colvin
3a6d82245b LibWeb: Implement Screen.isExtended attribute
- Add WindowManagement to PolicyControlledFeature enum
- Add screen_count() virtual method to PageClient
- Store all screen rects in WebContent::PageClient, derive both
  screen_rect() and screen_count() from stored data
- Implement screen_count() overrides in SVGPageClient and PageHost
- Replace FIXME stub in Screen.cpp with spec-compliant implementation
2026-01-16 20:34:58 +01:00
Jelle Raaijmakers
bf77aeb3dc Tests/LibWeb: Support WPT variant meta tags in test-web
Add support for WPT test variants, which allow a single test file to be
run multiple times with different URL query parameters. Tests declare
variants using `<meta name="variant" content="?param=value">` tags.

When test-web encounters a test with variants, it expands that test into
multiple runs, each with its own expectation file using the naming
convention `testname@variant.txt` (e.g., `test@run_type=uri.txt`).

Implementation details:
- WebContent observes variant meta tags and communicates them to the
  test runner via a new `did_receive_test_variant_metadata` IPC call
- test-web dynamically expands tests with variants during execution,
  waking idle views after each test completion to pick up new work
- Use index-based test tracking to avoid dangling references when the
  test vector grows during variant expansion
- Introduce TestRunContext to group test run state, and store a static
  pointer to it for signal handler access

This enables proper testing of WPT tests that use variants, such as the
html5lib parsing tests (which test uri, write, and write_single modes)
and the editing/bold tests (which split across multiple ranges).
2026-01-16 16:44:13 +00:00
Andreas Kling
770811e343 LibDevTools: Only send network response bodies when DevTools connected
To avoid unnecessary IPC traffic, we now only send network response
bodies when a DevTools client is connected.

This requires tracking DevTools connection state in ViewImplementation
so we can propagate it to new WebContent processes created during
cross-site navigation.
2026-01-15 20:10:19 +01:00
Andreas Kling
681d00c218 LibDevTools: Pass request initiator type to network panel
Propagate the request initiator type (e.g., "xmlhttprequest", "fetch",
"script", "stylesheet") from LibWeb through the IPC layer to DevTools.

This enables Firefox DevTools to correctly identify XHR/fetch requests
and display appropriate cause types in the Network panel's "Initiator"
column.
2026-01-15 20:10:19 +01:00
Andreas Kling
31ffd2e8e5 LibDevTools: Add request and response body viewing to network panel
This adds support for viewing request payloads (POST data) and response
bodies in the Firefox DevTools network panel.

Request bodies are captured when network requests start and passed
through IPC to the NetworkEventActor, which returns them via the
getRequestPostData protocol method.

Response bodies are streamed via a new IPC message as data is received,
accumulated in NetworkEventActor (with a 10MB size limit to prevent
memory issues), and returned via getResponseContent. Text content is
returned as UTF-8, while binary content (images, etc.) is base64.
2026-01-15 20:10:19 +01:00
Andreas Kling
cd8778f662 LibDevTools: Stream console messages instead of polling by index
Previously, console messages were sent using an index-based system where
DevTools would be notified of new message indices and then request them
in batches. This created synchronization issues during page navigation
when the WebContent process resets while DevTools still has stale index
state.

This changes to a push-based model where console messages are sent
immediately as resources when they are logged, matching how Firefox
DevTools handles console messages. Each message is pushed through IPC
and forwarded to DevTools as a "console-message" or "error-message"
resource.

This eliminates the need for index tracking in FrameActor and simplifies
the entire console message pipeline from WebContent through to DevTools.
2026-01-15 20:10:19 +01:00
Andreas Kling
cf010885d5 LibDevTools: Add Firefox DevTools network monitoring support
Hook ResourceLoader to emit network request lifecycle events through
IPC to the UI process, where FrameActor creates NetworkEventActor
instances that serialize requests using Firefox's Remote Debug Protocol.

The Network panel now shows requests with method, URL, status, MIME
type, size, and timing information. Several features remain stubbed
(POST data, response content, cause detection) marked with FIXMEs.
2026-01-15 20:10:19 +01:00
Shannon Booth
6107775ebe WebWorker: Move hack for initializing global scope's URL even earlier
In the next commit, we will rely on global scope's URL being
initialized even earlier in the process of setting up the environment
for the Worker global. Move this hack just before that.
2026-01-13 16:59:54 +01:00
Jonathan Gamble
fc22c9ea38 LibWeb+WebContent: Allow WebContent to disentangle zoom from css pixels
So Ladybird can paint scrollbar & resizer chrome at the same size
regardless of zoom level while still respecting device pixel ratio
2026-01-12 11:00:14 +00:00
Timothy Flynn
763b8bf11f RequestServer: Remove unused Request getters
These were used at one point, probably before the migration of cache
utilities to LibHTTP.
2026-01-10 23:31:42 +01:00
Timothy Flynn
9f2ac14521 LibHTTP+RequestServer: Do not flush partial responses to the cache index
If the cURL request completes with anything other than CURLE_OK, we must
not keep the cache entry. For example, if the server's connection closes
while transferring data, we receive CURLE_PARTIAL_FILE. We don't want
this cache entry to be treated as valid in a subsequent request.
2026-01-08 11:59:12 +01:00
Timothy Flynn
884efef99d LibRequests+RequestServer: Add an error code for CURLE_PARTIAL_FILE 2026-01-08 11:59:12 +01:00
Tete17
23c39298da LibWeb: Set maximum OpenSSL threads in processes with JS
This is used in openssl as a limit rather than a target so it is
safe to set it equal to the hardware limit.
2026-01-04 15:56:54 +01:00
R-Goc
1f3e20cebf LibMedia: Add a WASAPI playback stream for Windows
Implement PlaybackStream using WASAPI. The design is similar to
PlaybackStreamAudioUnit in that it uses a task queue. A high priority
thread is used to render the stream. All the stream controls save for
the exit being requested which happens on destruction of the stream are
managed by the render thread.

Due to the design of the windows audio mixer the audio we receive must
be resampled to match the sample rate of the mixer. We use a float based
interleaved PCM stream which matches both our existing code and the
audio mixer which internally usues floats.

Having to use a mutex around a queue for the task queue is suboptimal,
in a future PR a MPSC queue could be added to AK and used instead.
2025-12-29 18:02:02 -06: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
0946d802bc LibHTTP+RequestServer: Mark a couple classes as final 2025-12-13 13:07:02 -06:00
Timothy Flynn
9cdf353d2a RequestServer: Add a debug log for request state transitions 2025-12-12 10:54:33 -05: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
R-Goc
f2bf643558 WebContent: Add missing includes on Windows
After header cleanup there were some includes missing when compiling for
windows not affecting other platforms because of ifdefs.
2025-12-05 07:07:52 -05:00
Callum Law
dca80ad5eb LibWeb: Account for animated values when computing font
Computing the font for an element in `compute_font` is premature since
we are yet to apply animated properties - instead we should compute the
value on the fly (with a cache to avoid unnecessary work) to ensure we
are respecting the latest values
2025-12-05 10:03:15 +00: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
adcf5462af LibWeb+WebContent: Rename the http-cache flag to http-memory-cache
Rather than having http-cache and http-disk-cache, let's rename the
former to http-memory-cache to be extra clear what we are talking about.
2025-12-02 12:19:42 +01:00
Timothy Flynn
005e965380 LibCore+RequestServer: Return size_t from system read/write functions
The system uses ssize_t so it can return -1 in case of an error. But in
our case, we will transform that to an AK::Error, thus we never return
-1. Let's return size_t instead.
2025-12-01 16:29:48 +01:00
Sam Atkins
62d7011f45 LibWeb/HTML: Update worker construction spec steps
This is largely editorial. One behaviour change is that events are now
sent from a global task on the DOMManipulation task source.

Somewhat awkwardly, the spec refers to `this` before the Worker exists.
As it's for getting the relevant global object / settings object, I've
had to work around that.

Corresponds to:
917c2f6a73
2025-12-01 15:02:27 +01:00
Timothy Flynn
079a2ba36a LibCore+RequestServer: Implement Core::System::send on Windows 2025-12-01 08:55:33 -05:00
Timothy Flynn
5c88c3718b LibCore: Do not include SocketAddressWindows.h in System.h
SocketAddressWindows.h contains (re)definitions of a bunch of system-
level types. This leads to a bunch of conflicts when trying to include
proper Windows headers in SystemWindows.cpp. This patch removes this
inclusion and just forward-declares the couple of types we need.
2025-12-01 06:34:32 -05: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
InvalidUsernameException
28ba610f32 Everywhere: Avoid large rebuilds when editing (Immutable)Bitmap headers
This reduces the number of recompiled files as follow:
- Bitmap.h: 1309 -> 101
- ImmutableBitmap.h: 1218 -> 75
2025-11-28 18:32:48 +01: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
Prajjwal
50a79c6af8 LibWeb: Change SessionHistoryTraversalQueue to use Promises
If multiple cross-document navigations are queued on
SessionHistoryTraversalQueue, running the next entry before the current
document load is finished may result in a deadlock. If the new document
has a navigable element of its own, it will append steps to SHTQ and
hang in nested spin_until.
This change uses promises to ensure that the current document loads
before the next entry is executed.

Fixes timeouts in the imported tests.

Co-authored-by: Sam Atkins <sam@ladybird.org>
2025-11-26 12:27:12 +01:00
Timothy Flynn
4470f94129 RequestServer: Store a couple of data hashes in disk cache entries
We currently have a FIXME to validate cached data with a crc32. But this
is sort of a non-starter, because we never actually have the cached data
in-memory - we transfer it to the WebContent process via system calls,
and it never reaches userspace in RequestServer.

Chrome makes a bit of an educated gamble here. They assume cosmic bit
blips are extremely unlikely, thus the cached data does not get verified
with a hash. Instead, they store non-cryptographic hashes of some select
fields, and they validate just those hashes.

Here, we store a hash of the cache key in the cache header, and a hash
of the cache header in the cache footer. With these validations, along
with other validations already in-place, we can be reasonably sure we
are not sending corrupt data to the WebContent process.
2025-11-21 08:48:42 +01:00
Timothy Flynn
3663e12585 RequestServer: Do not request partial content for failed cache reads
This effectively reverts 9b8f6b8108.

I misunderstood what Chrome was doing here - they will issue a range
request only for what they call "sparse" cache entries. These entries
are basically used to cache partial large file, e.g. a multi-gigabyte
video. If they hit a legitimate read error, they will fail the request
with a ERR_CACHE_READ_FAILURE status.

We will now (again) fail with a network error when a cache read fails.
2025-11-21 08:48:42 +01:00
Timothy Flynn
4fddd6a681 RequestServer: Do not log disk cache version mismatches on first-run
Particularly on test runs, this is just noise.
2025-11-21 08:48:42 +01:00
Timothy Flynn
4de3f77d37 RequestServer: Add a hook to advance a request's clock time for testing
For example, we will want to be able to test that a cached object was
expired after N seconds. Rather than waiting that time during testing,
this adds a testing-only request header to internally advance the clock
for a single HTTP request.
2025-11-20 09:33:49 +01:00
Timothy Flynn
b2c112c41a LibWebView+RequestServer: Add a simple test mode for the HTTP disk cache
This mode allows us to test the HTTP disk cache with two mechanisms:

1. If RequestServer is launched with --http-disk-cache-mode=testing, it
   will cache requests with a X-Ladybird-Enable-Disk-Cache header.

2. In test mode, RS will include a X-Ladybird-Disk-Cache-Status response
   header indicating how the response was handled by the cache. There is
   no standard way for a web request to know what happened with respect
   to the disk cache, so this fills that hole for testing.

This mode is not exposed to users.
2025-11-20 09:33:49 +01:00
Timothy Flynn
0020af37cd RequestServer: Do not pack the disk cache header and footer structures
This is causing misaligned reads with Address Sanitizer enabled. We
could maintain the packed attribute, and deal with alignment - but we
ended up not actually needing these to be packed anyways. The only thing
we need to know is the serialized size of the header, which we can just
determine differently.
2025-11-20 09:33:49 +01:00
Timothy Flynn
71f9c77ee1 RequestServer: Remove headers exempted from storage from in-memory cache
We previously excluded headers exempted from storage when we serialized
the headers into the database. However, we stored the original headers
in-memory. So when a subsequent request hit CacheIndex::find_entry, we
would return an entry with response headers that should have been
excluded.
2025-11-20 09:33:49 +01:00
Timothy Flynn
a580392109 RequestServer: Compute response ages without truncating sub-fractions
We can use Duration as-is without coercing values to seconds. This
probably doesn't make much difference in real-world scenarios, but when
we hammer the cache during tests, this truncation will cause flakey
behavior.
2025-11-20 09:33:49 +01:00
ayeteadoe
8348c55570 RequestServer: Support HTTP response write retries on Windows
The Windows RequestPipe implementation uses a non blocking local socket
pair, which means the non-fatal "resource is temporarily unavailable"
error that can occur in the non-blocking HTTP Response data writes can
be retried. This was seen often when loading https://ladybird.org.

While the EAGAIN errno is defined on Windows, WSAEWOULDBLOCK is the
error code returned in this scenario, so we were not detecting that we
could retry and treated the failed write attempt as a proper error.

We now detect WSAEWOULDBLOCK and convert it into the errno equivalent
EWOULDBLOCK. There is precedent for doing a similar conversion in the
Windows PosixSocketHelper::read() implementation.

Finally, we retry when we receive either EAGAIN or EWOULDBLOCK error
codes on all platforms. While POSIX allows these 2 error codes to have
the same value, which they do on Linux according to
https://www.man7.org/linux/man-pages/man3/errno.3.html, it is not
guarenteed. So we now ensure platforms that return EWOULDBLOCK with a
value different than EAGAIN also perform write retries.
2025-11-19 09:17:18 +01:00
Andreas Kling
837d5fb7ea RequestServer: Add heuristic cacheability and freshness per RFC 9111
This commit extends is_cacheable() to allow storage of responses that
rely on heuristic cacheability, including status codes defined as
heuristically cacheable.

We implement heuristic freshness lifetime calculation based on the
Last-Modified header as guidance, and apply it when no explicit
expiration information is present.
2025-11-15 10:07:49 -05:00
Andreas Kling
880a7e6c2a RequestServer: Don't update Content-Length during cache revalidation
We were treating Content-Type as exempt from header updates during cache
revalidation and incorrectly allowing Content-Length to get overwritten
when handling an HTTP 304 response.

This caused cached entries to end up with a mismatched Content-Length
that described the validating response instead of the stored body.
2025-11-15 10:07:49 -05: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
d5c00a493c LibDatabase+RequestServer: Store ByteString data as a BLOB
We currently store ByteString as TEXT, but that is interpreted by SQLite
as UTF-8. All string-related operations will try to operate on the text
as if it is stored with UTF-8. We should use BLOB instead, which does
not make any encoding assumptions.

The only user of ByteString in the database currently is the HTTP disk
cache. So we bump its version here to remove existing data. Again, we
will want to handle changes like this more gracefully eventually.
2025-11-12 09:06:21 -05:00
Andreas Kling
2c389ae96c RequestServer: Allow caching of HTTP responses with "Expires" header
Per RFC 9111, we're allowed to cache HTTP responses that don't have a
"Cache-Control" header, provided they do have an "Expires" header.

This lets us cache JavaScript resources on https://x.com/ and makes
it load much faster when cached.
2025-11-10 07:34:49 -05:00
Undefine
769bbe6021 LibCore: Remove unused KeepAsChild and disown mechanisms
Those went unused and did nothing on systems other than SerenityOS.
2025-11-07 11:27:51 +01:00
Undefine
3c0d787c53 LibCore: Remove unused working_directory parameter
This was unused and a no-op on systems other than SerenityOS.
2025-11-07 11:27:51 +01:00
Luke Wilde
167de08c81 LibWeb: Remove exception throwing from Fetch
These were only here to manage OOMs, but there's not really any way to
recover from small OOMs in Fetch especially with its async nature.
2025-11-07 04:08:30 +01:00
Tim Ledbetter
f6f238d15c ImageDecoder+LibWeb: Perform initial alpha conversion in ImageDecoder
This change moves the initial alpha premultiplication step for all
decoded images from WebContent to the ImageDecoder process. This
doesn't reduce the overall amount of work, but it can make sites with a
lot of images more responsive.
2025-11-06 17:56:29 +01:00
Luke Wilde
82bd3d3891 LibWeb: Avoid invoking Trusted Types where avoidable
Prevents observably calling Trusted Types, which can run arbitrary JS,
cause crashes due to use of MUST and allow arbitrary JS to modify
internal elements.
2025-11-06 11:43:06 -05:00
Timothy Flynn
e0a8eb3767 LibWeb+WebContent: Hook Fetch's HTTP cache into the clear-cache action
And fix a typo in an invocation to clear the cache.
2025-11-05 18:27:36 +01:00
Timothy Flynn
ac246caa0c LibWeb: Remove now-unused Resource and ResourceClient
And deal with the fallout of transitive includes.
2025-11-05 18:27:36 +01:00
ayeteadoe
782cf581e4 CMake: Make Ladybird and all Services executables console applications
We set bInheritHandles to TRUE for all child processes we spawn. Some
of the types of objects that support handle inheritence is all of the
STD handles (STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE) and
the console screen buffer. This means if Ladybird and all the child
service processes it launches/communicates with our console apps, only
a single console needs to be allocated and all child process output
their logs to that single console.
2025-11-03 13:23:47 -05:00
Tim Ledbetter
fe377977d9 RequestServer: Add a CURL_DEBUG flag
This sets `CURLOPT_VERBOSE` to 1, which enables detailed logging of
all cURL connections to stderr.
2025-11-03 11:55:56 -05:00
Timothy Flynn
a4e3890c05 RequestServer: Implement stale cache revalidation
When a request becomes stale, we will now issue a revalidation request
(if the response indicates it may be revalidated). We do this by issuing
a normal fetch request, with If-None-Match and/or If-Modified-Since
request headers.

If the server replies with an HTTP 304 status, we update the stored
response headers to match the 304's headers, and serve the response to
the client from the cache.

If the server replies with any other code, we remove the cache entry.
We will open a new cache entry to cache the new response, if possible.
2025-11-02 13:03:29 -05:00
Timothy Flynn
3d45a209b6 RequestServer: Rename CacheEntryReader::m_headers to m_response_headers
Let's be extra clear what we're talking about here.
2025-11-02 13:03:29 -05:00
Timothy Flynn
20cd19be4d RequestServer: Store HTTP response headers in the cache index
We currently store response headers in the cache entry file, before the
response body. When we implement cache revalidation, we will need to
update the stored response headers with whatever headers are received
in a 304 response. It's not unlikely that those headers will have a size
that differs from the stored headers. We would then have to rewrite the
entire response body after the new headers.

Instead of dealing with those inefficiencies, let's instead store the
response headers in the cache index. This will allow us to update the
headers with a simple SQL query.
2025-11-02 13:03:29 -05:00
Timothy Flynn
bf7c5cdf07 RequestServer: Create a cache metadata table
This currently just holds a cache version. If we make a breaking change
to the cache format, we can increment the version here to wipe the cache
database. This is certainly a blunt hammer approach; we will want to
handle such changes more gracefully when we can.
2025-11-02 13:03:29 -05:00
ayeteadoe
f846b6f2d9 CMake: Remove unnecessary WebContent dependencies on Windows
In the initial work that got Ladybird running on Windows, there were
some DLLs that WebContent implicitly depended on which was causing
runtime errors when launching as they didn't exist in libexec.

So the workaround was to explicitly link the targets that had issues to
WebContent and use lagom_copy_runtime_dlls() to ensure they got copied
to libexec.

But given libexec is not a standard Windows convention, in a later
review we made sure Services got output to the bin folder, but those
initial workarounds were not removed even though they were now
unnecessary.
2025-11-01 07:58:12 -04:00
ayeteadoe
643f0de422 RequestServer: Instruct curl to use Windows CA cert store
This is required for supporting HTTPS requests. Otherwise we fail with
CURLE_PEER_FAILED_VERIFICATION.
2025-10-29 21:07:52 -06:00
ayeteadoe
95f239a357 CMake: Add Windows executable helper function
The function currently has 2 purposes: (1) To copy dependent dlls for
executables to output binary directory. This ensures that these helper
processes can be ran after a build given not all DLLs from vcpkg libs
get implicitly copied to the bin folder. (2) Allow fully background
and/or GUI processes to use the Windows Subsystem. This prevents
unnecessarily launching a console for the process, as we either require
no user interaction or the user interaction is all handled in the GUI.
2025-10-29 21:07:52 -06:00
ayeteadoe
11ec7c9cea RequestServer: Create RequestPipe abstraction for request data transfer
The Win32 API equivalent to pipe2() is CreatePipe(), which creates read
and write anonymous pipe handles that we can set to non-blocking via
SetNamedPipeHandleState(); however, this initial approach caused issues
as our Windows infrastructure assumes socket-based handles/fds and that
we don't use Windows pipes at all, see Core::System::is_socket() in
SystemWindows.cpp. So we use socketpair() to keep our current
assumptions true.

Given that Windows uses socketpair() and Unix uses pipe2(), this
RequestPipe abstraction avoids ifdef soup by hiding the details about
how the read/write fds pair is created and how response data is written
to the client.
2025-10-29 17:47:02 -04:00