From 751ccf170ab6faea6fa76d5d6bb5c5aea38c06ff Mon Sep 17 00:00:00 2001 From: dbemiller Date: Tue, 24 Oct 2017 15:16:10 -0400 Subject: [PATCH] Make response headers available to the specs (#1748) * Updated the bidderFactory to make headers accessible to the spec files. * Updated the platform.io adapter to handle the new format. * Updated the jcm adapter. --- modules/adbutlerBidAdapter.js | 1 + modules/appnexusAstBidAdapter.js | 1 + modules/beachfrontBidAdapter.js | 1 + modules/jcmBidAdapter.js | 1 + modules/platformioBidAdapter.js | 2 +- modules/pulsepointLiteBidAdapter.js | 1 + modules/rubiconBidAdapter.js | 1 + src/adapters/bidderFactory.js | 25 +++++++++++++++++-- test/spec/modules/adbutlerBidAdapter_spec.js | 24 ++++++++++-------- .../modules/appnexusAstBidAdapter_spec.js | 8 +++--- .../spec/modules/beachfrontBidAdapter_spec.js | 8 +++--- test/spec/modules/jcmBidAdapter_spec.js | 4 +-- .../spec/modules/platformioBidAdapter_spec.js | 4 +-- .../modules/pulsepointLiteBidAdapter_spec.js | 6 ++--- test/spec/modules/rubiconBidAdapter_spec.js | 12 ++++----- test/spec/unit/core/bidderFactory_spec.js | 15 ++++++++--- 16 files changed, 75 insertions(+), 39 deletions(-) diff --git a/modules/adbutlerBidAdapter.js b/modules/adbutlerBidAdapter.js index f633eba98a3d..44a2ef49f51e 100644 --- a/modules/adbutlerBidAdapter.js +++ b/modules/adbutlerBidAdapter.js @@ -74,6 +74,7 @@ export const spec = { var width; var height; + serverResponse = serverResponse.body; if (serverResponse && serverResponse.status === 'SUCCESS' && bidObj) { CPM = serverResponse.cpm; minCPM = utils.getBidIdParameter('minCPM', bidObj.params); diff --git a/modules/appnexusAstBidAdapter.js b/modules/appnexusAstBidAdapter.js index c4e2686db15b..9a2cea8a229b 100644 --- a/modules/appnexusAstBidAdapter.js +++ b/modules/appnexusAstBidAdapter.js @@ -87,6 +87,7 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: function(serverResponse, {bidderRequest}) { + serverResponse = serverResponse.body; const bids = []; if (!serverResponse || serverResponse.error) { let errorMessage = `in response for ${bidderRequest.bidderCode} adapter`; diff --git a/modules/beachfrontBidAdapter.js b/modules/beachfrontBidAdapter.js index 2729dcdd3248..d4fcc3e3578e 100644 --- a/modules/beachfrontBidAdapter.js +++ b/modules/beachfrontBidAdapter.js @@ -23,6 +23,7 @@ export const spec = { }, interpretResponse(response, { bidRequest }) { + response = response.body; if (!response || !response.url || !response.bidPrice) { utils.logWarn(`No valid bids from ${spec.code} bidder`); return []; diff --git a/modules/jcmBidAdapter.js b/modules/jcmBidAdapter.js index 3e0e46b8b77a..4c9792a00f2b 100644 --- a/modules/jcmBidAdapter.js +++ b/modules/jcmBidAdapter.js @@ -44,6 +44,7 @@ export const spec = { interpretResponse: function(serverResponse) { const bidResponses = []; + serverResponse = serverResponse.body; // loop through serverResponses if (serverResponse) { if (serverResponse.bids) { diff --git a/modules/platformioBidAdapter.js b/modules/platformioBidAdapter.js index c33551ed3963..2fb23ab92b33 100644 --- a/modules/platformioBidAdapter.js +++ b/modules/platformioBidAdapter.js @@ -24,7 +24,7 @@ export const spec = { }; }, interpretResponse: (response, request) => ( - bidResponseAvailable(request, response) + bidResponseAvailable(request, response.body) ), }; function bidResponseAvailable(bidRequest, bidResponse) { diff --git a/modules/pulsepointLiteBidAdapter.js b/modules/pulsepointLiteBidAdapter.js index 00b5c014e98e..99a83871dd88 100644 --- a/modules/pulsepointLiteBidAdapter.js +++ b/modules/pulsepointLiteBidAdapter.js @@ -69,6 +69,7 @@ export const spec = { function bidResponseAvailable(bidRequest, bidResponse) { const idToImpMap = {}; const idToBidMap = {}; + bidResponse = bidResponse.body // extract the request bids and the response bids, keyed by impr-id const ortbRequest = parse(bidRequest.data); ortbRequest.imp.forEach(imp => { diff --git a/modules/rubiconBidAdapter.js b/modules/rubiconBidAdapter.js index 69981ba2b561..866e02bc258d 100644 --- a/modules/rubiconBidAdapter.js +++ b/modules/rubiconBidAdapter.js @@ -230,6 +230,7 @@ export const spec = { * @return {Bid[]} An array of bids which */ interpretResponse: function(responseObj, {bidRequest}) { + responseObj = responseObj.body let ads = responseObj.ads; // check overall response diff --git a/src/adapters/bidderFactory.js b/src/adapters/bidderFactory.js index 12b7b931a9be..87dfd372b9c6 100644 --- a/src/adapters/bidderFactory.js +++ b/src/adapters/bidderFactory.js @@ -44,7 +44,7 @@ import { logWarn, logError, parseQueryStringParameters, delayExecution } from 's * @property {function(BidRequest[], bidderRequest): ServerRequest|ServerRequest[]} buildRequests Build the request to the Server * which requests Bids for the given array of Requests. Each BidRequest in the argument array is guaranteed to have * passed the isBidRequestValid() test. - * @property {function(*, BidRequest): Bid[]} interpretResponse Given a successful response from the Server, + * @property {function(ServerResponse, BidRequest): Bid[]} interpretResponse Given a successful response from the Server, * interpret it and return the Bid objects. This function will be run inside a try/catch. * If it throws any errors, your bids will be discarded. * @property {function(SyncOptions, Array): UserSync[]} [getUserSyncs] Given an array of all the responses @@ -72,6 +72,15 @@ import { logWarn, logError, parseQueryStringParameters, delayExecution } from 's * JSON-serialized into the Request body. */ +/** + * @typedef {object} ServerResponse + * + * @property {*} body The response body. If this is legal JSON, then it will be parsed. Otherwise it'll be a + * string with the body's content. + * @property {{get: function(string): string} headers The response headers. + * Call this like `ServerResponse.headers.get("Content-Type")` + */ + /** * @typedef {object} Bid * @@ -263,10 +272,16 @@ export function newBidder(spec) { // If the server responds successfully, use the adapter code to unpack the Bids from it. // If the adapter code fails, no bids should be added. After all the bids have been added, make // sure to call the `onResponse` function so that we're one step closer to calling fillNoBids(). - function onSuccess(response) { + function onSuccess(response, responseObj) { try { response = JSON.parse(response); } catch (e) { /* response might not be JSON... that's ok. */ } + + // Make response headers available for #1742. These are lazy-loaded because most adapters won't need them. + response = { + body: response, + headers: headerParser(responseObj) + }; responses.push(response); let bids; @@ -296,6 +311,12 @@ export function newBidder(spec) { logWarn(`Bidder ${spec.code} made bid for unknown request ID: ${bid.requestId}. Ignoring.`); } } + + function headerParser(xmlHttpResponse) { + return { + get: responseObj.getResponseHeader.bind(responseObj) + }; + } } // If the server responds with an error, there's not much we can do. Log it, and make sure to diff --git a/test/spec/modules/adbutlerBidAdapter_spec.js b/test/spec/modules/adbutlerBidAdapter_spec.js index 352358be8d05..de40f72073bb 100644 --- a/test/spec/modules/adbutlerBidAdapter_spec.js +++ b/test/spec/modules/adbutlerBidAdapter_spec.js @@ -121,17 +121,19 @@ describe('AdButler adapter', () => { describe('bid responses', () => { it('should return complete bid response', () => { let serverResponse = { - status: 'SUCCESS', - account_id: 167283, - zone_id: 210093, - cpm: 1.5, - width: 300, - height: 250, - place: 0, - ad_code: '', - tracking_pixels: [ - 'http://tracking.pixel.com/params=info' - ] + body: { + status: 'SUCCESS', + account_id: 167283, + zone_id: 210093, + cpm: 1.5, + width: 300, + height: 250, + place: 0, + ad_code: '', + tracking_pixels: [ + 'http://tracking.pixel.com/params=info' + ] + } }, bids = spec.interpretResponse(serverResponse, {'bidRequest': bidRequests[0]}); diff --git a/test/spec/modules/appnexusAstBidAdapter_spec.js b/test/spec/modules/appnexusAstBidAdapter_spec.js index d07ee6df5436..d76cc08810f2 100644 --- a/test/spec/modules/appnexusAstBidAdapter_spec.js +++ b/test/spec/modules/appnexusAstBidAdapter_spec.js @@ -306,7 +306,7 @@ describe('AppNexusAdapter', () => { ]; let bidderRequest; - let result = spec.interpretResponse(response, {bidderRequest}); + let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(Object.keys(result[0])).to.deep.equal(Object.keys(expectedResponse[0])); }); @@ -322,7 +322,7 @@ describe('AppNexusAdapter', () => { }; let bidderRequest; - let result = spec.interpretResponse(response, {bidderRequest}); + let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(result.length).to.equal(0); }); @@ -343,7 +343,7 @@ describe('AppNexusAdapter', () => { }; let bidderRequest; - let result = spec.interpretResponse(response, {bidderRequest}); + let result = spec.interpretResponse({ body: response }, {bidderRequest}); expect(result[0]).to.have.property('vastUrl'); expect(result[0]).to.have.property('descriptionUrl'); expect(result[0]).to.have.property('mediaType', 'video'); @@ -376,7 +376,7 @@ describe('AppNexusAdapter', () => { }; let bidderRequest; - let result = spec.interpretResponse(response1, {bidderRequest}); + let result = spec.interpretResponse({ body: response1 }, {bidderRequest}); expect(result[0].native.title).to.equal('Native Creative'); expect(result[0].native.body).to.equal('Cool description great stuff'); expect(result[0].native.cta).to.equal('Do it'); diff --git a/test/spec/modules/beachfrontBidAdapter_spec.js b/test/spec/modules/beachfrontBidAdapter_spec.js index 43df639613f4..92e165739723 100644 --- a/test/spec/modules/beachfrontBidAdapter_spec.js +++ b/test/spec/modules/beachfrontBidAdapter_spec.js @@ -104,7 +104,7 @@ describe('BeachfrontAdapter', () => { describe('spec.interpretResponse', () => { it('should return no bids if the response is not valid', () => { - const bidResponse = spec.interpretResponse(null, { bidRequest }); + const bidResponse = spec.interpretResponse({ body: null }, { bidRequest }); expect(bidResponse.length).to.equal(0); }); @@ -112,7 +112,7 @@ describe('BeachfrontAdapter', () => { const serverResponse = { bidPrice: 5.00 }; - const bidResponse = spec.interpretResponse(serverResponse, { bidRequest }); + const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest }); expect(bidResponse.length).to.equal(0); }); @@ -120,7 +120,7 @@ describe('BeachfrontAdapter', () => { const serverResponse = { url: 'http://reachms.bfmio.com/getmu?aid=bid:19c4a196-fb21-4c81-9a1a-ecc5437a39da' }; - const bidResponse = spec.interpretResponse(serverResponse, { bidRequest }); + const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest }); expect(bidResponse.length).to.equal(0); }); @@ -130,7 +130,7 @@ describe('BeachfrontAdapter', () => { url: 'http://reachms.bfmio.com/getmu?aid=bid:19c4a196-fb21-4c81-9a1a-ecc5437a39da', cmpId: '123abc' }; - const bidResponse = spec.interpretResponse(serverResponse, { bidRequest }); + const bidResponse = spec.interpretResponse({ body: serverResponse }, { bidRequest }); expect(bidResponse).to.deep.equal({ requestId: bidRequest.bidId, bidderCode: spec.code, diff --git a/test/spec/modules/jcmBidAdapter_spec.js b/test/spec/modules/jcmBidAdapter_spec.js index a063d6b9805d..95356a9658e4 100644 --- a/test/spec/modules/jcmBidAdapter_spec.js +++ b/test/spec/modules/jcmBidAdapter_spec.js @@ -94,7 +94,7 @@ describe('jcmAdapter', () => { } ]; - let result = spec.interpretResponse(serverResponse); + let result = spec.interpretResponse({ body: serverResponse }); expect(Object.keys(result[0]).length).to.equal(Object.keys(expectedResponse[0]).length); expect(Object.keys(result[0]).requestId).to.equal(Object.keys(expectedResponse[0]).requestId); expect(Object.keys(result[0]).bidderCode).to.equal(Object.keys(expectedResponse[0]).bidderCode); @@ -112,7 +112,7 @@ describe('jcmAdapter', () => { it('handles nobid responses', () => { let serverResponse = {'bids': []}; - let result = spec.interpretResponse(serverResponse); + let result = spec.interpretResponse({ body: serverResponse }); expect(result.length).to.equal(0); }); }); diff --git a/test/spec/modules/platformioBidAdapter_spec.js b/test/spec/modules/platformioBidAdapter_spec.js index 1b07b4049d47..86bf52cac727 100644 --- a/test/spec/modules/platformioBidAdapter_spec.js +++ b/test/spec/modules/platformioBidAdapter_spec.js @@ -63,7 +63,7 @@ describe('Platformio Adapter Tests', () => { }] }] }; - const bids = spec.interpretResponse(ortbResponse, request); + const bids = spec.interpretResponse({ body: ortbResponse }, request); expect(bids).to.have.lengthOf(1); // verify first bid const bid = bids[0]; @@ -78,7 +78,7 @@ describe('Platformio Adapter Tests', () => { it('Verify full passback', () => { const request = spec.buildRequests(slotConfigs); - const bids = spec.interpretResponse(null, request) + const bids = spec.interpretResponse({ body: null }, request) expect(bids).to.have.lengthOf(0); }); diff --git a/test/spec/modules/pulsepointLiteBidAdapter_spec.js b/test/spec/modules/pulsepointLiteBidAdapter_spec.js index 96f5c7a8d1fd..9731164cd50f 100644 --- a/test/spec/modules/pulsepointLiteBidAdapter_spec.js +++ b/test/spec/modules/pulsepointLiteBidAdapter_spec.js @@ -89,7 +89,7 @@ describe('PulsePoint Lite Adapter Tests', () => { }] }] }; - const bids = spec.interpretResponse(ortbResponse, request); + const bids = spec.interpretResponse({ body: ortbResponse }, request); expect(bids).to.have.lengthOf(1); // verify first bid const bid = bids[0]; @@ -104,7 +104,7 @@ describe('PulsePoint Lite Adapter Tests', () => { it('Verify full passback', () => { const request = spec.buildRequests(slotConfigs); - const bids = spec.interpretResponse(null, request) + const bids = spec.interpretResponse({ body: null }, request) expect(bids).to.have.lengthOf(0); }); @@ -171,7 +171,7 @@ describe('PulsePoint Lite Adapter Tests', () => { }] }] }; - const bids = spec.interpretResponse(ortbResponse, request); + const bids = spec.interpretResponse({ body: ortbResponse }, request); // verify bid const bid = bids[0]; expect(bid.cpm).to.equal(1.25); diff --git a/test/spec/modules/rubiconBidAdapter_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js index 620fc56e5164..6c08c66f4858 100644 --- a/test/spec/modules/rubiconBidAdapter_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -604,7 +604,7 @@ describe('the rubicon adapter', () => { ] }; - let bids = spec.interpretResponse(response, { + let bids = spec.interpretResponse({ body: response }, { bidRequest: bidderRequest.bids[0] }); @@ -654,7 +654,7 @@ describe('the rubicon adapter', () => { }] }; - let bids = spec.interpretResponse(response, { + let bids = spec.interpretResponse({ body: response }, { bidRequest: bidderRequest.bids[0] }); @@ -677,7 +677,7 @@ describe('the rubicon adapter', () => { 'ads': [] }; - let bids = spec.interpretResponse(response, { + let bids = spec.interpretResponse({ body: response }, { bidRequest: bidderRequest.bids[0] }); @@ -701,7 +701,7 @@ describe('the rubicon adapter', () => { }] }; - let bids = spec.interpretResponse(response, { + let bids = spec.interpretResponse({ body: response }, { bidRequest: bidderRequest.bids[0] }); @@ -711,7 +711,7 @@ describe('the rubicon adapter', () => { it('should handle an error because of malformed json response', () => { let response = '{test{'; - let bids = spec.interpretResponse(response, { + let bids = spec.interpretResponse({ body: response }, { bidRequest: bidderRequest.bids[0] }); @@ -752,7 +752,7 @@ describe('the rubicon adapter', () => { 'account_id': 7780 }; - let bids = spec.interpretResponse(response, { + let bids = spec.interpretResponse({ body: response }, { bidRequest: bidderRequest.bids[0] }); diff --git a/test/spec/unit/core/bidderFactory_spec.js b/test/spec/unit/core/bidderFactory_spec.js index e91ddcf39a45..3260b66da28c 100644 --- a/test/spec/unit/core/bidderFactory_spec.js +++ b/test/spec/unit/core/bidderFactory_spec.js @@ -265,7 +265,9 @@ describe('bidders created by newBidder', () => { beforeEach(() => { ajaxStub = sinon.stub(ajax, 'ajax', function(url, callbacks) { - callbacks.success('response body'); + const fakeResponse = sinon.stub(); + fakeResponse.returns('headerContent'); + callbacks.success('response body', { getResponseHeader: fakeResponse }); }); userSyncStub = sinon.stub(userSync, 'registerSync') }); @@ -275,7 +277,7 @@ describe('bidders created by newBidder', () => { userSyncStub.restore(); }); - it('should call spec.interpretResponse() with the response body content', () => { + it('should call spec.interpretResponse() with the response content', () => { const bidder = newBidder(spec); spec.isBidRequestValid.returns(true); @@ -289,7 +291,9 @@ describe('bidders created by newBidder', () => { bidder.callBids(MOCK_BIDS_REQUEST); expect(spec.interpretResponse.calledOnce).to.equal(true); - expect(spec.interpretResponse.firstCall.args[0]).to.equal('response body'); + const response = spec.interpretResponse.firstCall.args[0] + expect(response.body).to.equal('response body') + expect(response.headers.get('some-header')).to.equal('headerContent'); expect(spec.interpretResponse.firstCall.args[1]).to.deep.equal({ method: 'POST', url: 'test.url.com', @@ -364,7 +368,10 @@ describe('bidders created by newBidder', () => { bidder.callBids(MOCK_BIDS_REQUEST); expect(spec.getUserSyncs.calledOnce).to.equal(true); - expect(spec.getUserSyncs.firstCall.args[1]).to.deep.equal(['response body']); + expect(spec.getUserSyncs.firstCall.args[1].length).to.equal(1); + expect(spec.getUserSyncs.firstCall.args[1][0].body).to.equal('response body'); + expect(spec.getUserSyncs.firstCall.args[1][0].headers).to.have.property('get'); + expect(spec.getUserSyncs.firstCall.args[1][0].headers.get).to.be.a('function'); }); it('should register usersync pixels', () => {