Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
// Tests that the blocking columns on moz_origins (block_until_ms and
// block_pages_until_ms) correctly gate origin autofill and adaptive autofill
// queries.
"use strict";
testEngine_setup();
ChromeUtils.defineESModuleGetters(this, {
UrlbarProviderAutofill:
"moz-src:///browser/components/urlbar/UrlbarProviderAutofill.sys.mjs",
});
// Helper: add a page visit and ensure frecency is recalculated so that origin
// autofill can pick it up.
async function addVisitAndRecalculate(
uri,
transition = PlacesUtils.history.TRANSITION_TYPED
) {
await PlacesTestUtils.addVisits({ uri, transition });
await PlacesFrecencyRecalculator.recalculateAnyOutdatedFrecencies();
}
// Helper: add an input history entry for adaptive autofill.
async function addInputHistory(url, input, useCount = 4) {
await PlacesUtils.withConnectionWrapper("addInputHistory", async db => {
await db.execute(
`INSERT OR REPLACE INTO moz_inputhistory (place_id, input, use_count)
VALUES (
(SELECT id FROM moz_places WHERE url_hash = hash(:url) AND url = :url),
:input,
:useCount
)`,
{ url, input: input.toLowerCase(), useCount }
);
});
}
// Choose a time far into the future for blocking and another time that has
// already expired, to test both cases.
const FUTURE_MS = Date.now() + 365 * 24 * 60 * 60 * 1000;
const PAST_MS = Date.now() - 1000;
add_setup(async function () {
// Blocking is only currently enabled when adaptive history autofill is
// enabled due to visible user controls only being available with the feature.
UrlbarPrefs.set("autoFill.adaptiveHistory.enabled", true);
registerCleanupFunction(() => {
UrlbarPrefs.set("autoFill.adaptiveHistory.enabled", false);
});
});
add_task(async function origin_autofill_not_blocked_when_null() {
let url = "https://example.com/";
await addVisitAndRecalculate(url);
// block_until_ms should be NULL by default.
let blockValue = await getOriginColumn(url, "block_until_ms");
Assert.equal(blockValue, null, "block_until_ms should be NULL by default");
let context = createContext("exam", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function origin_autofill_blocked_when_future_timestamp() {
let url = "https://example.com/";
await addVisitAndRecalculate(url);
await UrlbarUtils.blockOriginAutofill(url, FUTURE_MS);
let context = createContext("exam", { isPrivate: false });
// Origin autofill should NOT happen; we should fall through to a non-autofill
// result (e.g. heuristic fallback / search).
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SearchService.defaultEngine.name,
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/",
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function origin_autofill_unblocked_when_expired() {
let url = "https://example.com/";
await addVisitAndRecalculate(url);
// Set block_until_ms to the past (already expired).
await UrlbarUtils.blockOriginAutofill(url, PAST_MS);
let context = createContext("exam", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function origin_autofill_blocked_across_variants() {
// Add two different scheme/www variants.
let httpsUrl = "https://example.com/";
let httpWwwUrl = "http://www.example.com/";
await addVisitAndRecalculate(httpsUrl);
await addVisitAndRecalculate(httpWwwUrl);
// Block via the http://www variant only.
await UrlbarUtils.blockOriginAutofill(httpWwwUrl, FUTURE_MS);
// Verify the block propagated to the https://example.com origin row too.
Assert.equal(
await getOriginColumn(httpsUrl, "block_until_ms"),
FUTURE_MS,
"https://example.com/ should also be blocked"
);
Assert.equal(
await getOriginColumn(httpWwwUrl, "block_until_ms"),
FUTURE_MS,
"http://www.example.com/ should be blocked"
);
// Searching "exam" would match example.com — should NOT autofill.
let context = createContext("exam", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SearchService.defaultEngine.name,
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for http://www.example.com/",
}),
makeVisitResult(context, {
title: "test visit for https://example.com/",
}),
],
});
// Searching "www.exam" would match www.example.com — should also NOT
// autofill. Since the input starts with "www.", the heuristic fallback
// generates a visit result (http://www.exam/) rather than a search result.
context = createContext("www.exam", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
source: UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
title: "www.exam/",
iconUri: "",
heuristic: true,
providerName: "UrlbarProviderHeuristicFallback",
}),
makeSearchResult(context, {
engineName: SearchService.defaultEngine.name,
}),
makeVisitResult(context, {
title: "test visit for http://www.example.com/",
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function origin_autofill_clearing_restores_variants() {
let httpsUrl = "https://example.com/";
let httpWwwUrl = "http://www.example.com/";
await addVisitAndRecalculate(httpsUrl);
await addVisitAndRecalculate(httpWwwUrl);
// Block via https://example.com.
await UrlbarUtils.blockOriginAutofill(httpsUrl, FUTURE_MS);
// Verify both are blocked.
Assert.equal(
await getOriginColumn(httpsUrl, "block_until_ms"),
FUTURE_MS,
"https://example.com/ should be blocked"
);
Assert.equal(
await getOriginColumn(httpWwwUrl, "block_until_ms"),
FUTURE_MS,
"http://www.example.com/ should be blocked"
);
// Clear via the OTHER variant: http://www.example.com.
let didUnblock = await UrlbarUtils.clearOriginAutofillBlock(httpWwwUrl);
Assert.ok(didUnblock, "Should report blocks were cleared");
// Both should now be unblocked.
Assert.equal(
await getOriginColumn(httpsUrl, "block_until_ms"),
null,
"https://example.com/ should be unblocked"
);
Assert.equal(
await getOriginColumn(httpWwwUrl, "block_until_ms"),
null,
"http://www.example.com/ should be unblocked"
);
// Origin autofill should work again for "exam".
let context = createContext("exam", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for http://www.example.com/",
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function adaptive_autofill_not_blocked_by_origin_block() {
let origin = "https://example.com/";
await addVisitAndRecalculate(url);
await addInputHistory(url, "exam");
// Block the origin only.
await UrlbarUtils.blockOriginAutofill(origin, FUTURE_MS);
let context = createContext("exam", {
isPrivate: false,
sources: [UrlbarUtils.RESULT_SOURCE.HISTORY],
});
await check_results({
context,
autofilled: "example.com/some/page",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/some/page",
heuristic: true,
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function adaptive_urls_blocked_by_pages_block() {
await addVisitAndRecalculate(pageUrl);
await addInputHistory(pageUrl, "exam", 8);
let pageUrl2 = "https://example.com/some/page2";
await addVisitAndRecalculate(pageUrl2);
await addInputHistory(pageUrl2, "exam", 8);
// Block URL-level autofill. Since there's no root URL with input history,
// there should be no adaptive autofill at all.
await UrlbarUtils.blockOriginPageAutofill(pageUrl, FUTURE_MS);
let context = createContext("exam", {
isPrivate: false,
sources: [UrlbarUtils.RESULT_SOURCE.HISTORY],
});
// Should fall back to origin autofill since adaptive URL is blocked.
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/some/page",
}),
makeVisitResult(context, {
title: "test visit for https://example.com/some/page2",
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function adaptive_url_blocked_but_root_still_allowed() {
await PlacesUtils.history.clear();
// Set up two URLs under the same origin: the root and a subpage.
let rootUrl = "https://example.com/";
await addVisitAndRecalculate(rootUrl);
await addVisitAndRecalculate(pageUrl);
// Add input history for both, with the page having a higher use_count so it
// would normally be preferred.
await addInputHistory(pageUrl, "exam", 8);
await addInputHistory(rootUrl, "exam", 4);
// Block URL-level autofill only (not the origin itself).
await UrlbarUtils.blockOriginPageAutofill(pageUrl, FUTURE_MS);
// The page URL should be filtered out, but the root URL should still be
// allowed.
let context = createContext("exam", {
isPrivate: false,
sources: [UrlbarUtils.RESULT_SOURCE.HISTORY],
});
// We expect the root URL to be adaptively autofilled instead of the page.
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/some/page",
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function adaptive_url_not_blocked_when_expired() {
await addVisitAndRecalculate(url);
await addInputHistory(url, "exam");
// Set block_pages_until_ms to the past (already expired).
await UrlbarUtils.blockOriginPageAutofill(url, PAST_MS);
let context = createContext("exam", {
isPrivate: false,
sources: [UrlbarUtils.RESULT_SOURCE.HISTORY],
});
// Expired block should have no effect; adaptive autofill should succeed.
await check_results({
context,
autofilled: "example.com/some/page",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/some/page",
heuristic: true,
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function both_blocks_active() {
await addVisitAndRecalculate(url);
await addInputHistory(url, "exam");
// Block both origin and URL-level autofill.
await UrlbarUtils.blockOriginAutofill(url, FUTURE_MS);
await UrlbarUtils.blockOriginPageAutofill(url, FUTURE_MS);
let context = createContext("exam", { isPrivate: false });
// Neither origin nor adaptive autofill should fire.
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SearchService.defaultEngine.name,
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/some/page",
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function clearing_block_restores_origin_autofill() {
let url = "https://example.com/";
await addVisitAndRecalculate(url);
// Block, then clear.
await UrlbarUtils.blockOriginAutofill(url, FUTURE_MS);
// Verify blocked.
let context = createContext("exam", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SearchService.defaultEngine.name,
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/",
}),
],
});
// Clear the block.
await UrlbarUtils.clearOriginAutofillBlock(url);
// Verify restored.
context = createContext("exam", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
],
});
await PlacesUtils.history.clear();
});
add_task(async function cross_origin_isolation() {
let blockedUrl = "https://example.com/";
let unblockedUrl = "https://example.org/";
await addVisitAndRecalculate(unblockedUrl);
await addVisitAndRecalculate(blockedUrl);
// Searching "exam" should autofill example.com since it was added to
// history after.
let context = createContext("exam", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.com/",
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.org/",
}),
],
});
// Block only example.com.
await UrlbarUtils.blockOriginAutofill(blockedUrl, FUTURE_MS);
// Searching "exam" should now autofill example.org since it is not blocked.
context = createContext("exam", { isPrivate: false });
await check_results({
context,
autofilled: "example.org/",
completed: "https://example.org/",
matches: [
makeVisitResult(context, {
title: "test visit for https://example.org/",
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/",
}),
],
});
// And searching "example.c" should NOT autofill because example.com is
// blocked.
context = createContext("example.c", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: SearchService.defaultEngine.name,
heuristic: true,
}),
makeVisitResult(context, {
title: "test visit for https://example.com/",
}),
],
});
await PlacesUtils.history.clear();
});