UNPKG

mk9-prebid

Version:

Header Bidding Management Library

152 lines (135 loc) 4.96 kB
/** * This module interacts with the server used to cache video ad content to be restored later. * At a high level, the expected workflow goes like this: * * - Request video ads from Bidders * - Generate IDs for each valid bid, and cache the key/value pair on the server. * - Return these IDs so that publishers can use them to fetch the bids later. * * This trickery helps integrate with ad servers, which set character limits on request params. */ import { ajax } from './ajax.js'; import { config } from './config.js'; import * as utils from './utils.js'; /** * @typedef {object} CacheableUrlBid * @property {string} vastUrl A URL which loads some valid VAST XML. */ /** * @typedef {object} CacheablePayloadBid * @property {string} vastXml Some VAST XML which loads an ad in a video player. */ /** * A CacheableBid describes the types which the videoCache can store. * * @typedef {CacheableUrlBid|CacheablePayloadBid} CacheableBid */ /** * Function which wraps a URI that serves VAST XML, so that it can be loaded. * * @param {string} uri The URI where the VAST content can be found. * @param {string} impUrl An impression tracker URL for the delivery of the video ad * @return A VAST URL which loads XML from the given URI. */ function wrapURI(uri, impUrl) { // Technically, this is vulnerable to cross-script injection by sketchy vastUrl bids. // We could make sure it's a valid URI... but since we're loading VAST XML from the // URL they provide anyway, that's probably not a big deal. let vastImp = (impUrl) ? `<![CDATA[${impUrl}]]>` : ``; return `<VAST version="3.0"> <Ad> <Wrapper> <AdSystem>prebid.org wrapper</AdSystem> <VASTAdTagURI><![CDATA[${uri}]]></VASTAdTagURI> <Impression>${vastImp}</Impression> <Creatives></Creatives> </Wrapper> </Ad> </VAST>`; } /** * Wraps a bid in the format expected by the prebid-server endpoints, or returns null if * the bid can't be converted cleanly. * * @param {CacheableBid} bid */ function toStorageRequest(bid) { const vastValue = bid.vastXml ? bid.vastXml : wrapURI(bid.vastUrl, bid.vastImpUrl); let payload = { type: 'xml', value: vastValue, ttlseconds: Number(bid.ttl) }; if (config.getConfig('cache.vasttrack')) { payload.bidder = bid.bidder; payload.bidid = bid.requestId; payload.aid = bid.auctionId; // function has a thisArg set to bidderRequest for accessing the auctionStart if (utils.isPlainObject(this) && this.hasOwnProperty('auctionStart')) { payload.timestamp = this.auctionStart; } } if (typeof bid.customCacheKey === 'string' && bid.customCacheKey !== '') { payload.key = bid.customCacheKey; } return payload; } /** * A function which should be called with the results of the storage operation. * * @callback videoCacheStoreCallback * * @param {Error} [error] The error, if one occurred. * @param {?string[]} uuids An array of unique IDs. The array will have one element for each bid we were asked * to store. It may include null elements if some of the bids were malformed, or an error occurred. * Each non-null element in this array is a valid input into the retrieve function, which will fetch * some VAST XML which can be used to render this bid's ad. */ /** * A function which bridges the APIs between the videoCacheStoreCallback and our ajax function's API. * * @param {videoCacheStoreCallback} done A callback to the "store" function. * @return {Function} A callback which interprets the cache server's responses, and makes up the right * arguments for our callback. */ function shimStorageCallback(done) { return { success: function (responseBody) { let ids; try { ids = JSON.parse(responseBody).responses } catch (e) { done(e, []); return; } if (ids) { done(null, ids); } else { done(new Error("The cache server didn't respond with a responses property."), []); } }, error: function (statusText, responseBody) { done(new Error(`Error storing video ad in the cache: ${statusText}: ${JSON.stringify(responseBody)}`), []); } } } /** * If the given bid is for a Video ad, generate a unique ID and cache it somewhere server-side. * * @param {CacheableBid[]} bids A list of bid objects which should be cached. * @param {videoCacheStoreCallback} [done] An optional callback which should be executed after * @param {BidderRequest} [bidderRequest] * the data has been stored in the cache. */ export function store(bids, done, bidderRequest) { const requestData = { puts: bids.map(toStorageRequest, bidderRequest) }; ajax(config.getConfig('cache.url'), shimStorageCallback(done), JSON.stringify(requestData), { contentType: 'text/plain', withCredentials: true }); } export function getCacheUrl(id) { return `${config.getConfig('cache.url')}?uuid=${id}`; }