Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions src/adapters/bidderFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,11 @@ export function newBidder<B extends BidderCode>(spec: BidderSpec<B>) {
const tidGuard = guardTids(bidderRequest);

const adUnitCodesHandled = {};
function addBidWithCode(adUnitCode: string, bid: Bid) {
function addBidWithCode(adUnitCode: string, bid: Bid, responseMediaType = null) {
const metrics = useMetrics(bid.metrics);
metrics.checkpoint('addBidResponse');
adUnitCodesHandled[adUnitCode] = true;
if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnitCode, bid))) {
if (metrics.measureTime('addBidResponse.validate', () => isValid(adUnitCode, bid, {responseMediaType}))) {
addBidResponse(adUnitCode, bid);
} else {
addBidResponse.reject(adUnitCode, bid, REJECTION_REASON.INVALID)
Expand Down Expand Up @@ -345,7 +345,11 @@ export function newBidder<B extends BidderCode>(spec: BidderSpec<B>) {
bid.deferBilling = bidRequest.deferBilling;
bid.deferRendering = bid.deferBilling && (bidResponse.deferRendering ?? typeof spec.onBidBillable !== 'function');
const prebidBid: Bid = Object.assign(createBid(bidRequest), bid, pick(bidRequest, Object.keys(TIDS)));
addBidWithCode(bidRequest.adUnitCode, prebidBid);
// codex agent bot: retain whether mediaType was explicitly set by the adapter response.
const responseMediaType = Object.prototype.hasOwnProperty.call(bidResponse, 'mediaType')
? bidResponse.mediaType
: null;
addBidWithCode(bidRequest.adUnitCode, prebidBid, responseMediaType);
} else {
logWarn(`Bidder ${spec.code} made bid for unknown request ID: ${bidResponse.requestId}. Ignoring.`);
addBidResponse.reject(null, bidResponse, REJECTION_REASON.INVALID_REQUEST_ID);
Expand Down Expand Up @@ -647,7 +651,7 @@ function validBidSize(adUnitCode, bid: BannerBid, {index = auctionManager.index}
}

// Validate the arguments sent to us by the adapter. If this returns false, the bid should be totally ignored.
export function isValid(adUnitCode: string, bid: Bid, {index = auctionManager.index} = {}) {
export function isValid(adUnitCode: string, bid: Bid, {index = auctionManager.index, responseMediaType = bid.mediaType} = {}) {
function hasValidKeys() {
const bidKeys = Object.keys(bid);
return COMMON_BID_RESPONSE_KEYS.every(key => bidKeys.includes(key) && ![undefined, null].includes(bid[key]));
Expand All @@ -672,6 +676,16 @@ export function isValid(adUnitCode: string, bid: Bid, {index = auctionManager.in
return false;
}

if (responseMediaType != null) {
const mediaTypes = index.getMediaTypes(bid);
if (mediaTypes && Object.keys(mediaTypes).length > 0) {
if (!mediaTypes.hasOwnProperty(responseMediaType)) {
logError(errorMessage(`Bid mediaType '${responseMediaType}' is not supported by the ad unit. Allowed: ${Object.keys(mediaTypes).join(', ')}`));
return false;
}
}
}

if (FEATURES.NATIVE && bid.mediaType === 'native' && !nativeBidIsValid(bid, {index})) {
logError(errorMessage('Native bid missing some required properties.'));
return false;
Expand Down
56 changes: 56 additions & 0 deletions test/spec/unit/core/bidderFactory_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,62 @@ describe('bidderFactory', () => {
});
});
})

describe('media type validation', () => {
let req;

function mkResponse(props) {
return Object.assign({
requestId: req.bidId,
cpm: 1,
ttl: 60,
creativeId: '123',
netRevenue: true,
currency: 'USD',
width: 1,
height: 2,
mediaType: 'banner',
}, props);
}

function checkValid(bid, opts = {}) {
return isValid('au', bid, {
index: stubAuctionIndex({bidRequests: [req]}),
...opts,
});
}

beforeEach(() => {
req = {
...MOCK_BIDS_REQUEST.bids[0],
mediaTypes: {
banner: {
sizes: [[1, 2]]
}
}
};
});

it('should reject video bid when ad unit only has banner', () => {
expect(checkValid(mkResponse({mediaType: 'video'}))).to.be.false;
});

it('should accept video bid when ad unit has both banner and video', () => {
req.mediaTypes = {
banner: {sizes: [[1, 2]]},
video: {context: 'instream'}
};
expect(checkValid(mkResponse({mediaType: 'video', vastUrl: 'http://vast.xml'}))).to.be.true;
});

it('should skip media type check when adapter omits mediaType', () => {
req.mediaTypes = {
video: {context: 'instream'}
};

expect(checkValid(mkResponse({mediaType: 'banner'}), {responseMediaType: null})).to.be.true;
});
});
});

describe('gzip compression', () => {
Expand Down
Loading