diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 4cc6807b670..54cf3596dbb 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -38,6 +38,7 @@ const VIDEO_TIME_TO_LIVE = 3600; // 1hr const NATIVE_TIME_TO_LIVE = 3600; // Since native can have video, use ttl same as video const NET_REVENUE = true; const MAX_REQUEST_LIMIT = 4; +const MAX_EID_SOURCES = 50; const OUTSTREAM_MINIMUM_PLAYER_SIZE = [144, 144]; const PRICE_TO_DOLLAR_FACTOR = { JPY: 1 @@ -111,7 +112,8 @@ export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); export const FEATURE_TOGGLES = { // Update with list of CFTs to be requested from Exchange REQUESTED_FEATURE_TOGGLES: [ - 'pbjs_enable_multiformat' + 'pbjs_enable_multiformat', + 'pbjs_allow_all_eids' ], featureToggles: {}, @@ -657,15 +659,23 @@ function getEidInfo(allEids) { let seenSources = {}; if (isArray(allEids)) { for (const eid of allEids) { - if (SOURCE_RTI_MAPPING.hasOwnProperty(eid.source) && deepAccess(eid, 'uids.0')) { + const isSourceMapped = SOURCE_RTI_MAPPING.hasOwnProperty(eid.source); + const allowAllEidsFeatureEnabled = FEATURE_TOGGLES.isFeatureEnabled('pbjs_allow_all_eids'); + const hasUids = deepAccess(eid, 'uids.0'); + + if ((isSourceMapped || allowAllEidsFeatureEnabled) && hasUids) { seenSources[eid.source] = true; - if (SOURCE_RTI_MAPPING[eid.source] != '') { + + if (isSourceMapped && SOURCE_RTI_MAPPING[eid.source] !== '') { eid.uids[0].ext = { rtiPartner: SOURCE_RTI_MAPPING[eid.source] }; } delete eid.uids[0].atype; toSend.push(eid); + if (toSend.length >= MAX_EID_SOURCES) { + break; + } } } } @@ -710,7 +720,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { // getting ixdiags for adunits of the video, outstream & multi format (MF) style const fledgeEnabled = deepAccess(bidderRequest, 'fledgeEnabled') let ixdiag = buildIXDiag(validBidRequests, fledgeEnabled); - for (var key in ixdiag) { + for (let key in ixdiag) { r.ext.ixdiag[key] = ixdiag[key]; } @@ -796,6 +806,9 @@ function addRTI(userEids, eidInfo) { let identityInfo = window.headertag.getIdentityInfo(); if (identityInfo && typeof identityInfo === 'object') { for (const partnerName in identityInfo) { + if (userEids.length >= MAX_EID_SOURCES) { + return + } if (identityInfo.hasOwnProperty(partnerName)) { let response = identityInfo[partnerName]; if (!response.responsePending && response.data && typeof response.data === 'object' && @@ -1274,6 +1287,7 @@ function buildIXDiag(validBidRequests, fledgeEnabled) { .map(bidRequest => bidRequest.adUnitCode) .filter((value, index, arr) => arr.indexOf(value) === index); + let allEids = deepAccess(validBidRequests, '0.userIdAsEids', []) let ixdiag = { mfu: 0, bu: 0, @@ -1286,7 +1300,8 @@ function buildIXDiag(validBidRequests, fledgeEnabled) { userIds: _getUserIds(validBidRequests[0]), url: window.location.href.split('?')[0], vpd: defaultVideoPlacement, - ae: fledgeEnabled + ae: fledgeEnabled, + eidLength: allEids.length }; // create ad unit map and collect the required diag properties diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 500f2239e55..05b401fe4db 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -919,6 +919,23 @@ describe('IndexexchangeAdapter', function () { const extractPayload = function (bidRequest) { return bidRequest.data } + const generateEid = function (numEid) { + const eids = []; + + for (let i = 1; i <= numEid; i++) { + const newEid = { + source: `eid_source_${i}.com`, + uids: [{ + id: `uid_id_${i}`, + }] + }; + + eids.push(newEid); + } + + return eids; + } + describe('inherited functions', function () { it('should exists and is a function', function () { const adapter = newBidder(spec); @@ -1485,6 +1502,17 @@ describe('IndexexchangeAdapter', function () { describe('buildRequestsUserId', function () { let validIdentityResponse; let validUserIdPayload; + const serverResponse = { + body: { + ext: { + pbjs_allow_all_eids: { + test: { + activated: false + } + } + } + } + }; beforeEach(function () { window.headertag = {}; @@ -1495,6 +1523,12 @@ describe('IndexexchangeAdapter', function () { afterEach(function () { delete window.headertag; + serverResponse.body.ext.features = { + pbjs_allow_all_eids: { + activated: false + } + }; + validIdentityResponse = {} }); it('IX adapter reads supported user modules from Prebid and adds it to Video', function () { @@ -1506,6 +1540,91 @@ describe('IndexexchangeAdapter', function () { expect(payload.user.eids).to.have.deep.members(DEFAULT_USERID_PAYLOAD); }); + it('IX adapter filters eids from prebid past the maximum eid limit', function () { + serverResponse.body.ext.features = { + pbjs_allow_all_eids: { + activated: true + } + }; + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); + let eid_sent_from_prebid = generateEid(55); + cloneValidBid[0].userIdAsEids = utils.deepClone(eid_sent_from_prebid); + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + const payload = extractPayload(request); + expect(payload.user.eids).to.have.lengthOf(50); + let eid_accepted = eid_sent_from_prebid.slice(0, 50); + expect(payload.user.eids).to.have.deep.members(eid_accepted); + expect(payload.ext.ixdiag.eidLength).to.equal(55); + }); + + it('IX adapter filters eids from IXL past the maximum eid limit', function () { + validIdentityResponse = { + MerkleIp: { + responsePending: false, + data: { + source: 'merkle.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + enc: 1 + } + }] + } + }, + LiveIntentIp: { + responsePending: false, + data: { + source: 'liveintent.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + rtiPartner: 'LDID', + enc: 1 + } + }] + } + } + }; + serverResponse.body.ext.features = { + pbjs_allow_all_eids: { + activated: true + } + }; + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); + let eid_sent_from_prebid = generateEid(49); + cloneValidBid[0].userIdAsEids = utils.deepClone(eid_sent_from_prebid); + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + const payload = extractPayload(request); + expect(payload.user.eids).to.have.lengthOf(50); + eid_sent_from_prebid.push({ + source: 'merkle.com', + uids: [{ + id: '1234-5678-9012-3456', + ext: { + keyID: '1234-5678', + enc: 1 + } + }] + }) + expect(payload.user.eids).to.have.deep.members(eid_sent_from_prebid); + expect(payload.ext.ixdiag.eidLength).to.equal(49); + }); + + it('All incoming eids are from unsupported source with feature toggle off', function () { + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + const cloneValidBid = utils.deepClone(DEFAULT_VIDEO_VALID_BID); + let eid_sent_from_prebid = generateEid(20); + cloneValidBid[0].userIdAsEids = utils.deepClone(eid_sent_from_prebid); + const request = spec.buildRequests(cloneValidBid, DEFAULT_OPTION)[0]; + const payload = extractPayload(request); + expect(payload.user.eids).to.be.undefined + expect(payload.ext.ixdiag.eidLength).to.equal(20); + }); + it('We continue to send in IXL identity info and Prebid takes precedence over IXL', function () { validIdentityResponse = { AdserverOrgIp: {