diff --git a/modules/openxBidAdapter.js b/modules/openxBidAdapter.js index 7be1023450f..9e1c5e2678c 100644 --- a/modules/openxBidAdapter.js +++ b/modules/openxBidAdapter.js @@ -10,6 +10,13 @@ const BIDDER_CODE = 'openx'; const BIDDER_CONFIG = 'hb_pb'; const BIDDER_VERSION = '2.1.7'; + +const USER_ID_CODE_TO_QUERY_ARG = { + idl_env: 'lre', // liveramp + pubcid: 'pubcid', // publisher common id + tdid: 'ttduuid' // the trade desk +}; + let shouldSendBoPixel = true; export function resetBoPixel() { @@ -59,7 +66,7 @@ export const spec = { let pixelType = syncOptions.iframeEnabled ? 'iframe' : 'image'; let url = utils.deepAccess(responses, '0.body.ads.pixels') || utils.deepAccess(responses, '0.body.pixels') || - '//u.openx.net/w/1.0/pd'; + 'https://u.openx.net/w/1.0/pd'; return [{ type: pixelType, url: url @@ -237,15 +244,26 @@ function buildCommonQueryParamsFromBids(bids, bidderRequest) { } } - if ((bids[0].userId && bids[0].userId.pubcid)) { - defaultParams.pubcid = bids[0].userId.pubcid; - } else if (bids[0].crumbs && bids[0].crumbs.pubcid) { - defaultParams.pubcid = bids[0].crumbs.pubcid; + // normalize publisher common id + if (utils.deepAccess(bids[0], 'crumbs.pubcid')) { + utils.deepSetValue(bids[0], 'userId.pubcid', utils.deepAccess(bids[0], 'crumbs.pubcid')); } + defaultParams = appendUserIdsToQueryParams(defaultParams, bids[0].userId); + return defaultParams; } +function appendUserIdsToQueryParams(queryParams, userIds) { + utils._each(userIds, (userIdValue, userIdProviderKey) => { + if (USER_ID_CODE_TO_QUERY_ARG.hasOwnProperty(userIdProviderKey)) { + queryParams[USER_ID_CODE_TO_QUERY_ARG[userIdProviderKey]] = userIdValue; + } + }); + + return queryParams; +} + function buildOXBannerRequest(bids, bidderRequest) { let customParamsForAllBids = []; let hasCustomParam = false; @@ -295,8 +313,8 @@ function buildOXBannerRequest(bids, bidderRequest) { } let url = queryParams.ph - ? `//u.openx.net/w/1.0/arj` - : `//${bids[0].params.delDomain}/w/1.0/arj`; + ? `https://u.openx.net/w/1.0/arj` + : `https://${bids[0].params.delDomain}/w/1.0/arj`; return { method: 'GET', @@ -309,8 +327,8 @@ function buildOXBannerRequest(bids, bidderRequest) { function buildOXVideoRequest(bid, bidderRequest) { let oxVideoParams = generateVideoParameters(bid, bidderRequest); let url = oxVideoParams.ph - ? `//u.openx.net/v/1.0/avjp` - : `//${bid.params.delDomain}/v/1.0/avjp`; + ? `https://u.openx.net/v/1.0/avjp` + : `https://${bid.params.delDomain}/v/1.0/avjp`; return { method: 'GET', url: url, @@ -425,7 +443,7 @@ function registerBeacon(mediaType, adUnit, startTime) { if (mediaType === VIDEO) { let url = parse(adUnit.colo); beaconParams.ph = adUnit.ph; - beaconUrl = `//${url.hostname}/w/1.0/bo?${buildQueryStringFromParams(beaconParams)}` + beaconUrl = `https://${url.hostname}/w/1.0/bo?${buildQueryStringFromParams(beaconParams)}` } else { let recordPixel = utils.deepAccess(adUnit, 'creative.0.tracking.impression'); let boBase = recordPixel.match(/([^?]+\/)ri\?/); diff --git a/test/spec/modules/openxBidAdapter_spec.js b/test/spec/modules/openxBidAdapter_spec.js index cf8f4f8d62b..378b864682e 100644 --- a/test/spec/modules/openxBidAdapter_spec.js +++ b/test/spec/modules/openxBidAdapter_spec.js @@ -116,7 +116,7 @@ describe('OpenxAdapter', function () { ads: { version: 0, count: 1, - pixels: 'http://testpixels.net', + pixels: 'https://testpixels.net', ad: [DEFAULT_TEST_ARJ_AD_UNIT] } }; @@ -203,13 +203,6 @@ describe('OpenxAdapter', function () { it('should return true multisize when required params found', function () { expect(spec.isBidRequestValid(multiformatBid)).to.equal(true); }); - - it('should send bid request to openx url via GET, with mediaType specified as banner', function () { - const request = spec.buildRequests([multiformatBid]); - expect(request[0].url).to.equal(`//${multiformatBid.params.delDomain}${URLBASE}`); - expect(request[0].data.ph).to.be.undefined; - expect(request[0].method).to.equal('GET'); - }); }); }); @@ -243,7 +236,7 @@ describe('OpenxAdapter', function () { }); it('should send bid request to openx url via GET, with mediaType specified as video', function () { const request = spec.buildRequests([videoBidWithMediaTypes]); - expect(request[0].url).to.equal(`//${videoBidWithMediaTypes.params.delDomain}${URLBASEVIDEO}`); + expect(request[0].url).to.equal(`https://${videoBidWithMediaTypes.params.delDomain}${URLBASEVIDEO}`); expect(request[0].data.ph).to.be.undefined; expect(request[0].method).to.equal('GET'); }); @@ -278,7 +271,7 @@ describe('OpenxAdapter', function () { }); it('should send bid request to openx url via GET, with mediaType specified as video', function () { const request = spec.buildRequests([videoBidWithDelDomainAndPlatform]); - expect(request[0].url).to.equal(`//u.openx.net${URLBASEVIDEO}`); + expect(request[0].url).to.equal(`https://u.openx.net${URLBASEVIDEO}`); expect(request[0].data.ph).to.equal(videoBidWithDelDomainAndPlatform.params.platform); expect(request[0].method).to.equal('GET'); }); @@ -310,7 +303,7 @@ describe('OpenxAdapter', function () { }); it('should send bid request to openx url via GET, with mediaType specified as video', function () { const request = spec.buildRequests([videoBidWithMediaType]); - expect(request[0].url).to.equal(`//${videoBidWithMediaType.params.delDomain}${URLBASEVIDEO}`); + expect(request[0].url).to.equal(`https://${videoBidWithMediaType.params.delDomain}${URLBASEVIDEO}`); expect(request[0].data.ph).to.be.undefined; expect(request[0].method).to.equal('GET'); }); @@ -430,28 +423,28 @@ describe('OpenxAdapter', function () { it('should send bid request to openx url via GET, with mediaType specified as banner', function () { const request = spec.buildRequests(bidRequestsWithMediaType); - expect(request[0].url).to.equal('//' + bidRequestsWithMediaType[0].params.delDomain + URLBASE); + expect(request[0].url).to.equal('https://' + bidRequestsWithMediaType[0].params.delDomain + URLBASE); expect(request[0].data.ph).to.be.undefined; expect(request[0].method).to.equal('GET'); }); it('should send bid request to openx url via GET, with mediaTypes specified with banner type', function () { const request = spec.buildRequests(bidRequestsWithMediaTypes); - expect(request[0].url).to.equal('//' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASE); + expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASE); expect(request[0].data.ph).to.be.undefined; expect(request[0].method).to.equal('GET'); }); it('should send bid request to openx platform url via GET, if platform is present', function () { const request = spec.buildRequests(bidRequestsWithPlatform); - expect(request[0].url).to.equal(`//u.openx.net${URLBASE}`); + expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`); expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform); expect(request[0].method).to.equal('GET'); }); it('should send bid request to openx platform url via GET, if both params present', function () { const request = spec.buildRequests(bidRequestsWithPlatformAndDelDomain); - expect(request[0].url).to.equal(`//u.openx.net${URLBASE}`); + expect(request[0].url).to.equal(`https://u.openx.net${URLBASE}`); expect(request[0].data.ph).to.equal(bidRequestsWithPlatform[0].params.platform); expect(request[0].method).to.equal('GET'); }); @@ -946,60 +939,124 @@ describe('OpenxAdapter', function () { expect(request[0].data.ns).to.equal(1); }); - describe('publisher common id query param', function() { - it('should not send a pubcid query param when there is no crumbs.pubcid defined in the bid requests', function () { - const request = spec.buildRequests(bidRequestsWithMediaType); - expect(request[0].data).to.not.have.any.keys('pubcid'); + describe('when there are userid providers', function() { + describe('with publisher common id', function() { + it('should not send a pubcid query param when there is no crumbs.pubcid and no userId.pubcid defined in the bid requests', function () { + const request = spec.buildRequests(bidRequestsWithMediaType); + expect(request[0].data).to.not.have.any.keys('pubcid'); + }); + + it('should send a pubcid query param when crumbs.pubcid is defined in the bid requests', function () { + const bidRequestsWithPubcid = [{ + bidder: 'openx', + params: { + unit: '11', + delDomain: 'test-del-domain' + }, + crumbs: { + pubcid: 'c4a4c843-2368-4b5e-b3b1-6ee4702b9ad6' + }, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1' + }]; + const request = spec.buildRequests(bidRequestsWithPubcid); + expect(request[0].data.pubcid).to.equal('c4a4c843-2368-4b5e-b3b1-6ee4702b9ad6'); + }); + + it('should send a pubcid query param when userId.pubcid is defined in the bid requests', function () { + const bidRequestsWithPubcid = [{ + bidder: 'openx', + params: { + unit: '11', + delDomain: 'test-del-domain' + }, + userId: { + pubcid: 'c1a4c843-2368-4b5e-b3b1-6ee4702b9ad6' + }, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1' + }]; + const request = spec.buildRequests(bidRequestsWithPubcid); + expect(request[0].data.pubcid).to.equal('c1a4c843-2368-4b5e-b3b1-6ee4702b9ad6'); + }); }); - it('should send a pubcid query param when crumbs.pubcid is defined in the bid requests', function () { - const bidRequestsWithPubcid = [{ - bidder: 'openx', - params: { - unit: '11', - delDomain: 'test-del-domain' - }, - crumbs: { - pubcid: 'c4a4c843-2368-4b5e-b3b1-6ee4702b9ad6' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - bidId: 'test-bid-id-1', - bidderRequestId: 'test-bid-request-1', - auctionId: 'test-auction-1' - }]; - const request = spec.buildRequests(bidRequestsWithPubcid); - expect(request[0].data.pubcid).to.equal('c4a4c843-2368-4b5e-b3b1-6ee4702b9ad6'); + describe('with the trade desk unified id', function () { + it('should not send a tdid query param when there is no userId.tdid defined in the bid requests', function () { + const request = spec.buildRequests(bidRequestsWithMediaType); + expect(request[0].data).to.not.have.any.keys('ttduuid'); + }); + + it('should send a tdid query param when userId.tdid is defined in the bid requests', function () { + const bidRequestsWithTdid = [{ + bidder: 'openx', + params: { + unit: '11', + delDomain: 'test-del-domain' + }, + userId: { + tdid: '00000000-aaaa-1111-bbbb-222222222222' + }, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1' + }]; + const request = spec.buildRequests(bidRequestsWithTdid); + expect(request[0].data.ttduuid).to.equal('00000000-aaaa-1111-bbbb-222222222222'); + }); }); - it('should send a pubcid query param when userId.pubcid is defined in the bid requests', function () { - const bidRequestsWithPubcid = [{ - bidder: 'openx', - params: { - unit: '11', - delDomain: 'test-del-domain' - }, - userId: { - pubcid: 'c1a4c843-2368-4b5e-b3b1-6ee4702b9ad6' - }, - adUnitCode: 'adunit-code', - mediaTypes: { - banner: { - sizes: [[300, 250], [300, 600]] - } - }, - bidId: 'test-bid-id-1', - bidderRequestId: 'test-bid-request-1', - auctionId: 'test-auction-1' - }]; - const request = spec.buildRequests(bidRequestsWithPubcid); - expect(request[0].data.pubcid).to.equal('c1a4c843-2368-4b5e-b3b1-6ee4702b9ad6'); + describe('with the liveRamp identity link envelope', function () { + it('should not send a tdid query param when there is no userId.lre defined in the bid requests', function () { + const request = spec.buildRequests(bidRequestsWithMediaType); + expect(request[0].data).to.not.have.any.keys('lre'); + }); + + it('should send a lre query param when userId.lre is defined in the bid requests', function () { + const bidRequestsWithLiveRampEnvelope = [{ + bidder: 'openx', + params: { + unit: '11', + delDomain: 'test-del-domain' + }, + userId: { + idl_env: '00000000-aaaa-1111-bbbb-222222222222' + }, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { + sizes: [[300, 250], [300, 600]] + } + }, + bidId: 'test-bid-id-1', + bidderRequestId: 'test-bid-request-1', + auctionId: 'test-auction-1' + }]; + const request = spec.buildRequests(bidRequestsWithLiveRampEnvelope); + expect(request[0].data.lre).to.equal('00000000-aaaa-1111-bbbb-222222222222'); + }); }); - }) + }); }); describe('buildRequests for video', function () { @@ -1039,13 +1096,13 @@ describe('OpenxAdapter', function () { it('should send bid request to openx url via GET, with mediaType as video', function () { const request = spec.buildRequests(bidRequestsWithMediaType); - expect(request[0].url).to.equal('//' + bidRequestsWithMediaType[0].params.delDomain + URLBASEVIDEO); + expect(request[0].url).to.equal('https://' + bidRequestsWithMediaType[0].params.delDomain + URLBASEVIDEO); expect(request[0].method).to.equal('GET'); }); it('should send bid request to openx url via GET, with mediaTypes having video parameter', function () { const request = spec.buildRequests(bidRequestsWithMediaTypes); - expect(request[0].url).to.equal('//' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASEVIDEO); + expect(request[0].url).to.equal('https://' + bidRequestsWithMediaTypes[0].params.delDomain + URLBASEVIDEO); expect(request[0].method).to.equal('GET'); }); @@ -1152,6 +1209,34 @@ describe('OpenxAdapter', function () { }); }); + describe('buildRequest for multi-format ad', function () { + const multiformatBid = { + bidder: 'openx', + params: { + unit: '12345678', + delDomain: 'test-del-domain' + }, + adUnitCode: 'adunit-code', + mediaTypes: { + banner: { + sizes: [[300, 250]] + }, + video: { + playerSize: [300, 250] + } + }, + bidId: '30b31c1838de1e', + bidderRequestId: '22edbae2733bf6', + auctionId: '1d1a030790a475', + transactionId: '4008d88a-8137-410b-aa35-fbfdabcb478e' + }; + + it('should send bid request to openx url via GET, with mediaType specified as banner', function () { + const request = spec.buildRequests([multiformatBid]); + expect(request[0].url).to.equal(`https://${multiformatBid.params.delDomain}${URLBASE}`); + }); + }); + describe('interpretResponse for banner ads', function () { beforeEach(function () { sinon.spy(userSync, 'registerSync'); @@ -1167,7 +1252,7 @@ describe('OpenxAdapter', function () { width: '300', height: '250', tracking: { - impression: 'http://openx-d.openx.net/v/1.0/ri?ts=ts' + impression: 'https://openx-d.openx.net/v/1.0/ri?ts=ts' } }; @@ -1202,7 +1287,7 @@ describe('OpenxAdapter', function () { bidRequest = { method: 'GET', - url: '//openx-d.openx.net/v/1.0/arj', + url: 'https://openx-d.openx.net/v/1.0/arj', data: {}, payload: {'bids': bidRequestConfigs, 'startTime': new Date()} }; @@ -1260,7 +1345,7 @@ describe('OpenxAdapter', function () { it('should register a beacon', function () { resetBoPixel(); spec.interpretResponse({body: bidResponse}, bidRequest); - sinon.assert.calledWith(userSync.registerSync, 'image', 'openx', sinon.match(new RegExp(`\/\/openx-d\.openx\.net.*\/bo\?.*ts=${adUnitOverride.ts}`))); + sinon.assert.calledWith(userSync.registerSync, 'image', 'openx', sinon.match(new RegExp(`https:\/\/openx-d\.openx\.net.*\/bo\?.*ts=${adUnitOverride.ts}`))); }); }); @@ -1292,7 +1377,7 @@ describe('OpenxAdapter', function () { bidRequest = { method: 'GET', - url: '//openx-d.openx.net/v/1.0/arj', + url: 'https://openx-d.openx.net/v/1.0/arj', data: {}, payload: {'bids': bidRequestConfigs, 'startTime': new Date()} }; @@ -1328,7 +1413,7 @@ describe('OpenxAdapter', function () { bidRequest = { method: 'GET', - url: '//openx-d.openx.net/v/1.0/arj', + url: 'https://openx-d.openx.net/v/1.0/arj', data: {}, payload: {'bids': bidRequestConfigs, 'startTime': new Date()} }; @@ -1340,7 +1425,7 @@ describe('OpenxAdapter', function () { { 'version': 1, 'count': 1, - 'pixels': 'http://testpixels.net', + 'pixels': 'https://testpixels.net', 'ad': [] } }; @@ -1399,7 +1484,7 @@ describe('OpenxAdapter', function () { }]; const bidRequest = { method: 'GET', - url: '//openx-d.openx.net/v/1.0/arj', + url: 'https://openx-d.openx.net/v/1.0/arj', data: {}, payload: {'bids': bidRequests, 'startTime': new Date()} }; @@ -1481,13 +1566,13 @@ describe('OpenxAdapter', function () { }]; const bidRequestsWithMediaTypes = { method: 'GET', - url: '//openx-d.openx.net/v/1.0/avjp', + url: 'https://openx-d.openx.net/v/1.0/avjp', data: {}, payload: {'bid': bidsWithMediaTypes[0], 'startTime': new Date()} }; const bidRequestsWithMediaType = { method: 'GET', - url: '//openx-d.openx.net/v/1.0/avjp', + url: 'https://openx-d.openx.net/v/1.0/avjp', data: {}, payload: {'bid': bidsWithMediaType[0], 'startTime': new Date()} }; @@ -1496,8 +1581,8 @@ describe('OpenxAdapter', function () { 'width': '640', 'height': '480', 'adid': '5678', - 'vastUrl': 'http://testvast.com/vastpath?colo=http://test-colo.com&ph=test-ph&ts=test-ts', - 'pixels': 'http://testpixels.net' + 'vastUrl': 'https://testvast.com/vastpath?colo=https://test-colo.com&ph=test-ph&ts=test-ts', + 'pixels': 'https://testpixels.net' }; it('should return correct bid response with MediaTypes', function () { @@ -1509,7 +1594,7 @@ describe('OpenxAdapter', function () { 'height': '480', 'mediaType': 'video', 'creativeId': '5678', - 'vastUrl': 'http://testvast.com', + 'vastUrl': 'https://testvast.com', 'ttl': 300, 'netRevenue': true, 'currency': 'USD' @@ -1529,7 +1614,7 @@ describe('OpenxAdapter', function () { 'height': '480', 'mediaType': 'video', 'creativeId': '5678', - 'vastUrl': 'http://testvast.com', + 'vastUrl': 'https://testvast.com', 'ttl': 300, 'netRevenue': true, 'currency': 'USD' @@ -1555,14 +1640,14 @@ describe('OpenxAdapter', function () { it('should register a beacon', function () { resetBoPixel(); spec.interpretResponse({body: bidResponse}, bidRequestsWithMediaTypes); - sinon.assert.calledWith(userSync.registerSync, 'image', 'openx', sinon.match(/^\/\/test-colo\.com/)) + sinon.assert.calledWith(userSync.registerSync, 'image', 'openx', sinon.match(/^https:\/\/test-colo\.com/)); sinon.assert.calledWith(userSync.registerSync, 'image', 'openx', sinon.match(/ph=test-ph/)); sinon.assert.calledWith(userSync.registerSync, 'image', 'openx', sinon.match(/ts=test-ts/)); }); }); describe('user sync', function () { - const syncUrl = 'http://testpixels.net'; + const syncUrl = 'https://testpixels.net'; describe('iframe sync', function () { it('should register the pixel iframe from banner ad response', function () { @@ -1586,7 +1671,7 @@ describe('OpenxAdapter', function () { {iframeEnabled: true}, [] ); - expect(syncs).to.deep.equal([{type: 'iframe', url: '//u.openx.net/w/1.0/pd'}]); + expect(syncs).to.deep.equal([{type: 'iframe', url: 'https://u.openx.net/w/1.0/pd'}]); }); }); @@ -1612,7 +1697,7 @@ describe('OpenxAdapter', function () { {pixelEnabled: true}, [] ); - expect(syncs).to.deep.equal([{type: 'image', url: '//u.openx.net/w/1.0/pd'}]); + expect(syncs).to.deep.equal([{type: 'image', url: 'https://u.openx.net/w/1.0/pd'}]); }); }); @@ -1663,7 +1748,7 @@ describe('OpenxAdapter', function () { if (adUnits.length) { mockedArjResponse.ads.count = adUnits.length; - mockedArjResponse.ads.ad = adUnits.map((adUnit, index) => { + mockedArjResponse.ads.ad = adUnits.map((adUnit) => { overrideKeyCheck(adUnit, DEFAULT_TEST_ARJ_AD_UNIT, 'OxArjAdUnit'); return Object.assign(utils.deepClone(DEFAULT_TEST_ARJ_AD_UNIT), adUnit); });