From eb4b3664ff0266cf57909abe83c3217cbee01d22 Mon Sep 17 00:00:00 2001 From: "shahin.rahbariasl" Date: Fri, 20 Jan 2023 14:56:35 -0500 Subject: [PATCH 1/7] feat: remove request splitting logic [PB-1389] --- modules/ixBidAdapter.js | 355 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 346 insertions(+), 9 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index bd598cf2d04..47d884e0be1 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -898,7 +898,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { const clonedRObject = deepClone(r); clonedRObject.site = mergeDeep({}, clonedRObject.site, site); - clonedRObject.user = mergeDeep({}, clonedRObject.user, user); + clonedRObject.user = mergeDeep({}, clonedRObject.user, user); const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; @@ -957,6 +957,331 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { return requests; } +/** + * Builds a request object to be sent to the ad server based on bid requests. + * + * @param {array} validBidRequests A list of valid bid request config objects. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {object} impressions An object containing a list of impression objects describing the bids for each transactionId + * @param {array} version Endpoint version denoting banner, video or native. + * @return {array} List of objects describing the request to the server. + * + */ +function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) { + // Always use secure HTTPS protocol. + let baseUrl = SECURE_BID_URL; + // Get ids from Prebid User ID Modules + let eidInfo = getEidInfo(deepAccess(validBidRequests, '0.userIdAsEids')); + let userEids = eidInfo.toSend; + const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); + + // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded + // and if the data for the partner exist + if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') { + let identityInfo = window.headertag.getIdentityInfo(); + if (identityInfo && typeof identityInfo === 'object') { + for (const partnerName in identityInfo) { + if (identityInfo.hasOwnProperty(partnerName)) { + let response = identityInfo[partnerName]; + if (!response.responsePending && response.data && typeof response.data === 'object' && + Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { + userEids.push(response.data); + } + } + } + } + } + + // If `roundel` alias bidder, only send requests if liveramp ids exist. + if (bidderRequest && bidderRequest.bidderCode === ALIAS_BIDDER_CODE && !eidInfo.seenSources['liveramp.com']) { + return []; + } + + const r = {}; + const tmax = deepAccess(bidderRequest, 'timeout'); + // Since bidderRequestId are the same for different bid request, just use the first one. + r.id = validBidRequests[0].bidderRequestId.toString(); + r.site = {}; + r.ext = {}; + r.ext.source = 'prebid'; + r.ext.ixdiag = {}; + r.ext.ixdiag.ls = storage.localStorageIsEnabled(); + r.imp = []; + r.at = 1; + + // getting ixdiags for adunits of the video, outstream & multi format (MF) style + let ixdiag = buildIXDiag(validBidRequests); + for (var key in ixdiag) { + r.ext.ixdiag[key] = ixdiag[key]; + } + + if (tmax) { + r.ext.ixdiag.tmax = tmax; + } + + if (config.getConfig('userSync')) { + r.ext.ixdiag.syncsPerBidder = config.getConfig('userSync').syncsPerBidder; + } + + // Get cached errors stored in LocalStorage + const cachedErrors = getCachedErrors(); + + if (!isEmpty(cachedErrors)) { + r.ext.ixdiag.err = cachedErrors; + } + + // Add number of available imps to ixDiag. + r.ext.ixdiag.imps = Object.keys(impressions).length; + + // set source.tid to auctionId for outgoing request to Exchange. + r.source = { + tid: validBidRequests[0].auctionId, + } + + // if an schain is provided, send it along + if (validBidRequests[0].schain) { + r.source.ext = {}; + r.source.ext.schain = validBidRequests[0].schain; + } + + if (userEids.length > 0) { + r.user = {}; + r.user.eids = userEids; + } + + if (document.referrer && document.referrer !== '') { + r.site.ref = document.referrer; + } + + // Apply GDPR information to the request if GDPR is enabled. + if (bidderRequest) { + if (bidderRequest.gdprConsent) { + gdprConsent = bidderRequest.gdprConsent; + + if (gdprConsent.hasOwnProperty('gdprApplies')) { + r.regs = { + ext: { + gdpr: gdprConsent.gdprApplies ? 1 : 0 + } + }; + } + + if (gdprConsent.hasOwnProperty('consentString')) { + r.user = r.user || {}; + r.user.ext = { + consent: gdprConsent.consentString || '' + }; + + if (gdprConsent.hasOwnProperty('addtlConsent') && gdprConsent.addtlConsent) { + r.user.ext.consented_providers_settings = { + consented_providers: gdprConsent.addtlConsent + }; + } + } + } + + if (bidderRequest.uspConsent) { + deepSetValue(r, 'regs.ext.us_privacy', bidderRequest.uspConsent); + usPrivacy = bidderRequest.uspConsent; + } + + if (pageUrl) { + r.site.page = pageUrl; + } + + if (bidderRequest.gppConsent) { + deepSetValue(r, 'regs.gpp', bidderRequest.gppConsent.gppString); + deepSetValue(r, 'regs.gpp_sid', bidderRequest.gppConsent.applicableSections); + } + } + + if (config.getConfig('coppa')) { + deepSetValue(r, 'regs.coppa', 1); + } + + const payload = {}; + // Use the siteId in the first bid request as the main siteId. + siteID = validBidRequests[0].params.siteId; + payload.s = siteID; + + // Parse additional runtime configs. + const bidderCode = (bidderRequest && bidderRequest.bidderCode) || 'ix'; + const otherIxConfig = config.getConfig(bidderCode); + const requests = []; + let requestSequenceNumber = 0; + const transactionIds = Object.keys(impressions); + let isFpdAdded = false; + + if (otherIxConfig) { + // Append firstPartyData to r.site.page if firstPartyData exists. + if (typeof otherIxConfig.firstPartyData === 'object') { + const firstPartyData = otherIxConfig.firstPartyData; + let firstPartyString = '?'; + for (const key in firstPartyData) { + if (firstPartyData.hasOwnProperty(key)) { + firstPartyString += `${encodeURIComponent(key)}=${encodeURIComponent(firstPartyData[key])}&`; + } + } + firstPartyString = firstPartyString.slice(0, -1); + + if ('page' in r.site) { + r.site.page += firstPartyString; + } else { + r.site.page = firstPartyString; + } + + } + } + + for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { + if (requests.length >= MAX_REQUEST_LIMIT) { + break; + } + + const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; + const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; + const sourceImpressions = { ixImps, missingBannerImpressions }; + const impressionObjects = Object.keys(sourceImpressions) + .map((key) => sourceImpressions[key]) + .filter(item => Array.isArray(item)) + .reduce((acc, curr) => acc.concat(...curr), []); + + const gpid = impressions[transactionIds[adUnitIndex]].gpid; + const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; + const tid = impressions[transactionIds[adUnitIndex]].tid; + const sid = impressions[transactionIds[adUnitIndex]].sid + + if (impressionObjects.length && BANNER in impressionObjects[0]) { + const { id, banner: { topframe } } = impressionObjects[0]; + const _bannerImpression = { + id, + banner: { + topframe, + format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) + }, + }; + + for (let i = 0; i < _bannerImpression.banner.format.length; i++) { + // We add sid in imp.ext.sid therefore, remove from banner.format[].ext + if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { + delete _bannerImpression.banner.format[i].ext.sid; + } + + // add floor per size + if ('bidfloor' in impressionObjects[i]) { + _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor + } + } + + const position = impressions[transactionIds[adUnitIndex]].pos; + if (isInteger(position)) { + _bannerImpression.banner.pos = position; + } + + if (dfpAdUnitCode || gpid || tid || sid) { + _bannerImpression.ext = {}; + _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; + _bannerImpression.ext.gpid = gpid; + _bannerImpression.ext.tid = tid; + _bannerImpression.ext.sid = sid; + } + + if ('bidfloor' in impressionObjects[0]) { + _bannerImpression.bidfloor = impressionObjects[0].bidfloor; + } + + if ('bidfloorcur' in impressionObjects[0]) { + _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; + } + + r.imp.push(_bannerImpression); + } else { + // set imp.ext.gpid to resolved gpid for each imp + impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); + r.imp.push(...impressionObjects); + } + + const fpd = deepAccess(bidderRequest, 'ortb2') || {}; + if (!isEmpty(fpd) && !isFpdAdded) { + r.ext.ixdiag.fpd = true; + + const site = { ...(fpd.site || fpd.context) }; + + Object.keys(site).forEach(key => { + if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { + delete site[key]; + } + }); + + const user = { ...fpd.user }; + + Object.keys(user).forEach(key => { + if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { + delete user[key]; + } + }); + + if (fpd.device) { + const sua = {...fpd.device.sua}; + if (!isEmpty(sua)) { + deepSetValue(r, 'device.sua', sua); + } + } + + if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { + if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { + deepSetValue(r, 'regs.gpp', fpd.regs.gpp) + } + + if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { + deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) + } + } + + const clonedRObject = deepClone(r); + + clonedRObject.site = mergeDeep({}, clonedRObject.site, site); + clonedRObject.user = mergeDeep({}, clonedRObject.user, user); + + r.site = mergeDeep({}, r.site, site); + r.user = mergeDeep({}, r.user, user); + isFpdAdded = true; + + } + + // add identifiers info to ixDiag + const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; + const tagId = impressions[transactionIds[adUnitIndex]].tagId; + const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; + const divId = impressions[transactionIds[adUnitIndex]].divId; + if (pbaAdSlot || tagId || adUnitCode || divId) { + r.ext.ixdiag.pbadslot = pbaAdSlot; + r.ext.ixdiag.tagid = tagId; + r.ext.ixdiag.adunitcode = adUnitCode; + r.ext.ixdiag.divId = divId; + } + + const isLastAdUnit = adUnitIndex === transactionIds.length - 1; + + if (isLastAdUnit) { + requests.push({ + method: 'POST', + url: baseUrl + '?s=' + siteID, + data: deepClone(r), + option: { + contentType: 'text/plain', + }, + validBidRequests + }); + + r.imp = []; + isFpdAdded = false; + } + } + + return requests; +} + /** * Return an object of user IDs stored by Prebid User ID module * @@ -1502,14 +1827,26 @@ export const spec = { } // Step 4: Build banner, video & native requests - if (Object.keys(bannerImps).length > 0) { - reqs.push(...buildRequest(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION)); - } - if (Object.keys(videoImps).length > 0) { - reqs.push(...buildRequest(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION)); - } - if (Object.keys(nativeImps).length > 0) { - reqs.push(...buildRequest(validBidRequests, bidderRequest, nativeImps)); + if (FEATURE_TOGGLES.isFeatureEnabled("pbjs_use_build_request_v2")) { + if (Object.keys(bannerImps).length > 0) { + reqs.push(...buildRequest_v2(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION)); + } + if (Object.keys(videoImps).length > 0) { + reqs.push(...buildRequest_v2(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION)); + } + if (Object.keys(nativeImps).length > 0) { + reqs.push(...buildRequest_v2(validBidRequests, bidderRequest, nativeImps)); + } + } else { + if (Object.keys(bannerImps).length > 0) { + reqs.push(...buildRequest(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION)); + } + if (Object.keys(videoImps).length > 0) { + reqs.push(...buildRequest(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION)); + } + if (Object.keys(nativeImps).length > 0) { + reqs.push(...buildRequest(validBidRequests, bidderRequest, nativeImps)); + } } return reqs; From 1c53ca4b66c77236a8a00aa86540e79fbce28ea1 Mon Sep 17 00:00:00 2001 From: "shahin.rahbariasl" Date: Mon, 23 Jan 2023 22:14:18 -0500 Subject: [PATCH 2/7] feat: remove splitting logic behind ft [PB-1389] --- modules/ixBidAdapter.js | 666 ++++++++----------------- test/spec/modules/ixBidAdapter_spec.js | 64 ++- 2 files changed, 264 insertions(+), 466 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 47d884e0be1..45fa44fd6d0 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -151,6 +151,12 @@ const MEDIA_TYPES = { Native: 4 }; +var baseRequestSize = 0; +var currentRequestSize = 0; +var wasAdUnitImpressionsTrimmed = false; +var currentImpressionSize = 0; +var build_request_v2 = false; + /** * Transform valid bid request config object to banner impression object that will be sent to ad server. * @@ -592,34 +598,29 @@ function getEidInfo(allEids) { * */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { + // V2 does not have request splitting logic. + build_request_v2 = FEATURE_TOGGLES.isFeatureEnabled("pbjs_use_build_request_v2"); + baseRequestSize = 0; + currentRequestSize = 0; + wasAdUnitImpressionsTrimmed = false; + currentImpressionSize = 0; + // Always use secure HTTPS protocol. let baseUrl = SECURE_BID_URL; // Get ids from Prebid User ID Modules let eidInfo = getEidInfo(deepAccess(validBidRequests, '0.userIdAsEids')); let userEids = eidInfo.toSend; - const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); let MAX_REQUEST_SIZE = 8000; // Modify request size limit if its FT is enabeld. - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_32kb_size_limit')) { - MAX_REQUEST_SIZE = 32000 + if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_32kb_size_limit') || FEATURE_TOGGLES.isFeatureEnabled('build_request_v2')) { + MAX_REQUEST_SIZE = 32000; } // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded // and if the data for the partner exist if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') { - let identityInfo = window.headertag.getIdentityInfo(); - if (identityInfo && typeof identityInfo === 'object') { - for (const partnerName in identityInfo) { - if (identityInfo.hasOwnProperty(partnerName)) { - let response = identityInfo[partnerName]; - if (!response.responsePending && response.data && typeof response.data === 'object' && - Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { - userEids.push(response.data); - } - } - } - } + addRTI(userEids, eidInfo); } // If `roundel` alias bidder, only send requests if liveramp ids exist. @@ -627,17 +628,8 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { return []; } - const r = {}; - const tmax = deepAccess(bidderRequest, 'timeout'); - // Since bidderRequestId are the same for different bid request, just use the first one. - r.id = validBidRequests[0].bidderRequestId.toString(); - r.site = {}; - r.ext = {}; - r.ext.source = 'prebid'; - r.ext.ixdiag = {}; - r.ext.ixdiag.ls = storage.localStorageIsEnabled(); - r.imp = []; - r.at = 1; + const requests = []; + let r = createRequest(validBidRequests); // getting ixdiags for adunits of the video, outstream & multi format (MF) style let ixdiag = buildIXDiag(validBidRequests); @@ -645,260 +637,40 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r.ext.ixdiag[key] = ixdiag[key]; } - if (tmax) { - r.ext.ixdiag.tmax = tmax; - } - - if (config.getConfig('userSync')) { - r.ext.ixdiag.syncsPerBidder = config.getConfig('userSync').syncsPerBidder; - } - - // Get cached errors stored in LocalStorage - const cachedErrors = getCachedErrors(); - - if (!isEmpty(cachedErrors)) { - r.ext.ixdiag.err = cachedErrors; - } - - // Add number of available imps to ixDiag. - r.ext.ixdiag.imps = Object.keys(impressions).length; - - // set source.tid to auctionId for outgoing request to Exchange. - r.source = { - tid: validBidRequests[0].auctionId, - } - - // if an schain is provided, send it along - if (validBidRequests[0].schain) { - r.source.ext = {}; - r.source.ext.schain = validBidRequests[0].schain; - } - - if (userEids.length > 0) { - r.user = {}; - r.user.eids = userEids; - } - - if (document.referrer && document.referrer !== '') { - r.site.ref = document.referrer; - } - - // Apply GDPR information to the request if GDPR is enabled. - if (bidderRequest) { - if (bidderRequest.gdprConsent) { - gdprConsent = bidderRequest.gdprConsent; - - if (gdprConsent.hasOwnProperty('gdprApplies')) { - r.regs = { - ext: { - gdpr: gdprConsent.gdprApplies ? 1 : 0 - } - }; - } - - if (gdprConsent.hasOwnProperty('consentString')) { - r.user = r.user || {}; - r.user.ext = { - consent: gdprConsent.consentString || '' - }; - - if (gdprConsent.hasOwnProperty('addtlConsent') && gdprConsent.addtlConsent) { - r.user.ext.consented_providers_settings = { - consented_providers: gdprConsent.addtlConsent - }; - } - } - } - - if (bidderRequest.uspConsent) { - deepSetValue(r, 'regs.ext.us_privacy', bidderRequest.uspConsent); - usPrivacy = bidderRequest.uspConsent; - } - - if (pageUrl) { - r.site.page = pageUrl; - } - - if (bidderRequest.gppConsent) { - deepSetValue(r, 'regs.gpp', bidderRequest.gppConsent.gppString); - deepSetValue(r, 'regs.gpp_sid', bidderRequest.gppConsent.applicableSections); - } - } + r = enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids); - if (config.getConfig('coppa')) { - deepSetValue(r, 'regs.coppa', 1); - } + r = applyRegulations(r, bidderRequest); - const payload = {}; - // Use the siteId in the first bid request as the main siteId. - siteID = validBidRequests[0].params.siteId; - payload.s = siteID; + let payload = {}; + createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, build_request_v2); - // Parse additional runtime configs. - const bidderCode = (bidderRequest && bidderRequest.bidderCode) || 'ix'; - const otherIxConfig = config.getConfig(bidderCode); - const requests = []; let requestSequenceNumber = 0; const transactionIds = Object.keys(impressions); - const baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length; - - if (baseRequestSize > MAX_REQUEST_SIZE) { - logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE }); - return requests; - } - - let currentRequestSize = baseRequestSize; - let fpdRequestSize = 0; let isFpdAdded = false; - if (otherIxConfig) { - // Append firstPartyData to r.site.page if firstPartyData exists. - if (typeof otherIxConfig.firstPartyData === 'object') { - const firstPartyData = otherIxConfig.firstPartyData; - let firstPartyString = '?'; - for (const key in firstPartyData) { - if (firstPartyData.hasOwnProperty(key)) { - firstPartyString += `${encodeURIComponent(key)}=${encodeURIComponent(firstPartyData[key])}&`; - } - } - firstPartyString = firstPartyString.slice(0, -1); - - fpdRequestSize = encodeURIComponent(firstPartyString).length; - - if (fpdRequestSize < MAX_REQUEST_SIZE) { - if ('page' in r.site) { - r.site.page += firstPartyString; - } else { - r.site.page = firstPartyString; - } - currentRequestSize += fpdRequestSize; - } else { - logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE }); + for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { + if (!build_request_v2) { + if (currentRequestSize >= MAX_REQUEST_SIZE) { + break; } } - } - - for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { - if (currentRequestSize >= MAX_REQUEST_SIZE || requests.length >= MAX_REQUEST_LIMIT) { + if (requests.length >= MAX_REQUEST_LIMIT) { break; } - const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; - const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; - let wasAdUnitImpressionsTrimmed = false; - let remainingRequestSize = MAX_REQUEST_SIZE - currentRequestSize; - const sourceImpressions = { ixImps, missingBannerImpressions }; - const impressionObjects = Object.keys(sourceImpressions) - .map((key) => sourceImpressions[key]) - .filter(item => Array.isArray(item)) - .reduce((acc, curr) => acc.concat(...curr), []); - - let currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; - - while (impressionObjects.length && currentImpressionSize > remainingRequestSize) { - wasAdUnitImpressionsTrimmed = true; - impressionObjects.pop(); - currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; - } - - const gpid = impressions[transactionIds[adUnitIndex]].gpid; - const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; - const tid = impressions[transactionIds[adUnitIndex]].tid; - const sid = impressions[transactionIds[adUnitIndex]].sid - - if (impressionObjects.length && BANNER in impressionObjects[0]) { - const { id, banner: { topframe } } = impressionObjects[0]; - const _bannerImpression = { - id, - banner: { - topframe, - format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) - }, - }; - - for (let i = 0; i < _bannerImpression.banner.format.length; i++) { - // We add sid in imp.ext.sid therefore, remove from banner.format[].ext - if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { - delete _bannerImpression.banner.format[i].ext.sid; - } - - // add floor per size - if ('bidfloor' in impressionObjects[i]) { - _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor - } - } - - const position = impressions[transactionIds[adUnitIndex]].pos; - if (isInteger(position)) { - _bannerImpression.banner.pos = position; - } - - if (dfpAdUnitCode || gpid || tid || sid) { - _bannerImpression.ext = {}; - _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; - _bannerImpression.ext.gpid = gpid; - _bannerImpression.ext.tid = tid; - _bannerImpression.ext.sid = sid; - } - - if ('bidfloor' in impressionObjects[0]) { - _bannerImpression.bidfloor = impressionObjects[0].bidfloor; - } - - if ('bidfloorcur' in impressionObjects[0]) { - _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; - } - - r.imp.push(_bannerImpression); - } else { - // set imp.ext.gpid to resolved gpid for each imp - impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); - r.imp.push(...impressionObjects); - } - + r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, build_request_v2); currentRequestSize += currentImpressionSize; const fpd = deepAccess(bidderRequest, 'ortb2') || {}; + const site = { ...(fpd.site || fpd.context) }; + const user = { ...fpd.user }; if (!isEmpty(fpd) && !isFpdAdded) { - r.ext.ixdiag.fpd = true; - - const site = { ...(fpd.site || fpd.context) }; - - Object.keys(site).forEach(key => { - if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { - delete site[key]; - } - }); - - const user = { ...fpd.user }; - - Object.keys(user).forEach(key => { - if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { - delete user[key]; - } - }); - - if (fpd.device) { - const sua = {...fpd.device.sua}; - if (!isEmpty(sua)) { - deepSetValue(r, 'device.sua', sua); - } - } - - if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { - if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { - deepSetValue(r, 'regs.gpp', fpd.regs.gpp) - } - - if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { - deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) - } - } + r = addFPD(bidderRequest, r, fpd, site, user); const clonedRObject = deepClone(r); clonedRObject.site = mergeDeep({}, clonedRObject.site, site); - clonedRObject.user = mergeDeep({}, clonedRObject.user, user); + clonedRObject.user = mergeDeep({}, clonedRObject.user, user); const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; @@ -914,20 +686,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { } // add identifiers info to ixDiag - const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; - const tagId = impressions[transactionIds[adUnitIndex]].tagId; - const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; - const divId = impressions[transactionIds[adUnitIndex]].divId; - if (pbaAdSlot || tagId || adUnitCode || divId) { - const clonedRObject = deepClone(r); - const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; - if (requestSize < MAX_REQUEST_SIZE) { - r.ext.ixdiag.pbadslot = pbaAdSlot; - r.ext.ixdiag.tagid = tagId; - r.ext.ixdiag.adunitcode = adUnitCode; - r.ext.ixdiag.divId = divId; - } - } + r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, build_request_v2); const isLastAdUnit = adUnitIndex === transactionIds.length - 1; @@ -957,48 +716,23 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { return requests; } -/** - * Builds a request object to be sent to the ad server based on bid requests. - * - * @param {array} validBidRequests A list of valid bid request config objects. - * @param {object} bidderRequest An object containing other info like gdprConsent. - * @param {object} impressions An object containing a list of impression objects describing the bids for each transactionId - * @param {array} version Endpoint version denoting banner, video or native. - * @return {array} List of objects describing the request to the server. - * - */ -function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) { - // Always use secure HTTPS protocol. - let baseUrl = SECURE_BID_URL; - // Get ids from Prebid User ID Modules - let eidInfo = getEidInfo(deepAccess(validBidRequests, '0.userIdAsEids')); - let userEids = eidInfo.toSend; - const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); - - // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded - // and if the data for the partner exist - if (window.headertag && typeof window.headertag.getIdentityInfo === 'function') { - let identityInfo = window.headertag.getIdentityInfo(); - if (identityInfo && typeof identityInfo === 'object') { - for (const partnerName in identityInfo) { - if (identityInfo.hasOwnProperty(partnerName)) { - let response = identityInfo[partnerName]; - if (!response.responsePending && response.data && typeof response.data === 'object' && - Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { - userEids.push(response.data); - } +function addRTI(userEids, eidInfo) { + let identityInfo = window.headertag.getIdentityInfo(); + if (identityInfo && typeof identityInfo === 'object') { + for (const partnerName in identityInfo) { + if (identityInfo.hasOwnProperty(partnerName)) { + let response = identityInfo[partnerName]; + if (!response.responsePending && response.data && typeof response.data === 'object' && + Object.keys(response.data).length && !eidInfo.seenSources[response.data.source]) { + userEids.push(response.data); } } } } +} - // If `roundel` alias bidder, only send requests if liveramp ids exist. - if (bidderRequest && bidderRequest.bidderCode === ALIAS_BIDDER_CODE && !eidInfo.seenSources['liveramp.com']) { - return []; - } - +function createRequest(validBidRequests) { const r = {}; - const tmax = deepAccess(bidderRequest, 'timeout'); // Since bidderRequestId are the same for different bid request, just use the first one. r.id = validBidRequests[0].bidderRequestId.toString(); r.site = {}; @@ -1008,13 +742,11 @@ function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) r.ext.ixdiag.ls = storage.localStorageIsEnabled(); r.imp = []; r.at = 1; + return r +} - // getting ixdiags for adunits of the video, outstream & multi format (MF) style - let ixdiag = buildIXDiag(validBidRequests); - for (var key in ixdiag) { - r.ext.ixdiag[key] = ixdiag[key]; - } - +function enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids) { + const tmax = deepAccess(bidderRequest, 'timeout'); if (tmax) { r.ext.ixdiag.tmax = tmax; } @@ -1053,6 +785,10 @@ function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) r.site.ref = document.referrer; } + return r +} + +function applyRegulations(r, bidderRequest) { // Apply GDPR information to the request if GDPR is enabled. if (bidderRequest) { if (bidderRequest.gdprConsent) { @@ -1085,6 +821,7 @@ function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) usPrivacy = bidderRequest.uspConsent; } + const pageUrl = deepAccess(bidderRequest, 'refererInfo.page'); if (pageUrl) { r.site.page = pageUrl; } @@ -1099,7 +836,10 @@ function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) deepSetValue(r, 'regs.coppa', 1); } - const payload = {}; + return r +} + +function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, build_request_v2) { // Use the siteId in the first bid request as the main siteId. siteID = validBidRequests[0].params.siteId; payload.s = siteID; @@ -1107,10 +847,16 @@ function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) // Parse additional runtime configs. const bidderCode = (bidderRequest && bidderRequest.bidderCode) || 'ix'; const otherIxConfig = config.getConfig(bidderCode); - const requests = []; - let requestSequenceNumber = 0; - const transactionIds = Object.keys(impressions); - let isFpdAdded = false; + + baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length; + + if (baseRequestSize > MAX_REQUEST_SIZE) { + logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE }); + return requests; + } + + currentRequestSize = baseRequestSize; + let fpdRequestSize = 0; if (otherIxConfig) { // Append firstPartyData to r.site.page if firstPartyData exists. @@ -1124,162 +870,168 @@ function buildRequest_v2(validBidRequests, bidderRequest, impressions, version) } firstPartyString = firstPartyString.slice(0, -1); - if ('page' in r.site) { - r.site.page += firstPartyString; + fpdRequestSize = encodeURIComponent(firstPartyString).length; + + if (!build_request_v2) { + if (fpdRequestSize < MAX_REQUEST_SIZE) { + if ('page' in r.site) { + r.site.page += firstPartyString; + } else { + r.site.page = firstPartyString; + } + currentRequestSize += fpdRequestSize; + } else { + logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE }); + } } else { - r.site.page = firstPartyString; - } - + if ('page' in r.site) { + r.site.page += firstPartyString; + } else { + r.site.page = firstPartyString; + } + } } } +} - for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { - if (requests.length >= MAX_REQUEST_LIMIT) { - break; - } +function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, build_request_v2) { + const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; + const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; - const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; - const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; - const sourceImpressions = { ixImps, missingBannerImpressions }; - const impressionObjects = Object.keys(sourceImpressions) - .map((key) => sourceImpressions[key]) - .filter(item => Array.isArray(item)) - .reduce((acc, curr) => acc.concat(...curr), []); - - const gpid = impressions[transactionIds[adUnitIndex]].gpid; - const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; - const tid = impressions[transactionIds[adUnitIndex]].tid; - const sid = impressions[transactionIds[adUnitIndex]].sid - - if (impressionObjects.length && BANNER in impressionObjects[0]) { - const { id, banner: { topframe } } = impressionObjects[0]; - const _bannerImpression = { - id, - banner: { - topframe, - format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) - }, - }; + let remainingRequestSize = MAX_REQUEST_SIZE - currentRequestSize; + const sourceImpressions = { ixImps, missingBannerImpressions }; + const impressionObjects = Object.keys(sourceImpressions) + .map((key) => sourceImpressions[key]) + .filter(item => Array.isArray(item)) + .reduce((acc, curr) => acc.concat(...curr), []); - for (let i = 0; i < _bannerImpression.banner.format.length; i++) { - // We add sid in imp.ext.sid therefore, remove from banner.format[].ext - if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { - delete _bannerImpression.banner.format[i].ext.sid; - } + currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; - // add floor per size - if ('bidfloor' in impressionObjects[i]) { - _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor - } - } + if (!build_request_v2) { + while (impressionObjects.length && currentImpressionSize > remainingRequestSize) { + wasAdUnitImpressionsTrimmed = true; + impressionObjects.pop(); + currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; + } + } - const position = impressions[transactionIds[adUnitIndex]].pos; - if (isInteger(position)) { - _bannerImpression.banner.pos = position; - } + const gpid = impressions[transactionIds[adUnitIndex]].gpid; + const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code; + const tid = impressions[transactionIds[adUnitIndex]].tid; + const sid = impressions[transactionIds[adUnitIndex]].sid - if (dfpAdUnitCode || gpid || tid || sid) { - _bannerImpression.ext = {}; - _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; - _bannerImpression.ext.gpid = gpid; - _bannerImpression.ext.tid = tid; - _bannerImpression.ext.sid = sid; - } + if (impressionObjects.length && BANNER in impressionObjects[0]) { + const { id, banner: { topframe } } = impressionObjects[0]; + const _bannerImpression = { + id, + banner: { + topframe, + format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext })) + }, + }; - if ('bidfloor' in impressionObjects[0]) { - _bannerImpression.bidfloor = impressionObjects[0].bidfloor; + for (let i = 0; i < _bannerImpression.banner.format.length; i++) { + // We add sid in imp.ext.sid therefore, remove from banner.format[].ext + if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) { + delete _bannerImpression.banner.format[i].ext.sid; } - if ('bidfloorcur' in impressionObjects[0]) { - _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; + // add floor per size + if ('bidfloor' in impressionObjects[i]) { + _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor; } + } - r.imp.push(_bannerImpression); - } else { - // set imp.ext.gpid to resolved gpid for each imp - impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); - r.imp.push(...impressionObjects); + const position = impressions[transactionIds[adUnitIndex]].pos; + if (isInteger(position)) { + _bannerImpression.banner.pos = position; } - const fpd = deepAccess(bidderRequest, 'ortb2') || {}; - if (!isEmpty(fpd) && !isFpdAdded) { - r.ext.ixdiag.fpd = true; + if (dfpAdUnitCode || gpid || tid || sid) { + _bannerImpression.ext = {}; + _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode; + _bannerImpression.ext.gpid = gpid; + _bannerImpression.ext.tid = tid; + _bannerImpression.ext.sid = sid; + } - const site = { ...(fpd.site || fpd.context) }; + if ('bidfloor' in impressionObjects[0]) { + _bannerImpression.bidfloor = impressionObjects[0].bidfloor; + } - Object.keys(site).forEach(key => { - if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { - delete site[key]; - } - }); + if ('bidfloorcur' in impressionObjects[0]) { + _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur; + } - const user = { ...fpd.user }; + r.imp.push(_bannerImpression); + } else { + // set imp.ext.gpid to resolved gpid for each imp + impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid)); + r.imp.push(...impressionObjects); + } - Object.keys(user).forEach(key => { - if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { - delete user[key]; - } - }); + return r; +} - if (fpd.device) { - const sua = {...fpd.device.sua}; - if (!isEmpty(sua)) { - deepSetValue(r, 'device.sua', sua); - } - } +function addFPD(bidderRequest, r, fpd, site, user) { + r.ext.ixdiag.fpd = true; - if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { - if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { - deepSetValue(r, 'regs.gpp', fpd.regs.gpp) - } + Object.keys(site).forEach(key => { + if (FIRST_PARTY_DATA.SITE.indexOf(key) === -1) { + delete site[key]; + } + }); - if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { - deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) - } - } + Object.keys(user).forEach(key => { + if (FIRST_PARTY_DATA.USER.indexOf(key) === -1) { + delete user[key]; + } + }); - const clonedRObject = deepClone(r); + if (fpd.device) { + const sua = {...fpd.device.sua}; + if (!isEmpty(sua)) { + deepSetValue(r, 'device.sua', sua); + } + } - clonedRObject.site = mergeDeep({}, clonedRObject.site, site); - clonedRObject.user = mergeDeep({}, clonedRObject.user, user); - - r.site = mergeDeep({}, r.site, site); - r.user = mergeDeep({}, r.user, user); - isFpdAdded = true; - + if (fpd.hasOwnProperty('regs') && !bidderRequest.gppConsent) { + if (fpd.regs.hasOwnProperty('gpp') && typeof fpd.regs.gpp == 'string') { + deepSetValue(r, 'regs.gpp', fpd.regs.gpp) } - // add identifiers info to ixDiag - const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; - const tagId = impressions[transactionIds[adUnitIndex]].tagId; - const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; - const divId = impressions[transactionIds[adUnitIndex]].divId; - if (pbaAdSlot || tagId || adUnitCode || divId) { + if (fpd.regs.hasOwnProperty('gpp_sid') && Array.isArray(fpd.regs.gpp_sid)) { + deepSetValue(r, 'regs.gpp_sid', fpd.regs.gpp_sid) + } + } + + return r; +} + +function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, build_request_v2) { + const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; + const tagId = impressions[transactionIds[adUnitIndex]].tagId; + const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; + const divId = impressions[transactionIds[adUnitIndex]].divId; + if (pbaAdSlot || tagId || adUnitCode || divId) { + const clonedRObject = deepClone(r); + const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; + if (!build_request_v2) { + if (requestSize < MAX_REQUEST_SIZE) { + r.ext.ixdiag.pbadslot = pbaAdSlot; + r.ext.ixdiag.tagid = tagId; + r.ext.ixdiag.adunitcode = adUnitCode; + r.ext.ixdiag.divId = divId; + } + } else { r.ext.ixdiag.pbadslot = pbaAdSlot; r.ext.ixdiag.tagid = tagId; r.ext.ixdiag.adunitcode = adUnitCode; r.ext.ixdiag.divId = divId; } - - const isLastAdUnit = adUnitIndex === transactionIds.length - 1; - - if (isLastAdUnit) { - requests.push({ - method: 'POST', - url: baseUrl + '?s=' + siteID, - data: deepClone(r), - option: { - contentType: 'text/plain', - }, - validBidRequests - }); - - r.imp = []; - isFpdAdded = false; - } } - return requests; + return r; } /** @@ -1827,26 +1579,14 @@ export const spec = { } // Step 4: Build banner, video & native requests - if (FEATURE_TOGGLES.isFeatureEnabled("pbjs_use_build_request_v2")) { - if (Object.keys(bannerImps).length > 0) { - reqs.push(...buildRequest_v2(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION)); - } - if (Object.keys(videoImps).length > 0) { - reqs.push(...buildRequest_v2(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION)); - } - if (Object.keys(nativeImps).length > 0) { - reqs.push(...buildRequest_v2(validBidRequests, bidderRequest, nativeImps)); - } - } else { - if (Object.keys(bannerImps).length > 0) { - reqs.push(...buildRequest(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION)); - } - if (Object.keys(videoImps).length > 0) { - reqs.push(...buildRequest(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION)); - } - if (Object.keys(nativeImps).length > 0) { - reqs.push(...buildRequest(validBidRequests, bidderRequest, nativeImps)); - } + if (Object.keys(bannerImps).length > 0) { + reqs.push(...buildRequest(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION)); + } + if (Object.keys(videoImps).length > 0) { + reqs.push(...buildRequest(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION)); + } + if (Object.keys(nativeImps).length > 0) { + reqs.push(...buildRequest(validBidRequests, bidderRequest, nativeImps)); } return reqs; diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 2327376d9ac..ed95d0dc490 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -3625,7 +3625,7 @@ describe('IndexexchangeAdapter', function () { expect(lsData.features.pbjs_use_32kb_size_limit.activated).to.be.true; }); - it('6 ad units should generate only 2 requests if 32kb size limit FT is enabled', function () { + it('6 ad units should generate only 3 requests if 32kb size limit FT is enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { activated: true @@ -3660,13 +3660,71 @@ describe('IndexexchangeAdapter', function () { const requests = spec.buildRequests([bid1, bid2, bid3, bid4, bid5, bid6], DEFAULT_OPTION); expect(requests).to.be.an('array'); - // 32KB size limit causes only 2 requests to get generated. - expect(requests).to.have.lengthOf(2); + // 32KB size limit causes only 3 requests to get generated. + expect(requests).to.have.lengthOf(3); + for (let request of requests) { + expect(request.method).to.equal('POST'); + } + }); + + it('6 ad units should generate only 1 request if build_request_v2 FT is enabled', function () { + sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + serverResponse.body.ext.features.pbjs_use_build_request_v2 = { + activated: true + }; + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + + const bid1 = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid1.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; + bid1.params.siteId = '121'; + bid1.adUnitCode = 'div-gpt-1' + bid1.transactionId = 'tr1'; + bid1.bidId = '2f6g5s5e'; + + const bid2 = utils.deepClone(bid1); + bid2.transactionId = 'tr2'; + + const bid3 = utils.deepClone(bid1); + bid3.transactionId = 'tr3'; + + const bid4 = utils.deepClone(bid1); + bid4.transactionId = 'tr4'; + + const bid5 = utils.deepClone(bid1); + bid5.transactionId = 'tr5'; + + const bid6 = utils.deepClone(bid1); + bid6.transactionId = 'tr6'; + + const requests = spec.buildRequests([bid1, bid2, bid3, bid4, bid5, bid6], DEFAULT_OPTION); + + expect(requests).to.be.an('array'); + // buildRequestv2 enabled causes only 1 requests to get generated. + expect(requests).to.have.lengthOf(1); for (let request of requests) { expect(request.method).to.equal('POST'); } }); + it('1 request with 2 ad units, build_request_v2 enabled', function () { + sandbox.stub(storage, 'localStorageIsEnabled').returns(true); + serverResponse.body.ext.features.pbjs_use_build_request_v2 = { + activated: true + }; + FEATURE_TOGGLES.setFeatureToggles(serverResponse); + + const bid = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); + bid.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; + bid.params.siteId = '124'; + bid.adUnitCode = 'div-gpt-1' + bid.transactionId = '152e36d1-1241-4242-t35e-y1dv34d12315'; + bid.bidId = '2f6g5s5e'; + + const requests = spec.buildRequests([bid, DEFAULT_BANNER_VALID_BID[0]], DEFAULT_OPTION); + expect(requests).to.be.an('array'); + expect(requests).to.have.lengthOf(1); + }); + it('4 ad units should generate only 1 requests if 32kb size limit FT is enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { From 448a7511127146f393535cbe9cf4bc142557e965 Mon Sep 17 00:00:00 2001 From: "shahin.rahbariasl" Date: Mon, 23 Jan 2023 22:28:02 -0500 Subject: [PATCH 3/7] feat: remove splitting logic behind ft [PB-1389] --- modules/ixBidAdapter.js | 26 +++++++++++++------------- test/spec/modules/ixBidAdapter_spec.js | 8 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 45fa44fd6d0..ab5171ceadb 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -155,7 +155,7 @@ var baseRequestSize = 0; var currentRequestSize = 0; var wasAdUnitImpressionsTrimmed = false; var currentImpressionSize = 0; -var build_request_v2 = false; +var buildRequestV2 = false; /** * Transform valid bid request config object to banner impression object that will be sent to ad server. @@ -599,7 +599,7 @@ function getEidInfo(allEids) { */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { // V2 does not have request splitting logic. - build_request_v2 = FEATURE_TOGGLES.isFeatureEnabled("pbjs_use_build_request_v2"); + buildRequestV2 = FEATURE_TOGGLES.isFeatureEnabled("pbjs_use_buildRequestV2"); baseRequestSize = 0; currentRequestSize = 0; wasAdUnitImpressionsTrimmed = false; @@ -613,7 +613,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { let MAX_REQUEST_SIZE = 8000; // Modify request size limit if its FT is enabeld. - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_32kb_size_limit') || FEATURE_TOGGLES.isFeatureEnabled('build_request_v2')) { + if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_32kb_size_limit') || FEATURE_TOGGLES.isFeatureEnabled('buildRequestV2')) { MAX_REQUEST_SIZE = 32000; } @@ -642,14 +642,14 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r = applyRegulations(r, bidderRequest); let payload = {}; - createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, build_request_v2); + createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, buildRequestV2); let requestSequenceNumber = 0; const transactionIds = Object.keys(impressions); let isFpdAdded = false; for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { - if (!build_request_v2) { + if (!buildRequestV2) { if (currentRequestSize >= MAX_REQUEST_SIZE) { break; } @@ -658,7 +658,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { break; } - r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, build_request_v2); + r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, buildRequestV2); currentRequestSize += currentImpressionSize; const fpd = deepAccess(bidderRequest, 'ortb2') || {}; @@ -686,7 +686,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { } // add identifiers info to ixDiag - r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, build_request_v2); + r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, buildRequestV2); const isLastAdUnit = adUnitIndex === transactionIds.length - 1; @@ -839,7 +839,7 @@ function applyRegulations(r, bidderRequest) { return r } -function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, build_request_v2) { +function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, buildRequestV2) { // Use the siteId in the first bid request as the main siteId. siteID = validBidRequests[0].params.siteId; payload.s = siteID; @@ -872,7 +872,7 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa fpdRequestSize = encodeURIComponent(firstPartyString).length; - if (!build_request_v2) { + if (!buildRequestV2) { if (fpdRequestSize < MAX_REQUEST_SIZE) { if ('page' in r.site) { r.site.page += firstPartyString; @@ -894,7 +894,7 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa } } -function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, build_request_v2) { +function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, buildRequestV2) { const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; @@ -907,7 +907,7 @@ function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; - if (!build_request_v2) { + if (!buildRequestV2) { while (impressionObjects.length && currentImpressionSize > remainingRequestSize) { wasAdUnitImpressionsTrimmed = true; impressionObjects.pop(); @@ -1008,7 +1008,7 @@ function addFPD(bidderRequest, r, fpd, site, user) { return r; } -function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, build_request_v2) { +function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, buildRequestV2) { const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; const tagId = impressions[transactionIds[adUnitIndex]].tagId; const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; @@ -1016,7 +1016,7 @@ function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload if (pbaAdSlot || tagId || adUnitCode || divId) { const clonedRObject = deepClone(r); const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; - if (!build_request_v2) { + if (!buildRequestV2) { if (requestSize < MAX_REQUEST_SIZE) { r.ext.ixdiag.pbadslot = pbaAdSlot; r.ext.ixdiag.tagid = tagId; diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index ed95d0dc490..77fcf44187f 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -3667,9 +3667,9 @@ describe('IndexexchangeAdapter', function () { } }); - it('6 ad units should generate only 1 request if build_request_v2 FT is enabled', function () { + it('6 ad units should generate only 1 request if buildRequestV2 FT is enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_build_request_v2 = { + serverResponse.body.ext.features.pbjs_use_buildRequestV2 = { activated: true }; FEATURE_TOGGLES.setFeatureToggles(serverResponse); @@ -3706,9 +3706,9 @@ describe('IndexexchangeAdapter', function () { } }); - it('1 request with 2 ad units, build_request_v2 enabled', function () { + it('1 request with 2 ad units, buildRequestV2 enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_build_request_v2 = { + serverResponse.body.ext.features.pbjs_use_buildRequestV2 = { activated: true }; FEATURE_TOGGLES.setFeatureToggles(serverResponse); From 66071ef521244c9b5d083c6416f8bd32d1ae2ee2 Mon Sep 17 00:00:00 2001 From: "shahin.rahbariasl" Date: Mon, 23 Jan 2023 22:29:02 -0500 Subject: [PATCH 4/7] feat: remove splitting logic behind ft [PB-1389] --- modules/ixBidAdapter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index ab5171ceadb..7958430be61 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -599,7 +599,7 @@ function getEidInfo(allEids) { */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { // V2 does not have request splitting logic. - buildRequestV2 = FEATURE_TOGGLES.isFeatureEnabled("pbjs_use_buildRequestV2"); + buildRequestV2 = FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2'); baseRequestSize = 0; currentRequestSize = 0; wasAdUnitImpressionsTrimmed = false; @@ -854,7 +854,7 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE }); return requests; } - + currentRequestSize = baseRequestSize; let fpdRequestSize = 0; @@ -889,7 +889,7 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa } else { r.site.page = firstPartyString; } - } + } } } } From 110974272a59a740b58a61ed188fcb06e09cd944 Mon Sep 17 00:00:00 2001 From: "shahin.rahbariasl" Date: Mon, 23 Jan 2023 22:33:33 -0500 Subject: [PATCH 5/7] feat: remove splitting logic behind ft [PB-1389] --- modules/ixBidAdapter.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 7958430be61..4d5deb09e13 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -151,11 +151,11 @@ const MEDIA_TYPES = { Native: 4 }; -var baseRequestSize = 0; -var currentRequestSize = 0; -var wasAdUnitImpressionsTrimmed = false; -var currentImpressionSize = 0; -var buildRequestV2 = false; +let baseRequestSize = 0; +let currentRequestSize = 0; +let wasAdUnitImpressionsTrimmed = false; +let currentImpressionSize = 0; +let buildRequestV2 = false; /** * Transform valid bid request config object to banner impression object that will be sent to ad server. From 17444b8e38e4583dee38ff10642fd7e4fa29d052 Mon Sep 17 00:00:00 2001 From: "shahin.rahbariasl" Date: Wed, 25 Jan 2023 13:25:23 -0500 Subject: [PATCH 6/7] feat: remove splitting logic behind ft [PB-1389] --- modules/ixBidAdapter.js | 4 -- test/spec/modules/ixBidAdapter_spec.js | 93 -------------------------- 2 files changed, 97 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 4d5deb09e13..48bb157ea36 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -612,10 +612,6 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { let userEids = eidInfo.toSend; let MAX_REQUEST_SIZE = 8000; - // Modify request size limit if its FT is enabeld. - if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_32kb_size_limit') || FEATURE_TOGGLES.isFeatureEnabled('buildRequestV2')) { - MAX_REQUEST_SIZE = 32000; - } // RTI ids will be included in the bid request if the function getIdentityInfo() is loaded // and if the data for the partner exist diff --git a/test/spec/modules/ixBidAdapter_spec.js b/test/spec/modules/ixBidAdapter_spec.js index 77fcf44187f..e4cc35ee706 100644 --- a/test/spec/modules/ixBidAdapter_spec.js +++ b/test/spec/modules/ixBidAdapter_spec.js @@ -3610,63 +3610,6 @@ describe('IndexexchangeAdapter', function () { expect(FEATURE_TOGGLES.featureToggles).to.deep.equal({}); }); - it('should set request size limit to 32KB when its feature enabled', () => { - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { - activated: true - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - const bid = utils.deepClone(DEFAULT_MULTIFORMAT_VIDEO_VALID_BID[0]); - bid.bidderRequestId = Array(10000).join('#'); - - expect(spec.isBidRequestValid(bid)).to.be.true; - spec.buildRequests([bid], {}); - const lsData = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_FEATURE_TOGGLES_KEY)); - expect(lsData.features.pbjs_use_32kb_size_limit.activated).to.be.true; - }); - - it('6 ad units should generate only 3 requests if 32kb size limit FT is enabled', function () { - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { - activated: true - }; - serverResponse.body.ext.features.pbjs_enable_post = { - activated: true - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - - const bid1 = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); - bid1.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; - bid1.params.siteId = '121'; - bid1.adUnitCode = 'div-gpt-1' - bid1.transactionId = 'tr1'; - bid1.bidId = '2f6g5s5e'; - - const bid2 = utils.deepClone(bid1); - bid2.transactionId = 'tr2'; - - const bid3 = utils.deepClone(bid1); - bid3.transactionId = 'tr3'; - - const bid4 = utils.deepClone(bid1); - bid4.transactionId = 'tr4'; - - const bid5 = utils.deepClone(bid1); - bid5.transactionId = 'tr5'; - - const bid6 = utils.deepClone(bid1); - bid6.transactionId = 'tr6'; - - const requests = spec.buildRequests([bid1, bid2, bid3, bid4, bid5, bid6], DEFAULT_OPTION); - - expect(requests).to.be.an('array'); - // 32KB size limit causes only 3 requests to get generated. - expect(requests).to.have.lengthOf(3); - for (let request of requests) { - expect(request.method).to.equal('POST'); - } - }); - it('6 ad units should generate only 1 request if buildRequestV2 FT is enabled', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); serverResponse.body.ext.features.pbjs_use_buildRequestV2 = { @@ -3724,42 +3667,6 @@ describe('IndexexchangeAdapter', function () { expect(requests).to.be.an('array'); expect(requests).to.have.lengthOf(1); }); - - it('4 ad units should generate only 1 requests if 32kb size limit FT is enabled', function () { - sandbox.stub(storage, 'localStorageIsEnabled').returns(true); - serverResponse.body.ext.features.pbjs_use_32kb_size_limit = { - activated: true - }; - serverResponse.body.ext.features.pbjs_enable_post = { - activated: true - }; - FEATURE_TOGGLES.setFeatureToggles(serverResponse); - - const bid1 = utils.deepClone(DEFAULT_BANNER_VALID_BID[0]); - bid1.mediaTypes.banner.sizes = LARGE_SET_OF_SIZES; - bid1.params.siteId = '121'; - bid1.adUnitCode = 'div-gpt-1' - bid1.transactionId = 'tr1'; - bid1.bidId = '2f6g5s5e'; - - const bid2 = utils.deepClone(bid1); - bid2.transactionId = 'tr2'; - - const bid3 = utils.deepClone(bid1); - bid3.transactionId = 'tr3'; - - const bid4 = utils.deepClone(bid1); - bid4.transactionId = 'tr4'; - - const requests = spec.buildRequests([bid1, bid2, bid3, bid4], DEFAULT_OPTION); - - expect(requests).to.be.an('array'); - // 32KB size limit causes only 1 requests to get generated. - expect(requests).to.have.lengthOf(1); - for (let request of requests) { - expect(request.method).to.equal('POST'); - } - }); }); describe('LocalStorage error codes', () => { From 5c02d615f870654088003c69182415253880b29c Mon Sep 17 00:00:00 2001 From: "shahin.rahbariasl" Date: Tue, 31 Jan 2023 12:04:16 -0500 Subject: [PATCH 7/7] feat: remove splitting logic behind ft [PB-1389] --- modules/ixBidAdapter.js | 95 +++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 13 deletions(-) diff --git a/modules/ixBidAdapter.js b/modules/ixBidAdapter.js index 48bb157ea36..1f96410e922 100644 --- a/modules/ixBidAdapter.js +++ b/modules/ixBidAdapter.js @@ -155,7 +155,6 @@ let baseRequestSize = 0; let currentRequestSize = 0; let wasAdUnitImpressionsTrimmed = false; let currentImpressionSize = 0; -let buildRequestV2 = false; /** * Transform valid bid request config object to banner impression object that will be sent to ad server. @@ -598,8 +597,6 @@ function getEidInfo(allEids) { * */ function buildRequest(validBidRequests, bidderRequest, impressions, version) { - // V2 does not have request splitting logic. - buildRequestV2 = FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2'); baseRequestSize = 0; currentRequestSize = 0; wasAdUnitImpressionsTrimmed = false; @@ -638,14 +635,15 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { r = applyRegulations(r, bidderRequest); let payload = {}; - createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, buildRequestV2); + createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE); let requestSequenceNumber = 0; const transactionIds = Object.keys(impressions); let isFpdAdded = false; for (let adUnitIndex = 0; adUnitIndex < transactionIds.length; adUnitIndex++) { - if (!buildRequestV2) { + // buildRequestV2 does not have request spliting logic. + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { if (currentRequestSize >= MAX_REQUEST_SIZE) { break; } @@ -654,7 +652,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { break; } - r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, buildRequestV2); + r = addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE); currentRequestSize += currentImpressionSize; const fpd = deepAccess(bidderRequest, 'ortb2') || {}; @@ -682,7 +680,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { } // add identifiers info to ixDiag - r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, buildRequestV2); + r = addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE); const isLastAdUnit = adUnitIndex === transactionIds.length - 1; @@ -712,6 +710,12 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) { return requests; } +/** + * addRTI adds RTI info of the partner to retrieved user IDs from prebid ID module. + * + * @param {array} userEids userEids info retrieved from prebid + * @param {array} eidInfo eidInfo info from prebid + */ function addRTI(userEids, eidInfo) { let identityInfo = window.headertag.getIdentityInfo(); if (identityInfo && typeof identityInfo === 'object') { @@ -727,6 +731,11 @@ function addRTI(userEids, eidInfo) { } } +/** + * createRequest creates the base request object + * @param {array} validBidRequests A list of valid bid request config objects. + * @return {object} Object describing the request to the server. + */ function createRequest(validBidRequests) { const r = {}; // Since bidderRequestId are the same for different bid request, just use the first one. @@ -741,6 +750,16 @@ function createRequest(validBidRequests) { return r } +/** + * enrichRequest adds userSync configs, source, and referer info to request and ixDiag objects. + * + * @param {object} r Base reuqest object. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {array} impressions A list of impressions to be added to the request. + * @param {array} validBidRequests A list of valid bid request config objects. + * @param {array} userEids User ID info retrieved from Prebid ID module. + * @return {object} Enriched object describing the request to the server. + */ function enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids) { const tmax = deepAccess(bidderRequest, 'timeout'); if (tmax) { @@ -784,6 +803,13 @@ function enrichRequest(r, bidderRequest, impressions, validBidRequests, userEids return r } +/** + * applyRegulations applies regulation info such as GDPR and GPP to the reqeust obejct. + * + * @param {object} r Base reuqest object. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @return {object} Object enriched with regulation info describing the request to the server. + */ function applyRegulations(r, bidderRequest) { // Apply GDPR information to the request if GDPR is enabled. if (bidderRequest) { @@ -835,7 +861,18 @@ function applyRegulations(r, bidderRequest) { return r } -function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE, buildRequestV2) { +/** + * createPayload creates the payload to be sent with the request. + * + * @param {array} validBidRequests A list of valid bid request config objects. + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {object} r Reuqest object. + * @param {string} baseUrl Base exchagne URL. + * @param {array} requests List of request obejcts. + * @param {object} payload Request payload object. + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + */ +function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, payload, MAX_REQUEST_SIZE) { // Use the siteId in the first bid request as the main siteId. siteID = validBidRequests[0].params.siteId; payload.s = siteID; @@ -868,7 +905,7 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa fpdRequestSize = encodeURIComponent(firstPartyString).length; - if (!buildRequestV2) { + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { if (fpdRequestSize < MAX_REQUEST_SIZE) { if ('page' in r.site) { r.site.page += firstPartyString; @@ -890,7 +927,17 @@ function createPayload(validBidRequests, bidderRequest, r, baseUrl, requests, pa } } -function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE, buildRequestV2) { +/** + * addImpressions adds impressions to request object + * + * @param {array} impressions List of impressions to be added to the request. + * @param {array} transactionIds List of transaction Ids. + * @param {object} r Reuqest object. + * @param {int} adUnitIndex Index of the current add unit + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + * @return {object} Reqyest object with added impressions describing the request to the server. + */ +function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST_SIZE) { const adUnitImpressions = impressions[transactionIds[adUnitIndex]]; const { missingImps: missingBannerImpressions = [], ixImps = [] } = adUnitImpressions; @@ -903,7 +950,7 @@ function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length; - if (!buildRequestV2) { + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { while (impressionObjects.length && currentImpressionSize > remainingRequestSize) { wasAdUnitImpressionsTrimmed = true; impressionObjects.pop(); @@ -969,6 +1016,16 @@ function addImpressions(impressions, transactionIds, r, adUnitIndex, MAX_REQUEST return r; } +/** + * addFPD adds ortb2 first party data to request object. + * + * @param {object} bidderRequest An object containing other info like gdprConsent. + * @param {object} r Reuqest object. + * @param {object} fpd ortb2 first party data. + * @param {object} site First party site data. + * @param {object} user First party user data. + * @return {object} Reqyest object with added FPD describing the request to the server. + */ function addFPD(bidderRequest, r, fpd, site, user) { r.ext.ixdiag.fpd = true; @@ -1004,7 +1061,19 @@ function addFPD(bidderRequest, r, fpd, site, user) { return r; } -function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE, buildRequestV2) { +/** + * addIdentifiersInfo adds indentifier info to ixDaig. + * + * @param {array} impressions List of impressions to be added to the request. + * @param {object} r Reuqest object. + * @param {array} transactionIds List of transaction Ids. + * @param {int} adUnitIndex Index of the current add unit + * @param {object} payload Request payload object. + * @param {string} baseUrl Base exchagne URL. + * @param {int} MAX_REQUEST_SIZE Maximum request size limit (buildrequest V1). + * @return {object} Reqyest object with added indentigfier info to ixDiag. + */ +function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload, baseUrl, MAX_REQUEST_SIZE) { const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot; const tagId = impressions[transactionIds[adUnitIndex]].tagId; const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode; @@ -1012,7 +1081,7 @@ function addIdentifiersInfo(impressions, r, transactionIds, adUnitIndex, payload if (pbaAdSlot || tagId || adUnitCode || divId) { const clonedRObject = deepClone(r); const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length; - if (!buildRequestV2) { + if (!FEATURE_TOGGLES.isFeatureEnabled('pbjs_use_buildRequestV2')) { if (requestSize < MAX_REQUEST_SIZE) { r.ext.ixdiag.pbadslot = pbaAdSlot; r.ext.ixdiag.tagid = tagId;