-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
refererDetection.js
181 lines (151 loc) · 5.04 KB
/
refererDetection.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
/**
* The referer detection module attempts to gather referer information from the current page that prebid.js resides in.
* The information that it tries to collect includes:
* The detected top url in the nav bar,
* Whether it was able to reach the top most window (if for example it was embedded in several iframes),
* The number of iframes it was embedded in if applicable,
* A list of the domains of each embedded window if applicable.
* Canonical URL which refers to an HTML link element, with the attribute of rel="canonical", found in the <head> element of your webpage
*/
import { logWarn } from './utils.js';
/**
* @param {Window} win Window
* @returns {Function}
*/
export function detectReferer(win) {
/**
* This function would return a read-only array of hostnames for all the parent frames.
* win.location.ancestorOrigins is only supported in webkit browsers. For non-webkit browsers it will return undefined.
*
* @param {Window} win Window object
* @returns {(undefined|Array)} Ancestor origins or undefined
*/
function getAncestorOrigins(win) {
try {
if (!win.location.ancestorOrigins) {
return;
}
return win.location.ancestorOrigins;
} catch (e) {
// Ignore error
}
}
/**
* This function returns canonical URL which refers to an HTML link element, with the attribute of rel="canonical", found in the <head> element of your webpage
*
* @param {Object} doc document
* @returns {string|null}
*/
function getCanonicalUrl(doc) {
try {
const element = doc.querySelector("link[rel='canonical']");
if (element !== null) {
return element.href;
}
} catch (e) {
// Ignore error
}
return null;
}
/**
* Referer info
* @typedef {Object} refererInfo
* @property {string} referer detected top url
* @property {boolean} reachedTop whether prebid was able to walk upto top window or not
* @property {number} numIframes number of iframes
* @property {string} stack comma separated urls of all origins
* @property {string} canonicalUrl canonical URL refers to an HTML link element, with the attribute of rel="canonical", found in the <head> element of your webpage
*/
/**
* Walk up the windows to get the origin stack and best available referrer, canonical URL, etc.
*
* @returns {refererInfo}
*/
function refererInfo() {
const stack = [];
const ancestors = getAncestorOrigins(win);
let currentWindow;
let bestReferrer;
let bestCanonicalUrl;
let reachedTop = false;
let level = 0;
let valuesFromAmp = false;
let inAmpFrame = false;
do {
const previousWindow = currentWindow;
const wasInAmpFrame = inAmpFrame;
let currentLocation;
let crossOrigin = false;
let foundReferrer = null;
inAmpFrame = false;
currentWindow = currentWindow ? currentWindow.parent : win;
try {
currentLocation = currentWindow.location.href || null;
} catch (e) {
crossOrigin = true;
}
if (crossOrigin) {
if (wasInAmpFrame) {
const context = previousWindow.context;
try {
foundReferrer = context.sourceUrl;
bestReferrer = foundReferrer;
valuesFromAmp = true;
if (currentWindow === win.top) {
reachedTop = true;
}
if (context.canonicalUrl) {
bestCanonicalUrl = context.canonicalUrl;
}
} catch (e) { /* Do nothing */ }
} else {
logWarn('Trying to access cross domain iframe. Continuing without referrer and location');
try {
const referrer = previousWindow.document.referrer;
if (referrer) {
foundReferrer = referrer;
if (currentWindow === win.top) {
reachedTop = true;
}
}
} catch (e) { /* Do nothing */ }
if (!foundReferrer && ancestors && ancestors[level - 1]) {
foundReferrer = ancestors[level - 1];
}
if (foundReferrer && !valuesFromAmp) {
bestReferrer = foundReferrer;
}
}
} else {
if (currentLocation) {
foundReferrer = currentLocation;
bestReferrer = foundReferrer;
valuesFromAmp = false;
if (currentWindow === win.top) {
reachedTop = true;
const canonicalUrl = getCanonicalUrl(currentWindow.document);
if (canonicalUrl) {
bestCanonicalUrl = canonicalUrl;
}
}
}
if (currentWindow.context && currentWindow.context.sourceUrl) {
inAmpFrame = true;
}
}
stack.push(foundReferrer);
level++;
} while (currentWindow !== win.top);
stack.reverse();
return {
referer: bestReferrer || null,
reachedTop,
isAmp: valuesFromAmp,
numIframes: level - 1,
stack,
canonicalUrl: bestCanonicalUrl || null
};
}
return refererInfo;
}
export const getRefererInfo = detectReferer(window);