Bug 1784369: Make opening in new window target for inheritance of sponsored sessions. r=daleharvey

Differential Revision: https://phabricator.services.mozilla.com/D154483
This commit is contained in:
Daisuke Akatsuka 2022-08-16 00:41:01 +00:00
Родитель da11385641
Коммит 9a83490432
7 изменённых файлов: 267 добавлений и 84 удалений

Просмотреть файл

@ -1186,6 +1186,11 @@ class ContextMenuChild extends JSWindowActorChild {
context.onMozExtLink = context.linkProtocol == "moz-extension";
context.onSaveableLink = this._isLinkSaveable(context.link);
context.isSponsoredLink =
(elem.ownerDocument.URL === "about:newtab" ||
elem.ownerDocument.URL === "about:home") &&
elem.dataset.isSponsoredLink === "true";
try {
if (elem.download) {
// Ignore download attribute on cross-origin links

Просмотреть файл

@ -2260,6 +2260,7 @@ var gBrowserInit = {
let hasValidUserGestureActivation = undefined;
let fromExternal = undefined;
let globalHistoryOptions = undefined;
if (window.arguments[1]) {
if (!(window.arguments[1] instanceof Ci.nsIPropertyBag2)) {
throw new Error(
@ -2276,6 +2277,18 @@ var gBrowserInit = {
if (extraOptions.hasKey("fromExternal")) {
fromExternal = extraOptions.getPropertyAsBool("fromExternal");
}
if (extraOptions.hasKey("triggeringSponsoredURL")) {
globalHistoryOptions = {
triggeringSponsoredURL: extraOptions.getPropertyAsACString(
"triggeringSponsoredURL"
),
};
if (extraOptions.hasKey("triggeringSponsoredURLVisitTimeMS")) {
globalHistoryOptions.triggeringSponsoredURLVisitTimeMS = extraOptions.getPropertyAsUint64(
"triggeringSponsoredURLVisitTimeMS"
);
}
}
}
try {
@ -2296,6 +2309,7 @@ var gBrowserInit = {
forceAboutBlankViewerInCurrent: !!window.arguments[6],
hasValidUserGestureActivation,
fromExternal,
globalHistoryOptions,
});
} catch (e) {
Cu.reportError(e);

Просмотреть файл

@ -243,6 +243,8 @@ class nsContextMenu {
this.inSyntheticDoc = context.inSyntheticDoc;
this.inAboutDevtoolsToolbox = context.inAboutDevtoolsToolbox;
this.isSponsoredLink = context.isSponsoredLink;
// Everything after this isn't sent directly from ContextMenu
if (this.target) {
this.ownerDoc = this.target.ownerDocument;
@ -1390,7 +1392,25 @@ class nsContextMenu {
// Open linked-to URL in a new window.
openLink() {
openLinkIn(this.linkURL, "window", this._openLinkInParameters());
let params;
if (this.isSponsoredLink) {
params = {
globalHistoryOptions: { triggeringSponsoredURL: this.linkURL },
};
} else if (this.browser.hasAttribute("triggeringSponsoredURL")) {
params = {
globalHistoryOptions: {
triggeringSponsoredURL: this.browser.getAttribute(
"triggeringSponsoredURL"
),
triggeringSponsoredURLVisitTimeMS: this.browser.getAttribute(
"triggeringSponsoredURLVisitTimeMS"
),
},
};
}
openLinkIn(this.linkURL, "window", this._openLinkInParameters(params));
}
// Open linked-to URL in a new private window.

Просмотреть файл

@ -421,6 +421,18 @@ function openLinkIn(url, where, params) {
if (params.fromExternal !== undefined) {
extraOptions.setPropertyAsBool("fromExternal", params.fromExternal);
}
if (aGlobalHistoryOptions?.triggeringSponsoredURL) {
extraOptions.setPropertyAsACString(
"triggeringSponsoredURL",
aGlobalHistoryOptions.triggeringSponsoredURL
);
if (aGlobalHistoryOptions.triggeringSponsoredURLVisitTimeMS) {
extraOptions.setPropertyAsUint64(
"triggeringSponsoredURLVisitTimeMS",
aGlobalHistoryOptions.triggeringSponsoredURLVisitTimeMS
);
}
}
var allowThirdPartyFixupSupports = Cc[
"@mozilla.org/supports-PRBool;1"

Просмотреть файл

@ -288,6 +288,7 @@ export class TopSiteLink extends React.PureComponent {
onKeyPress={this.onKeyPress}
onClick={onClick}
draggable={true}
data-is-sponsored-link={!!link.sponsored_tile_id}
>
<div className="tile" aria-hidden={true}>
<div

Просмотреть файл

@ -11610,7 +11610,8 @@ class TopSiteLink extends (external_React_default()).PureComponent {
tabIndex: "0",
onKeyPress: this.onKeyPress,
onClick: onClick,
draggable: true
draggable: true,
"data-is-sponsored-link": !!link.sponsored_tile_id
}, /*#__PURE__*/external_React_default().createElement("div", {
className: "tile",
"aria-hidden": true

Просмотреть файл

@ -6,6 +6,8 @@
// Test whether a visit information is annotated correctly when clicking a tile.
if (AppConstants.platform === "macosx") {
requestLongerTimeout(3);
} else {
requestLongerTimeout(2);
}
@ -22,6 +24,7 @@ const OPEN_TYPE = {
CURRENT_BY_CLICK: 0,
NEWTAB_BY_CLICK: 1,
NEWTAB_BY_CONTEXTMENU: 2,
NEWWINDOW_BY_CONTEXTMENU: 3,
};
const FRECENCY = {
@ -29,6 +32,8 @@ const FRECENCY = {
VISITED: 100,
SPONSORED: -1,
BOOKMARKED: 2075,
NEWWINDOW_TYPED: 100,
NEWWINDOW_BOOKMARKED: 175,
};
const {
@ -61,30 +66,12 @@ async function assertDatabase({ targetURL, expected }) {
);
}
async function openAndTest({
linkSelector,
linkURL,
redirectTo = null,
openType = OPEN_TYPE.CURRENT_BY_CLICK,
expected,
}) {
const destinationURL = redirectTo || linkURL;
info("Open specific link and wait for loading.");
const isNewTab = openType !== OPEN_TYPE.CURRENT_BY_CLICK;
const onLoad = isNewTab
? BrowserTestUtils.waitForNewTab(gBrowser, destinationURL, true)
: BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
destinationURL
);
async function waitForLocationChanged(destinationURL) {
// If nodeIconChanged of browserPlacesViews.js is called after the target node
// is lost during test, "No DOM node set for aPlacesNode" error occur. To avoid
// this failure, wait for the onLocationChange event that triggers
// nodeIconChanged to occur.
const onLocationChanged = new Promise(resolve => {
return new Promise(resolve => {
gBrowser.addTabsProgressListener({
async onLocationChange(aBrowser, aWebProgress, aRequest, aLocation) {
if (aLocation.spec === destinationURL) {
@ -97,6 +84,16 @@ async function openAndTest({
},
});
});
}
async function openAndTest({
linkSelector,
linkURL,
redirectTo = null,
openType = OPEN_TYPE.CURRENT_BY_CLICK,
expected,
}) {
const destinationURL = redirectTo || linkURL;
// Wait for content is ready.
await SpecialPowers.spawn(
@ -109,14 +106,48 @@ async function openAndTest({
}
);
// Open the link by type.
if (openType === OPEN_TYPE.NEWTAB_BY_CLICK) {
info("Open specific link by type and wait for loading.");
if (openType === OPEN_TYPE.CURRENT_BY_CLICK) {
const onLoad = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
destinationURL
);
const onLocationChanged = waitForLocationChanged(destinationURL);
await BrowserTestUtils.synthesizeMouseAtCenter(
linkSelector,
{ ctrlKey: isNewTab, metaKey: isNewTab },
{},
gBrowser.selectedBrowser
);
await onLoad;
await onLocationChanged;
} else if (openType === OPEN_TYPE.NEWTAB_BY_CLICK) {
const onLoad = BrowserTestUtils.waitForNewTab(
gBrowser,
destinationURL,
true
);
const onLocationChanged = waitForLocationChanged(destinationURL);
await BrowserTestUtils.synthesizeMouseAtCenter(
linkSelector,
{ ctrlKey: true, metaKey: true },
gBrowser.selectedBrowser
);
const tab = await onLoad;
await onLocationChanged;
BrowserTestUtils.removeTab(tab);
} else if (openType === OPEN_TYPE.NEWTAB_BY_CONTEXTMENU) {
const onLoad = BrowserTestUtils.waitForNewTab(
gBrowser,
destinationURL,
true
);
const onLocationChanged = waitForLocationChanged(destinationURL);
const onPopup = BrowserTestUtils.waitForEvent(document, "popupshown");
await BrowserTestUtils.synthesizeMouseAtCenter(
linkSelector,
@ -130,19 +161,27 @@ async function openAndTest({
);
openLinkMenuItem.click();
contextMenu.hidePopup();
} else {
const tab = await onLoad;
await onLocationChanged;
BrowserTestUtils.removeTab(tab);
} else if (openType === OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU) {
const onLoad = BrowserTestUtils.waitForNewWindow({ url: destinationURL });
const onPopup = BrowserTestUtils.waitForEvent(document, "popupshown");
await BrowserTestUtils.synthesizeMouseAtCenter(
linkSelector,
{},
{ type: "contextmenu" },
gBrowser.selectedBrowser
);
}
await onPopup;
const contextMenu = document.getElementById("contentAreaContextMenu");
const openLinkMenuItem = contextMenu.querySelector("#context-openlink");
openLinkMenuItem.click();
contextMenu.hidePopup();
const maybeNewTab = await onLoad;
await onLocationChanged;
if (isNewTab) {
BrowserTestUtils.removeTab(maybeNewTab);
const win = await onLoad;
await BrowserTestUtils.closeWindow(win);
}
info("Check database for the destination.");
@ -174,17 +213,48 @@ add_setup(async function() {
});
add_task(async function basic() {
const SPONSORED_LINK = {
label: "test_label",
url: "http://example.com/",
sponsored_position: 1,
sponsored_tile_id: 12345,
sponsored_impression_url: "http://impression.example.com/",
sponsored_click_url: "http://click.example.com/",
};
const NORMAL_LINK = {
label: "test_label",
url: "http://example.com/",
};
const BOOKMARKS = [
{
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
url: Services.io.newURI("http://example.com/"),
title: "test bookmark",
},
];
const testData = [
{
description: "Sponsored tile",
link: {
label: "test_label",
url: "http://example.com/",
sponsored_position: 1,
sponsored_tile_id: 12345,
sponsored_impression_url: "http://impression.example.com/",
sponsored_click_url: "http://click.example.com/",
link: SPONSORED_LINK,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.SPONSORED,
},
},
{
description: "Sponsored tile in new tab",
link: SPONSORED_LINK,
openType: OPEN_TYPE.NEWTAB_BY_CLICK,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.SPONSORED,
},
},
{
description: "Sponsored tile in new window",
link: SPONSORED_LINK,
openType: OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.SPONSORED,
@ -192,88 +262,110 @@ add_task(async function basic() {
},
{
description: "Bookmarked result",
link: {
label: "test_label",
url: "http://example.com/",
},
bookmarks: [
{
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
url: Services.io.newURI("http://example.com/"),
title: "test bookmark",
},
],
link: NORMAL_LINK,
bookmarks: BOOKMARKS,
expected: {
source: VISIT_SOURCE_BOOKMARKED,
frecency: FRECENCY.BOOKMARKED,
},
},
{
description: "Sponsored and bookmarked result",
link: {
label: "test_label",
url: "http://example.com/",
sponsored_position: 1,
sponsored_tile_id: 12345,
sponsored_impression_url: "http://impression.example.com/",
sponsored_click_url: "http://click.example.com/",
description: "Bookmarked result in new tab",
link: NORMAL_LINK,
openType: OPEN_TYPE.NEWTAB_BY_CLICK,
bookmarks: BOOKMARKS,
expected: {
source: VISIT_SOURCE_BOOKMARKED,
frecency: FRECENCY.BOOKMARKED,
},
bookmarks: [
{
parentGuid: PlacesUtils.bookmarks.toolbarGuid,
url: Services.io.newURI("http://example.com/"),
title: "test bookmark",
},
],
},
{
description: "Bookmarked result in new window",
link: NORMAL_LINK,
openType: OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU,
bookmarks: BOOKMARKS,
expected: {
source: VISIT_SOURCE_BOOKMARKED,
frecency: FRECENCY.NEWWINDOW_BOOKMARKED,
},
},
{
description: "Sponsored and bookmarked result",
link: SPONSORED_LINK,
bookmarks: BOOKMARKS,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.BOOKMARKED,
},
},
{
description: "Organic tile",
link: {
label: "test_label",
url: "http://example.com/",
description: "Sponsored and bookmarked result in new tab",
link: SPONSORED_LINK,
openType: OPEN_TYPE.NEWTAB_BY_CLICK,
bookmarks: BOOKMARKS,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.BOOKMARKED,
},
},
{
description: "Sponsored and bookmarked result in new window",
link: SPONSORED_LINK,
openType: OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU,
bookmarks: BOOKMARKS,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.NEWWINDOW_BOOKMARKED,
},
},
{
description: "Organic tile",
link: NORMAL_LINK,
expected: {
source: VISIT_SOURCE_ORGANIC,
frecency: FRECENCY.TYPED,
},
},
{
description: "Organic tile in new tab",
link: NORMAL_LINK,
openType: OPEN_TYPE.NEWTAB_BY_CLICK,
expected: {
source: VISIT_SOURCE_ORGANIC,
frecency: FRECENCY.TYPED,
},
},
{
description: "Organic tile in new window",
link: NORMAL_LINK,
openType: OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU,
expected: {
source: VISIT_SOURCE_ORGANIC,
frecency: FRECENCY.NEWWINDOW_TYPED,
},
},
];
for (const { description, link, bookmarks, expected } of testData) {
for (const { description, link, openType, bookmarks, expected } of testData) {
info(description);
await BrowserTestUtils.withNewTab("about:home", async () => {
// Setup test tile.
await pin(link);
// Test with new tab.
for (const bookmark of bookmarks || []) {
await PlacesUtils.bookmarks.insert(bookmark);
}
await openAndTest({
linkSelector: ".top-site-button",
linkURL: link.url,
openType: OPEN_TYPE.NEWTAB_BY_CLICK,
openType,
expected,
});
await clearHistoryAndBookmarks();
// Test with same tab.
for (const bookmark of bookmarks || []) {
await PlacesUtils.bookmarks.insert(bookmark);
}
await openAndTest({
linkSelector: ".top-site-button",
linkURL: link.url,
expected,
});
await clearHistoryAndBookmarks();
unpin(link);
});
}
@ -375,6 +467,19 @@ add_task(async function inherit() {
},
});
info("Open link on first page to show second page in new window");
await openAndTest({
linkSelector: "a",
linkURL: secondURL,
openType: OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.SPONSORED,
triggerURL: link.url,
},
});
await PlacesTestUtils.clearHistoryVisits();
info("Open link on first page to show second page in new tab");
await openAndTest({
linkSelector: "a",
@ -399,6 +504,19 @@ add_task(async function inherit() {
},
});
info("Open link on first page to show second page in new window");
await openAndTest({
linkSelector: "a",
linkURL: thirdURL,
openType: OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU,
expected: {
source: VISIT_SOURCE_SPONSORED,
frecency: FRECENCY.SPONSORED,
triggerURL: link.url,
},
});
await PlacesTestUtils.clearHistoryVisits();
info(
"Open link on second page to show third page in new tab by context menu"
);
@ -500,6 +618,18 @@ add_task(async function timeout() {
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(r => setTimeout(r, 1000));
info("Open link on first page to show second page in new window");
await openAndTest({
linkSelector: "a",
linkURL: secondURL,
openType: OPEN_TYPE.NEWWINDOW_BY_CONTEXTMENU,
expected: {
source: VISIT_SOURCE_ORGANIC,
frecency: FRECENCY.VISITED,
},
});
await PlacesTestUtils.clearHistoryVisits();
info("Open link on first page to show second page in new tab");
await openAndTest({
linkSelector: "a",