Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use MessageChannel for cross-frame messages #154

Merged
merged 2 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions src/messaging.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {parseUrl} from './utils.js';

export function prebidMessenger(publisherURL, win = window) {
const prebidDomain = (() => {
if (publisherURL == null) {
return null;
}
const parsedUrl = parseUrl(publisherURL);
return parsedUrl.protocol + '://' + parsedUrl.host;
})();

return function sendMessage(message, onResponse) {
if (prebidDomain == null) {
throw new Error('Missing pubUrl')
}
message = JSON.stringify(message);
let messagePort;
if (onResponse == null) {
win.parent.postMessage(message, prebidDomain);
} else {
const channel = new MessageChannel();
messagePort = channel.port1;
messagePort.onmessage = onResponse;
win.addEventListener('message', windowListener);
win.parent.postMessage(message, prebidDomain, [channel.port2]);
}

return function stopListening() {
if (messagePort != null) {
win.removeEventListener('message', windowListener);
messagePort.onmessage = null;
messagePort = null;
}
}

function windowListener(ev) {
if ((ev.origin || (ev.originalEvent && ev.originalEvent.origin)) === prebidDomain) {
onResponse(ev);
}
}

}
}
59 changes: 32 additions & 27 deletions src/nativeAssetManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { sendRequest, loadScript } from './utils';
import {prebidMessenger} from './messaging.js';

/*
* Native asset->key mapping from Prebid.js/src/constants.json
Expand Down Expand Up @@ -56,17 +57,28 @@ const assetTypeMapping = {
const DEFAULT_CACHE_HOST = 'prebid.adnxs.com';
const DEFAULT_CACHE_PATH = '/pbc/v1/cache';

export function newNativeAssetManager(win) {
export function newNativeAssetManager(win, pubUrl) {
const sendMessage = prebidMessenger(pubUrl, win);
let callback;
let errorCountEscapeHatch = 0;
let cancelMessageListener;

function stopListening() {
if (cancelMessageListener != null) {
cancelMessageListener();
cancelMessageListener = null;
}
}



function getCacheEndpoint(cacheHost, cachePath) {
let host = (typeof cacheHost === 'undefined' || cacheHost === "") ? DEFAULT_CACHE_HOST : cacheHost;
let path = (typeof cachePath === 'undefined' || cachePath === "") ? DEFAULT_CACHE_PATH : cachePath;

return `https://${host}${path}`;
}

function parseResponse(response) {
let bidObject;
try {
Expand All @@ -76,7 +88,7 @@ export function newNativeAssetManager(win) {
}
return bidObject;
}

function transformToPrebidKeys(adMarkup) {
let assets = [];
let clicktrackers;
Expand Down Expand Up @@ -105,7 +117,7 @@ export function newNativeAssetManager(win) {
'key' : 'title',
'value' : asset.title.text
})
}
}
})

if (adMarkup.link) {
Expand Down Expand Up @@ -137,7 +149,7 @@ export function newNativeAssetManager(win) {
win.document.body.innerHTML = newHtml;

callback && callback({
clickTrackers: data.clicktrackers,
clickTrackers: data.clicktrackers,
impTrackers: data.imptrackers
});
} else {
Expand Down Expand Up @@ -177,11 +189,11 @@ export function newNativeAssetManager(win) {

if (flag && win.pbNativeData.hasOwnProperty('requestAllAssets') && win.pbNativeData.requestAllAssets) {
callback = cb;
requestAllAssets(adId);
cancelMessageListener = requestAllAssets(adId);
} else if (placeholders.length > 0) {
callback = cb;
requestAssets(adId, placeholders);
}
cancelMessageListener = requestAssets(adId, placeholders);
}
}

/*
Expand All @@ -196,12 +208,12 @@ export function newNativeAssetManager(win) {
const placeholderKey = NATIVE_KEYS[key];
const placeholder = (adId && !flag) ? `${placeholderKey}:${adId}` : `${placeholderKey}`;
const placeholderIndex = (~doc.body.innerHTML.indexOf(placeholder)) ? doc.body.innerHTML.indexOf(placeholder) : (doc.head.innerHTML && doc.head.innerHTML.indexOf(placeholder));

if (~placeholderIndex) {
placeholders.push(placeholderKey);
}
});

return placeholders;
}

Expand All @@ -210,33 +222,27 @@ export function newNativeAssetManager(win) {
* creative template, and setups up a listener for when Prebid responds.
*/
function requestAssets(adId, assets) {
win.addEventListener('message', replaceAssets, false);

const message = {
message: 'Prebid Native',
action: 'assetRequest',
adId,
assets,
};


win.parent.postMessage(JSON.stringify(message), '*');
return sendMessage(message, replaceAssets);
}

