Problem: TestWebDriverSessionHistory flakes on slow (Sanitizer) CI
runners. The subtest checking that cancellation of a script-initiated
cross-site “back” by a beforeunload handler intermittently failed the
assertion “Expected beforeunload to cancel script-initiated cross-site
history.back(), got [url_b, 0]”. scriptBeforeUnloadCount was 0, not 1.
Cause: history.back() appends its traversal to the traversable’s session
history queue and returns immediately. So the beforeunload prompt to
unload runs async. The test read scriptBeforeUnloadCount in a separate
execute_script right after — with no wait. So on a slow runner, the read
beats the dispatch, and sees 0. Every other script-initiated navigation
in the test waits for its target document to load — and the “refresh”
beforeunload check already polls. But the canceled “back” loads no
target document — and this one waited for nothing.
Fix: Poll with wait_for_script_result until the page is still on /b and
window.scriptBeforeUnloadCount has incremented, before asserting the
final state — mirroring the “refresh” beforeunload check.
Problem: TestWebDriverSessionHistory failed intermittently on the slower
sanitizer CI runners. The UI history already matched what’s expected,
but webContentHistoryMatchesUI was still false — because the snapshot
was caught mid process-swap. The failing assertion varied from run to
run, making it almost certainly a sampling race.
Cause: A cross-site history navigation swaps the WebContent process and
re-seeds its history, and the UI-process mirror converges to that
asynchronously — after the script-visible navigation has finished. But
expect_ui_session_history sampled the mirror once, and asserted right
away — so it could read the state before convergence.
Fix: When a converged state is expected, wait for it instead of sampling
once: Poll until the UI history matches and WebContent matches the UI.
Keep UI process session history authoritative across overlapping
fallback loads and traversals. WebContent can finish a superseded
history load with a live document matching the UI seed URL while its
local step, document state id, and Navigation API keys still describe
a temporary partial list.
Reconstruct the current entry around the UI-owned list in that case.
This avoids making the UI process adopt WebContent's incomplete
snapshot.
Track UI-started fallback loads by URL so unrelated navigations cannot
consume the pending seed state. Resolve deferred WebDriver completions
through the view registry so callbacks queued before a process swap do
not touch a destroyed view.
Add WebDriver coverage that waits for explicit UI/WebContent history
convergence after the relevant document events. The waits poll
observable history state instead of depending on timing.
Wait for the WebDriver session history test to observe the UI-process
mirror after a same-document pushState setup before it starts testing a
browser UI history traversal.
The script-visible URL changes before the asynchronous session history
snapshot reaches the UI process, especially in sanitizer CI. The test
already needs the UI and WebContent histories to match at this point, so
wait for that condition directly instead of sampling the mirror at once.
Keep WebDriver Back and Forward waiting after accepted history
traversals, even when the traversal does not change the top-level
entry. UI-owned session history can still complete same-document
traversals asynchronously, so returning immediately let later
commands race with a pending traversal and observe stale history
state.
The WebDriver session history test covers this path. Give that test a
larger CTest timeout so sanitizer CI has enough room for the full
script.
Add a browser-driven WebDriver scenario for process swaps, renderer
crashes, nested frame history, reloads, and POST replacement cases. The
test drives the browser through the same UI-owned history paths used by
real back and forward actions.
Cover canceled navigations, javascript: no-op loads, source-document
traversal checks, and restored scroll state after crash recovery.
Add fast coverage for merging WebContent snapshots into the UI-owned
session history mirror. The tests exercise seeding, nested histories,
reload state, replacement entries, and traversal target selection.
This adds a WebUI to view the local browsing history, with controls to
search and delete entries. The APIs used to search history are paginated
to prevent excessive query sizes.
Show web URLs without their scheme, a leading host www., or the
root slash while the location field is not being edited. Restore the
fully serialized URL while editing so the original scheme is preserved,
but keep mouse focus stable until release so clicks target the visible
text.
Keep the domain emphasis for shortened Qt location text by deriving the
highlight ranges from the serialized URL and remapping them to the
visible display form. Special URLs like about, data, and file remain
unchanged. Add LibWebView coverage for the shared display helper used by
both UI frontends.
The preload list is static, immutable data compiled into LibHTTP.
ResourceLoader consults it in-process at the fetch layer before
falling back to the dynamic, per-profile store in the browser
process, so a preloaded host is upgraded without a synchronous IPC.
HSTSStore stays the dynamic store only; the preload list cannot be
unset by a max-age=0 response because it is consulted first, before
the store is ever queried.
Maintain a stack of URLs and when they were closed, and allow popping
the most recent one.
These are stored directly on HistoryStore instead of its Storage object,
because they should never persist regardless of which backend we're
using. Even so, we still clear them along with other history data.
This test only checked that the end state, after clearing the storage,
didn't contain the entry. This is the same behaviour we'd expect if it
wasn't disabled, so to test for that, run the same "is this empty?"
check after each step.
Route the existing Clear Browsing Data dialog through HistoryStore's
time-range deletion path as well. That makes the Settings action
remove visited pages from persisted history and from history-backed
address bar suggestions instead of only touching cache and site data.
Add a history checkbox to the dialog, thread its state through the
Settings WebUI message, and cover remove_entries_accessed_since() for
both transient and persisted stores in TestHistoryStore.
Replace the frontend-facing Vector<String> flow with structured
AutocompleteSuggestion objects carrying source, section, title,
and favicon metadata.
Build merged history and literal-URL rows in LibWebView, deduplicate
equivalent URL suggestions, move the autocomplete URL helpers out
of URL.h, and update the history and URL tests around the new model.
Record visits as soon as a page produces useful metadata such as a
title or favicon so pages that never finish loading still become
autocomplete candidates.
Store favicons in the history schema from the start instead of
introducing an upgrade path inside this series, and cover persisted
metadata behavior in TestHistoryStore.
Teach LibWebView autocomplete to query HistoryStore before falling back
to remote engines and move the wiring out of the AppKit frontend.
Refine matching so scheme and www. boilerplate do not dominate results,
short title and substring queries stay quiet, and history tracing can
explain what the ranking code is doing.
Add a HistoryStore abstraction with transient and persisted backends,
normalize recorded URLs, and skip non-browsable schemes.
Cover lookup and persistence in TestHistoryStore so history-driven
features can share one backend.
LibURL parses "localhost:8000" as a URL with a scheme of "localhost" and
basename of "8000". Similar to "mailto:" URLs. We then drop the URL as
having an invalid scheme.
Let's explicitly check for such localhost URLs here and prepend a valid
scheme, as it is a bit of a special case.
This is to prepare for custom search engines. If we use AK::format, it
would be trivial for a user (or bad actor) to come up with a template
search engine URL that ultimately crashes the browser due to internal
assertions in AK::format. For example:
https://example.com/crash={1}
Rather than coming up with a complicated pre-format validator, let's
just not use AK::format. Custom URLs will signify their template query
parameters with "%s". So we can do the same with our built-in engines.
When it comes time to format the URL, we will do a simple string
replacement.
This URL library ends up being a relatively fundamental base library of
the system, as LibCore depends on LibURL.
This change has two main benefits:
* Moving AK back more towards being an agnostic library that can
be used between the kernel and userspace. URL has never really fit
that description - and is not used in the kernel.
* URL _should_ depend on LibUnicode, as it needs punnycode support.
However, it's not really possible to do this inside of AK as it can't
depend on any external library. This change brings us a little closer
to being able to do that, but unfortunately we aren't there quite
yet, as the code generators depend on LibCore.
The current helpers assume that a valid URL is a full URL (i.e. contains
the "://" separator between the scheme and domain). This isn't true, as
"file:" alone is parsed as a valid URL.
We must also avoid simply searching for the parsed public suffix in the
original URL string. For example, "com" is a public suffix. If we search
for that in the URL "com.com", we will think the public suffix starts at
index 0.