From 86357a8614e1c5bf8c6fceae0f45586cb5c6e4e7 Mon Sep 17 00:00:00 2001 From: Denis Logachev Date: Fri, 19 Oct 2018 21:14:38 +0300 Subject: [PATCH] Ref and meta keyword collection feature (#3184) --- modules/adkernelBidAdapter.js | 40 +++++++++++++------- test/spec/modules/adkernelBidAdapter_spec.js | 20 +++++----- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/modules/adkernelBidAdapter.js b/modules/adkernelBidAdapter.js index dffcaacec3d..9bdab13de7b 100644 --- a/modules/adkernelBidAdapter.js +++ b/modules/adkernelBidAdapter.js @@ -3,6 +3,7 @@ import { BANNER, VIDEO } from 'src/mediaTypes'; import {registerBidder} from 'src/adapters/bidderFactory'; import find from 'core-js/library/fn/array/find'; import includes from 'core-js/library/fn/array/includes'; +import {parse as parseUrl} from 'src/url' const VIDEO_TARGETING = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'linearity', 'boxingallowed', 'playbackmethod', 'delivery', @@ -22,13 +23,13 @@ export const spec = { 'zoneId' in bidRequest.params && !isNaN(Number(bidRequest.params.zoneId)); }, buildRequests: function(bidRequests, bidderRequest) { - let impDispatch = dispatchImps(bidRequests); + let impDispatch = dispatchImps(bidRequests, bidderRequest.refererInfo); const gdprConsent = bidderRequest.gdprConsent; const auctionId = bidderRequest.auctionId; const requests = []; Object.keys(impDispatch).forEach(host => { Object.keys(impDispatch[host]).forEach(zoneId => { - const request = buildRtbRequest(impDispatch[host][zoneId], auctionId, gdprConsent); + const request = buildRtbRequest(impDispatch[host][zoneId], auctionId, gdprConsent, bidderRequest.refererInfo); requests.push({ method: 'GET', url: `${window.location.protocol}//${host}/rtbg`, @@ -96,8 +97,9 @@ registerBidder(spec); /** * Dispatch impressions by ad network host and zone */ -function dispatchImps(bidRequests) { - return bidRequests.map(buildImp) +function dispatchImps(bidRequests, refererInfo) { + let secure = (refererInfo && refererInfo.referer.indexOf('https:') === 0); + return bidRequests.map(bidRequest => buildImp(bidRequest, secure)) .reduce((acc, curr, index) => { let bidRequest = bidRequests[index]; let zoneId = bidRequest.params.zoneId; @@ -112,7 +114,7 @@ function dispatchImps(bidRequests) { /** * Builds parameters object for single impression */ -function buildImp(bidRequest) { +function buildImp(bidRequest, secure) { const imp = { 'id': bidRequest.bidId, 'tagid': bidRequest.adUnitCode @@ -137,7 +139,7 @@ function buildImp(bidRequest) { .forEach(param => imp.video[param] = bidRequest.params.video[param]); } } - if (utils.getTopWindowLocation().protocol === 'https:') { + if (secure) { imp.secure = 1; } return imp; @@ -149,7 +151,7 @@ function buildImp(bidRequest) { * @return Array[Array[Number]] */ function canonicalizeSizesArray(sizes) { - if (sizes.length == 2 && !utils.isArray(sizes[0])) { + if (sizes.length === 2 && !utils.isArray(sizes[0])) { return [sizes]; } return sizes; @@ -160,12 +162,14 @@ function canonicalizeSizesArray(sizes) { * @param imps collection of impressions * @param auctionId * @param gdprConsent + * @param refInfo + * @return Object complete rtb request */ -function buildRtbRequest(imps, auctionId, gdprConsent) { +function buildRtbRequest(imps, auctionId, gdprConsent, refInfo) { let req = { 'id': auctionId, 'imp': imps, - 'site': createSite(), + 'site': createSite(refInfo), 'at': 1, 'device': { 'ip': 'caller', @@ -197,12 +201,20 @@ function getLanguage() { /** * Creates site description object */ -function createSite() { - var location = utils.getTopWindowLocation(); - return { - 'domain': location.hostname, - 'page': location.href.split('?')[0] +function createSite(refInfo) { + let url = parseUrl(refInfo.referer); + let result = { + 'domain': url.hostname, + 'page': url.protocol + '://' + url.hostname + url.pathname }; + if (self === top && document.referrer) { + result.ref = document.referrer; + } + let keywords = document.getElementsByTagName('meta')['keywords']; + if (keywords && keywords.content) { + result.keywords = keywords.content; + } + return result; } /** diff --git a/test/spec/modules/adkernelBidAdapter_spec.js b/test/spec/modules/adkernelBidAdapter_spec.js index 590e0ebb96e..3243b980b9f 100644 --- a/test/spec/modules/adkernelBidAdapter_spec.js +++ b/test/spec/modules/adkernelBidAdapter_spec.js @@ -1,7 +1,6 @@ import {expect} from 'chai'; import {spec} from 'modules/adkernelBidAdapter'; import * as utils from 'src/utils'; -import {parse as parseUrl} from 'src/url'; describe('Adkernel adapter', function () { const bid1_zone1 = { @@ -113,15 +112,13 @@ describe('Adkernel adapter', function () { } }; - function buildRequest(bidRequests, bidderRequest = {}, url = 'https://example.com/index.html', dnt = true) { - let wmock = sinon.stub(utils, 'getTopWindowLocation').callsFake(() => { - let loc = parseUrl(url); - loc.protocol += ':'; - return loc; - }); + function buildBidderRequest(url = 'https://example.com/index.html', params = {}) { + return Object.assign({}, params, {refererInfo: {referer: url, reachedTop: true}}) + } + const DEFAULT_BIDDER_REQUEST = buildBidderRequest(); + function buildRequest(bidRequests, bidderRequest = DEFAULT_BIDDER_REQUEST, dnt = true) { let dntmock = sinon.stub(utils, 'getDNT').callsFake(() => dnt); let pbRequests = spec.buildRequests(bidRequests, bidderRequest); - wmock.restore(); dntmock.restore(); let rtbRequests = pbRequests.map(r => JSON.parse(r.data.r)); return [pbRequests, rtbRequests]; @@ -195,7 +192,8 @@ describe('Adkernel adapter', function () { it('should contain gdpr-related information if consent is configured', function () { let [_, bidRequests] = buildRequest([bid1_zone1], - {gdprConsent: {gdprApplies: true, consentString: 'test-consent-string', vendorData: {}}}); + buildBidderRequest('http://example.com/index.html', + {gdprConsent: {gdprApplies: true, consentString: 'test-consent-string', vendorData: {}}})); let bidRequest = bidRequests[0]; expect(bidRequest).to.have.property('regs'); expect(bidRequest.regs.ext).to.be.eql({'gdpr': 1}); @@ -204,7 +202,7 @@ describe('Adkernel adapter', function () { }); it('should\'t contain consent string if gdpr isn\'t applied', function () { - let [_, bidRequests] = buildRequest([bid1_zone1], {gdprConsent: {gdprApplies: false}}); + let [_, bidRequests] = buildRequest([bid1_zone1], buildBidderRequest('https://example.com/index.html', {gdprConsent: {gdprApplies: false}})); let bidRequest = bidRequests[0]; expect(bidRequest).to.have.property('regs'); expect(bidRequest.regs.ext).to.be.eql({'gdpr': 0}); @@ -212,7 +210,7 @@ describe('Adkernel adapter', function () { }); it('should\'t pass dnt if state is unknown', function () { - let [_, bidRequests] = buildRequest([bid1_zone1], {}, 'https://example.com/index.html', false); + let [_, bidRequests] = buildRequest([bid1_zone1], DEFAULT_BIDDER_REQUEST, false); expect(bidRequests[0].device).to.not.have.property('dnt'); }); });