/*
* Sends postmessage to Prebid for asset placeholders found in the native
* creative template, and setups up a listener for when Prebid responds.
*/
function requestAllAssets(adId) {
win.addEventListener('message', replaceAssets, false);

const message = {
message: 'Prebid Native',
action: 'allAssetRequest',
adId,
};

win.parent.postMessage(JSON.stringify(message), '*');
return sendMessage(message, replaceAssets);
}

/*
Expand All @@ -249,8 +255,7 @@ export function newNativeAssetManager(win) {
adId,
height,
};

win.parent.postMessage(JSON.stringify(message), '*');
sendMessage(message);
}

/*
Expand All @@ -267,7 +272,7 @@ export function newNativeAssetManager(win) {
* if for some reason Prebid never responds with the native assets,
* get rid of this listener because other messages won't stop coming
*/
win.removeEventListener('message', replaceAssets);
stopListening();
}
return;
}
Expand All @@ -287,15 +292,15 @@ export function newNativeAssetManager(win) {

win.document.body.innerHTML = body + newHtml;
callback && callback();
win.removeEventListener('message', replaceAssets);
stopListening();
requestHeightResize(data.adId, (document.body.clientHeight || document.body.offsetHeight));
} else if (document.getElementById('pb-native-renderer')) {
document.getElementById('pb-native-renderer').addEventListener('load', function() {
const newHtml = (win.renderAd && win.renderAd(data.assets)) || '';

win.document.body.innerHTML = body + newHtml;
callback && callback();
win.removeEventListener('message', replaceAssets);
stopListening();
requestHeightResize(data.adId, (document.body.clientHeight || document.body.offsetHeight));
});
} else {
Expand All @@ -304,7 +309,7 @@ export function newNativeAssetManager(win) {

win.document.body.innerHTML = body + newHtml;
callback && callback();
win.removeEventListener('message', replaceAssets);
stopListening();
requestHeightResize(data.adId, (document.body.clientHeight || document.body.offsetHeight));
})
}
Expand All @@ -313,14 +318,14 @@ export function newNativeAssetManager(win) {
const newHtml = replace(template, data);
win.document.body.innerHTML = body + newHtml;
callback && callback();
win.removeEventListener('message', replaceAssets);
stopListening();
requestHeightResize(data.adId, (document.body.clientHeight || document.body.offsetHeight));
} else {
const newHtml = replace(body, data);

win.document.body.innerHTML = newHtml;
callback && callback();
win.removeEventListener('message', replaceAssets);
stopListening();
}
}
}
Expand Down
15 changes: 6 additions & 9 deletions src/nativeRenderManager.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/*
* Script to handle firing impression and click trackers from native teamplates
*/
import { parseUrl, triggerPixel, transformAuctionTargetingData } from './utils';
import { newNativeAssetManager } from './nativeAssetManager';
import {newNativeAssetManager} from './nativeAssetManager';
import {prebidMessenger} from './messaging.js';

const AD_ANCHOR_CLASS_NAME = 'pb-click';
const AD_DATA_ADID_ATTRIBUTE = 'pbAdId';

