1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 ChromeUtils.defineESModuleGetters(lazy, {
8 Region: "resource://gre/modules/Region.sys.mjs",
11 export const CONTEXTUAL_SERVICES_PING_TYPES = {
12 TOPSITES_IMPRESSION: "topsites-impression",
13 TOPSITES_SELECTION: "topsites-click",
14 QS_BLOCK: "quicksuggest-block",
15 QS_IMPRESSION: "quicksuggest-impression",
16 QS_SELECTION: "quicksuggest-click",
19 export var PartnerLinkAttribution = {
21 * Sends an attribution request to an anonymizing proxy.
23 * @param {string} targetURL
24 * The URL we are routing through the anonmyzing proxy.
25 * @param {string} source
26 * The source of the anonmized request, e.g. "urlbar".
27 * @param {string} [campaignID]
28 * The campaign ID for attribution. This should be a valid path on the
29 * anonymizing proxy. For example, if `campaignID` was `foo`, we'd send an
30 * attribution request to https://topsites.mozilla.com/cid/foo.
31 * Optional. If it's not provided, we default to the topsites campaign.
33 async makeRequest({ targetURL, source, campaignID }) {
34 let partner = targetURL.match(/^https?:\/\/(?:www.)?([^.]*)/)[1];
36 function record(method, objectString) {
37 recordTelemetryEvent({
43 record("click", source);
45 let attributionUrl = Services.prefs.getStringPref(
46 "browser.partnerlink.attributionURL"
48 if (!attributionUrl) {
49 record("attribution", "abort");
53 // The default campaign is topsites.
55 campaignID = Services.prefs.getStringPref(
56 "browser.partnerlink.campaign.topsites"
59 attributionUrl = attributionUrl + campaignID;
60 let result = await sendRequest(attributionUrl, source, targetURL);
61 record("attribution", result ? "success" : "failure");
65 * Makes a request to the attribution URL for a search engine search.
67 * @param {nsISearchEngine} engine
68 * The search engine to save the attribution for.
69 * @param {nsIURI} targetUrl
70 * The target URL to filter and include in the attribution.
72 async makeSearchEngineRequest(engine, targetUrl) {
74 if (engine.attribution?.cid) {
75 cid = engine.attribution.cid;
76 } else if (engine.sendAttributionRequest) {
77 cid = Services.prefs.getStringPref(
78 "browser.partnerlink.campaign.topsites"
84 let searchUrlQueryParamName = engine.searchUrlQueryParamName;
85 if (!searchUrlQueryParamName) {
86 console.error("makeSearchEngineRequest can't find search terms key");
91 if (typeof url == "string") {
92 url = Services.io.newURI(url);
95 let targetParams = new URLSearchParams(url.query);
96 if (!targetParams.has(searchUrlQueryParamName)) {
97 console.error("makeSearchEngineRequest can't remove target search terms");
101 let attributionUrl = Services.prefs.getStringPref(
102 "browser.partnerlink.attributionURL",
105 attributionUrl = attributionUrl + cid;
107 targetParams.delete(searchUrlQueryParamName);
108 let strippedTargetUrl = `${url.prePath}${url.filePath}`;
109 let newParams = targetParams.toString();
111 strippedTargetUrl += "?" + newParams;
114 await sendRequest(attributionUrl, "searchurl", strippedTargetUrl);
118 async function sendRequest(attributionUrl, source, targetURL) {
119 const request = new Request(attributionUrl);
120 request.headers.set("X-Region", lazy.Region.home);
121 request.headers.set("X-Source", source);
122 request.headers.set("X-Target-URL", targetURL);
123 const response = await fetch(request);
127 function recordTelemetryEvent({ method, objectString, value }) {
128 Services.telemetry.setEventRecordingEnabled("partner_link", true);
129 Services.telemetry.recordEvent("partner_link", method, objectString, value);