diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js
index 4f1eb298794..7ebe5dd0ecc 100644
--- a/modules/sovrnBidAdapter.js
+++ b/modules/sovrnBidAdapter.js
@@ -1,7 +1,9 @@
-import * as utils from 'src/utils';
-import { registerBidder } from 'src/adapters/bidderFactory';
-import { BANNER } from 'src/mediaTypes';
-import { REPO_AND_VERSION } from 'src/constants';
+import * as utils from 'src/utils'
+import { registerBidder } from 'src/adapters/bidderFactory'
+import { BANNER } from 'src/mediaTypes'
+import { REPO_AND_VERSION } from 'src/constants'
+const errorUrl = 'https://pcb.aws.lijit.com/c'
+let errorpxls = []
export const spec = {
code: 'sovrn',
@@ -22,48 +24,59 @@ export const spec = {
* @return object of parameters for Prebid AJAX request
*/
buildRequests: function(bidReqs, bidderRequest) {
- const loc = utils.getTopWindowLocation();
- let sovrnImps = [];
- let iv;
- utils._each(bidReqs, function (bid) {
- iv = iv || utils.getBidIdParameter('iv', bid.params);
- sovrnImps.push({
- id: bid.bidId,
- banner: { w: 1, h: 1 },
- tagid: String(utils.getBidIdParameter('tagid', bid.params)),
- bidfloor: utils.getBidIdParameter('bidfloor', bid.params)
+ try {
+ const loc = utils.getTopWindowLocation();
+ let sovrnImps = [];
+ let iv;
+ utils._each(bidReqs, function (bid) {
+ iv = iv || utils.getBidIdParameter('iv', bid.params);
+ bid.sizes = ((utils.isArray(bid.sizes) && utils.isArray(bid.sizes[0])) ? bid.sizes : [bid.sizes])
+ bid.sizes = bid.sizes.filter(size => utils.isArray(size))
+ const processedSizes = bid.sizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)}))
+ sovrnImps.push({
+ id: bid.bidId,
+ banner: {
+ format: processedSizes,
+ w: 1,
+ h: 1,
+ },
+ tagid: String(utils.getBidIdParameter('tagid', bid.params)),
+ bidfloor: utils.getBidIdParameter('bidfloor', bid.params)
+ });
});
- });
- const sovrnBidReq = {
- id: utils.getUniqueIdentifierStr(),
- imp: sovrnImps,
- site: {
- domain: loc.host,
- page: loc.host + loc.pathname + loc.search + loc.hash
- }
- };
+ const sovrnBidReq = {
+ id: utils.getUniqueIdentifierStr(),
+ imp: sovrnImps,
+ site: {
+ domain: loc.host,
+ page: loc.host + loc.pathname + loc.search + loc.hash
+ }
+ };
- if (bidderRequest && bidderRequest.gdprConsent) {
- sovrnBidReq.regs = {
- ext: {
- gdpr: +bidderRequest.gdprConsent.gdprApplies
- }};
- sovrnBidReq.user = {
- ext: {
- consent: bidderRequest.gdprConsent.consentString
- }};
- }
+ if (bidderRequest && bidderRequest.gdprConsent) {
+ sovrnBidReq.regs = {
+ ext: {
+ gdpr: +bidderRequest.gdprConsent.gdprApplies
+ }};
+ sovrnBidReq.user = {
+ ext: {
+ consent: bidderRequest.gdprConsent.consentString
+ }};
+ }
- let url = `//ap.lijit.com/rtb/bid?` +
- `src=${REPO_AND_VERSION}`;
- if (iv) url += `&iv=${iv}`;
+ let url = `//ap.lijit.com/rtb/bid?` +
+ `src=${REPO_AND_VERSION}`;
+ if (iv) url += `&iv=${iv}`;
- return {
- method: 'POST',
- url: url,
- data: JSON.stringify(sovrnBidReq),
- options: {contentType: 'text/plain'}
- };
+ return {
+ method: 'POST',
+ url: url,
+ data: JSON.stringify(sovrnBidReq),
+ options: {contentType: 'text/plain'}
+ }
+ } catch (e) {
+ new LogError(e, {bidReqs, bidderRequest}).append()
+ }
},
/**
@@ -72,48 +85,99 @@ export const spec = {
* @return {Bid[]} An array of formatted bids.
*/
interpretResponse: function({ body: {id, seatbid} }) {
- let sovrnBidResponses = [];
- if (id &&
- seatbid &&
- seatbid.length > 0 &&
- seatbid[0].bid &&
- seatbid[0].bid.length > 0) {
- seatbid[0].bid.map(sovrnBid => {
- sovrnBidResponses.push({
- requestId: sovrnBid.impid,
- cpm: parseFloat(sovrnBid.price),
- width: parseInt(sovrnBid.w),
- height: parseInt(sovrnBid.h),
- creativeId: sovrnBid.crid || sovrnBid.id,
- dealId: sovrnBid.dealid || null,
- currency: 'USD',
- netRevenue: true,
- mediaType: BANNER,
- ad: decodeURIComponent(`${sovrnBid.adm}`),
- ttl: 60
+ try {
+ let sovrnBidResponses = [];
+ if (id &&
+ seatbid &&
+ seatbid.length > 0 &&
+ seatbid[0].bid &&
+ seatbid[0].bid.length > 0) {
+ seatbid[0].bid.map(sovrnBid => {
+ sovrnBidResponses.push({
+ requestId: sovrnBid.impid,
+ cpm: parseFloat(sovrnBid.price),
+ width: parseInt(sovrnBid.w),
+ height: parseInt(sovrnBid.h),
+ creativeId: sovrnBid.crid || sovrnBid.id,
+ dealId: sovrnBid.dealid || null,
+ currency: 'USD',
+ netRevenue: true,
+ mediaType: BANNER,
+ ad: decodeURIComponent(`${sovrnBid.adm}`),
+ ttl: 60
+ });
});
- });
+ }
+ return sovrnBidResponses
+ } catch (e) {
+ new LogError(e, {id, seatbid}).append()
}
- return sovrnBidResponses;
},
getUserSyncs: function(syncOptions, serverResponses, gdprConsent) {
- if (serverResponses && serverResponses.length !== 0 && syncOptions.iframeEnabled) {
- let iidArr = serverResponses.filter(rsp => rsp.body && rsp.body.ext && rsp.body.ext.iid)
- .map(rsp => { return rsp.body.ext.iid });
- let consentString = '';
- if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') {
- consentString = gdprConsent.consentString
+ try {
+ let tracks = []
+ if (serverResponses && serverResponses.length !== 0 && syncOptions.iframeEnabled) {
+ let iidArr = serverResponses.filter(rsp => rsp.body && rsp.body.ext && rsp.body.ext.iid)
+ .map(rsp => { return rsp.body.ext.iid });
+ let consentString = '';
+ if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') {
+ consentString = gdprConsent.consentString
+ }
+ if (iidArr[0]) {
+ tracks.push({
+ type: 'iframe',
+ url: '//ap.lijit.com/beacon?informer=' + iidArr[0] + '&gdpr_consent=' + consentString,
+ });
+ }
+ }
+ if (errorpxls.length && syncOptions.pixelEnabled) {
+ tracks = tracks.concat(errorpxls)
}
- if (iidArr[0]) {
- return [{
- type: 'iframe',
- url: '//ap.lijit.com/beacon?informer=' + iidArr[0] + '&gdpr_consent=' + consentString,
- }];
+ return tracks
+ } catch (e) {
+ if (syncOptions.pixelEnabled) {
+ return errorpxls
}
+ return []
}
- return [];
},
-};
+}
+
+export class LogError {
+ constructor(e, data) {
+ utils.logError(e)
+ this.error = {}
+ this.error.t = utils.timestamp()
+ this.error.m = e.message
+ this.error.s = e.stack
+ this.error.d = data
+ this.error.v = REPO_AND_VERSION
+ this.error.u = utils.getTopWindowLocation().href
+ this.error.ua = navigator.userAgent
+ }
+ buildErrorString(obj) {
+ return errorUrl + '?b=' + btoa(JSON.stringify(obj))
+ }
+ append() {
+ let errstr = this.buildErrorString(this.error)
+ if (errstr.length > 2083) {
+ delete this.error.d
+ errstr = this.buildErrorString(this.error)
+ if (errstr.length > 2083) {
+ delete this.error.s
+ errstr = this.buildErrorString(this.error)
+ if (errstr.length > 2083) {
+ errstr = this.buildErrorString({m: 'unknown error message', t: this.error.t, u: this.error.u})
+ }
+ }
+ }
+ let obj = {type: 'image', url: errstr}
+ errorpxls.push(obj)
+ }
+ static getErrPxls() {
+ return errorpxls
+ }
+}
registerBidder(spec);
diff --git a/test/spec/modules/sovrnBidAdapter_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js
index 22c93505ecf..a774aa64062 100644
--- a/test/spec/modules/sovrnBidAdapter_spec.js
+++ b/test/spec/modules/sovrnBidAdapter_spec.js
@@ -1,7 +1,8 @@
import { expect } from 'chai';
-import { spec } from 'modules/sovrnBidAdapter';
+import { spec, LogError } from 'modules/sovrnBidAdapter';
import { newBidder } from 'src/adapters/bidderFactory';
import { REPO_AND_VERSION } from 'src/constants';
+import { SSL_OP_SINGLE_ECDH_USE } from 'constants';
const ENDPOINT = `//ap.lijit.com/rtb/bid?src=${REPO_AND_VERSION}`;
@@ -16,7 +17,8 @@ describe('sovrnBidAdapter', function() {
},
'adUnitCode': 'adunit-code',
'sizes': [
- [300, 250]
+ [300, 250],
+ [300, 600]
],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
@@ -47,7 +49,8 @@ describe('sovrnBidAdapter', function() {
},
'adUnitCode': 'adunit-code',
'sizes': [
- [300, 250]
+ [300, 250],
+ [300, 600]
],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
@@ -64,6 +67,33 @@ describe('sovrnBidAdapter', function() {
expect(request.url).to.equal(ENDPOINT)
});
+ it('sets the proper banner object', function() {
+ const payload = JSON.parse(request.data);
+ expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}, {w: 300, h: 600}])
+ expect(payload.imp[0].banner.w).to.equal(1)
+ expect(payload.imp[0].banner.h).to.equal(1)
+ })
+
+ it('accepts a single array as a size', function() {
+ const singleSize = [{
+ 'bidder': 'sovrn',
+ 'params': {
+ 'tagid': '403370',
+ 'iv': 'vet'
+ },
+ 'adUnitCode': 'adunit-code',
+ 'sizes': [300, 250],
+ 'bidId': '30b31c1838de1e',
+ 'bidderRequestId': '22edbae2733bf6',
+ 'auctionId': '1d1a030790a475'
+ }];
+ const request = spec.buildRequests(singleSize)
+ const payload = JSON.parse(request.data)
+ expect(payload.imp[0].banner.format).to.deep.equal([{w: 300, h: 250}])
+ expect(payload.imp[0].banner.w).to.equal(1)
+ expect(payload.imp[0].banner.h).to.equal(1)
+ })
+
it('sends \'iv\' as query param if present', function () {
const ivBidRequests = [{
'bidder': 'sovrn',
@@ -73,7 +103,8 @@ describe('sovrnBidAdapter', function() {
},
'adUnitCode': 'adunit-code',
'sizes': [
- [300, 250]
+ [300, 250],
+ [300, 600]
],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
@@ -116,7 +147,8 @@ describe('sovrnBidAdapter', function() {
},
'adUnitCode': 'adunit-code',
'sizes': [
- [300, 250]
+ [300, 250],
+ [300, 600]
],
'bidId': '30b31c1838de1e',
'bidderRequestId': '22edbae2733bf6',
@@ -268,19 +300,99 @@ describe('sovrnBidAdapter', function() {
'type': 'iframe',
'url': '//ap.lijit.com/beacon?informer=13487408&gdpr_consent=',
}
- ];
+ ]
let returnStatement = spec.getUserSyncs(syncOptions, serverResponse);
expect(returnStatement[0]).to.deep.equal(expectedReturnStatement[0]);
- });
+ })
it('should not return if iid missing on server response', () => {
- let returnStatement = spec.getUserSyncs(syncOptions, []);
+ let returnStatement = spec.getUserSyncs(syncOptions, [])
expect(returnStatement).to.be.empty;
- });
+ })
it('should not return if iframe syncs disabled', () => {
- let returnStatement = spec.getUserSyncs(iframeDisabledSyncOptions, serverResponse);
- expect(returnStatement).to.be.empty;
- });
- });
-});
+ let returnStatement = spec.getUserSyncs(iframeDisabledSyncOptions, serverResponse)
+ expect(returnStatement).to.be.empty
+ })
+ })
+ describe('LogError', () => {
+ it('should build and append an error object', () => {
+ const thrown = {
+ message: 'message',
+ stack: 'stack'
+ }
+ const data = {name: 'Oscar Hathenswiotch'}
+ const err = new LogError(thrown, data)
+ err.append()
+ const errList = LogError.getErrPxls()
+ expect(errList.length).to.equal(1)
+ const errdata = JSON.parse(atob(errList[0].url.split('=')[1]))
+ expect(errdata.d.name).to.equal('Oscar Hathenswiotch')
+ })
+ it('should drop data when there is too much', () => {
+ const thrown = {
+ message: 'message',
+ stack: 'stack'
+ }
+ const tooLong = () => {
+ let str = ''
+ for (let i = 0; i < 10000; i++) {
+ str = str + String.fromCharCode(i % 100)
+ }
+ return str
+ }
+ const data = {name: 'Oscar Hathenswiotch', tooLong: tooLong()}
+ const err = new LogError(thrown, data)
+ err.append()
+ const errList = LogError.getErrPxls()
+ expect(errList.length).to.equal(2)
+ const errdata = JSON.parse(atob(errList[1].url.split('=')[1]))
+ expect(errdata.d).to.be.an('undefined')
+ })
+ it('should drop data and stack when there is too much', () => {
+ const thrown = {
+ message: 'message',
+ stack: 'stack'
+ }
+ const tooLong = () => {
+ let str = ''
+ for (let i = 0; i < 10000; i++) {
+ str = str + String.fromCharCode(i % 100)
+ }
+ return str
+ }
+ const data = {name: 'Oscar Hathenswiotch'}
+ thrown.stack = tooLong()
+ const err = new LogError(thrown, data)
+ err.append()
+ const errList = LogError.getErrPxls()
+ expect(errList.length).to.equal(3)
+ const errdata = JSON.parse(atob(errList[2].url.split('=')[1]))
+ expect(errdata.d).to.be.an('undefined')
+ expect(errdata.s).to.be.an('undefined')
+ })
+ it('should drop send a reduced message when other reduction methods fail', () => {
+ const thrown = {
+ message: 'message',
+ stack: 'stack'
+ }
+ const tooLong = () => {
+ let str = ''
+ for (let i = 0; i < 10000; i++) {
+ str = str + String.fromCharCode(i % 100)
+ }
+ return str
+ }
+ const data = {name: 'Oscar Hathenswiotch'}
+ thrown.message = tooLong()
+ const err = new LogError(thrown, data)
+ err.append()
+ const errList = LogError.getErrPxls()
+ expect(errList.length).to.equal(4)
+ const errdata = JSON.parse(atob(errList[3].url.split('=')[1]))
+ expect(errdata.d).to.be.an('undefined')
+ expect(errdata.s).to.be.an('undefined')
+ expect(errdata.m).to.equal('unknown error message')
+ })
+ })
+})