export function newNativeRenderManager(win) {
let publisherDomain;
let sendMessage;


function findAdElements(className) {
Expand All @@ -30,8 +30,7 @@ export function newNativeRenderManager(win) {
if (action === 'click') {
message.action = 'click';
}

win.parent.postMessage(JSON.stringify(message), publisherDomain);
sendMessage(message);
}
}

Expand All @@ -51,12 +50,10 @@ export function newNativeRenderManager(win) {
// START OF MAIN CODE
let renderNativeAd = function(nativeTag) {
window.pbNativeData = nativeTag;
const targetingData = transformAuctionTargetingData(nativeTag);
const nativeAssetManager = newNativeAssetManager(window);
sendMessage = prebidMessenger(nativeTag.pubUrl, win);
const nativeAssetManager = newNativeAssetManager(window, nativeTag.pubUrl);

if (nativeTag.hasOwnProperty('adId')) {
let parsedUrl = parseUrl(window.pbNativeData.pubUrl);
publisherDomain = parsedUrl.protocol + '://' + parsedUrl.host;

if (nativeTag.hasOwnProperty('rendererUrl') && !nativeTag.rendererUrl.match(/##.*##/i)) {
const scr = document.createElement('SCRIPT');
Expand Down
11 changes: 5 additions & 6 deletions src/nativeTrackerManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
*/
import { parseUrl, triggerPixel, transformAuctionTargetingData } from './utils';
import { newNativeAssetManager } from './nativeAssetManager';
import {prebidMessenger} from './messaging.js';

const AD_ANCHOR_CLASS_NAME = 'pb-click';
const AD_DATA_ADID_ATTRIBUTE = 'pbAdId';

export function newNativeTrackerManager(win) {
let publisherDomain;
let sendMessage;

function findAdElements(className) {
let adElements = win.document.getElementsByClassName(className);
Expand Down Expand Up @@ -63,14 +64,15 @@ export function newNativeTrackerManager(win) {
message.action = 'click';
}

win.parent.postMessage(JSON.stringify(message), publisherDomain);
sendMessage(message);
}
}

// START OF MAIN CODE
let startTrackers = function (dataObject) {
const targetingData = transformAuctionTargetingData(dataObject);
const nativeAssetManager = newNativeAssetManager(window);
sendMessage = prebidMessenger(targetingData.pubUrl, win);
const nativeAssetManager = newNativeAssetManager(window, targetingData.pubUrl);

if (targetingData && targetingData.env === 'mobile-app') {
let cb = function({clickTrackers, impTrackers} = {}) {
Expand All @@ -84,9 +86,6 @@ export function newNativeTrackerManager(win) {
}
nativeAssetManager.loadMobileAssets(targetingData, cb);
} else {
let parsedUrl = parseUrl(targetingData && targetingData.pubUrl);
publisherDomain = parsedUrl.protocol + '://' + parsedUrl.host;

let adElements = findAdElements(AD_ANCHOR_CLASS_NAME);

nativeAssetManager.loadAssets(
Expand Down
19 changes: 6 additions & 13 deletions src/renderingManager.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as utils from './utils';
import * as domHelper from './domHelper';
import {triggerPixel} from './utils';
import {prebidMessenger} from './messaging.js';

const DEFAULT_CACHE_HOST = 'prebid.adnxs.com';
const DEFAULT_CACHE_PATH = '/pbc/v1/cache';
Expand Down Expand Up @@ -70,10 +71,9 @@ export function newRenderingManager(win, environment) {
*/
function renderCrossDomain(adId, pubAdServerDomain = '', pubUrl) {
let windowLocation = win.location;
let parsedUrl = utils.parseUrl(pubUrl);
let publisherDomain = parsedUrl.protocol + '://' + parsedUrl.host;
let adServerDomain = pubAdServerDomain || win.location.hostname;
let fullAdServerDomain = windowLocation.protocol + '//' + adServerDomain;
const sendMessage = prebidMessenger(pubUrl, win);

function renderAd(ev) {
let key = ev.message ? 'message' : 'data';
Expand All @@ -84,9 +84,7 @@ export function newRenderingManager(win, environment) {
return;
}

let origin = ev.origin || ev.originalEvent.origin;
if (adObject.message && adObject.message === 'Prebid Response' &&
publisherDomain === origin &&
adObject.adId === adId) {
try {
let body = win.document.body;
Expand Down Expand Up @@ -138,25 +136,20 @@ export function newRenderingManager(win, environment) {
if (!success) {
payload.info = {reason, message};
}
ev.source.postMessage(JSON.stringify(payload), publisherDomain);
sendMessage(payload);
}
}


function requestAdFromPrebid() {
let message = JSON.stringify({
let message = {
message: 'Prebid Request',
adId: adId,
adServerDomain: fullAdServerDomain
});
win.parent.postMessage(message, publisherDomain);
}

function listenAdFromPrebid() {
win.addEventListener('message', renderAd, false);
}
sendMessage(message, renderAd);
}

listenAdFromPrebid();
requestAdFromPrebid();
}

Expand Down
Loading