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
99 changes: 33 additions & 66 deletions src/main/java/org/prebid/server/auction/ExchangeService.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import io.vertx.core.CompositeFuture;
import io.vertx.core.Future;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.collections4.map.CaseInsensitiveMap;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -32,9 +31,9 @@
import org.prebid.server.activity.infrastructure.payload.impl.BidRequestActivityInvocationPayload;
import org.prebid.server.auction.aliases.AlternateBidderCodesConfig;
import org.prebid.server.auction.aliases.BidderAliases;
import org.prebid.server.auction.bidderrequestpostprocessor.BidderRequestPostProcessor;
import org.prebid.server.auction.bidderrequestpostprocessor.BidderRequestRejectedException;
import org.prebid.server.auction.externalortb.StoredResponseProcessor;
import org.prebid.server.auction.mediatypeprocessor.MediaTypeProcessingResult;
import org.prebid.server.auction.mediatypeprocessor.MediaTypeProcessor;
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.auction.model.AuctionParticipation;
import org.prebid.server.auction.model.BidRejectionReason;
Expand All @@ -51,7 +50,6 @@
import org.prebid.server.auction.versionconverter.OrtbVersion;
import org.prebid.server.bidder.Bidder;
import org.prebid.server.bidder.BidderCatalog;
import org.prebid.server.bidder.BidderInfo;
import org.prebid.server.bidder.HttpBidderRequester;
import org.prebid.server.bidder.Usersyncer;
import org.prebid.server.bidder.model.BidderBid;
Expand Down Expand Up @@ -144,7 +142,7 @@ public class ExchangeService {
private final ImpAdjuster impAdjuster;
private final SupplyChainResolver supplyChainResolver;
private final DebugResolver debugResolver;
private final MediaTypeProcessor mediaTypeProcessor;
private final BidderRequestPostProcessor bidderRequestPostProcessor;
private final UidUpdater uidUpdater;
private final TimeoutResolver timeoutResolver;
private final TimeoutFactory timeoutFactory;
Expand All @@ -171,7 +169,7 @@ public ExchangeService(double logSamplingRate,
ImpAdjuster impAdjuster,
SupplyChainResolver supplyChainResolver,
DebugResolver debugResolver,
MediaTypeProcessor mediaTypeProcessor,
BidderRequestPostProcessor bidderRequestPostProcessor,
UidUpdater uidUpdater,
TimeoutResolver timeoutResolver,
TimeoutFactory timeoutFactory,
Expand All @@ -198,7 +196,7 @@ public ExchangeService(double logSamplingRate,
this.impAdjuster = Objects.requireNonNull(impAdjuster);
this.supplyChainResolver = Objects.requireNonNull(supplyChainResolver);
this.debugResolver = Objects.requireNonNull(debugResolver);
this.mediaTypeProcessor = Objects.requireNonNull(mediaTypeProcessor);
this.bidderRequestPostProcessor = Objects.requireNonNull(bidderRequestPostProcessor);
this.uidUpdater = Objects.requireNonNull(uidUpdater);
this.timeoutResolver = Objects.requireNonNull(timeoutResolver);
this.timeoutFactory = Objects.requireNonNull(timeoutFactory);
Expand Down Expand Up @@ -435,7 +433,7 @@ private void removeInvalidBidRejectionTrackers(Map<String, BidRejectionTracker>
BidderAliases aliases) {

final Set<String> bidderNames = new HashSet<>(bidRejectionTrackers.keySet());
for (String bidder: bidderNames) {
for (String bidder : bidderNames) {
if (!isValidBidder(bidder, aliases)) {
bidRejectionTrackers.remove(bidder);
logger.warn("Pre-rejected impressions of the bidder {} have been removed. "
Expand Down Expand Up @@ -492,13 +490,12 @@ private Future<List<AuctionParticipation>> extractAuctionParticipations(
.filter(bidder -> isBidderCallActivityAllowed(bidder, context))
.distinct()
.toList();
final Map<String, Map<String, String>> impBidderToStoredBidResponse =
storedResponseResult.getImpBidderToStoredBidResponse();

return makeAuctionParticipation(
bidders,
context,
aliases,
impBidderToStoredBidResponse,
storedResponseResult.getImpBidderToStoredBidResponse(),
imps,
bidderToMultiBid);
}
Expand Down Expand Up @@ -539,7 +536,7 @@ private Future<List<AuctionParticipation>> makeAuctionParticipation(

final BidRequest bidRequest = context.getBidRequest();
final ExtRequest requestExt = bidRequest.getExt();
final ExtRequestPrebid prebid = requestExt == null ? null : requestExt.getPrebid();
final ExtRequestPrebid prebid = requestExt != null ? requestExt.getPrebid() : null;
final Map<String, ExtBidderConfigOrtb> biddersToConfigs = getBiddersToConfigs(prebid);
final Map<String, List<String>> eidPermissions = getEidPermissions(prebid);
final Map<String, Pair<User, Device>> bidderToUserAndDevice =
Expand Down Expand Up @@ -1157,69 +1154,39 @@ private Future<BidderResponse> processAndRequestBids(AuctionContext auctionConte
Timeout timeout,
BidderAliases aliases) {

final String bidderName = bidderRequest.getBidder();
final MediaTypeProcessingResult mediaTypeProcessingResult = mediaTypeProcessor.process(
bidderRequest.getBidRequest(), bidderName, aliases, auctionContext.getAccount());
final List<BidderError> mediaTypeProcessingErrors = mediaTypeProcessingResult.getErrors();
if (mediaTypeProcessingResult.isRejected()) {
return processReject(
auctionContext,
BidRejectionReason.REQUEST_BLOCKED_UNSUPPORTED_MEDIA_TYPE,
mediaTypeProcessingErrors,
bidderName);
}
if (isUnacceptableCurrency(auctionContext, aliases.resolveBidder(bidderName))) {
return processReject(
auctionContext,
BidRejectionReason.REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY,
List.of(BidderError.generic("No match between the configured currencies and bidRequest.cur")),
bidderName);
}

return Future.succeededFuture(mediaTypeProcessingResult.getBidRequest())
.map(bidderRequest::with)
.compose(modifiedBidderRequest -> invokeHooksAndRequestBids(
auctionContext, modifiedBidderRequest, timeout, aliases))
.map(bidderResponse -> bidderResponse.with(
addWarnings(bidderResponse.getSeatBid(), mediaTypeProcessingErrors)));
}

private boolean isUnacceptableCurrency(AuctionContext auctionContext, String originalBidderName) {
final List<String> requestCurrencies = auctionContext.getBidRequest().getCur();
final List<String> bidAcceptableCurrencies =
Optional.ofNullable(bidderCatalog.bidderInfoByName(originalBidderName))
.map(BidderInfo::getCurrencyAccepted)
.orElse(null);

if (CollectionUtils.isEmpty(requestCurrencies) || CollectionUtils.isEmpty(bidAcceptableCurrencies)) {
return false;
}

return !CollectionUtils.containsAny(requestCurrencies, bidAcceptableCurrencies);
}

private static Future<BidderResponse> processReject(AuctionContext auctionContext,
BidRejectionReason bidRejectionReason,
List<BidderError> warnings,
String bidderName) {

auctionContext.getBidRejectionTrackers()
.get(bidderName)
.rejectAll(bidRejectionReason);
final BidderSeatBid bidderSeatBid = BidderSeatBid.builder()
.warnings(warnings)
.build();
return Future.succeededFuture(BidderResponse.of(bidderName, bidderSeatBid, 0));
return bidderRequestPostProcessor.process(bidderRequest, aliases, auctionContext)
.compose(result -> invokeHooksAndRequestBids(auctionContext, result.getValue(), timeout, aliases)
.map(response -> response.with(addWarnings(response.getSeatBid(), result.getErrors()))))
.recover(throwable -> recoverBidderRequestRejection(
auctionContext, bidderRequest.getBidder(), throwable));
}

private static BidderSeatBid addWarnings(BidderSeatBid seatBid, List<BidderError> warnings) {
return CollectionUtils.isNotEmpty(warnings)
? seatBid.toBuilder()
.warnings(ListUtils.union(warnings, seatBid.getWarnings()))
.warnings(ListUtil.union(warnings, seatBid.getWarnings()))
.build()
: seatBid;
}

private static Future<BidderResponse> recoverBidderRequestRejection(AuctionContext auctionContext,
String bidderName,
Throwable throwable) {

if (throwable instanceof BidderRequestRejectedException rejection) {
auctionContext.getBidRejectionTrackers()
.get(bidderName)
.rejectAll(rejection.getRejectionReason());
final BidderSeatBid bidderSeatBid = BidderSeatBid.builder()
.warnings(rejection.getErrors())
.build();

return Future.succeededFuture(BidderResponse.of(bidderName, bidderSeatBid, 0));
}

return Future.failedFuture(throwable);
}

private Future<BidderResponse> invokeHooksAndRequestBids(AuctionContext auctionContext,
BidderRequest bidderRequest,
Timeout timeout,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package org.prebid.server.auction.bidderrequestpostprocessor;

import com.fasterxml.jackson.databind.node.ObjectNode;
import com.iab.openrtb.request.BidRequest;
import io.vertx.core.Future;
import org.prebid.server.auction.aliases.BidderAliases;
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.auction.model.BidderRequest;
import org.prebid.server.bidder.model.Result;
import org.prebid.server.proto.openrtb.ext.request.ExtRequest;
import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid;

import java.util.Collections;

public class BidderRequestCleaner implements BidderRequestPostProcessor {

@Override
public Future<Result<BidderRequest>> process(BidderRequest bidderRequest,
BidderAliases aliases,
AuctionContext auctionContext) {

final BidRequest bidRequest = bidderRequest.getBidRequest();
final ExtRequest ext = bidRequest.getExt();
final ExtRequestPrebid extPrebid = ext != null ? ext.getPrebid() : null;
final ObjectNode bidderControls = extPrebid != null ? extPrebid.getBiddercontrols() : null;

if (bidderControls == null) {
return resultOf(bidderRequest);
}

final ExtRequest cleanedExt = ExtRequest.of(extPrebid.toBuilder().biddercontrols(null).build());
cleanedExt.addProperties(ext.getProperties());

return resultOf(bidderRequest.with(bidRequest.toBuilder().ext(cleanedExt).build()));
}

private static Future<Result<BidderRequest>> resultOf(BidderRequest bidderRequest) {
return Future.succeededFuture(Result.of(bidderRequest, Collections.emptyList()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package org.prebid.server.auction.bidderrequestpostprocessor;

import com.iab.openrtb.request.BidRequest;
import io.vertx.core.Future;
import org.apache.commons.collections4.CollectionUtils;
import org.prebid.server.auction.aliases.BidderAliases;
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.auction.model.BidRejectionReason;
import org.prebid.server.auction.model.BidderRequest;
import org.prebid.server.bidder.BidderCatalog;
import org.prebid.server.bidder.BidderInfo;
import org.prebid.server.bidder.model.BidderError;
import org.prebid.server.bidder.model.Result;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;

public class BidderRequestCurrencyBlocker implements BidderRequestPostProcessor {

private final BidderCatalog bidderCatalog;

public BidderRequestCurrencyBlocker(BidderCatalog bidderCatalog) {
this.bidderCatalog = Objects.requireNonNull(bidderCatalog);
}

@Override
public Future<Result<BidderRequest>> process(BidderRequest bidderRequest,
BidderAliases aliases,
AuctionContext auctionContext) {

if (isAcceptableCurrency(bidderRequest.getBidRequest(), aliases.resolveBidder(bidderRequest.getBidder()))) {
return Future.succeededFuture(Result.of(bidderRequest, Collections.emptyList()));
}

return Future.failedFuture(new BidderRequestRejectedException(
BidRejectionReason.REQUEST_BLOCKED_UNACCEPTABLE_CURRENCY,
List.of(BidderError.generic("No match between the configured currencies and bidRequest.cur"))));
}

private boolean isAcceptableCurrency(BidRequest bidRequest, String originalBidderName) {
final List<String> requestCurrencies = bidRequest.getCur();
final Set<String> bidAcceptableCurrencies =
Optional.ofNullable(bidderCatalog.bidderInfoByName(originalBidderName))
.map(BidderInfo::getCurrencyAccepted)
.orElse(null);

return CollectionUtils.isEmpty(requestCurrencies)
|| CollectionUtils.isEmpty(bidAcceptableCurrencies)
|| requestCurrencies.stream().anyMatch(bidAcceptableCurrencies::contains);
}
}
Loading
Loading