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

Support additional AMP params #1379

Merged
merged 4 commits into from
Aug 2, 2021
Merged
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
20 changes: 13 additions & 7 deletions docs/endpoints/openrtb2/amp.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,14 @@ This endpoint supports the following query parameters:
6. `curl` - the canonical URL of the page
7. `timeout` - the publisher-specified timeout for the RTC callout
- A configuration option `amp.default-timeout-ms` may be set to account for estimated latency so that Prebid Server can handle timeouts from adapters and respond to the AMP RTC request before it times out.
8. `us_privacy` - CCPA value for request.
9. `gdpr_consent` - GDPR value for request.
8. `gdpr_consent` - consent string for request.
9. `consent_string` - consent string for request.
10. `debug` - When set to `1`, the responses will contain extra info for debugging.
11. `account` - accountId parameter for Site object.
12. `slot` - tagId parameter for Imp object.
13. `gdpr_applies` - GDPR param for Regs Ext object.
14. `consent_type` - param to define what type of consent_string passed.
15. `attl_consent` - consentedProviders param for User Ext ConsentedProvidersSettings object.


For information on how these get from AMP into this endpoint, see [this pull request adding the query params to the Prebid callout](https://github.com/ampproject/amphtml/pull/14155) and [this issue adding support for network-level RTC macros](https://github.com/ampproject/amphtml/issues/12374).
Expand All @@ -130,11 +133,14 @@ If present, these will override parts of your Stored Request.
1. `ow`, `oh`, `w`, `h`, and/or `ms` will be used to set `request.imp[0].banner.format` if `request.imp[0].banner` is present.
2. `curl` will be used to set `request.site.page`
3. `timeout` will generally be used to set `request.tmax`. However, the Prebid Server host can [configure](../../config.md) their deploy to reduce this timeout for technical reasons.
4. `us_privacy` will be used to set `request.regs.ext.us_privacy`
5. `debug` will be used to set `request.test`, causing the `response.debug` to have extra debugging info in it.
6. `account` - will be used to set `site.publisher.id` parameter for Site object.
7. `slot` - will be used to set `tagId` parameter to overwrite Imp object.
8. `gdpr_consent` will be used to set `user.ext.consent`.
4. `debug` will be used to set `request.test`, causing the `response.debug` to have extra debugging info in it.
5. `account` - will be used to set `site.publisher.id` parameter for Site object.
6. `slot` - will be used to set `tagId` parameter to overwrite Imp object.
7. `gdpr_applies` will be used to set `request.regs.ext.gdpr`
8. `consent_type` will be used to check what should be done with consent string
9. `attl_consent` will be used to set `user.ext.ConsentedProvidersSettings.consented_providers`.
10. `gdpr_consent` will be used to set `request.regs.ext.us_privacy` or `user.ext.consent`
11. `consent_string` will be used to set `request.regs.ext.us_privacy` or `user.ext.consent`. This param has bigger priority then `gdpr_consent`.



Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.prebid.server.auction.model;

/**
* Describes consent types that can be present in `consent_type` amp query param
*/
public enum ConsentType {

tcfV1, tcfV2, usPrivacy, unknown;
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@
import org.prebid.server.auction.StoredRequestProcessor;
import org.prebid.server.auction.TimeoutResolver;
import org.prebid.server.auction.model.AuctionContext;
import org.prebid.server.auction.model.ConsentType;
import org.prebid.server.exception.InvalidRequestException;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.metric.MetricName;
import org.prebid.server.model.Endpoint;
import org.prebid.server.model.HttpRequestContext;
import org.prebid.server.privacy.ccpa.Ccpa;
import org.prebid.server.privacy.gdpr.TcfDefinerService;
import org.prebid.server.proto.openrtb.ext.request.ConsentedProvidersSettings;
import org.prebid.server.proto.openrtb.ext.request.ExtMediaTypePriceGranularity;
import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity;
import org.prebid.server.proto.openrtb.ext.request.ExtRegs;
Expand Down Expand Up @@ -76,6 +78,9 @@ public class AmpRequestFactory {
private static final String TIMEOUT_REQUEST_PARAM = "timeout";
private static final String GDPR_CONSENT_PARAM = "gdpr_consent";
private static final String CONSENT_PARAM = "consent_string";
private static final String GDPR_APPLIES_PARAM = "gdpr_applies";
private static final String CONSENT_TYPE_PARAM = "consent_type";
private static final String ATTL_CONSENT_PARAM = "attl_consent";

private static final int NO_LIMIT_SPLIT_MODE = -1;
private static final String AMP_CHANNEL = "amp";
Expand Down Expand Up @@ -153,14 +158,17 @@ private Future<BidRequest> parseBidRequest(HttpRequestContext httpRequest, Aucti
return Future.failedFuture(new InvalidRequestException("AMP requests require an AMP tag_id"));
}

final ConsentType consentType = consentTypeFromQueryStringParams(httpRequest);
final String consentString = consentStringFromQueryStringParams(httpRequest);
final String attlConsent = attlConsentFromQueryStringParams(httpRequest);
final Integer gdpr = gdprFromQueryStringParams(httpRequest);
final Integer debug = debugFromQueryStringParam(httpRequest);
final Long timeout = timeoutFromQueryString(httpRequest);

final BidRequest bidRequest = BidRequest.builder()
.site(createSite(httpRequest))
.user(createUser(consentString))
.regs(createRegs(consentString))
.user(createUser(consentType, consentString, attlConsent))
.regs(createRegs(consentString, consentType, gdpr))
.test(debug)
.tmax(timeout)
.ext(createExt(httpRequest, tagId, debug))
Expand All @@ -185,16 +193,33 @@ private static Site createSite(HttpRequestContext httpRequest) {
: null;
}

private static User createUser(String consentString) {
return StringUtils.isNotBlank(consentString) && TcfDefinerService.isConsentStringValid(consentString)
? User.builder().ext(ExtUser.builder().consent(consentString).build()).build()
: null;
private static User createUser(ConsentType consentType, String consentString, String attlConsent) {
final boolean tcfV2ConsentProvided = (StringUtils.isNotBlank(consentString)
&& TcfDefinerService.isConsentStringValid(consentString))
&& (consentType == null || consentType == ConsentType.tcfV2);

if (StringUtils.isNotBlank(attlConsent) || tcfV2ConsentProvided) {
final ExtUser.ExtUserBuilder userExtBuilder = ExtUser.builder();
if (tcfV2ConsentProvided) {
userExtBuilder.consent(consentString);
}
if (StringUtils.isNotBlank(attlConsent)) {
userExtBuilder.consentedProvidersSettings(ConsentedProvidersSettings.of(attlConsent));
}
return User.builder().ext(userExtBuilder.build()).build();
}

return null;
}

private static Regs createRegs(String consentString) {
return StringUtils.isNotBlank(consentString) && Ccpa.isValid(consentString)
? Regs.of(null, ExtRegs.of(null, consentString))
: null;
private static Regs createRegs(String consentString, ConsentType consentType, Integer gdpr) {
final boolean ccpaProvided = Ccpa.isValid(consentString)
&& (consentType == null || consentType == ConsentType.usPrivacy);
if (ccpaProvided || gdpr != null) {
return Regs.of(null, ExtRegs.of(gdpr, ccpaProvided ? consentString : null));
}

return null;
}

private static ExtRequest createExt(HttpRequestContext httpRequest, String tagId, Integer debug) {
Expand All @@ -221,13 +246,45 @@ private static String canonicalUrl(HttpRequestContext httpRequest) {
}
}

private static ConsentType consentTypeFromQueryStringParams(HttpRequestContext httpRequest) {
final String consentTypeParam = httpRequest.getQueryParams().get(CONSENT_TYPE_PARAM);
if (consentTypeParam == null) {
return null;
}
switch (consentTypeParam) {
case "1":
return ConsentType.tcfV1;
case "2":
return ConsentType.tcfV2;
case "3":
return ConsentType.usPrivacy;
default:
return ConsentType.unknown;
}
}

private static String consentStringFromQueryStringParams(HttpRequestContext httpRequest) {
final String requestConsentParam = httpRequest.getQueryParams().get(CONSENT_PARAM);
final String requestGdprConsentParam = httpRequest.getQueryParams().get(GDPR_CONSENT_PARAM);

return ObjectUtils.firstNonNull(requestConsentParam, requestGdprConsentParam);
}

private static String attlConsentFromQueryStringParams(HttpRequestContext httpRequest) {
return httpRequest.getQueryParams().get(ATTL_CONSENT_PARAM);
}

private static Integer gdprFromQueryStringParams(HttpRequestContext httpRequest) {
final String gdprAppliesParam = httpRequest.getQueryParams().get(GDPR_APPLIES_PARAM);
if (StringUtils.equals(gdprAppliesParam, "true")) {
return 1;
} else if (StringUtils.equals(gdprAppliesParam, "false")) {
return 0;
}

return null;
}

private static Long timeoutFromQueryString(HttpRequestContext httpRequest) {
final String timeoutQueryParam = httpRequest.getQueryParams().get(TIMEOUT_REQUEST_PARAM);
if (timeoutQueryParam == null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.prebid.server.proto.openrtb.ext.request;

import lombok.AllArgsConstructor;
import lombok.Value;

@AllArgsConstructor(staticName = "of")
@Value
public class ConsentedProvidersSettings {

String consentedProviders;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.prebid.server.proto.openrtb.ext.request;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.Builder;
Expand Down Expand Up @@ -46,6 +47,12 @@ public class ExtUser extends FlexibleExtension {
*/
JsonNode digitrust;

/**
* Defines the contract for bidrequest.user.ext.ConsentedProvidersSettings
*/
@JsonProperty("ConsentedProvidersSettings")
ConsentedProvidersSettings consentedProvidersSettings;

@JsonIgnore
public boolean isEmpty() {
return Objects.equals(this, EMPTY);
Expand Down
Loading