Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Insert Entrypoint hook invocation logic #1203

Merged
merged 13 commits into from
Mar 31, 2021
122 changes: 71 additions & 51 deletions src/main/java/org/prebid/server/auction/AmpRequestFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.iab.openrtb.request.User;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.logging.Logger;
import io.vertx.core.logging.LoggerFactory;
import io.vertx.ext.web.RoutingContext;
Expand All @@ -23,8 +22,11 @@
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.auction.model.Tuple2;
import org.prebid.server.exception.InvalidRequestException;
import org.prebid.server.hooks.execution.model.HookExecutionContext;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.metric.MetricName;
import org.prebid.server.model.Endpoint;
import org.prebid.server.model.HttpRequestWrapper;
import org.prebid.server.privacy.ccpa.Ccpa;
import org.prebid.server.privacy.gdpr.TcfDefinerService;
import org.prebid.server.proto.openrtb.ext.request.ExtMediaTypePriceGranularity;
Expand Down Expand Up @@ -88,6 +90,7 @@ public AmpRequestFactory(StoredRequestProcessor storedRequestProcessor,
FpdResolver fpdResolver,
TimeoutResolver timeoutResolver,
JacksonMapper mapper) {

this.storedRequestProcessor = Objects.requireNonNull(storedRequestProcessor);
this.auctionRequestFactory = Objects.requireNonNull(auctionRequestFactory);
this.ortbTypesResolver = Objects.requireNonNull(ortbTypesResolver);
Expand All @@ -101,35 +104,51 @@ public AmpRequestFactory(StoredRequestProcessor storedRequestProcessor,
* Creates {@link AuctionContext} based on {@link RoutingContext}.
*/
public Future<AuctionContext> fromRequest(RoutingContext routingContext, long startTime) {
final String tagId = routingContext.request().getParam(TAG_ID_REQUEST_PARAM);
if (StringUtils.isBlank(tagId)) {
return Future.failedFuture(new InvalidRequestException("AMP requests require an AMP tag_id"));
}
return createBidRequest(routingContext, tagId)
.compose(bidRequestWithErrors -> auctionRequestFactory.toAuctionContext(
routingContext,
bidRequestWithErrors.getLeft(),
MetricName.amp,
bidRequestWithErrors.getRight(),
startTime,
timeoutResolver));
final HookExecutionContext hookExecutionContext = HookExecutionContext.of(Endpoint.openrtb2_amp);

return auctionRequestFactory.executeEntrypointHooks(
routingContext,
routingContext.getBodyAsString(),
hookExecutionContext)
.compose(httpRequest -> createBidRequest(httpRequest)
.compose(bidRequestWithErrors -> auctionRequestFactory.toAuctionContext(
httpRequest,
bidRequestWithErrors.getLeft(),
MetricName.amp,
bidRequestWithErrors.getRight(),
startTime,
timeoutResolver,
hookExecutionContext)));
}

/**
* Creates {@link BidRequest} and sets properties which were not set explicitly by the client, but can be
* updated by values derived from headers and other request attributes.
*/
private Future<Tuple2<BidRequest, List<String>>> createBidRequest(RoutingContext context, String tagId) {
private Future<Tuple2<BidRequest, List<String>>> createBidRequest(HttpRequestWrapper httpRequest) {
final String tagId = readAndValidateTagId(httpRequest);

final List<String> errors = new ArrayList<>();
return storedRequestProcessor.processAmpRequest(context.request().getParam(ACCOUNT_REQUEST_PARAM), tagId)
return storedRequestProcessor.processAmpRequest(httpRequest.getQueryParams().get(ACCOUNT_REQUEST_PARAM), tagId)
.map(bidRequest -> validateStoredBidRequest(tagId, bidRequest))
.map(bidRequest -> fillExplicitParameters(bidRequest, context))
.map(bidRequest -> overrideParameters(bidRequest, context.request(), errors))
.map(bidRequest -> auctionRequestFactory.fillImplicitParameters(bidRequest, context, timeoutResolver))
.map(bidRequest -> fillExplicitParameters(bidRequest, httpRequest))
.map(bidRequest -> overrideParameters(bidRequest, httpRequest, errors))
.map(bidRequest -> auctionRequestFactory.fillImplicitParameters(
bidRequest, httpRequest, timeoutResolver))
.map(auctionRequestFactory::validateRequest)
.map(bidRequest -> Tuple2.of(bidRequest, errors));
}

private static String readAndValidateTagId(HttpRequestWrapper httpRequest) {
final String tagId = httpRequest.getQueryParams().get(TAG_ID_REQUEST_PARAM);

if (StringUtils.isBlank(tagId)) {
throw new InvalidRequestException("AMP requests require an AMP tag_id");
}

return tagId;
}

/**
* Throws {@link InvalidRequestException} in case of invalid {@link BidRequest}.
*/
Expand Down Expand Up @@ -165,7 +184,7 @@ private static BidRequest validateStoredBidRequest(String tagId, BidRequest bidR
* - Sets {@link BidRequest}.test = 1 if it was passed in {@link RoutingContext}
* - Updates {@link BidRequest}.ext.prebid.amp.data with all query parameters
*/
private BidRequest fillExplicitParameters(BidRequest bidRequest, RoutingContext context) {
private BidRequest fillExplicitParameters(BidRequest bidRequest, HttpRequestWrapper httpRequest) {
final List<Imp> imps = bidRequest.getImp();
// Force HTTPS as AMP requires it, but pubs can forget to set it.
final Imp imp = imps.get(0);
Expand Down Expand Up @@ -198,7 +217,7 @@ private BidRequest fillExplicitParameters(BidRequest bidRequest, RoutingContext
setChannel = prebid.getChannel() == null;
}

final Integer debugQueryParam = debugFromQueryStringParam(context);
final Integer debugQueryParam = debugFromQueryStringParam(httpRequest);

final Integer test = bidRequest.getTest();
final Integer updatedTest = debugQueryParam != null && !Objects.equals(debugQueryParam, test)
Expand All @@ -210,7 +229,7 @@ private BidRequest fillExplicitParameters(BidRequest bidRequest, RoutingContext
? debugQueryParam
: null;

final Map<String, String> updatedAmpData = updateAmpData(prebid, context.request());
final Map<String, String> updatedAmpData = updateAmpData(prebid, httpRequest);

final BidRequest result;
if (setSecure
Expand Down Expand Up @@ -241,17 +260,17 @@ private BidRequest fillExplicitParameters(BidRequest bidRequest, RoutingContext
/**
* Returns debug flag from request query string if it is equal to either 0 or 1, or null if otherwise.
*/
private static Integer debugFromQueryStringParam(RoutingContext context) {
final String debug = context.request().getParam(DEBUG_REQUEST_PARAM);
private static Integer debugFromQueryStringParam(HttpRequestWrapper httpRequest) {
final String debug = httpRequest.getQueryParams().get(DEBUG_REQUEST_PARAM);
return Objects.equals(debug, "1") ? Integer.valueOf(1) : Objects.equals(debug, "0") ? 0 : null;
}

/**
* Extracts parameters from http request and overrides corresponding attributes in {@link BidRequest}.
*/
private BidRequest overrideParameters(BidRequest bidRequest, HttpServerRequest request, List<String> errors) {
final String requestConsentParam = request.getParam(CONSENT_PARAM);
final String requestGdprConsentParam = request.getParam(GDPR_CONSENT_PARAM);
private BidRequest overrideParameters(BidRequest bidRequest, HttpRequestWrapper httpRequest, List<String> errors) {
final String requestConsentParam = httpRequest.getQueryParams().get(CONSENT_PARAM);
final String requestGdprConsentParam = httpRequest.getQueryParams().get(GDPR_CONSENT_PARAM);
final String consentString = ObjectUtils.firstNonNull(requestConsentParam, requestGdprConsentParam);

String gdprConsent = null;
Expand All @@ -268,14 +287,15 @@ private BidRequest overrideParameters(BidRequest bidRequest, HttpServerRequest r
}
}

final String requestTargeting = request.getParam(TARGETING_REQUEST_PARAM);
final String requestTargeting = httpRequest.getQueryParams().get(TARGETING_REQUEST_PARAM);
final ObjectNode targetingNode = readTargeting(requestTargeting);
ortbTypesResolver.normalizeTargeting(targetingNode, errors, implicitParametersExtractor.refererFrom(request));
ortbTypesResolver.normalizeTargeting(
targetingNode, errors, implicitParametersExtractor.refererFrom(httpRequest));
final Targeting targeting = parseTargeting(targetingNode);

final Site updatedSite = overrideSite(bidRequest.getSite(), request);
final Imp updatedImp = overrideImp(bidRequest.getImp().get(0), request, targetingNode);
final Long updatedTimeout = overrideTimeout(bidRequest.getTmax(), request);
final Site updatedSite = overrideSite(bidRequest.getSite(), httpRequest);
final Imp updatedImp = overrideImp(bidRequest.getImp().get(0), httpRequest, targetingNode);
final Long updatedTimeout = overrideTimeout(bidRequest.getTmax(), httpRequest);
final User updatedUser = overrideUser(bidRequest.getUser(), gdprConsent);
final Regs updatedRegs = overrideRegs(bidRequest.getRegs(), ccpaConsent);
final ExtRequest updatedExtBidRequest = overrideExtBidRequest(bidRequest.getExt(), targeting);
Expand Down Expand Up @@ -328,9 +348,9 @@ private Targeting parseTargeting(ObjectNode targetingNode) {
}
}

private Site overrideSite(Site site, HttpServerRequest request) {
final String canonicalUrl = canonicalUrl(request);
final String accountId = request.getParam(ACCOUNT_REQUEST_PARAM);
private Site overrideSite(Site site, HttpRequestWrapper httpRequest) {
final String canonicalUrl = canonicalUrl(httpRequest);
final String accountId = httpRequest.getQueryParams().get(ACCOUNT_REQUEST_PARAM);

final boolean hasSite = site != null;
final ExtSite siteExt = hasSite ? site.getExt() : null;
Expand Down Expand Up @@ -362,19 +382,19 @@ private Site overrideSite(Site site, HttpServerRequest request) {
return null;
}

private static String canonicalUrl(HttpServerRequest request) {
private static String canonicalUrl(HttpRequestWrapper httpRequest) {
try {
return HttpUtil.decodeUrl(request.getParam(CURL_REQUEST_PARAM));
return HttpUtil.decodeUrl(httpRequest.getQueryParams().get(CURL_REQUEST_PARAM));
} catch (IllegalArgumentException e) {
return null;
}
}

private Imp overrideImp(Imp imp, HttpServerRequest request, ObjectNode targetingNode) {
final String tagId = request.getParam(SLOT_REQUEST_PARAM);
private Imp overrideImp(Imp imp, HttpRequestWrapper httpRequest, ObjectNode targetingNode) {
final String tagId = httpRequest.getQueryParams().get(SLOT_REQUEST_PARAM);
final Banner banner = imp.getBanner();
final List<Format> overwrittenFormats = banner != null
? createOverrideBannerFormats(request, banner.getFormat())
? createOverrideBannerFormats(httpRequest, banner.getFormat())
: null;
if (StringUtils.isNotBlank(tagId) || CollectionUtils.isNotEmpty(overwrittenFormats) || targetingNode != null) {
return imp.toBuilder()
Expand All @@ -389,12 +409,12 @@ private Imp overrideImp(Imp imp, HttpServerRequest request, ObjectNode targeting
/**
* Creates formats from request parameters to override origin amp banner formats.
*/
private static List<Format> createOverrideBannerFormats(HttpServerRequest request, List<Format> formats) {
final int overrideWidth = parseIntParamOrZero(request, OW_REQUEST_PARAM);
final int width = parseIntParamOrZero(request, W_REQUEST_PARAM);
final int overrideHeight = parseIntParamOrZero(request, OH_REQUEST_PARAM);
final int height = parseIntParamOrZero(request, H_REQUEST_PARAM);
final String multiSizeParam = request.getParam(MS_REQUEST_PARAM);
private static List<Format> createOverrideBannerFormats(HttpRequestWrapper httpRequest, List<Format> formats) {
final int overrideWidth = parseIntParamOrZero(httpRequest, OW_REQUEST_PARAM);
final int width = parseIntParamOrZero(httpRequest, W_REQUEST_PARAM);
final int overrideHeight = parseIntParamOrZero(httpRequest, OH_REQUEST_PARAM);
final int height = parseIntParamOrZero(httpRequest, H_REQUEST_PARAM);
final String multiSizeParam = httpRequest.getQueryParams().get(MS_REQUEST_PARAM);

final List<Format> paramsFormats = createFormatsFromParams(overrideWidth, width, overrideHeight, height,
multiSizeParam);
Expand All @@ -404,8 +424,8 @@ private static List<Format> createOverrideBannerFormats(HttpServerRequest reques
: updateFormatsFromParams(formats, width, height);
}

private static Integer parseIntParamOrZero(HttpServerRequest request, String name) {
return parseIntOrZero(request.getParam(name));
private static Integer parseIntParamOrZero(HttpRequestWrapper httpRequest, String name) {
return parseIntOrZero(httpRequest.getQueryParams().get(name));
}

private static Integer parseIntOrZero(String param) {
Expand Down Expand Up @@ -469,8 +489,8 @@ private static Banner overrideBanner(Banner banner, List<Format> formats) {
: banner;
}

private static Long overrideTimeout(Long tmax, HttpServerRequest request) {
final String timeoutQueryParam = request.getParam(TIMEOUT_REQUEST_PARAM);
private static Long overrideTimeout(Long tmax, HttpRequestWrapper httpRequest) {
final String timeoutQueryParam = httpRequest.getQueryParams().get(TIMEOUT_REQUEST_PARAM);
if (timeoutQueryParam == null) {
return null;
}
Expand Down Expand Up @@ -554,11 +574,11 @@ private static List<Format> parseMultiSizeParam(String ms) {
return formats;
}

private static Map<String, String> updateAmpData(ExtRequestPrebid prebid, HttpServerRequest request) {
private static Map<String, String> updateAmpData(ExtRequestPrebid prebid, HttpRequestWrapper httpRequest) {
final ExtRequestPrebidAmp amp = prebid != null ? prebid.getAmp() : null;
final Map<String, String> existingAmpData = amp != null ? amp.getData() : null;

final MultiMap queryParams = request.params();
final MultiMap queryParams = httpRequest.getQueryParams();
if (queryParams.isEmpty()) {
return null;
}
Expand Down
Loading