From dee61acf47568e5fa85281b0fa26b39f623acd75 Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Mon, 22 Mar 2021 17:13:15 +0200 Subject: [PATCH 01/12] Add HookStageExecutor and dependent types --- .../hooks/execution/HookStageExecutor.java | 19 ++++++++++++ .../execution/model/ExecutionAction.java | 6 ++++ .../execution/model/ExecutionStatus.java | 6 ++++ .../model/GroupExecutionOutcome.java | 11 +++++++ .../execution/model/HookExecutionOutcome.java | 29 +++++++++++++++++++ .../model/HookStageExecutionResult.java | 13 +++++++++ .../server/hooks/execution/model/Stage.java | 6 ++++ .../model/StageExecutionOutcome.java | 11 +++++++ 8 files changed, 101 insertions(+) create mode 100644 src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/ExecutionAction.java create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/ExecutionStatus.java create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/GroupExecutionOutcome.java create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/HookExecutionOutcome.java create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/Stage.java create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/StageExecutionOutcome.java diff --git a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java new file mode 100644 index 00000000000..18f01c3f02c --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java @@ -0,0 +1,19 @@ +package org.prebid.server.hooks.execution; + +import io.vertx.core.Future; +import io.vertx.core.MultiMap; +import org.prebid.server.hooks.execution.model.HookStageExecutionResult; +import org.prebid.server.hooks.v1.endpoint.EndpointPayload; +import org.prebid.server.model.Endpoint; + +public class HookStageExecutor { + + public Future> executeEndpointHooks( + MultiMap queryParams, + MultiMap headers, + String body, + Endpoint endpoint) { + + return null; + } +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/ExecutionAction.java b/src/main/java/org/prebid/server/hooks/execution/model/ExecutionAction.java new file mode 100644 index 00000000000..5e13aa3f14c --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/ExecutionAction.java @@ -0,0 +1,6 @@ +package org.prebid.server.hooks.execution.model; + +public enum ExecutionAction { + + no_action, update, reject +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/ExecutionStatus.java b/src/main/java/org/prebid/server/hooks/execution/model/ExecutionStatus.java new file mode 100644 index 00000000000..502de1af780 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/ExecutionStatus.java @@ -0,0 +1,6 @@ +package org.prebid.server.hooks.execution.model; + +public enum ExecutionStatus { + + success, failure, timeout +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/GroupExecutionOutcome.java b/src/main/java/org/prebid/server/hooks/execution/model/GroupExecutionOutcome.java new file mode 100644 index 00000000000..91bd0915d88 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/GroupExecutionOutcome.java @@ -0,0 +1,11 @@ +package org.prebid.server.hooks.execution.model; + +import lombok.Value; + +import java.util.List; + +@Value(staticConstructor = "of") +public class GroupExecutionOutcome { + + List hooks; +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionOutcome.java b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionOutcome.java new file mode 100644 index 00000000000..897ffd14199 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionOutcome.java @@ -0,0 +1,29 @@ +package org.prebid.server.hooks.execution.model; + +import lombok.Builder; +import lombok.Value; + +import java.util.List; + +@Builder +@Value +public class HookExecutionOutcome { + + String moduleCode; + + String hookCode; + + Long executionTime; + + ExecutionStatus status; + + String message; + + ExecutionAction action; + + List errors; + + List warnings; + + List debugMessages; +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java b/src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java new file mode 100644 index 00000000000..24f6307f5b9 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java @@ -0,0 +1,13 @@ +package org.prebid.server.hooks.execution.model; + +import lombok.Value; + +@Value(staticConstructor = "of") +public class HookStageExecutionResult { + + boolean shouldReject; + + PAYLOAD payload; + + StageExecutionOutcome executionOutcome; +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/Stage.java b/src/main/java/org/prebid/server/hooks/execution/model/Stage.java new file mode 100644 index 00000000000..35590f671f9 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/Stage.java @@ -0,0 +1,6 @@ +package org.prebid.server.hooks.execution.model; + +public enum Stage { + + endpoint, auction_request, bidder_request, bidder_response, auction_response +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/StageExecutionOutcome.java b/src/main/java/org/prebid/server/hooks/execution/model/StageExecutionOutcome.java new file mode 100644 index 00000000000..055fc26dc54 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/StageExecutionOutcome.java @@ -0,0 +1,11 @@ +package org.prebid.server.hooks.execution.model; + +import lombok.Value; + +import java.util.List; + +@Value(staticConstructor = "of") +public class StageExecutionOutcome { + + List groups; +} From 71a6a96e40446845a1af9a5536600356d5b74dd8 Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Mon, 22 Mar 2021 17:13:30 +0200 Subject: [PATCH 02/12] Rename hook name to hook code --- src/main/java/org/prebid/server/hooks/v1/Hook.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/hooks/v1/Hook.java b/src/main/java/org/prebid/server/hooks/v1/Hook.java index b8088bd287f..83c24ddf23e 100644 --- a/src/main/java/org/prebid/server/hooks/v1/Hook.java +++ b/src/main/java/org/prebid/server/hooks/v1/Hook.java @@ -6,5 +6,5 @@ public interface Hook { Future> call(PAYLOAD payload, CONTEXT invocationContext); - String name(); + String code(); } From 412af926ad608c074f127e887a7de54b9fe6f37a Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Mon, 22 Mar 2021 17:14:55 +0200 Subject: [PATCH 03/12] Rename "endpoint hook" to "entrypoint hook" --- .../prebid/server/hooks/execution/HookStageExecutor.java | 4 ++-- .../org/prebid/server/hooks/v1/endpoint/EndpointHook.java | 8 -------- .../prebid/server/hooks/v1/entrypoint/EntrypointHook.java | 8 ++++++++ .../EntrypointPayload.java} | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) delete mode 100644 src/main/java/org/prebid/server/hooks/v1/endpoint/EndpointHook.java create mode 100644 src/main/java/org/prebid/server/hooks/v1/entrypoint/EntrypointHook.java rename src/main/java/org/prebid/server/hooks/v1/{endpoint/EndpointPayload.java => entrypoint/EntrypointPayload.java} (56%) diff --git a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java index 18f01c3f02c..804b3b61021 100644 --- a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java +++ b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java @@ -3,12 +3,12 @@ import io.vertx.core.Future; import io.vertx.core.MultiMap; import org.prebid.server.hooks.execution.model.HookStageExecutionResult; -import org.prebid.server.hooks.v1.endpoint.EndpointPayload; +import org.prebid.server.hooks.v1.entrypoint.EntrypointPayload; import org.prebid.server.model.Endpoint; public class HookStageExecutor { - public Future> executeEndpointHooks( + public Future> executeEndpointHooks( MultiMap queryParams, MultiMap headers, String body, diff --git a/src/main/java/org/prebid/server/hooks/v1/endpoint/EndpointHook.java b/src/main/java/org/prebid/server/hooks/v1/endpoint/EndpointHook.java deleted file mode 100644 index 31d4769d716..00000000000 --- a/src/main/java/org/prebid/server/hooks/v1/endpoint/EndpointHook.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.prebid.server.hooks.v1.endpoint; - -import org.prebid.server.hooks.v1.Hook; -import org.prebid.server.hooks.v1.InvocationContext; - -public interface EndpointHook extends Hook { - -} diff --git a/src/main/java/org/prebid/server/hooks/v1/entrypoint/EntrypointHook.java b/src/main/java/org/prebid/server/hooks/v1/entrypoint/EntrypointHook.java new file mode 100644 index 00000000000..a8aaee16ecf --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/v1/entrypoint/EntrypointHook.java @@ -0,0 +1,8 @@ +package org.prebid.server.hooks.v1.entrypoint; + +import org.prebid.server.hooks.v1.Hook; +import org.prebid.server.hooks.v1.InvocationContext; + +public interface EntrypointHook extends Hook { + +} diff --git a/src/main/java/org/prebid/server/hooks/v1/endpoint/EndpointPayload.java b/src/main/java/org/prebid/server/hooks/v1/entrypoint/EntrypointPayload.java similarity index 56% rename from src/main/java/org/prebid/server/hooks/v1/endpoint/EndpointPayload.java rename to src/main/java/org/prebid/server/hooks/v1/entrypoint/EntrypointPayload.java index 5d9f964cd35..3b28219bb5e 100644 --- a/src/main/java/org/prebid/server/hooks/v1/endpoint/EndpointPayload.java +++ b/src/main/java/org/prebid/server/hooks/v1/entrypoint/EntrypointPayload.java @@ -1,8 +1,8 @@ -package org.prebid.server.hooks.v1.endpoint; +package org.prebid.server.hooks.v1.entrypoint; import io.vertx.core.MultiMap; -public interface EndpointPayload { +public interface EntrypointPayload { MultiMap queryParams(); From 5edcca24b3c67d54b069be1b8b6502433a2d2893 Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Tue, 23 Mar 2021 11:47:14 +0200 Subject: [PATCH 04/12] Invoke entrypoint stage hooks in AuctionRequestFactory - WIP --- .../server/auction/AuctionRequestFactory.java | 99 +++++++++++++++---- .../hooks/execution/HookStageExecutor.java | 2 +- .../execution/model/HookExecutionContext.java | 13 +++ .../server/hooks/execution/model/Stage.java | 2 +- .../server/model/HttpRequestWrapper.java | 16 +++ .../spring/config/ServiceConfiguration.java | 2 +- .../auction/AuctionRequestFactoryTest.java | 20 ++-- 7 files changed, 120 insertions(+), 34 deletions(-) create mode 100644 src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java create mode 100644 src/main/java/org/prebid/server/model/HttpRequestWrapper.java diff --git a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java index b117663cf94..53e2627f3fc 100644 --- a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java @@ -11,9 +11,7 @@ import com.iab.openrtb.request.Publisher; import com.iab.openrtb.request.Site; import com.iab.openrtb.request.Source; -import io.netty.buffer.ByteBufInputStream; import io.vertx.core.Future; -import io.vertx.core.buffer.Buffer; import io.vertx.core.http.HttpServerRequest; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; @@ -23,6 +21,8 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.IpAddress; +import org.prebid.server.auction.model.Tuple2; +import org.prebid.server.auction.model.Tuple3; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.cookie.UidsCookieService; import org.prebid.server.exception.BlacklistedAccountException; @@ -33,10 +33,15 @@ import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.geolocation.model.GeoInfo; +import org.prebid.server.hooks.execution.HookStageExecutor; +import org.prebid.server.hooks.execution.model.HookExecutionContext; +import org.prebid.server.hooks.execution.model.Stage; import org.prebid.server.identity.IdGenerator; import org.prebid.server.json.JacksonMapper; import org.prebid.server.log.ConditionalLogger; import org.prebid.server.metric.MetricName; +import org.prebid.server.model.Endpoint; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.privacy.model.PrivacyContext; import org.prebid.server.proto.openrtb.ext.request.ExtDevice; import org.prebid.server.proto.openrtb.ext.request.ExtMediaTypePriceGranularity; @@ -63,6 +68,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Currency; +import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -104,13 +110,14 @@ public class AuctionRequestFactory { private final BidderCatalog bidderCatalog; private final RequestValidator requestValidator; private final InterstitialProcessor interstitialProcessor; + private final OrtbTypesResolver ortbTypesResolver; private final TimeoutResolver timeoutResolver; private final TimeoutFactory timeoutFactory; private final ApplicationSettings applicationSettings; private final IdGenerator sourceIdGenerator; private final PrivacyEnforcementService privacyEnforcementService; + private final HookStageExecutor hookStageExecutor; private final JacksonMapper mapper; - private final OrtbTypesResolver ortbTypesResolver; public AuctionRequestFactory(long maxRequestSize, boolean enforceValidAccount, @@ -131,6 +138,7 @@ public AuctionRequestFactory(long maxRequestSize, ApplicationSettings applicationSettings, IdGenerator sourceIdGenerator, PrivacyEnforcementService privacyEnforcementService, + HookStageExecutor hookStageExecutor, JacksonMapper mapper) { this.maxRequestSize = maxRequestSize; @@ -152,6 +160,7 @@ public AuctionRequestFactory(long maxRequestSize, this.applicationSettings = Objects.requireNonNull(applicationSettings); this.sourceIdGenerator = Objects.requireNonNull(sourceIdGenerator); this.privacyEnforcementService = Objects.requireNonNull(privacyEnforcementService); + this.hookStageExecutor = Objects.requireNonNull(hookStageExecutor); this.mapper = Objects.requireNonNull(mapper); } @@ -172,21 +181,22 @@ private static String validateCurrency(String code) { */ public Future fromRequest(RoutingContext routingContext, long startTime) { final List errors = new ArrayList<>(); - final BidRequest incomingBidRequest; + final String body; try { - incomingBidRequest = parseRequest(routingContext, errors); + body = extractAndValidateBody(routingContext); } catch (InvalidRequestException e) { return Future.failedFuture(e); } - return updateBidRequest(routingContext, incomingBidRequest) - .compose(bidRequest -> toAuctionContext( - routingContext, - bidRequest, - requestTypeMetric(bidRequest), - errors, - startTime, - timeoutResolver)); + return parseRequest(body, routingContext, errors) + .compose(tuple -> updateBidRequest(routingContext, tuple.getMiddle()) // FIXME: use httpRequest + .compose(bidRequest -> toAuctionContext( + routingContext, // FIXME: use httpRequest + bidRequest, + requestTypeMetric(bidRequest), + errors, + startTime, + timeoutResolver))); } /** @@ -226,8 +236,44 @@ Future toAuctionContext(RoutingContext routingContext, *

* Throws {@link InvalidRequestException} if body is empty, exceeds max request size or couldn't be deserialized. */ - private BidRequest parseRequest(RoutingContext context, List errors) { - final Buffer body = context.getBody(); + private Future> parseRequest( + String body, + RoutingContext context, + List errors) { + + return hookStageExecutor.executeEntrypointStage( + context.queryParams(), + context.request().headers(), + body, + Endpoint.openrtb2_auction) + .map(stageResult -> { + if (stageResult.isShouldReject()) { + // FIXME: rejection + throw new InvalidRequestException("Hooks rejected request"); + } + + final HttpRequestWrapper httpRequest = HttpRequestWrapper.builder() + .queryParams(stageResult.getPayload().queryParams()) + .headers(stageResult.getPayload().headers()) + .body(stageResult.getPayload().body()) + .build(); + + final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() + .stageOutcomes(new EnumMap<>(Stage.class)) + .build(); + hookExecutionContext.getStageOutcomes().put(Stage.entrypoint, stageResult.getExecutionOutcome()); + + return Tuple2.of(httpRequest, hookExecutionContext); + }) + .map(tuple -> Tuple3.of( + tuple.getLeft(), + normalizeAndDeserializeRequest(tuple.getLeft().getBody(), context, errors), // FIXME: use + // httpRequest + tuple.getRight())); + } + + private String extractAndValidateBody(RoutingContext context) { + final String body = context.getBodyAsString(); if (body == null) { throw new InvalidRequestException("Incoming request has no body"); } @@ -237,16 +283,27 @@ private BidRequest parseRequest(RoutingContext context, List errors) { String.format("Request size exceeded max size of %d bytes.", maxRequestSize)); } - final JsonNode bidRequestNode; - try (ByteBufInputStream inputStream = new ByteBufInputStream(body.getByteBuf())) { - bidRequestNode = mapper.mapper().readTree(inputStream); - } catch (IOException e) { - throw new InvalidRequestException(String.format("Error decoding bidRequest: %s", e.getMessage())); - } + return body; + } + + private BidRequest normalizeAndDeserializeRequest(String body, RoutingContext context, List errors) { + final JsonNode bidRequestNode = bodyAsJsonNode(body); final String referer = paramsExtractor.refererFrom(context.request()); ortbTypesResolver.normalizeBidRequest(bidRequestNode, errors, referer); + return jsonNodeAsBidRequest(bidRequestNode); + } + + private JsonNode bodyAsJsonNode(String body) { + try { + return mapper.mapper().readTree(body); + } catch (IOException e) { + throw new InvalidRequestException(String.format("Error decoding bidRequest: %s", e.getMessage())); + } + } + + private BidRequest jsonNodeAsBidRequest(JsonNode bidRequestNode) { try { return mapper.mapper().treeToValue(bidRequestNode, BidRequest.class); } catch (JsonProcessingException e) { diff --git a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java index 804b3b61021..dec32af5e4f 100644 --- a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java +++ b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java @@ -8,7 +8,7 @@ public class HookStageExecutor { - public Future> executeEndpointHooks( + public Future> executeEntrypointStage( MultiMap queryParams, MultiMap headers, String body, diff --git a/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java new file mode 100644 index 00000000000..54df43b9672 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java @@ -0,0 +1,13 @@ +package org.prebid.server.hooks.execution.model; + +import lombok.Builder; +import lombok.Value; + +import java.util.EnumMap; + +@Builder +@Value +public class HookExecutionContext { + + EnumMap stageOutcomes; +} diff --git a/src/main/java/org/prebid/server/hooks/execution/model/Stage.java b/src/main/java/org/prebid/server/hooks/execution/model/Stage.java index 35590f671f9..11fb33bf3b2 100644 --- a/src/main/java/org/prebid/server/hooks/execution/model/Stage.java +++ b/src/main/java/org/prebid/server/hooks/execution/model/Stage.java @@ -2,5 +2,5 @@ public enum Stage { - endpoint, auction_request, bidder_request, bidder_response, auction_response + entrypoint, auction_request, bidder_request, bidder_response, auction_response } diff --git a/src/main/java/org/prebid/server/model/HttpRequestWrapper.java b/src/main/java/org/prebid/server/model/HttpRequestWrapper.java new file mode 100644 index 00000000000..72671c6c887 --- /dev/null +++ b/src/main/java/org/prebid/server/model/HttpRequestWrapper.java @@ -0,0 +1,16 @@ +package org.prebid.server.model; + +import io.vertx.core.MultiMap; +import lombok.Builder; +import lombok.Value; + +@Builder +@Value +public class HttpRequestWrapper { + + MultiMap queryParams; + + MultiMap headers; + + String body; +} diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index ed75c5ddfb1..07fb447dc79 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -222,7 +222,7 @@ AuctionRequestFactory auctionRequestFactory( applicationSettings, sourceIdGenerator, privacyEnforcementService, - mapper); + hookStageExecutor, mapper); } @Bean diff --git a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java index 8b6e8bce0b0..49bda0e2d01 100644 --- a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java @@ -172,7 +172,7 @@ public void setUp() { applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); } @Test @@ -213,7 +213,7 @@ public void shouldReturnFailedFutureIfAccountIsEnforcedAndIdIsNotProvided() { applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); givenValidBidRequest(); @@ -252,7 +252,7 @@ public void shouldReturnFailedFutureIfAccountIsEnforcedAndFailedGetAccountById() applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); given(applicationSettings.getAccountById(any(), any())) .willReturn(Future.failedFuture(new PreBidException("Not found"))); @@ -326,7 +326,7 @@ public void shouldReturnFailedFutureIfRequestBodyExceedsMaxRequestSize() { applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); given(routingContext.getBody()).willReturn(Buffer.buffer("body")); @@ -1685,7 +1685,7 @@ public void shouldSetDefaultIncludeBidderKeysToFalseIfIncludeBidderKeysIsMissedA applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) .ext(ExtRequest.of(ExtRequestPrebid.builder() @@ -1728,7 +1728,7 @@ public void shouldSetCacheWinningonlyFromConfigWhenExtRequestPrebidIsNull() { applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1770,7 +1770,7 @@ public void shouldSetCacheWinningonlyFromConfigWhenExtRequestPrebidCacheIsNull() applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1812,7 +1812,7 @@ public void shouldSetCacheWinningonlyFromConfigWhenCacheWinningonlyIsNull() { applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1905,7 +1905,7 @@ public void shouldSetCacheWinningonlyFromRequestWhenCacheWinningonlyIsPresent() applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1949,7 +1949,7 @@ public void shouldNotSetCacheWinningonlyFromConfigWhenCacheWinningonlyIsNullAndC applicationSettings, idGenerator, privacyEnforcementService, - jacksonMapper); + hookStageExecutor, jacksonMapper); final ExtRequest extBidRequest = ExtRequest.of(ExtRequestPrebid.builder() .cache(ExtRequestPrebidCache.of(null, null, null)) From 73844a469cede6684842260f4105121e5b353c30 Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Wed, 24 Mar 2021 11:14:32 +0200 Subject: [PATCH 05/12] Invoke entrypoint stage hooks in AuctionRequestFactory - WIP --- .../server/auction/AmpRequestFactory.java | 13 +- .../server/auction/AuctionRequestFactory.java | 170 +++++++++--------- .../auction/BidResponsePostProcessor.java | 19 +- .../server/auction/ExchangeService.java | 4 +- .../auction/ImplicitParametersExtractor.java | 24 +-- .../server/auction/VideoRequestFactory.java | 9 +- .../server/auction/model/AuctionContext.java | 7 +- .../exception/RejectedRequestException.java | 16 ++ .../hooks/execution/HookStageExecutor.java | 3 +- .../execution/model/HookExecutionContext.java | 3 + .../model/HookStageExecutionResult.java | 2 - .../server/model/HttpRequestWrapper.java | 6 + .../spring/config/ServiceConfiguration.java | 3 +- .../server/auction/AmpRequestFactoryTest.java | 6 +- .../auction/AuctionRequestFactoryTest.java | 36 ++-- .../ImplicitParametersExtractorTest.java | 52 +++--- .../auction/VideoRequestFactoryTest.java | 7 +- 17 files changed, 222 insertions(+), 158 deletions(-) create mode 100644 src/main/java/org/prebid/server/exception/RejectedRequestException.java diff --git a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java index 9d07d648978..ddebc90eb0e 100644 --- a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java @@ -107,12 +107,15 @@ public Future fromRequest(RoutingContext routingContext, long st } return createBidRequest(routingContext, tagId) .compose(bidRequestWithErrors -> auctionRequestFactory.toAuctionContext( - routingContext, + // FIXME + null, bidRequestWithErrors.getLeft(), MetricName.amp, bidRequestWithErrors.getRight(), startTime, - timeoutResolver)); + timeoutResolver, + // FIXME + null)); } /** @@ -125,7 +128,8 @@ private Future>> createBidRequest(RoutingContext .map(bidRequest -> validateStoredBidRequest(tagId, bidRequest)) .map(bidRequest -> fillExplicitParameters(bidRequest, context)) .map(bidRequest -> overrideParameters(bidRequest, context.request(), errors)) - .map(bidRequest -> auctionRequestFactory.fillImplicitParameters(bidRequest, context, timeoutResolver)) + // FIXME + .map(bidRequest -> auctionRequestFactory.fillImplicitParameters(bidRequest, null, timeoutResolver)) .map(auctionRequestFactory::validateRequest) .map(bidRequest -> Tuple2.of(bidRequest, errors)); } @@ -270,7 +274,8 @@ private BidRequest overrideParameters(BidRequest bidRequest, HttpServerRequest r final String requestTargeting = request.getParam(TARGETING_REQUEST_PARAM); final ObjectNode targetingNode = readTargeting(requestTargeting); - ortbTypesResolver.normalizeTargeting(targetingNode, errors, implicitParametersExtractor.refererFrom(request)); + // FIXME + ortbTypesResolver.normalizeTargeting(targetingNode, errors, implicitParametersExtractor.refererFrom(null)); final Targeting targeting = parseTargeting(targetingNode); final Site updatedSite = overrideSite(bidRequest.getSite(), request); diff --git a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java index 53e2627f3fc..c63c99bf404 100644 --- a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java @@ -12,7 +12,6 @@ import com.iab.openrtb.request.Site; import com.iab.openrtb.request.Source; import io.vertx.core.Future; -import io.vertx.core.http.HttpServerRequest; import io.vertx.core.logging.Logger; import io.vertx.core.logging.LoggerFactory; import io.vertx.ext.web.RoutingContext; @@ -21,21 +20,22 @@ import org.apache.commons.lang3.StringUtils; import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.IpAddress; -import org.prebid.server.auction.model.Tuple2; -import org.prebid.server.auction.model.Tuple3; import org.prebid.server.bidder.BidderCatalog; import org.prebid.server.cookie.UidsCookieService; import org.prebid.server.exception.BlacklistedAccountException; import org.prebid.server.exception.BlacklistedAppException; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.PreBidException; +import org.prebid.server.exception.RejectedRequestException; import org.prebid.server.exception.UnauthorizedAccountException; import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.geolocation.model.GeoInfo; import org.prebid.server.hooks.execution.HookStageExecutor; import org.prebid.server.hooks.execution.model.HookExecutionContext; +import org.prebid.server.hooks.execution.model.HookStageExecutionResult; import org.prebid.server.hooks.execution.model.Stage; +import org.prebid.server.hooks.v1.entrypoint.EntrypointPayload; import org.prebid.server.identity.IdGenerator; import org.prebid.server.json.JacksonMapper; import org.prebid.server.log.ConditionalLogger; @@ -188,15 +188,46 @@ public Future fromRequest(RoutingContext routingContext, long st return Future.failedFuture(e); } - return parseRequest(body, routingContext, errors) - .compose(tuple -> updateBidRequest(routingContext, tuple.getMiddle()) // FIXME: use httpRequest + final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() + .endpoint(Endpoint.openrtb2_auction) + .stageOutcomes(new EnumMap<>(Stage.class)) + .build(); + + return hookStageExecutor.executeEntrypointStage( + routingContext.queryParams(), + routingContext.request().headers(), + body, + hookExecutionContext) + .map(stageResult -> toHttpRequest(stageResult, routingContext, hookExecutionContext)) + .compose(httpRequest -> updateBidRequest( + httpRequest, + parseRequest(httpRequest, errors)) .compose(bidRequest -> toAuctionContext( - routingContext, // FIXME: use httpRequest + httpRequest, bidRequest, requestTypeMetric(bidRequest), errors, startTime, - timeoutResolver))); + timeoutResolver, + hookExecutionContext))); + } + + private HttpRequestWrapper toHttpRequest(HookStageExecutionResult stageResult, + RoutingContext routingContext, + HookExecutionContext hookExecutionContext) { + + if (stageResult.isShouldReject()) { + throw new RejectedRequestException(hookExecutionContext); + } + + return HttpRequestWrapper.builder() + .absoluteUri(routingContext.request().absoluteURI()) + .queryParams(stageResult.getPayload().queryParams()) + .headers(stageResult.getPayload().headers()) + .body(stageResult.getPayload().body()) + .scheme(routingContext.request().scheme()) + .remoteHost(routingContext.request().remoteAddress().host()) + .build(); } /** @@ -204,21 +235,22 @@ public Future fromRequest(RoutingContext routingContext, long st *

* Note: {@link TimeoutResolver} used here as argument because this method is utilized in AMP processing. */ - Future toAuctionContext(RoutingContext routingContext, + Future toAuctionContext(HttpRequestWrapper httpRequest, BidRequest bidRequest, MetricName requestTypeMetric, List errors, long startTime, - TimeoutResolver timeoutResolver) { + TimeoutResolver timeoutResolver, + HookExecutionContext hookExecutionContext) { final Timeout timeout = timeout(bidRequest, startTime, timeoutResolver); - return accountFrom(bidRequest, timeout, routingContext) + return accountFrom(bidRequest, timeout, httpRequest) .compose(account -> privacyEnforcementService.contextFromBidRequest( bidRequest, account, requestTypeMetric, timeout, errors) .map(privacyContext -> AuctionContext.builder() - .routingContext(routingContext) - .uidsCookie(uidsCookieService.parseFromRequest(routingContext)) + .httpRequest(httpRequest) + .uidsCookie(uidsCookieService.parseFromRequest(null)) .bidRequest(enrichBidRequestWithAccountAndPrivacyData( bidRequest, account, privacyContext)) .requestTypeMetric(requestTypeMetric) @@ -228,50 +260,10 @@ Future toAuctionContext(RoutingContext routingContext, .debugWarnings(new ArrayList<>()) .privacyContext(privacyContext) .geoInfo(privacyContext.getTcfContext().getGeoInfo()) + .hookExecutionContext(hookExecutionContext) .build())); } - /** - * Parses request body to {@link BidRequest}. - *

- * Throws {@link InvalidRequestException} if body is empty, exceeds max request size or couldn't be deserialized. - */ - private Future> parseRequest( - String body, - RoutingContext context, - List errors) { - - return hookStageExecutor.executeEntrypointStage( - context.queryParams(), - context.request().headers(), - body, - Endpoint.openrtb2_auction) - .map(stageResult -> { - if (stageResult.isShouldReject()) { - // FIXME: rejection - throw new InvalidRequestException("Hooks rejected request"); - } - - final HttpRequestWrapper httpRequest = HttpRequestWrapper.builder() - .queryParams(stageResult.getPayload().queryParams()) - .headers(stageResult.getPayload().headers()) - .body(stageResult.getPayload().body()) - .build(); - - final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() - .stageOutcomes(new EnumMap<>(Stage.class)) - .build(); - hookExecutionContext.getStageOutcomes().put(Stage.entrypoint, stageResult.getExecutionOutcome()); - - return Tuple2.of(httpRequest, hookExecutionContext); - }) - .map(tuple -> Tuple3.of( - tuple.getLeft(), - normalizeAndDeserializeRequest(tuple.getLeft().getBody(), context, errors), // FIXME: use - // httpRequest - tuple.getRight())); - } - private String extractAndValidateBody(RoutingContext context) { final String body = context.getBodyAsString(); if (body == null) { @@ -286,10 +278,10 @@ private String extractAndValidateBody(RoutingContext context) { return body; } - private BidRequest normalizeAndDeserializeRequest(String body, RoutingContext context, List errors) { - final JsonNode bidRequestNode = bodyAsJsonNode(body); + private BidRequest parseRequest(HttpRequestWrapper httpRequest, List errors) { + final JsonNode bidRequestNode = bodyAsJsonNode(httpRequest.getBody()); - final String referer = paramsExtractor.refererFrom(context.request()); + final String referer = paramsExtractor.refererFrom(httpRequest); ortbTypesResolver.normalizeBidRequest(bidRequestNode, errors, referer); return jsonNodeAsBidRequest(bidRequestNode); @@ -315,9 +307,9 @@ private BidRequest jsonNodeAsBidRequest(JsonNode bidRequestNode) { * Sets {@link BidRequest} properties which were not set explicitly by the client, but can be * updated by values derived from headers and other request attributes. */ - private Future updateBidRequest(RoutingContext context, BidRequest bidRequest) { + private Future updateBidRequest(HttpRequestWrapper httpRequest, BidRequest bidRequest) { return storedRequestProcessor.processStoredRequests(accountIdFrom(bidRequest), bidRequest) - .map(resolvedBidRequest -> fillImplicitParameters(resolvedBidRequest, context, timeoutResolver)) + .map(resolvedBidRequest -> fillImplicitParameters(resolvedBidRequest, httpRequest, timeoutResolver)) .map(this::validateRequest) .map(interstitialProcessor::process); } @@ -328,23 +320,25 @@ private Future updateBidRequest(RoutingContext context, BidRequest b *

* Note: {@link TimeoutResolver} used here as argument because this method is utilized in AMP processing. */ - BidRequest fillImplicitParameters(BidRequest bidRequest, RoutingContext context, TimeoutResolver timeoutResolver) { + BidRequest fillImplicitParameters(BidRequest bidRequest, + HttpRequestWrapper httpRequest, + TimeoutResolver timeoutResolver) { + checkBlacklistedApp(bidRequest); final BidRequest result; - final HttpServerRequest request = context.request(); final Device device = bidRequest.getDevice(); - final Device populatedDevice = populateDevice(device, bidRequest.getApp(), request); + final Device populatedDevice = populateDevice(device, bidRequest.getApp(), httpRequest); final Site site = bidRequest.getSite(); - final Site populatedSite = bidRequest.getApp() != null ? null : populateSite(site, request); + final Site populatedSite = bidRequest.getApp() != null ? null : populateSite(site, httpRequest); final Source source = bidRequest.getSource(); final Source populatedSource = populateSource(source); final List imps = bidRequest.getImp(); - final List populatedImps = populateImps(imps, request); + final List populatedImps = populateImps(imps, httpRequest); final Integer at = bidRequest.getAt(); final Integer resolvedAt = resolveAt(at); @@ -393,7 +387,7 @@ private void checkBlacklistedApp(BidRequest bidRequest) { * Populates the request body's 'device' section from the incoming http request if the original is partially filled * and the request contains necessary info (User-Agent, IP-address). */ - private Device populateDevice(Device device, App app, HttpServerRequest request) { + private Device populateDevice(Device device, App app, HttpRequestWrapper httpRequest) { final String deviceIp = device != null ? device.getIp() : null; final String deviceIpv6 = device != null ? device.getIpv6() : null; @@ -401,7 +395,7 @@ private Device populateDevice(Device device, App app, HttpServerRequest request) String resolvedIpv6 = sanitizeIp(deviceIpv6, IpAddress.IP.v6); if (resolvedIp == null && resolvedIpv6 == null) { - final IpAddress requestIp = findIpFromRequest(request); + final IpAddress requestIp = findIpFromRequest(httpRequest); resolvedIp = getIpIfVersionIs(requestIp, IpAddress.IP.v4); resolvedIpv6 = getIpIfVersionIs(requestIp, IpAddress.IP.v6); @@ -410,7 +404,7 @@ private Device populateDevice(Device device, App app, HttpServerRequest request) logWarnIfNoIp(resolvedIp, resolvedIpv6); final String ua = device != null ? device.getUa() : null; - final Integer dnt = resolveDntHeader(request); + final Integer dnt = resolveDntHeader(httpRequest); final Integer lmt = resolveLmt(device, app); if (!Objects.equals(deviceIp, resolvedIp) @@ -422,7 +416,7 @@ private Device populateDevice(Device device, App app, HttpServerRequest request) final Device.DeviceBuilder builder = device == null ? Device.builder() : device.toBuilder(); if (StringUtils.isBlank(ua)) { - builder.ua(paramsExtractor.uaFrom(request)); + builder.ua(paramsExtractor.uaFrom(httpRequest)); } if (dnt != null) { builder.dnt(dnt); @@ -442,8 +436,8 @@ private Device populateDevice(Device device, App app, HttpServerRequest request) return null; } - private Integer resolveDntHeader(HttpServerRequest request) { - final String dnt = request.getHeader(HttpUtil.DNT_HEADER.toString()); + private Integer resolveDntHeader(HttpRequestWrapper request) { + final String dnt = request.getHeaders().get(HttpUtil.DNT_HEADER.toString()); return StringUtils.equalsAny(dnt, "0", "1") ? Integer.valueOf(dnt) : null; } @@ -452,7 +446,7 @@ private String sanitizeIp(String ip, IpAddress.IP version) { return ipAddress != null && ipAddress.getVersion() == version ? ipAddress.getIp() : null; } - private IpAddress findIpFromRequest(HttpServerRequest request) { + private IpAddress findIpFromRequest(HttpRequestWrapper request) { final List requestIps = paramsExtractor.ipFrom(request); return requestIps.stream() .map(ipAddressHelper::toIpAddress) @@ -557,9 +551,9 @@ private static Integer resolveLmtForIos14Minor2AndHigher(Device device) { * Populates the request body's 'site' section from the incoming http request if the original is partially filled * and the request contains necessary info (domain, page). */ - private Site populateSite(Site site, HttpServerRequest request) { + private Site populateSite(Site site, HttpRequestWrapper httpRequest) { final String page = site != null ? StringUtils.trimToNull(site.getPage()) : null; - final String updatedPage = page == null ? paramsExtractor.refererFrom(request) : null; + final String updatedPage = page == null ? paramsExtractor.refererFrom(httpRequest) : null; final String domain = site != null ? StringUtils.trimToNull(site.getDomain()) : null; final String updatedDomain = domain == null @@ -612,12 +606,12 @@ private Source populateSource(Source source) { * - Updates imps with security 1, when secured request was received and imp security was not defined. * - Moves bidder parameters from imp.ext._bidder_ to imp.ext.prebid.bidder._bidder_ */ - private List populateImps(List imps, HttpServerRequest request) { + private List populateImps(List imps, HttpRequestWrapper httpRequest) { if (CollectionUtils.isEmpty(imps)) { return null; } - final Integer secureFromRequest = paramsExtractor.secureFrom(request); + final Integer secureFromRequest = paramsExtractor.secureFrom(httpRequest); if (!shouldModifyImps(imps, secureFromRequest)) { return imps; @@ -984,7 +978,7 @@ private Timeout timeout(BidRequest bidRequest, long startTime, TimeoutResolver t /** * Returns {@link Account} fetched by {@link ApplicationSettings}. */ - private Future accountFrom(BidRequest bidRequest, Timeout timeout, RoutingContext routingContext) { + private Future accountFrom(BidRequest bidRequest, Timeout timeout, HttpRequestWrapper httpRequest) { final String accountId = accountIdFrom(bidRequest); final boolean blankAccountId = StringUtils.isBlank(accountId); @@ -995,10 +989,10 @@ private Future accountFrom(BidRequest bidRequest, Timeout timeout, Rout } return blankAccountId - ? responseForEmptyAccount(routingContext) + ? responseForEmptyAccount(httpRequest) : applicationSettings.getAccountById(accountId, timeout) .compose(this::ensureAccountActive, - exception -> accountFallback(exception, accountId, routingContext)); + exception -> accountFallback(exception, accountId, httpRequest)); } /** @@ -1033,21 +1027,25 @@ private String parentAccountIdFromExtPublisher(ExtPublisher extPublisher) { return extPublisherPrebid != null ? StringUtils.stripToNull(extPublisherPrebid.getParentAccount()) : null; } - private Future responseForEmptyAccount(RoutingContext routingContext) { - EMPTY_ACCOUNT_LOGGER.warn(accountErrorMessage("Account not specified", routingContext), 100); + private Future responseForEmptyAccount(HttpRequestWrapper httpRequest) { + EMPTY_ACCOUNT_LOGGER.warn(accountErrorMessage("Account not specified", httpRequest), 100); return responseForUnknownAccount(StringUtils.EMPTY); } - private static String accountErrorMessage(String message, RoutingContext routingContext) { - final HttpServerRequest request = routingContext.request(); - return String.format("%s, Url: %s and Referer: %s", message, request.absoluteURI(), - request.headers().get(HttpUtil.REFERER_HEADER)); + private static String accountErrorMessage(String message, HttpRequestWrapper httpRequest) { + return String.format( + "%s, Url: %s and Referer: %s", + message, + httpRequest.getAbsoluteUri(), + httpRequest.getHeaders().get(HttpUtil.REFERER_HEADER)); } - private Future accountFallback(Throwable exception, String accountId, - RoutingContext routingContext) { + private Future accountFallback(Throwable exception, + String accountId, + HttpRequestWrapper httpRequest) { + if (exception instanceof PreBidException) { - UNKNOWN_ACCOUNT_LOGGER.warn(accountErrorMessage(exception.getMessage(), routingContext), 100); + UNKNOWN_ACCOUNT_LOGGER.warn(accountErrorMessage(exception.getMessage(), httpRequest), 100); } else { logger.warn("Error occurred while fetching account: {0}", exception.getMessage()); logger.debug("Error occurred while fetching account", exception); diff --git a/src/main/java/org/prebid/server/auction/BidResponsePostProcessor.java b/src/main/java/org/prebid/server/auction/BidResponsePostProcessor.java index fcad2277082..eca5308f77f 100644 --- a/src/main/java/org/prebid/server/auction/BidResponsePostProcessor.java +++ b/src/main/java/org/prebid/server/auction/BidResponsePostProcessor.java @@ -3,9 +3,9 @@ import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.response.BidResponse; import io.vertx.core.Future; -import io.vertx.ext.web.RoutingContext; import org.prebid.server.cookie.UidsCookie; import org.prebid.server.cookie.proto.Uids; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.settings.model.Account; /** @@ -17,15 +17,18 @@ public interface BidResponsePostProcessor { /** * This method is called when auction is finished. * - * @param context represents initial web request + * @param httpRequest represents initial web request * @param uidsCookie auction request {@link Uids} container * @param bidRequest original auction request * @param bidResponse auction result * @param account {@link Account} fetched from request * @return a {@link Future} with (possibly modified) auction result */ - Future postProcess(RoutingContext context, UidsCookie uidsCookie, BidRequest bidRequest, - BidResponse bidResponse, Account account); + Future postProcess(HttpRequestWrapper httpRequest, + UidsCookie uidsCookie, + BidRequest bidRequest, + BidResponse bidResponse, + Account account); /** * Returns {@link NoOpBidResponsePostProcessor} instance that just does nothing to original auction result. @@ -39,8 +42,12 @@ static BidResponsePostProcessor noOp() { */ class NoOpBidResponsePostProcessor implements BidResponsePostProcessor { @Override - public Future postProcess(RoutingContext context, UidsCookie uidsCookie, BidRequest bidRequest, - BidResponse bidResponse, Account account) { + public Future postProcess(HttpRequestWrapper httpRequest, + UidsCookie uidsCookie, + BidRequest bidRequest, + BidResponse bidResponse, + Account account) { + return Future.succeededFuture(bidResponse); } } diff --git a/src/main/java/org/prebid/server/auction/ExchangeService.java b/src/main/java/org/prebid/server/auction/ExchangeService.java index b344fcba230..caa5a7bf680 100644 --- a/src/main/java/org/prebid/server/auction/ExchangeService.java +++ b/src/main/java/org/prebid/server/auction/ExchangeService.java @@ -45,12 +45,12 @@ import org.prebid.server.proto.openrtb.ext.request.ExtApp; import org.prebid.server.proto.openrtb.ext.request.ExtBidderConfigOrtb; import org.prebid.server.proto.openrtb.ext.request.ExtImpPrebid; -import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidDataEidPermissions; import org.prebid.server.proto.openrtb.ext.request.ExtRequest; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidBidderConfig; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidCache; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidData; +import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidDataEidPermissions; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidMultiBid; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidSchain; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidSchainSchain; @@ -186,7 +186,7 @@ public Future holdAuction(AuctionContext context) { bidderToMultiBid, debugEnabled)) .compose(bidResponse -> bidResponsePostProcessor.postProcess( - context.getRoutingContext(), uidsCookie, bidRequest, bidResponse, account)); + context.getHttpRequest(), uidsCookie, bidRequest, bidResponse, account)); } private BidderAliases aliases(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java b/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java index a69526d2349..c7ff5515db6 100644 --- a/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java +++ b/src/main/java/org/prebid/server/auction/ImplicitParametersExtractor.java @@ -2,9 +2,9 @@ import de.malkusch.whoisServerList.publicSuffixList.PublicSuffixList; import io.vertx.core.MultiMap; -import io.vertx.core.http.HttpServerRequest; import org.apache.commons.lang3.StringUtils; import org.prebid.server.exception.PreBidException; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.util.HttpUtil; import java.net.MalformedURLException; @@ -30,10 +30,10 @@ public ImplicitParametersExtractor(PublicSuffixList psl) { * Determines Referer by checking 'url_override' request parameter, or if it's empty 'Referer' header. Then if * result is not blank and missing 'http://' prefix appends it. */ - public String refererFrom(HttpServerRequest request) { - final String urlOverride = request.getParam("url_override"); + public String refererFrom(HttpRequestWrapper request) { + final String urlOverride = request.getQueryParams().get("url_override"); final String url = StringUtils.isNotBlank(urlOverride) ? urlOverride - : StringUtils.trimToNull(request.headers().get(HttpUtil.REFERER_HEADER)); + : StringUtils.trimToNull(request.getHeaders().get(HttpUtil.REFERER_HEADER)); return StringUtils.isNotBlank(url) && !StringUtils.startsWith(url, "http") ? String.format("http://%s", url) @@ -73,8 +73,8 @@ public String domainFrom(String urlString) throws PreBidException { /** * Determines IP-Address candidates by checking http headers and remote host address. */ - public List ipFrom(HttpServerRequest request) { - final MultiMap headers = request.headers(); + public List ipFrom(HttpRequestWrapper request) { + final MultiMap headers = request.getHeaders(); final List candidates = new ArrayList<>(); candidates.add(headers.get("True-Client-IP")); @@ -83,7 +83,7 @@ public List ipFrom(HttpServerRequest request) { candidates.addAll(Arrays.asList(xff.split(","))); } candidates.add(headers.get("X-Real-IP")); - candidates.add(request.remoteAddress().host()); + candidates.add(request.getRemoteHost()); return candidates.stream() .map(StringUtils::trimToNull) @@ -94,17 +94,17 @@ public List ipFrom(HttpServerRequest request) { /** * Determines User-Agent by checking 'User-Agent' http header. */ - public String uaFrom(HttpServerRequest request) { - return StringUtils.trimToNull(request.headers().get(HttpUtil.USER_AGENT_HEADER)); + public String uaFrom(HttpRequestWrapper request) { + return StringUtils.trimToNull(request.getHeaders().get(HttpUtil.USER_AGENT_HEADER)); } /** * Determines the value of 'secure' flag by checking if 'X-Forwarded-Proto' contains 'value' or if HTTP request * scheme is 'https'. Returns 1 if one of these conditions evaluates to true or null otherwise. */ - public Integer secureFrom(HttpServerRequest httpRequest) { - return StringUtils.equalsIgnoreCase(httpRequest.headers().get("X-Forwarded-Proto"), "https") - || StringUtils.equalsIgnoreCase(httpRequest.scheme(), "https") + public Integer secureFrom(HttpRequestWrapper httpRequest) { + return StringUtils.equalsIgnoreCase(httpRequest.getHeaders().get("X-Forwarded-Proto"), "https") + || StringUtils.equalsIgnoreCase(httpRequest.getScheme(), "https") ? 1 : null; } } diff --git a/src/main/java/org/prebid/server/auction/VideoRequestFactory.java b/src/main/java/org/prebid/server/auction/VideoRequestFactory.java index 556eedcb9c8..88628b6b5e8 100644 --- a/src/main/java/org/prebid/server/auction/VideoRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/VideoRequestFactory.java @@ -77,12 +77,15 @@ public Future> fromRequest(RoutingContext routingC final Set podConfigIds = podConfigIds(incomingBidRequest); return createBidRequest(routingContext, incomingBidRequest, storedRequestId, podConfigIds) .compose(bidRequestToPodError -> auctionRequestFactory.toAuctionContext( - routingContext, + // FIXME + null, bidRequestToPodError.getData(), MetricName.video, new ArrayList<>(), startTime, - timeoutResolver) + timeoutResolver, + // FIXME + null) .map(auctionContext -> WithPodErrors.of(auctionContext, bidRequestToPodError.getPodErrors()))); } @@ -193,7 +196,7 @@ private WithPodErrors validateRequest(WithPodErrors requ private WithPodErrors fillImplicitParameters(RoutingContext routingContext, WithPodErrors bidRequestToErrors) { final BidRequest bidRequest = auctionRequestFactory - .fillImplicitParameters(bidRequestToErrors.getData(), routingContext, timeoutResolver); + .fillImplicitParameters(bidRequestToErrors.getData(), null, timeoutResolver); // FIXME return WithPodErrors.of(bidRequest, bidRequestToErrors.getPodErrors()); } } diff --git a/src/main/java/org/prebid/server/auction/model/AuctionContext.java b/src/main/java/org/prebid/server/auction/model/AuctionContext.java index f752377e0db..c0ac2c8fbb2 100644 --- a/src/main/java/org/prebid/server/auction/model/AuctionContext.java +++ b/src/main/java/org/prebid/server/auction/model/AuctionContext.java @@ -1,14 +1,15 @@ package org.prebid.server.auction.model; import com.iab.openrtb.request.BidRequest; -import io.vertx.ext.web.RoutingContext; import lombok.Builder; import lombok.Value; import org.prebid.server.cache.model.DebugHttpCall; import org.prebid.server.cookie.UidsCookie; import org.prebid.server.execution.Timeout; import org.prebid.server.geolocation.model.GeoInfo; +import org.prebid.server.hooks.execution.model.HookExecutionContext; import org.prebid.server.metric.MetricName; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.privacy.model.PrivacyContext; import org.prebid.server.settings.model.Account; @@ -19,7 +20,7 @@ @Value public class AuctionContext { - RoutingContext routingContext; + HttpRequestWrapper httpRequest; UidsCookie uidsCookie; @@ -40,4 +41,6 @@ public class AuctionContext { PrivacyContext privacyContext; GeoInfo geoInfo; + + HookExecutionContext hookExecutionContext; } diff --git a/src/main/java/org/prebid/server/exception/RejectedRequestException.java b/src/main/java/org/prebid/server/exception/RejectedRequestException.java new file mode 100644 index 00000000000..6fb932ae6fa --- /dev/null +++ b/src/main/java/org/prebid/server/exception/RejectedRequestException.java @@ -0,0 +1,16 @@ +package org.prebid.server.exception; + +import org.prebid.server.hooks.execution.model.HookExecutionContext; + +public class RejectedRequestException extends RuntimeException { + + private final HookExecutionContext hookExecutionContext; + + public RejectedRequestException(HookExecutionContext hookExecutionContext) { + this.hookExecutionContext = hookExecutionContext; + } + + public HookExecutionContext getHookExecutionContext() { + return hookExecutionContext; + } +} diff --git a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java index dec32af5e4f..b7999d5b9a4 100644 --- a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java +++ b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java @@ -2,6 +2,7 @@ import io.vertx.core.Future; import io.vertx.core.MultiMap; +import org.prebid.server.hooks.execution.model.HookExecutionContext; import org.prebid.server.hooks.execution.model.HookStageExecutionResult; import org.prebid.server.hooks.v1.entrypoint.EntrypointPayload; import org.prebid.server.model.Endpoint; @@ -12,7 +13,7 @@ public Future> executeEntrypointStag MultiMap queryParams, MultiMap headers, String body, - Endpoint endpoint) { + HookExecutionContext context) { return null; } diff --git a/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java index 54df43b9672..b0667e53962 100644 --- a/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java +++ b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java @@ -2,6 +2,7 @@ import lombok.Builder; import lombok.Value; +import org.prebid.server.model.Endpoint; import java.util.EnumMap; @@ -9,5 +10,7 @@ @Value public class HookExecutionContext { + Endpoint endpoint; + EnumMap stageOutcomes; } diff --git a/src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java b/src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java index 24f6307f5b9..3e3eb98b400 100644 --- a/src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java +++ b/src/main/java/org/prebid/server/hooks/execution/model/HookStageExecutionResult.java @@ -8,6 +8,4 @@ public class HookStageExecutionResult { boolean shouldReject; PAYLOAD payload; - - StageExecutionOutcome executionOutcome; } diff --git a/src/main/java/org/prebid/server/model/HttpRequestWrapper.java b/src/main/java/org/prebid/server/model/HttpRequestWrapper.java index 72671c6c887..39a2d3d31c6 100644 --- a/src/main/java/org/prebid/server/model/HttpRequestWrapper.java +++ b/src/main/java/org/prebid/server/model/HttpRequestWrapper.java @@ -8,9 +8,15 @@ @Value public class HttpRequestWrapper { + String absoluteUri; + MultiMap queryParams; MultiMap headers; String body; + + String scheme; + + String remoteHost; } diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index 07fb447dc79..5335c57791d 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -222,7 +222,8 @@ AuctionRequestFactory auctionRequestFactory( applicationSettings, sourceIdGenerator, privacyEnforcementService, - hookStageExecutor, mapper); + null, + mapper); } @Bean diff --git a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java index 0adc684d253..d54f322bb3a 100644 --- a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java @@ -1254,7 +1254,8 @@ public void shouldReturnAddErrorToAuctionContextWhenPrivacyIsNotValid() { // then @SuppressWarnings("unchecked") final ArgumentCaptor> errorsCaptor = ArgumentCaptor.forClass( List.class); - verify(auctionRequestFactory).toAuctionContext(any(), any(), any(), errorsCaptor.capture(), anyLong(), any()); + verify(auctionRequestFactory).toAuctionContext( + any(), any(), any(), errorsCaptor.capture(), anyLong(), any(), any()); assertThat(errorsCaptor.getValue()).contains("Amp request parameter consent_string or gdpr_consent have" + " invalid format: consent-value"); } @@ -1476,7 +1477,8 @@ private void givenBidRequest( given(auctionRequestFactory.fillImplicitParameters(any(), any(), any())).willAnswer(answerWithFirstArgument()); given(auctionRequestFactory.validateRequest(any())).willAnswer(answerWithFirstArgument()); - given(auctionRequestFactory.toAuctionContext(any(), any(), eq(MetricName.amp), anyList(), anyLong(), any())) + given(auctionRequestFactory.toAuctionContext( + any(), any(), eq(MetricName.amp), anyList(), anyLong(), any(), any())) .willAnswer(invocationOnMock -> Future.succeededFuture( AuctionContext.builder() .bidRequest((BidRequest) invocationOnMock.getArguments()[1]) diff --git a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java index 49bda0e2d01..9aea7668fcb 100644 --- a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java @@ -172,7 +172,8 @@ public void setUp() { applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); } @Test @@ -213,7 +214,8 @@ public void shouldReturnFailedFutureIfAccountIsEnforcedAndIdIsNotProvided() { applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); givenValidBidRequest(); @@ -252,7 +254,8 @@ public void shouldReturnFailedFutureIfAccountIsEnforcedAndFailedGetAccountById() applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); given(applicationSettings.getAccountById(any(), any())) .willReturn(Future.failedFuture(new PreBidException("Not found"))); @@ -326,7 +329,8 @@ public void shouldReturnFailedFutureIfRequestBodyExceedsMaxRequestSize() { applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); given(routingContext.getBody()).willReturn(Buffer.buffer("body")); @@ -1685,7 +1689,8 @@ public void shouldSetDefaultIncludeBidderKeysToFalseIfIncludeBidderKeysIsMissedA applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) .ext(ExtRequest.of(ExtRequestPrebid.builder() @@ -1728,7 +1733,8 @@ public void shouldSetCacheWinningonlyFromConfigWhenExtRequestPrebidIsNull() { applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1770,7 +1776,8 @@ public void shouldSetCacheWinningonlyFromConfigWhenExtRequestPrebidCacheIsNull() applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1812,7 +1819,8 @@ public void shouldSetCacheWinningonlyFromConfigWhenCacheWinningonlyIsNull() { applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1905,7 +1913,8 @@ public void shouldSetCacheWinningonlyFromRequestWhenCacheWinningonlyIsPresent() applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1949,7 +1958,8 @@ public void shouldNotSetCacheWinningonlyFromConfigWhenCacheWinningonlyIsNullAndC applicationSettings, idGenerator, privacyEnforcementService, - hookStageExecutor, jacksonMapper); + null, + jacksonMapper); final ExtRequest extBidRequest = ExtRequest.of(ExtRequestPrebid.builder() .cache(ExtRequestPrebidCache.of(null, null, null)) @@ -2150,10 +2160,12 @@ public void shouldReturnAuctionContextWithRoutingContext() { givenValidBidRequest(); // when - final RoutingContext context = factory.fromRequest(routingContext, 0L).result().getRoutingContext(); + + // FIXME +// final RoutingContext context = factory.fromRequest(routingContext, 0L).result().getRoutingContext(); // then - assertThat(context).isSameAs(routingContext); +// assertThat(context).isSameAs(routingContext); } @Test diff --git a/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java b/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java index 12b57310bbc..7b75159a19f 100644 --- a/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java +++ b/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java @@ -3,22 +3,19 @@ import de.malkusch.whoisServerList.publicSuffixList.PublicSuffixList; import de.malkusch.whoisServerList.publicSuffixList.PublicSuffixListFactory; import io.vertx.core.http.CaseInsensitiveHeaders; -import io.vertx.core.http.HttpServerRequest; -import io.vertx.core.net.impl.SocketAddressImpl; import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; import org.prebid.server.exception.PreBidException; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.util.HttpUtil; import java.net.MalformedURLException; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatCode; -import static org.mockito.BDDMockito.given; public class ImplicitParametersExtractorTest { @@ -28,13 +25,16 @@ public class ImplicitParametersExtractorTest { private final PublicSuffixList psl = new PublicSuffixListFactory().build(); private ImplicitParametersExtractor extractor; - @Mock - private HttpServerRequest httpRequest; + + private HttpRequestWrapper httpRequest; @Before public void setUp() { // minimal request - given(httpRequest.headers()).willReturn(new CaseInsensitiveHeaders()); + httpRequest = HttpRequestWrapper.builder() + .queryParams(new CaseInsensitiveHeaders()) + .headers(new CaseInsensitiveHeaders()) + .build(); extractor = new ImplicitParametersExtractor(psl); } @@ -42,7 +42,7 @@ public void setUp() { @Test public void refererFromShouldReturnRefererFromRefererHeader() { // given - httpRequest.headers().set(HttpUtil.REFERER_HEADER, "http://example.com"); + httpRequest.getHeaders().set(HttpUtil.REFERER_HEADER, "http://example.com"); // when and then assertThat(extractor.refererFrom(httpRequest)).isEqualTo("http://example.com"); @@ -51,8 +51,8 @@ public void refererFromShouldReturnRefererFromRefererHeader() { @Test public void refererFromShouldReturnRefererFromRefererHeaderIfUrlOverrideParamBlank() { // given - httpRequest.headers().set(HttpUtil.REFERER_HEADER, "http://example.com"); - given(httpRequest.getParam("url_override")).willReturn(""); + httpRequest.getHeaders().set(HttpUtil.REFERER_HEADER, "http://example.com"); + httpRequest.getQueryParams().set("url_override", ""); // when and then assertThat(extractor.refererFrom(httpRequest)).isEqualTo("http://example.com"); @@ -61,7 +61,7 @@ public void refererFromShouldReturnRefererFromRefererHeaderIfUrlOverrideParamBla @Test public void refererFromShouldReturnRefererFromRequestParamIfUrlOverrideParamExists() { // given - given(httpRequest.getParam("url_override")).willReturn("http://exampleoverrride.com"); + httpRequest.getQueryParams().set("url_override", "http://exampleoverrride.com"); // when and then assertThat(extractor.refererFrom(httpRequest)).isEqualTo("http://exampleoverrride.com"); @@ -70,7 +70,7 @@ public void refererFromShouldReturnRefererFromRequestParamIfUrlOverrideParamExis @Test public void refererFromShouldReturnRefererWithHttpSchemeIfUrlOverrideParamDoesNotContainScheme() { // given - given(httpRequest.getParam("url_override")).willReturn("example.com"); + httpRequest.getQueryParams().set("url_override", "example.com"); // when and then assertThat(extractor.refererFrom(httpRequest)).isEqualTo("http://example.com"); @@ -79,7 +79,7 @@ public void refererFromShouldReturnRefererWithHttpSchemeIfUrlOverrideParamDoesNo @Test public void refererFromShouldReturnRefererWithHttpSchemeIfRefererHeaderDoesNotContainScheme() { // given - httpRequest.headers().set(HttpUtil.REFERER_HEADER, "example.com"); + httpRequest.getHeaders().set(HttpUtil.REFERER_HEADER, "example.com"); // when and then assertThat(extractor.refererFrom(httpRequest)).isEqualTo("http://example.com"); @@ -123,10 +123,13 @@ public void domainFromShouldDeriveDomainFromUrl() { @Test public void ipFromShouldReturnIpFromHeadersAndRemoteAddress() { // given - httpRequest.headers().set("True-Client-IP", "192.168.144.1 "); - httpRequest.headers().set("X-Forwarded-For", "192.168.144.2 , 192.168.144.3 "); - httpRequest.headers().set("X-Real-IP", "192.168.144.4 "); - given(httpRequest.remoteAddress()).willReturn(new SocketAddressImpl(0, "192.168.144.5")); + httpRequest = HttpRequestWrapper.builder() + .headers(new CaseInsensitiveHeaders()) + .remoteHost("192.168.144.5") + .build(); + httpRequest.getHeaders().set("True-Client-IP", "192.168.144.1 "); + httpRequest.getHeaders().set("X-Forwarded-For", "192.168.144.2 , 192.168.144.3 "); + httpRequest.getHeaders().set("X-Real-IP", "192.168.144.4 "); // when and then assertThat(extractor.ipFrom(httpRequest)).containsExactly( @@ -136,8 +139,11 @@ public void ipFromShouldReturnIpFromHeadersAndRemoteAddress() { @Test public void ipFromShouldNotReturnNullsAndEmptyValues() { // given - httpRequest.headers().set("X-Real-IP", " "); - given(httpRequest.remoteAddress()).willReturn(new SocketAddressImpl(0, "192.168.144.5")); + httpRequest = HttpRequestWrapper.builder() + .headers(new CaseInsensitiveHeaders()) + .remoteHost("192.168.144.5") + .build(); + httpRequest.getHeaders().set("X-Real-IP", " "); // when and then assertThat(extractor.ipFrom(httpRequest)).containsExactly("192.168.144.5"); @@ -146,7 +152,7 @@ public void ipFromShouldNotReturnNullsAndEmptyValues() { @Test public void uaFromShouldReturnUaFromUserAgentHeader() { // given - httpRequest.headers().set(HttpUtil.USER_AGENT_HEADER, " user agent "); + httpRequest.getHeaders().set(HttpUtil.USER_AGENT_HEADER, " user agent "); // when and then assertThat(extractor.uaFrom(httpRequest)).isEqualTo("user agent"); @@ -155,7 +161,7 @@ public void uaFromShouldReturnUaFromUserAgentHeader() { @Test public void secureFromShouldReturnOneIfXForwardedProtoIsHttps() { // given - httpRequest.headers().set("X-Forwarded-Proto", "https"); + httpRequest.getHeaders().set("X-Forwarded-Proto", "https"); // when and then assertThat(extractor.secureFrom(httpRequest)).isEqualTo(1); @@ -164,7 +170,9 @@ public void secureFromShouldReturnOneIfXForwardedProtoIsHttps() { @Test public void secureFromShouldReturnOneIfConnectedViaSSL() { // given - given(httpRequest.scheme()).willReturn("https"); + httpRequest = HttpRequestWrapper.builder() + .scheme("https") + .build(); // when and then assertThat(extractor.secureFrom(httpRequest)).isEqualTo(1); diff --git a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java index 12e9c997341..71423a1a461 100644 --- a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java @@ -212,7 +212,7 @@ public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingExc given(auctionRequestFactory.validateRequest(any())).willAnswer(invocation -> invocation.getArgument(0)); given(auctionRequestFactory.fillImplicitParameters(any(), any(), any())) .willAnswer(invocation -> invocation.getArgument(0)); - given(auctionRequestFactory.toAuctionContext(any(), any(), any(), anyList(), anyLong(), any())) + given(auctionRequestFactory.toAuctionContext(any(), any(), any(), anyList(), anyLong(), any(), any())) .willReturn(Future.succeededFuture()); // when @@ -222,9 +222,10 @@ public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingExc verify(routingContext).getBody(); verify(videoStoredRequestProcessor).processVideoRequest("", null, emptySet(), requestVideo); verify(auctionRequestFactory).validateRequest(bidRequest); - verify(auctionRequestFactory).fillImplicitParameters(bidRequest, routingContext, timeoutResolver); + verify(auctionRequestFactory).fillImplicitParameters(bidRequest, /*FIXME*/ null, timeoutResolver); verify(auctionRequestFactory).toAuctionContext( - routingContext, bidRequest, MetricName.video, new ArrayList<>(), 0, timeoutResolver); + // FIXME + null, bidRequest, MetricName.video, new ArrayList<>(), 0, timeoutResolver, null); assertThat(result.result().getPodErrors()).isEqualTo(mergedBidRequest.getPodErrors()); } From ff385cc5d47140cf0081b82a8c32f0edee92448c Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Wed, 24 Mar 2021 12:33:45 +0200 Subject: [PATCH 06/12] Invoke entrypoint stage hooks in AmpRequestFactory - WIP --- .../server/auction/AmpRequestFactory.java | 132 ++++++++++-------- .../server/auction/AuctionRequestFactory.java | 19 ++- 2 files changed, 89 insertions(+), 62 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java index ddebc90eb0e..a96b4c90c81 100644 --- a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java @@ -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; @@ -23,8 +22,12 @@ 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.hooks.execution.model.Stage; 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; @@ -45,6 +48,7 @@ import java.util.ArrayList; import java.util.Collections; +import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -88,6 +92,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); @@ -101,39 +106,54 @@ public AmpRequestFactory(StoredRequestProcessor storedRequestProcessor, * Creates {@link AuctionContext} based on {@link RoutingContext}. */ public Future 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( - // FIXME - null, - bidRequestWithErrors.getLeft(), - MetricName.amp, - bidRequestWithErrors.getRight(), - startTime, - timeoutResolver, - // FIXME - null)); + final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() + .endpoint(Endpoint.openrtb2_amp) + .stageOutcomes(new EnumMap<>(Stage.class)) + .build(); + + 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>> createBidRequest(RoutingContext context, String tagId) { + private Future>> createBidRequest(HttpRequestWrapper httpRequest) { + final String tagId = readAndValidateTagId(httpRequest); + final List 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)) - // FIXME - .map(bidRequest -> auctionRequestFactory.fillImplicitParameters(bidRequest, null, 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}. */ @@ -169,7 +189,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 imps = bidRequest.getImp(); // Force HTTPS as AMP requires it, but pubs can forget to set it. final Imp imp = imps.get(0); @@ -202,7 +222,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) @@ -214,7 +234,7 @@ private BidRequest fillExplicitParameters(BidRequest bidRequest, RoutingContext ? debugQueryParam : null; - final Map updatedAmpData = updateAmpData(prebid, context.request()); + final Map updatedAmpData = updateAmpData(prebid, httpRequest); final BidRequest result; if (setSecure @@ -245,17 +265,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 errors) { - final String requestConsentParam = request.getParam(CONSENT_PARAM); - final String requestGdprConsentParam = request.getParam(GDPR_CONSENT_PARAM); + private BidRequest overrideParameters(BidRequest bidRequest, HttpRequestWrapper httpRequest, List 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; @@ -272,15 +292,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); - // FIXME - ortbTypesResolver.normalizeTargeting(targetingNode, errors, implicitParametersExtractor.refererFrom(null)); + 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); @@ -333,9 +353,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; @@ -367,19 +387,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 overwrittenFormats = banner != null - ? createOverrideBannerFormats(request, banner.getFormat()) + ? createOverrideBannerFormats(httpRequest, banner.getFormat()) : null; if (StringUtils.isNotBlank(tagId) || CollectionUtils.isNotEmpty(overwrittenFormats) || targetingNode != null) { return imp.toBuilder() @@ -394,12 +414,12 @@ private Imp overrideImp(Imp imp, HttpServerRequest request, ObjectNode targeting /** * Creates formats from request parameters to override origin amp banner formats. */ - private static List createOverrideBannerFormats(HttpServerRequest request, List 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 createOverrideBannerFormats(HttpRequestWrapper httpRequest, List 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 paramsFormats = createFormatsFromParams(overrideWidth, width, overrideHeight, height, multiSizeParam); @@ -409,8 +429,8 @@ private static List 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) { @@ -474,8 +494,8 @@ private static Banner overrideBanner(Banner banner, List 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; } @@ -559,11 +579,11 @@ private static List parseMultiSizeParam(String ms) { return formats; } - private static Map updateAmpData(ExtRequestPrebid prebid, HttpServerRequest request) { + private static Map updateAmpData(ExtRequestPrebid prebid, HttpRequestWrapper httpRequest) { final ExtRequestPrebidAmp amp = prebid != null ? prebid.getAmp() : null; final Map existingAmpData = amp != null ? amp.getData() : null; - final MultiMap queryParams = request.params(); + final MultiMap queryParams = httpRequest.getQueryParams(); if (queryParams.isEmpty()) { return null; } diff --git a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java index c63c99bf404..21ce4556416 100644 --- a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java @@ -193,12 +193,7 @@ public Future fromRequest(RoutingContext routingContext, long st .stageOutcomes(new EnumMap<>(Stage.class)) .build(); - return hookStageExecutor.executeEntrypointStage( - routingContext.queryParams(), - routingContext.request().headers(), - body, - hookExecutionContext) - .map(stageResult -> toHttpRequest(stageResult, routingContext, hookExecutionContext)) + return executeEntrypointHooks(routingContext, body, hookExecutionContext) .compose(httpRequest -> updateBidRequest( httpRequest, parseRequest(httpRequest, errors)) @@ -212,6 +207,18 @@ public Future fromRequest(RoutingContext routingContext, long st hookExecutionContext))); } + protected Future executeEntrypointHooks(RoutingContext routingContext, + String body, + HookExecutionContext hookExecutionContext) { + + return hookStageExecutor.executeEntrypointStage( + routingContext.queryParams(), + routingContext.request().headers(), + body, + hookExecutionContext) + .map(stageResult -> toHttpRequest(stageResult, routingContext, hookExecutionContext)); + } + private HttpRequestWrapper toHttpRequest(HookStageExecutionResult stageResult, RoutingContext routingContext, HookExecutionContext hookExecutionContext) { From ce0762db9f2e4483e2a1fd25179ec3b97dd66202 Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Wed, 24 Mar 2021 12:53:13 +0200 Subject: [PATCH 07/12] Invoke entrypoint stage hooks in VideoRequestFactory - WIP --- .../server/auction/AuctionRequestFactory.java | 19 +-- .../server/auction/VideoRequestFactory.java | 108 +++++++++++------- 2 files changed, 76 insertions(+), 51 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java index 21ce4556416..44b3e4ba790 100644 --- a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java @@ -194,9 +194,7 @@ public Future fromRequest(RoutingContext routingContext, long st .build(); return executeEntrypointHooks(routingContext, body, hookExecutionContext) - .compose(httpRequest -> updateBidRequest( - httpRequest, - parseRequest(httpRequest, errors)) + .compose(httpRequest -> createBidRequest(httpRequest, errors) .compose(bidRequest -> toAuctionContext( httpRequest, bidRequest, @@ -208,8 +206,8 @@ public Future fromRequest(RoutingContext routingContext, long st } protected Future executeEntrypointHooks(RoutingContext routingContext, - String body, - HookExecutionContext hookExecutionContext) { + String body, + HookExecutionContext hookExecutionContext) { return hookStageExecutor.executeEntrypointStage( routingContext.queryParams(), @@ -311,10 +309,17 @@ private BidRequest jsonNodeAsBidRequest(JsonNode bidRequestNode) { } /** - * Sets {@link BidRequest} properties which were not set explicitly by the client, but can be + * Parses {@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 updateBidRequest(HttpRequestWrapper httpRequest, BidRequest bidRequest) { + private Future createBidRequest(HttpRequestWrapper httpRequest, List errors) { + final BidRequest bidRequest; + try { + bidRequest = parseRequest(httpRequest, errors); + } catch (Exception e) { + return Future.failedFuture(e); + } + return storedRequestProcessor.processStoredRequests(accountIdFrom(bidRequest), bidRequest) .map(resolvedBidRequest -> fillImplicitParameters(resolvedBidRequest, httpRequest, timeoutResolver)) .map(this::validateRequest) diff --git a/src/main/java/org/prebid/server/auction/VideoRequestFactory.java b/src/main/java/org/prebid/server/auction/VideoRequestFactory.java index 88628b6b5e8..cf36c89c263 100644 --- a/src/main/java/org/prebid/server/auction/VideoRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/VideoRequestFactory.java @@ -10,7 +10,6 @@ import com.iab.openrtb.request.video.PodError; import com.iab.openrtb.request.video.Podconfig; import io.vertx.core.Future; -import io.vertx.core.buffer.Buffer; import io.vertx.ext.web.RoutingContext; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; @@ -18,15 +17,20 @@ import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.auction.model.WithPodErrors; import org.prebid.server.exception.InvalidRequestException; +import org.prebid.server.hooks.execution.model.HookExecutionContext; +import org.prebid.server.hooks.execution.model.Stage; import org.prebid.server.json.DecodeException; 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.proto.openrtb.ext.request.ExtPublisher; import org.prebid.server.proto.openrtb.ext.request.ExtPublisherPrebid; import org.prebid.server.util.HttpUtil; import java.util.ArrayList; import java.util.Collections; +import java.util.EnumMap; import java.util.List; import java.util.Objects; import java.util.Set; @@ -62,31 +66,44 @@ public VideoRequestFactory(int maxRequestSize, */ public Future> fromRequest(RoutingContext routingContext, long startTime) { - final BidRequestVideo incomingBidRequest; + final String body; try { - incomingBidRequest = parseRequest(routingContext); + body = extractAndValidateBody(routingContext); } catch (InvalidRequestException e) { return Future.failedFuture(e); } - final String storedRequestId = incomingBidRequest.getStoredrequestid(); - if (StringUtils.isBlank(storedRequestId) && enforceStoredRequest) { - return Future.failedFuture(new InvalidRequestException("Unable to find required stored request id")); + final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() + .endpoint(Endpoint.openrtb2_video) + .stageOutcomes(new EnumMap<>(Stage.class)) + .build(); + + return auctionRequestFactory.executeEntrypointHooks(routingContext, body, hookExecutionContext) + .compose(httpRequest -> createBidRequest(httpRequest) + .compose(bidRequestToPodError -> auctionRequestFactory.toAuctionContext( + httpRequest, + bidRequestToPodError.getData(), + MetricName.video, + new ArrayList<>(), + startTime, + timeoutResolver, + hookExecutionContext) + .map(auctionContext -> WithPodErrors.of( + auctionContext, bidRequestToPodError.getPodErrors())))); + } + + private String extractAndValidateBody(RoutingContext context) { + final String body = context.getBodyAsString(); + if (body == null) { + throw new InvalidRequestException("Incoming request has no body"); } - final Set podConfigIds = podConfigIds(incomingBidRequest); - return createBidRequest(routingContext, incomingBidRequest, storedRequestId, podConfigIds) - .compose(bidRequestToPodError -> auctionRequestFactory.toAuctionContext( - // FIXME - null, - bidRequestToPodError.getData(), - MetricName.video, - new ArrayList<>(), - startTime, - timeoutResolver, - // FIXME - null) - .map(auctionContext -> WithPodErrors.of(auctionContext, bidRequestToPodError.getPodErrors()))); + if (body.length() > maxRequestSize) { + throw new InvalidRequestException( + String.format("Request size exceeded max size of %d bytes.", maxRequestSize)); + } + + return body; } /** @@ -126,30 +143,20 @@ private String parentAccountIdFromExtPublisher(ExtPublisher extPublisher) { *

* Throws {@link InvalidRequestException} if body is empty, exceeds max request size or couldn't be deserialized. */ - private BidRequestVideo parseRequest(RoutingContext context) { - final Buffer body = context.getBody(); - if (body == null) { - throw new InvalidRequestException("Incoming request has no body"); - } - - if (body.length() > maxRequestSize) { - throw new InvalidRequestException( - String.format("Request size exceeded max size of %d bytes.", maxRequestSize)); - } - + private BidRequestVideo parseRequest(HttpRequestWrapper httpRequest) { try { - final BidRequestVideo bidRequestVideo = mapper.decodeValue(body, BidRequestVideo.class); - return insertDeviceUa(context, bidRequestVideo); + final BidRequestVideo bidRequestVideo = mapper.decodeValue(httpRequest.getBody(), BidRequestVideo.class); + return insertDeviceUa(httpRequest, bidRequestVideo); } catch (DecodeException e) { throw new InvalidRequestException(e.getMessage()); } } - private BidRequestVideo insertDeviceUa(RoutingContext context, BidRequestVideo bidRequestVideo) { + private BidRequestVideo insertDeviceUa(HttpRequestWrapper httpRequest, BidRequestVideo bidRequestVideo) { final Device device = bidRequestVideo.getDevice(); final String deviceUa = device != null ? device.getUa() : null; if (StringUtils.isBlank(deviceUa)) { - final String userAgentHeader = context.request().getHeader(HttpUtil.USER_AGENT_HEADER); + final String userAgentHeader = httpRequest.getHeaders().get(HttpUtil.USER_AGENT_HEADER); if (StringUtils.isEmpty(userAgentHeader)) { throw new InvalidRequestException("Device.UA and User-Agent Header is not presented"); } @@ -172,19 +179,30 @@ private static Set podConfigIds(BidRequestVideo incomingBidRequest) { .filter(Objects::nonNull) .map(String::valueOf) .collect(Collectors.toSet()); - } else { - return Collections.emptySet(); } + + return Collections.emptySet(); } - private Future> createBidRequest(RoutingContext routingContext, - BidRequestVideo bidRequestVideo, - String storedVideoId, - Set podConfigIds) { + private Future> createBidRequest(HttpRequestWrapper httpRequest) { + + final BidRequestVideo bidRequestVideo; + try { + bidRequestVideo = parseRequest(httpRequest); + } catch (InvalidRequestException e) { + return Future.failedFuture(e); + } + + final String storedRequestId = bidRequestVideo.getStoredrequestid(); + if (StringUtils.isBlank(storedRequestId) && enforceStoredRequest) { + return Future.failedFuture(new InvalidRequestException("Unable to find required stored request id")); + } + + final Set podConfigIds = podConfigIds(bidRequestVideo); return storedRequestProcessor.processVideoRequest( - accountIdFrom(bidRequestVideo), storedVideoId, podConfigIds, bidRequestVideo) - .map(bidRequestToErrors -> fillImplicitParameters(routingContext, bidRequestToErrors)) + accountIdFrom(bidRequestVideo), storedRequestId, podConfigIds, bidRequestVideo) + .map(bidRequestToErrors -> fillImplicitParameters(httpRequest, bidRequestToErrors)) .map(this::validateRequest); } @@ -193,10 +211,12 @@ private WithPodErrors validateRequest(WithPodErrors requ return WithPodErrors.of(bidRequest, requestToPodErrors.getPodErrors()); } - private WithPodErrors fillImplicitParameters(RoutingContext routingContext, + private WithPodErrors fillImplicitParameters(HttpRequestWrapper httpRequest, WithPodErrors bidRequestToErrors) { + final BidRequest bidRequest = auctionRequestFactory - .fillImplicitParameters(bidRequestToErrors.getData(), null, timeoutResolver); // FIXME + .fillImplicitParameters(bidRequestToErrors.getData(), httpRequest, timeoutResolver); + return WithPodErrors.of(bidRequest, bidRequestToErrors.getPodErrors()); } } From ca657ac16e0461768ac8ff9a04fd41f983d55dcb Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Wed, 24 Mar 2021 12:57:04 +0200 Subject: [PATCH 08/12] Create shortcut factory method in HookExecutionContext --- .../java/org/prebid/server/auction/AmpRequestFactory.java | 7 +------ .../org/prebid/server/auction/AuctionRequestFactory.java | 7 +------ .../org/prebid/server/auction/VideoRequestFactory.java | 5 +---- .../hooks/execution/model/HookExecutionContext.java | 8 +++++--- 4 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java index a96b4c90c81..2c428741117 100644 --- a/src/main/java/org/prebid/server/auction/AmpRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AmpRequestFactory.java @@ -23,7 +23,6 @@ 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.hooks.execution.model.Stage; import org.prebid.server.json.JacksonMapper; import org.prebid.server.metric.MetricName; import org.prebid.server.model.Endpoint; @@ -48,7 +47,6 @@ import java.util.ArrayList; import java.util.Collections; -import java.util.EnumMap; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -106,10 +104,7 @@ public AmpRequestFactory(StoredRequestProcessor storedRequestProcessor, * Creates {@link AuctionContext} based on {@link RoutingContext}. */ public Future fromRequest(RoutingContext routingContext, long startTime) { - final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() - .endpoint(Endpoint.openrtb2_amp) - .stageOutcomes(new EnumMap<>(Stage.class)) - .build(); + final HookExecutionContext hookExecutionContext = HookExecutionContext.of(Endpoint.openrtb2_amp); return auctionRequestFactory.executeEntrypointHooks( routingContext, diff --git a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java index 44b3e4ba790..58f68d6f9cb 100644 --- a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java @@ -34,7 +34,6 @@ import org.prebid.server.hooks.execution.HookStageExecutor; import org.prebid.server.hooks.execution.model.HookExecutionContext; import org.prebid.server.hooks.execution.model.HookStageExecutionResult; -import org.prebid.server.hooks.execution.model.Stage; import org.prebid.server.hooks.v1.entrypoint.EntrypointPayload; import org.prebid.server.identity.IdGenerator; import org.prebid.server.json.JacksonMapper; @@ -68,7 +67,6 @@ import java.util.Arrays; import java.util.Collections; import java.util.Currency; -import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -188,10 +186,7 @@ public Future fromRequest(RoutingContext routingContext, long st return Future.failedFuture(e); } - final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() - .endpoint(Endpoint.openrtb2_auction) - .stageOutcomes(new EnumMap<>(Stage.class)) - .build(); + final HookExecutionContext hookExecutionContext = HookExecutionContext.of(Endpoint.openrtb2_auction); return executeEntrypointHooks(routingContext, body, hookExecutionContext) .compose(httpRequest -> createBidRequest(httpRequest, errors) diff --git a/src/main/java/org/prebid/server/auction/VideoRequestFactory.java b/src/main/java/org/prebid/server/auction/VideoRequestFactory.java index cf36c89c263..192b0362c97 100644 --- a/src/main/java/org/prebid/server/auction/VideoRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/VideoRequestFactory.java @@ -73,10 +73,7 @@ public Future> fromRequest(RoutingContext routingC return Future.failedFuture(e); } - final HookExecutionContext hookExecutionContext = HookExecutionContext.builder() - .endpoint(Endpoint.openrtb2_video) - .stageOutcomes(new EnumMap<>(Stage.class)) - .build(); + final HookExecutionContext hookExecutionContext = HookExecutionContext.of(Endpoint.openrtb2_video); return auctionRequestFactory.executeEntrypointHooks(routingContext, body, hookExecutionContext) .compose(httpRequest -> createBidRequest(httpRequest) diff --git a/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java index b0667e53962..b8ff5ba3e2c 100644 --- a/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java +++ b/src/main/java/org/prebid/server/hooks/execution/model/HookExecutionContext.java @@ -1,16 +1,18 @@ package org.prebid.server.hooks.execution.model; -import lombok.Builder; import lombok.Value; import org.prebid.server.model.Endpoint; import java.util.EnumMap; -@Builder -@Value +@Value(staticConstructor = "of") public class HookExecutionContext { Endpoint endpoint; EnumMap stageOutcomes; + + public static HookExecutionContext of(Endpoint endpoint) { + return of(endpoint, new EnumMap<>(Stage.class)); + } } From 84945fcddf96be5e5f0898db581e8734ae997376 Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Wed, 24 Mar 2021 17:48:23 +0200 Subject: [PATCH 09/12] Fix unit tests --- .../server/auction/AmpRequestFactoryTest.java | 186 +++++++++++------- .../auction/AuctionRequestFactoryTest.java | 119 ++++++++--- .../auction/VideoRequestFactoryTest.java | 67 +++++-- 3 files changed, 250 insertions(+), 122 deletions(-) diff --git a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java index d54f322bb3a..7e4ef6d9259 100644 --- a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java @@ -13,6 +13,7 @@ import io.vertx.core.Future; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.impl.SocketAddressImpl; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -26,6 +27,8 @@ import org.prebid.server.auction.model.AuctionContext; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.metric.MetricName; +import org.prebid.server.model.Endpoint; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.proto.openrtb.ext.ExtIncludeBrandCategory; import org.prebid.server.proto.openrtb.ext.request.ExtGranularityRange; import org.prebid.server.proto.openrtb.ext.request.ExtPriceGranularity; @@ -52,6 +55,7 @@ import static java.util.Arrays.asList; import static java.util.Collections.singletonList; +import static java.util.Collections.singletonMap; import static java.util.function.Function.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.tuple; @@ -59,6 +63,7 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; @@ -93,9 +98,15 @@ public void setUp() { given(timeoutResolver.resolve(any())).willReturn(2000L); given(timeoutResolver.adjustTimeout(anyLong())).willReturn(1900L); - given(httpRequest.getParam(eq("tag_id"))).willReturn("tagId"); - given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap()); + given(httpRequest.remoteAddress()).willReturn(new SocketAddressImpl(1234, "host")); given(routingContext.request()).willReturn(httpRequest); + given(routingContext.queryParams()).willReturn( + MultiMap.caseInsensitiveMultiMap() + .add("tag_id", "tagId")); + + given(auctionRequestFactory.executeEntrypointHooks(any(), any(), any())) + .willAnswer(invocation -> toHttpRequest(invocation.getArgument(0), invocation.getArgument(1))); + given(fpdResolver.resolveApp(any(), any())) .willAnswer(invocationOnMock -> invocationOnMock.getArgument(0)); given(fpdResolver.resolveSite(any(), any())) @@ -113,7 +124,7 @@ public void setUp() { @Test public void shouldReturnFailedFutureIfRequestHasNoTagId() { // given - given(httpRequest.getParam("tag_id")).willReturn(null); + routingContext.queryParams().set("tag_id", (String) null); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -207,6 +218,7 @@ public void shouldReturnBidRequestWithDefaultPrebidValuesIfPrebidIsNull() { .extracting(BidRequest::getExt) .extracting(ExtRequest::getPrebid) .containsExactly(ExtRequestPrebid.builder() + .amp(ExtRequestPrebidAmp.of(singletonMap("tag_id", "tagId"))) .targeting(ExtRequestTargeting.builder() .pricegranularity(mapper.valueToTree(ExtPriceGranularity.of(2, singletonList(ExtGranularityRange.of(BigDecimal.valueOf(20), @@ -503,7 +515,7 @@ public void shouldReturnBidRequestWithImpSecureEqualsToOneIfInitiallyItWasNotSec @Test public void shouldRespondWithBidRequestWithTestFlagOn() { // given - given(httpRequest.getParam("debug")).willReturn("1"); + routingContext.queryParams().add("debug", "1"); givenBidRequest( builder -> builder @@ -524,7 +536,7 @@ public void shouldRespondWithBidRequestWithTestFlagOn() { @Test public void shouldRespondWithBidRequestWithDebugFlagOn() { // given - given(httpRequest.getParam("debug")).willReturn("1"); + routingContext.queryParams().add("debug", "1"); givenBidRequest( builder -> builder @@ -545,7 +557,7 @@ public void shouldRespondWithBidRequestWithDebugFlagOn() { @Test public void shouldReturnBidRequestWithOverriddenTagIdBySlotParamValue() { // given - given(httpRequest.getParam("slot")).willReturn("Overridden-tagId"); + routingContext.queryParams().add("slot", "Overridden-tagId"); givenBidRequest( builder -> builder @@ -565,7 +577,7 @@ public void shouldReturnBidRequestWithOverriddenTagIdBySlotParamValue() { @Test public void shouldSetBidRequestSiteExt() { // given - given(httpRequest.getParam("curl")).willReturn(""); + routingContext.queryParams().add("curl", ""); givenBidRequest( builder -> builder @@ -585,7 +597,7 @@ public void shouldSetBidRequestSiteExt() { @Test public void shouldReturnBidRequestWithOverriddenSitePageAndDomainByCurlParamValue() { // given - given(httpRequest.getParam("curl")).willReturn("http://overridden.site.page:8080/path"); + routingContext.queryParams().add("curl", "http://overridden.site.page:8080/path"); givenBidRequest( builder -> builder @@ -607,7 +619,7 @@ public void shouldReturnBidRequestWithOverriddenSitePageAndDomainByCurlParamValu @Test public void shouldReturnBidRequestWithSitePageAndDomainContainingCurlParamValueWhenSiteNotInRequest() { // given - given(httpRequest.getParam("curl")).willReturn("http://overridden.site.page:8080/path"); + routingContext.queryParams().add("curl", "http://overridden.site.page:8080/path"); givenBidRequest( builder -> builder @@ -629,7 +641,7 @@ public void shouldReturnBidRequestWithSitePageAndDomainContainingCurlParamValueW @Test public void shouldReturnBidRequestWithSitePublisherIdOverriddenWithAccountParamValue() { // given - given(httpRequest.getParam("account")).willReturn("accountId"); + routingContext.queryParams().add("account", "accountId"); givenBidRequest( builder -> builder @@ -652,7 +664,7 @@ public void shouldReturnBidRequestWithSitePublisherIdOverriddenWithAccountParamV @Test public void shouldReturnBidRequestWithSitePublisherIdFromAccountParamWhenSiteDoesNotExist() { // given - given(httpRequest.getParam("account")).willReturn("accountId"); + routingContext.queryParams().add("account", "accountId"); givenBidRequest( builder -> builder @@ -675,7 +687,7 @@ public void shouldReturnBidRequestWithSitePublisherIdFromAccountParamWhenSiteDoe @Test public void shouldReturnBidRequestWithSitePublisherIdFromAccountParamWhenSitePublisherDoesNotExist() { // given - given(httpRequest.getParam("account")).willReturn("accountId"); + routingContext.queryParams().add("account", "accountId"); givenBidRequest( builder -> builder @@ -698,11 +710,11 @@ public void shouldReturnBidRequestWithSitePublisherIdFromAccountParamWhenSitePub @Test public void shouldReturnRequestWithOverriddenBannerFormatByOverwriteWHParamsRespectingThemOverWH() { // given - given(httpRequest.getParam("w")).willReturn("10"); - given(httpRequest.getParam("ow")).willReturn("1000"); - given(httpRequest.getParam("h")).willReturn("20"); - given(httpRequest.getParam("oh")).willReturn("2000"); - given(httpRequest.getParam("ms")).willReturn("44x88,66x99"); + routingContext.queryParams().add("w", "10"); + routingContext.queryParams().add("ow", "1000"); + routingContext.queryParams().add("h", "20"); + routingContext.queryParams().add("oh", "2000"); + routingContext.queryParams().add("ms", "44x88,66x99"); givenBidRequest( builder -> builder @@ -730,10 +742,10 @@ public void shouldReturnRequestWithOverriddenBannerFormatByOverwriteWHParamsResp @Test public void shouldReturnBidRequestWithOverriddenBannerFromOWAndHParamAndMultiListIfOHIsMissed() { // given - given(httpRequest.getParam("ow")).willReturn("10"); - given(httpRequest.getParam("w")).willReturn("30"); - given(httpRequest.getParam("h")).willReturn("40"); - given(httpRequest.getParam("ms")).willReturn("50x60"); + routingContext.queryParams().add("ow", "10"); + routingContext.queryParams().add("w", "30"); + routingContext.queryParams().add("h", "40"); + routingContext.queryParams().add("ms", "50x60"); givenBidRequest( builder -> builder @@ -761,10 +773,10 @@ public void shouldReturnBidRequestWithOverriddenBannerFromOWAndHParamAndMultiLis @Test public void shouldReturnBidRequestWithOverriddenBannerFromWAndOHParamAndMultiListIfOWIsMissed() { // given - given(httpRequest.getParam("oh")).willReturn("20"); - given(httpRequest.getParam("w")).willReturn("30"); - given(httpRequest.getParam("h")).willReturn("40"); - given(httpRequest.getParam("ms")).willReturn("50x60"); + routingContext.queryParams().add("oh", "20"); + routingContext.queryParams().add("w", "30"); + routingContext.queryParams().add("h", "40"); + routingContext.queryParams().add("ms", "50x60"); givenBidRequest( builder -> builder @@ -792,9 +804,9 @@ public void shouldReturnBidRequestWithOverriddenBannerFromWAndOHParamAndMultiLis @Test public void shouldReturnBidRequestWithBannerFromHWParamsAndMultiList() { // given - given(httpRequest.getParam("w")).willReturn("30"); - given(httpRequest.getParam("h")).willReturn("40"); - given(httpRequest.getParam("ms")).willReturn("50x60"); + routingContext.queryParams().add("w", "30"); + routingContext.queryParams().add("h", "40"); + routingContext.queryParams().add("ms", "50x60"); givenBidRequest( builder -> builder @@ -822,8 +834,8 @@ public void shouldReturnBidRequestWithBannerFromHWParamsAndMultiList() { @Test public void shouldReturnBidRequestWithOverriddenBannerFromWAndHParamsIfOwOhAndMultiListAreMissed() { // given - given(httpRequest.getParam("w")).willReturn("30"); - given(httpRequest.getParam("h")).willReturn("40"); + routingContext.queryParams().add("w", "30"); + routingContext.queryParams().add("h", "40"); givenBidRequest( builder -> builder @@ -851,7 +863,7 @@ public void shouldReturnBidRequestWithOverriddenBannerFromWAndHParamsIfOwOhAndMu @Test public void shouldReturnBidRequestWithUpdatedWidthForAllBannerFormatsWhenOnlyWIsPresentInParams() { // given - given(httpRequest.getParam("w")).willReturn("30"); + routingContext.queryParams().add("w", "30"); givenBidRequest( builder -> builder @@ -877,7 +889,7 @@ public void shouldReturnBidRequestWithUpdatedWidthForAllBannerFormatsWhenOnlyWIs @Test public void shouldReturnBidRequestWithUpdatedHeightForAllBannerFormatsWhenOnlyHIsPresentInParams() { // given - given(httpRequest.getParam("h")).willReturn("40"); + routingContext.queryParams().add("h", "40"); givenBidRequest( builder -> builder @@ -903,7 +915,7 @@ public void shouldReturnBidRequestWithUpdatedHeightForAllBannerFormatsWhenOnlyHI @Test public void shouldReturnBidRequestWithOverriddenBannerFormatsByMultiSizeParams() { // given - given(httpRequest.getParam("ms")).willReturn("44x88,66x99"); + routingContext.queryParams().add("ms", "44x88,66x99"); givenBidRequest( builder -> builder @@ -931,7 +943,7 @@ public void shouldReturnBidRequestWithOverriddenBannerFormatsByMultiSizeParams() @Test public void shouldReturnBidRequestWithOriginalBannerFormatsWhenMultiSizeParamContainsCompletelyInvalidValue() { // given - given(httpRequest.getParam("ms")).willReturn(","); + routingContext.queryParams().add("ms", ","); givenBidRequest( builder -> builder @@ -959,7 +971,7 @@ public void shouldReturnBidRequestWithOriginalBannerFormatsWhenMultiSizeParamCon @Test public void shouldReturnBidRequestWithOriginBannerFormatsWhenMultiSizeParamContainsAtLeastOneInvalidValue() { // given - given(httpRequest.getParam("ms")).willReturn(",33x,44x77,abc,"); + routingContext.queryParams().add("ms", ",33x,44x77,abc,"); givenBidRequest( builder -> builder @@ -987,7 +999,7 @@ public void shouldReturnBidRequestWithOriginBannerFormatsWhenMultiSizeParamConta @Test public void shouldReturnBidRequestOverriddenBannerFormatsWhenMsParamSizePairHasOneInvalidValue() { // given - given(httpRequest.getParam("ms")).willReturn("900xZ"); + routingContext.queryParams().add("ms", "900xZ"); givenBidRequest( builder -> builder @@ -1015,7 +1027,7 @@ public void shouldReturnBidRequestOverriddenBannerFormatsWhenMsParamSizePairHasO @Test public void shouldReturnBidRequestWithOriginBannerFormatsWhenMultiSizeParamContainsAtLeastOneZeroPairSize() { // given - given(httpRequest.getParam("ms")).willReturn("44x77, 0x0"); + routingContext.queryParams().add("ms", "44x77, 0x0"); givenBidRequest( builder -> builder @@ -1043,7 +1055,7 @@ public void shouldReturnBidRequestWithOriginBannerFormatsWhenMultiSizeParamConta @Test public void shouldReturnBidRequestWithOverriddenBannerFormatsWhenMultiSizeParamContainsPartiallyInvalidParams() { // given - given(httpRequest.getParam("ms")).willReturn("33x,44x77"); + routingContext.queryParams().add("ms", "33x,44x77"); givenBidRequest( builder -> builder @@ -1071,11 +1083,11 @@ public void shouldReturnBidRequestWithOverriddenBannerFormatsWhenMultiSizeParamC @Test public void shouldReturnBidRequestWithOriginBannerFormatsWhenAllParametersAreZero() { // given - given(httpRequest.getParam("ow")).willReturn("0"); - given(httpRequest.getParam("oh")).willReturn("0"); - given(httpRequest.getParam("w")).willReturn("0"); - given(httpRequest.getParam("h")).willReturn("0"); - given(httpRequest.getParam("ms")).willReturn("0x0"); + routingContext.queryParams().add("ow", "0"); + routingContext.queryParams().add("oh", "0"); + routingContext.queryParams().add("w", "0"); + routingContext.queryParams().add("h", "0"); + routingContext.queryParams().add("ms", "0x0"); givenBidRequest( builder -> builder @@ -1103,9 +1115,9 @@ public void shouldReturnBidRequestWithOriginBannerFormatsWhenAllParametersAreZer @Test public void shouldReturnBidRequestWithOverriddenBannerWhenInvalidParamTreatedAsZeroValue() { // given - given(httpRequest.getParam("ow")).willReturn("100"); - given(httpRequest.getParam("oh")).willReturn("invalid"); - given(httpRequest.getParam("h")).willReturn("200"); + routingContext.queryParams().add("ow", "100"); + routingContext.queryParams().add("oh", "invalid"); + routingContext.queryParams().add("h", "200"); givenBidRequest( builder -> builder @@ -1133,7 +1145,7 @@ public void shouldReturnBidRequestWithOverriddenBannerWhenInvalidParamTreatedAsZ @Test public void shouldReturnBidRequestWithOverriddenTmaxWhenTimeoutParamIsAvailable() { // given - given(httpRequest.getParam("timeout")).willReturn("1000"); + routingContext.queryParams().add("timeout", "1000"); givenBidRequest( builder -> builder @@ -1148,9 +1160,9 @@ public void shouldReturnBidRequestWithOverriddenTmaxWhenTimeoutParamIsAvailable( } @Test - public void shouldReturnBidRequestWithUnmodifiedUserWhenGdprConsentParamIsNullOrBlank() { + public void shouldReturnBidRequestWithUnmodifiedUserWhenGdprConsentParamIsBlank() { // given - given(httpRequest.getParam("gdpr_consent")).willReturn(null, ""); + routingContext.queryParams().add("gdpr_consent", ""); givenBidRequest( builder -> builder @@ -1161,22 +1173,18 @@ public void shouldReturnBidRequestWithUnmodifiedUserWhenGdprConsentParamIsNullOr Imp.builder().build()); // when - final BidRequest firstResult = factory.fromRequest(routingContext, 0L).result().getBidRequest(); - final BidRequest secondResult = factory.fromRequest(routingContext, 0L).result().getBidRequest(); + final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); // then - final User expectedUser = User.builder() + assertThat(request.getUser()).isEqualTo(User.builder() .ext(ExtUser.builder().consent("should-remain").build()) - .build(); - - assertThat(firstResult.getUser()).isEqualTo(expectedUser); - assertThat(secondResult.getUser()).isEqualTo(expectedUser); + .build()); } @Test public void shouldReturnBidRequestWithOverriddenUserExtConsentWhenGdprConsentParamIsValid() { // given - given(httpRequest.getParam("gdpr_consent")).willReturn("BONV8oqONXwgmADACHENAO7pqzAAppY"); + routingContext.queryParams().add("gdpr_consent", "BONV8oqONXwgmADACHENAO7pqzAAppY"); givenBidRequest( builder -> builder @@ -1201,7 +1209,7 @@ public void shouldReturnBidRequestWithOverriddenUserExtConsentWhenGdprConsentPar @Test public void shouldReturnBidRequestWithNewUserThatContainsUserExtConsentWhenInitialUserIsMissing() { // given - given(httpRequest.getParam("gdpr_consent")).willReturn("BONV8oqONXwgmADACHENAO7pqzAAppY"); + routingContext.queryParams().add("gdpr_consent", "BONV8oqONXwgmADACHENAO7pqzAAppY"); givenBidRequest( builder -> builder @@ -1221,7 +1229,7 @@ public void shouldReturnBidRequestWithNewUserThatContainsUserExtConsentWhenIniti @Test public void shouldKeepEmptyUserWhenGdprConsentIsInvalid() { // given - given(httpRequest.getParam("gdpr_consent")).willReturn("consent-value"); + routingContext.queryParams().add("gdpr_consent", "consent-value"); givenBidRequest( builder -> builder @@ -1240,7 +1248,7 @@ public void shouldKeepEmptyUserWhenGdprConsentIsInvalid() { @Test public void shouldReturnAddErrorToAuctionContextWhenPrivacyIsNotValid() { // given - given(httpRequest.getParam("gdpr_consent")).willReturn("consent-value"); + routingContext.queryParams().add("gdpr_consent", "consent-value"); givenBidRequest( builder -> builder @@ -1263,8 +1271,9 @@ public void shouldReturnAddErrorToAuctionContextWhenPrivacyIsNotValid() { @Test public void shouldReturnBidRequestWithExtPrebidDataBiddersUpdatedByFpdResolver() throws JsonProcessingException { // given - given(httpRequest.getParam("targeting")) - .willReturn(mapper.writeValueAsString(Targeting.of(Arrays.asList("appnexus", "rubicon"), null, null))); + routingContext.queryParams() + .add("targeting", mapper.writeValueAsString( + Targeting.of(Arrays.asList("appnexus", "rubicon"), null, null))); given(fpdResolver.resolveBidRequestExt(any(), any())) .willReturn(ExtRequest.of(ExtRequestPrebid.builder() @@ -1289,8 +1298,9 @@ public void shouldReturnBidRequestWithExtPrebidDataBiddersUpdatedByFpdResolver() @Test public void shouldReturnBidRequestImpExtContextDataWithTargetingAttributes() throws JsonProcessingException { // given - given(httpRequest.getParam("targeting")) - .willReturn(mapper.writeValueAsString(Targeting.of(Arrays.asList("appnexus", "rubicon"), null, null))); + routingContext.queryParams() + .add("targeting", mapper.writeValueAsString( + Targeting.of(Arrays.asList("appnexus", "rubicon"), null, null))); given(fpdResolver.resolveImpExt(any(), any())) .willReturn(mapper.createObjectNode().set("context", mapper.createObjectNode() @@ -1316,7 +1326,7 @@ public void shouldReturnBidRequestImpExtContextDataWithTargetingAttributes() thr @Test public void shouldThrowInvalidRequestExceptionWhenTargetingHasTypeOtherToObject() { // given - given(httpRequest.getParam("targeting")).willReturn("[\"a\"]", null, null); + routingContext.queryParams().add("targeting", "[\"a\"]"); givenBidRequest( builder -> builder @@ -1350,7 +1360,7 @@ public void shouldReturnBidRequestWithoutRegsExtWhenNoPrivacyPolicyIsExist() { @Test public void shouldReturnBidRequestWithRegsExtUsPrivacyWhenUsPrivacyParamIsValid() { // given - given(httpRequest.getParam("gdpr_consent")).willReturn("1N--"); + routingContext.queryParams().add("gdpr_consent", "1N--"); givenBidRequest( builder -> builder.ext(ExtRequest.empty()), @@ -1367,7 +1377,7 @@ public void shouldReturnBidRequestWithRegsExtUsPrivacyWhenUsPrivacyParamIsValid( @Test public void shouldReturnBidRequestWithRegsExtUsPrivacyWhenConsentStringIsValid() { // given - given(httpRequest.getParam("consent_string")).willReturn("1Y-N"); + routingContext.queryParams().add("consent_string", "1Y-N"); givenBidRequest( builder -> builder @@ -1409,9 +1419,9 @@ public void shouldPassExtPrebidDebugFlagIfPresent() { @Test public void shouldReturnBidRequestWithCreatedExtPrebidAmpData() { // given - given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() + routingContext.queryParams() .add("queryParam1", "value1") - .add("queryParam2", "value2")); + .add("queryParam2", "value2"); givenBidRequest( builder -> builder.ext(ExtRequest.of(null)), @@ -1424,6 +1434,7 @@ public void shouldReturnBidRequestWithCreatedExtPrebidAmpData() { final Map expectedAmpData = new HashMap<>(); expectedAmpData.put("queryParam1", "value1"); expectedAmpData.put("queryParam2", "value2"); + expectedAmpData.put("tag_id", "tagId"); assertThat(singletonList(result)) .extracting(BidRequest::getExt) .extracting(ExtRequest::getPrebid) @@ -1436,9 +1447,9 @@ public void shouldReturnBidRequestWithCreatedExtPrebidAmpData() { @Test public void shouldReturnBidRequestWithUpdatedExtPrebidAmpData() { // given - given(httpRequest.params()).willReturn(MultiMap.caseInsensitiveMultiMap() + routingContext.queryParams() .add("queryParam1", "value1") - .add("queryParam2", "value2")); + .add("queryParam2", "value2"); final Map existingAmpData = new HashMap<>(); existingAmpData.put("queryParam2", "value2InRequest"); @@ -1457,6 +1468,7 @@ public void shouldReturnBidRequestWithUpdatedExtPrebidAmpData() { expectedAmpData.put("queryParam1", "value1"); expectedAmpData.put("queryParam2", "value2"); expectedAmpData.put("queryParam3", "value3"); + expectedAmpData.put("tag_id", "tagId"); assertThat(singletonList(result)) .extracting(BidRequest::getExt) .extracting(ExtRequest::getPrebid) @@ -1465,6 +1477,27 @@ public void shouldReturnBidRequestWithUpdatedExtPrebidAmpData() { .containsOnly(expectedAmpData); } + @Test + public void shouldPassHookExecutionContextWithAmpEndpoint() { + // given + givenBidRequest( + builder -> builder.ext(ExtRequest.empty()), + Imp.builder().build()); + + // when + factory.fromRequest(routingContext, 0L); + + // then + verify(auctionRequestFactory).toAuctionContext( + any(), + any(), + any(), + any(), + anyLong(), + any(), + argThat(context -> context.getEndpoint() == Endpoint.openrtb2_amp)); + } + private void givenBidRequest( Function bidRequestBuilderCustomizer, Imp... imps) { @@ -1485,6 +1518,17 @@ private void givenBidRequest( .build())); } + private static Future toHttpRequest(RoutingContext routingContext, String body) { + return Future.succeededFuture(HttpRequestWrapper.builder() + .absoluteUri(routingContext.request().absoluteURI()) + .queryParams(routingContext.queryParams()) + .headers(routingContext.request().headers()) + .body(body) + .scheme(routingContext.request().scheme()) + .remoteHost(routingContext.request().remoteAddress().host()) + .build()); + } + private static ExtRequest givenRequestExt(ExtRequestTargeting extRequestTargeting) { return ExtRequest.of(ExtRequestPrebid.builder() .targeting(extRequestTargeting) diff --git a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java index 9aea7668fcb..94cf3a36265 100644 --- a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java @@ -16,10 +16,12 @@ import com.iab.openrtb.request.User; import com.iab.openrtb.request.Video; import io.vertx.core.Future; -import io.vertx.core.buffer.Buffer; -import io.vertx.core.http.CaseInsensitiveHeaders; +import io.vertx.core.MultiMap; import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.impl.SocketAddressImpl; import io.vertx.ext.web.RoutingContext; +import lombok.Value; +import lombok.experimental.Accessors; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -42,8 +44,14 @@ import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; import org.prebid.server.geolocation.model.GeoInfo; +import org.prebid.server.hooks.execution.HookStageExecutor; +import org.prebid.server.hooks.execution.model.HookExecutionContext; +import org.prebid.server.hooks.execution.model.HookStageExecutionResult; +import org.prebid.server.hooks.v1.entrypoint.EntrypointPayload; import org.prebid.server.identity.IdGenerator; 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.model.TcfContext; import org.prebid.server.privacy.model.Privacy; @@ -118,23 +126,26 @@ public class AuctionRequestFactoryTest extends VertxTest { @Mock private InterstitialProcessor interstitialProcessor; @Mock + private OrtbTypesResolver ortbTypesResolver; + @Mock + private TimeoutResolver timeoutResolver; + @Mock + private TimeoutFactory timeoutFactory; + @Mock private ApplicationSettings applicationSettings; @Mock private IdGenerator idGenerator; @Mock private PrivacyEnforcementService privacyEnforcementService; + @Mock + private HookStageExecutor hookStageExecutor; private AuctionRequestFactory factory; + @Mock private RoutingContext routingContext; @Mock private HttpServerRequest httpRequest; - @Mock - private OrtbTypesResolver ortbTypesResolver; - @Mock - private TimeoutResolver timeoutResolver; - @Mock - private TimeoutFactory timeoutFactory; @Before public void setUp() { @@ -142,7 +153,8 @@ public void setUp() { given(idGenerator.generateId()).willReturn(null); given(routingContext.request()).willReturn(httpRequest); - given(httpRequest.headers()).willReturn(new CaseInsensitiveHeaders()); + given(httpRequest.headers()).willReturn(MultiMap.caseInsensitiveMultiMap()); + given(httpRequest.remoteAddress()).willReturn(new SocketAddressImpl(1234, "host")); given(timeoutResolver.resolve(any())).willReturn(2000L); given(timeoutResolver.adjustTimeout(anyLong())).willReturn(1900L); @@ -152,6 +164,14 @@ public void setUp() { Privacy.of("0", EMPTY, Ccpa.EMPTY, 0), TcfContext.empty()))); + given(hookStageExecutor.executeEntrypointStage(any(), any(), any(), any())) + .willAnswer(invocation -> Future.succeededFuture(HookStageExecutionResult.of( + false, + EntrypointPayloadImpl.of( + invocation.getArgument(0), + invocation.getArgument(1), + invocation.getArgument(2))))); + factory = new AuctionRequestFactory( Integer.MAX_VALUE, false, @@ -172,14 +192,14 @@ public void setUp() { applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); } @Test public void shouldReturnFailedFutureIfRequestBodyIsMissing() { // given - given(routingContext.getBody()).willReturn(null); + given(routingContext.getBodyAsString()).willReturn(null); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -214,7 +234,7 @@ public void shouldReturnFailedFutureIfAccountIsEnforcedAndIdIsNotProvided() { applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); givenValidBidRequest(); @@ -254,7 +274,7 @@ public void shouldReturnFailedFutureIfAccountIsEnforcedAndFailedGetAccountById() applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); given(applicationSettings.getAccountById(any(), any())) @@ -329,10 +349,10 @@ public void shouldReturnFailedFutureIfRequestBodyExceedsMaxRequestSize() { applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); - given(routingContext.getBody()).willReturn(Buffer.buffer("body")); + given(routingContext.getBodyAsString()).willReturn("body"); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -347,7 +367,7 @@ public void shouldReturnFailedFutureIfRequestBodyExceedsMaxRequestSize() { @Test public void shouldReturnFailedFutureIfRequestBodyCouldNotBeParsed() { // given - given(routingContext.getBody()).willReturn(Buffer.buffer("body")); + given(routingContext.getBodyAsString()).willReturn("body"); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -521,7 +541,7 @@ public void shouldNotSetDeviceDntIfHeaderHasInvalidValue() { @Test public void shouldSetDeviceDntIfHeaderExists() { // given - given(httpRequest.getHeader("DNT")).willReturn("1"); + httpRequest.headers().add("DNT", "1"); givenValidBidRequest(); // when @@ -534,7 +554,8 @@ public void shouldSetDeviceDntIfHeaderExists() { @Test public void shouldOverrideDeviceDntIfHeaderExists() { // given - given(httpRequest.getHeader("DNT")).willReturn("0"); + httpRequest.headers().add("DNT", "0"); + givenBidRequest(BidRequest.builder() .device(Device.builder().dnt(1).build()) .build()); @@ -1689,7 +1710,7 @@ public void shouldSetDefaultIncludeBidderKeysToFalseIfIncludeBidderKeysIsMissedA applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() .imp(singletonList(Imp.builder().ext(mapper.createObjectNode()).build())) @@ -1733,7 +1754,7 @@ public void shouldSetCacheWinningonlyFromConfigWhenExtRequestPrebidIsNull() { applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() @@ -1776,7 +1797,7 @@ public void shouldSetCacheWinningonlyFromConfigWhenExtRequestPrebidCacheIsNull() applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() @@ -1819,7 +1840,7 @@ public void shouldSetCacheWinningonlyFromConfigWhenCacheWinningonlyIsNull() { applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() @@ -1913,7 +1934,7 @@ public void shouldSetCacheWinningonlyFromRequestWhenCacheWinningonlyIsPresent() applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); givenBidRequest(BidRequest.builder() @@ -1958,7 +1979,7 @@ public void shouldNotSetCacheWinningonlyFromConfigWhenCacheWinningonlyIsNullAndC applicationSettings, idGenerator, privacyEnforcementService, - null, + hookStageExecutor, jacksonMapper); final ExtRequest extBidRequest = ExtRequest.of(ExtRequestPrebid.builder() @@ -2137,7 +2158,7 @@ public void shouldPassExtPrebidDebugFlagIfPresent() { @Test public void shouldReturnFailedFutureIfRequestValidationFailed() { // given - given(routingContext.getBody()).willReturn(Buffer.buffer("{}")); + given(routingContext.getBodyAsString()).willReturn("{}"); given(storedRequestProcessor.processStoredRequests(any(), any())) .willReturn(Future.succeededFuture(BidRequest.builder().build())); @@ -2155,17 +2176,29 @@ public void shouldReturnFailedFutureIfRequestValidationFailed() { } @Test - public void shouldReturnAuctionContextWithRoutingContext() { + public void shouldReturnAuctionContextWithHttpRequest() { // given + given(httpRequest.absoluteURI()).willReturn("absoluteUri"); + given(routingContext.queryParams()).willReturn(MultiMap.caseInsensitiveMultiMap()); + routingContext.queryParams().add("urloverride", "overriddendomain.com"); + httpRequest.headers().add("DHT", "1"); + given(httpRequest.scheme()).willReturn("https"); + givenValidBidRequest(); // when - - // FIXME -// final RoutingContext context = factory.fromRequest(routingContext, 0L).result().getRoutingContext(); + final HttpRequestWrapper httpRequest = + factory.fromRequest(routingContext, 0L).result().getHttpRequest(); // then -// assertThat(context).isSameAs(routingContext); + assertThat(httpRequest.getAbsoluteUri()).isEqualTo("absoluteUri"); + assertThat(httpRequest.getQueryParams()).hasSize(1); + assertThat(httpRequest.getQueryParams().get("urloverride")).isEqualTo("overriddendomain.com"); + assertThat(httpRequest.getHeaders()).hasSize(1); + assertThat(httpRequest.getHeaders().get("DHT")).isEqualTo("1"); + assertThat(httpRequest.getBody()).isEqualTo("{}"); + assertThat(httpRequest.getScheme()).isEqualTo("https"); + assertThat(httpRequest.getRemoteHost()).isEqualTo("host"); } @Test @@ -2441,6 +2474,19 @@ public void shouldReturnAuctionContextWithAppRequestTypeMetric() { assertThat(auctionContextFuture.result().getRequestTypeMetric()).isEqualTo(MetricName.openrtb2app); } + @Test + public void shouldReturnAuctionContextWithHookExecutionContext() { + // given + givenValidBidRequest(); + + // when + final HookExecutionContext hookExecutionContext = + factory.fromRequest(routingContext, 0L).result().getHookExecutionContext(); + + // then + assertThat(hookExecutionContext).isEqualTo(HookExecutionContext.of(Endpoint.openrtb2_auction)); + } + @Test public void shouldEnrichRequestWithIpAddressAndCountryAndSaveAuctionContext() { // given @@ -2480,7 +2526,7 @@ private void givenImplicitParams(String referer, String domain, String ip, IpAdd private void givenBidRequest(BidRequest bidRequest) { try { - given(routingContext.getBody()).willReturn(Buffer.buffer(mapper.writeValueAsString(bidRequest))); + given(routingContext.getBodyAsString()).willReturn(mapper.writeValueAsString(bidRequest)); } catch (JsonProcessingException e) { throw new RuntimeException(e); } @@ -2494,4 +2540,15 @@ private void givenBidRequest(BidRequest bidRequest) { private void givenValidBidRequest() { givenBidRequest(BidRequest.builder().build()); } + + @Accessors(fluent = true) + @Value(staticConstructor = "of") + private static class EntrypointPayloadImpl implements EntrypointPayload { + + MultiMap queryParams; + + MultiMap headers; + + String body; + } } diff --git a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java index 71423a1a461..64728400045 100644 --- a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java @@ -11,8 +11,9 @@ import com.iab.openrtb.request.video.BidRequestVideo; import com.iab.openrtb.request.video.PodError; import io.vertx.core.Future; -import io.vertx.core.buffer.Buffer; +import io.vertx.core.MultiMap; import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.net.impl.SocketAddressImpl; import io.vertx.ext.web.RoutingContext; import org.junit.Before; import org.junit.Rule; @@ -25,6 +26,8 @@ import org.prebid.server.auction.model.WithPodErrors; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.metric.MetricName; +import org.prebid.server.model.Endpoint; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.proto.openrtb.ext.ExtIncludeBrandCategory; import org.prebid.server.proto.openrtb.ext.request.ExtRequest; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; @@ -33,17 +36,19 @@ import org.prebid.server.proto.openrtb.ext.request.ExtRequestTargeting; import org.prebid.server.util.HttpUtil; -import java.util.ArrayList; import java.util.Arrays; +import static java.util.Collections.emptyList; import static java.util.Collections.emptySet; import static java.util.Collections.singletonList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.ArgumentMatchers.same; import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.verify; @@ -69,8 +74,11 @@ public class VideoRequestFactoryTest extends VertxTest { @Before public void setUp() { + given(auctionRequestFactory.executeEntrypointHooks(any(), any(), any())) + .willAnswer(invocation -> toHttpRequest(invocation.getArgument(0), invocation.getArgument(1))); + given(routingContext.request()).willReturn(httpServerRequest); - given(httpServerRequest.getParam(anyString())).willReturn("test"); + given(httpServerRequest.remoteAddress()).willReturn(new SocketAddressImpl(1234, "host")); factory = new VideoRequestFactory( Integer.MAX_VALUE, @@ -84,7 +92,7 @@ public void setUp() { @Test public void shouldReturnFailedFutureIfRequestBodyIsMissing() { // given - given(routingContext.getBody()).willReturn(null); + given(routingContext.getBodyAsString()).willReturn(null); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -99,9 +107,10 @@ public void shouldReturnFailedFutureIfRequestBodyIsMissing() { @Test public void shouldReturnFailedFutureIfStoredRequestIsEnforcedAndIdIsNotProvided() throws JsonProcessingException { // given - given(routingContext.getBody()) - .willReturn(Buffer.buffer(mapper.writeValueAsBytes(BidRequestVideo.builder().build()))); - given(routingContext.request().getHeader(HttpUtil.USER_AGENT_HEADER)).willReturn("123"); + given(routingContext.getBodyAsString()) + .willReturn(mapper.writeValueAsString(BidRequestVideo.builder().build())); + given(routingContext.request().headers()).willReturn(MultiMap.caseInsensitiveMultiMap() + .add(HttpUtil.USER_AGENT_HEADER, "123")); factory = new VideoRequestFactory( Integer.MAX_VALUE, true, @@ -131,7 +140,7 @@ public void shouldReturnFailedFutureIfRequestBodyExceedsMaxRequestSize() { timeoutResolver, jacksonMapper); - given(routingContext.getBody()).willReturn(Buffer.buffer("body")); + given(routingContext.getBodyAsString()).willReturn("body"); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -146,7 +155,7 @@ public void shouldReturnFailedFutureIfRequestBodyExceedsMaxRequestSize() { @Test public void shouldReturnFailedFutureIfRequestBodyCouldNotBeParsed() { // given - given(routingContext.getBody()).willReturn(Buffer.buffer("body")); + given(routingContext.getBodyAsString()).willReturn("body"); // when final Future future = factory.fromRequest(routingContext, 0L); @@ -206,7 +215,7 @@ public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingExc final BidRequestVideo requestVideo = BidRequestVideo.builder().device( Device.builder().ua("123").build()).build(); - given(routingContext.getBody()).willReturn(Buffer.buffer(mapper.writeValueAsBytes(requestVideo))); + given(routingContext.getBodyAsString()).willReturn(mapper.writeValueAsString(requestVideo)); given(videoStoredRequestProcessor.processVideoRequest(any(), any(), any(), any())) .willReturn(Future.succeededFuture(mergedBidRequest)); given(auctionRequestFactory.validateRequest(any())).willAnswer(invocation -> invocation.getArgument(0)); @@ -219,13 +228,18 @@ public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingExc final Future> result = factory.fromRequest(routingContext, 0L); // then - verify(routingContext).getBody(); - verify(videoStoredRequestProcessor).processVideoRequest("", null, emptySet(), requestVideo); - verify(auctionRequestFactory).validateRequest(bidRequest); - verify(auctionRequestFactory).fillImplicitParameters(bidRequest, /*FIXME*/ null, timeoutResolver); + verify(routingContext).getBodyAsString(); + verify(videoStoredRequestProcessor).processVideoRequest(eq(""), isNull(), eq(emptySet()), eq(requestVideo)); + verify(auctionRequestFactory).validateRequest(eq(bidRequest)); + verify(auctionRequestFactory).fillImplicitParameters(eq(bidRequest), any(), same(timeoutResolver)); verify(auctionRequestFactory).toAuctionContext( - // FIXME - null, bidRequest, MetricName.video, new ArrayList<>(), 0, timeoutResolver, null); + any(), + eq(bidRequest), + eq(MetricName.video), + eq(emptyList()), + eq(0L), + same(timeoutResolver), + argThat(context -> context.getEndpoint() == Endpoint.openrtb2_video)); assertThat(result.result().getPodErrors()).isEqualTo(mergedBidRequest.getPodErrors()); } @@ -234,8 +248,9 @@ public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingExc public void shouldReplaceDeviceUaWithUserAgentHeaderIfPresented() throws JsonProcessingException { // given final BidRequestVideo requestVideo = BidRequestVideo.builder().build(); - given(routingContext.getBody()).willReturn(Buffer.buffer(mapper.writeValueAsBytes(requestVideo))); - given(routingContext.request().getHeader(HttpUtil.USER_AGENT_HEADER)).willReturn("user-agent-123"); + given(routingContext.getBodyAsString()).willReturn(mapper.writeValueAsString(requestVideo)); + given(routingContext.request().headers()).willReturn(MultiMap.caseInsensitiveMultiMap() + .add((HttpUtil.USER_AGENT_HEADER), "user-agent-123")); final WithPodErrors emptyMergeObject = WithPodErrors.of(null, null); given(videoStoredRequestProcessor.processVideoRequest(any(), any(), any(), any())) @@ -256,7 +271,8 @@ public void shouldReplaceDeviceUaWithUserAgentHeaderIfPresented() throws JsonPro public void shouldReturnErrorIfDeviceUaAndUserAgentHeaderIsEmpty() throws JsonProcessingException { // given final BidRequestVideo requestVideo = BidRequestVideo.builder().build(); - given(routingContext.getBody()).willReturn(Buffer.buffer(mapper.writeValueAsBytes(requestVideo))); + given(routingContext.getBodyAsString()).willReturn(mapper.writeValueAsString(requestVideo)); + given(httpServerRequest.headers()).willReturn(MultiMap.caseInsensitiveMultiMap()); // when Future> future = factory.fromRequest(routingContext, 0L); @@ -267,4 +283,15 @@ public void shouldReturnErrorIfDeviceUaAndUserAgentHeaderIsEmpty() throws JsonPr .isInstanceOf(InvalidRequestException.class) .hasMessage("Device.UA and User-Agent Header is not presented"); } + + private static Future toHttpRequest(RoutingContext routingContext, String body) { + return Future.succeededFuture(HttpRequestWrapper.builder() + .absoluteUri(routingContext.request().absoluteURI()) + .queryParams(routingContext.queryParams()) + .headers(routingContext.request().headers()) + .body(body) + .scheme(routingContext.request().scheme()) + .remoteHost(routingContext.request().remoteAddress().host()) + .build()); + } } From bff3677314a144a5b96abdfb99f2076fb39ac08b Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Tue, 30 Mar 2021 15:30:52 +0300 Subject: [PATCH 10/12] Add and fix tests --- .../hooks/execution/HookStageExecutor.java | 18 ++++- .../spring/config/ServiceConfiguration.java | 11 ++- .../server/auction/AmpRequestFactoryTest.java | 30 ++++++++ .../auction/AuctionRequestFactoryTest.java | 73 ++++++++++++++++--- .../ImplicitParametersExtractorTest.java | 2 + .../auction/VideoRequestFactoryTest.java | 34 +++++++++ 6 files changed, 153 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java index b7999d5b9a4..97acdd7548f 100644 --- a/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java +++ b/src/main/java/org/prebid/server/hooks/execution/HookStageExecutor.java @@ -5,7 +5,6 @@ import org.prebid.server.hooks.execution.model.HookExecutionContext; import org.prebid.server.hooks.execution.model.HookStageExecutionResult; import org.prebid.server.hooks.v1.entrypoint.EntrypointPayload; -import org.prebid.server.model.Endpoint; public class HookStageExecutor { @@ -15,6 +14,21 @@ public Future> executeEntrypointStag String body, HookExecutionContext context) { - return null; + return Future.succeededFuture(HookStageExecutionResult.of(false, new EntrypointPayload() { + @Override + public MultiMap queryParams() { + return queryParams; + } + + @Override + public MultiMap headers() { + return headers; + } + + @Override + public String body() { + return body; + } + })); } } diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index 5335c57791d..f9bcc879220 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -37,6 +37,7 @@ import org.prebid.server.currency.CurrencyConversionService; import org.prebid.server.events.EventsService; import org.prebid.server.execution.TimeoutFactory; +import org.prebid.server.hooks.execution.HookStageExecutor; import org.prebid.server.identity.IdGenerator; import org.prebid.server.identity.NoneIdGenerator; import org.prebid.server.identity.UUIDIdGenerator; @@ -177,6 +178,11 @@ TimeoutResolver ampTimeoutResolver( return new TimeoutResolver(defaultTimeout, maxTimeout, timeoutAdjustment); } + @Bean + HookStageExecutor hookStageExecutor() { + return new HookStageExecutor(); + } + @Bean AuctionRequestFactory auctionRequestFactory( @Value("${auction.max-request-size}") @Min(0) int maxRequestSize, @@ -197,7 +203,8 @@ AuctionRequestFactory auctionRequestFactory( ApplicationSettings applicationSettings, PrivacyEnforcementService privacyEnforcementService, IdGenerator sourceIdGenerator, - JacksonMapper mapper) { + JacksonMapper mapper, + HookStageExecutor hookStageExecutor) { final List blacklistedApps = splitToList(blacklistedAppsString); final List blacklistedAccounts = splitToList(blacklistedAccountsString); @@ -222,7 +229,7 @@ AuctionRequestFactory auctionRequestFactory( applicationSettings, sourceIdGenerator, privacyEnforcementService, - null, + hookStageExecutor, mapper); } diff --git a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java index 7e4ef6d9259..0d57142371a 100644 --- a/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AmpRequestFactoryTest.java @@ -66,8 +66,11 @@ import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; public class AmpRequestFactoryTest extends VertxTest { @@ -203,6 +206,33 @@ public void shouldReturnFailedFutureIfStoredBidRequestHasNoExt() { .hasSize(1).containsOnly("AMP requests require Ext to be set"); } + @Test + public void shouldUseQueryParamsModifiedByEntrypointHooks() { + // given + doAnswer(invocation -> Future.succeededFuture(HttpRequestWrapper.builder() + .queryParams(MultiMap.caseInsensitiveMultiMap() + .add("tag_id", "tagId") + .add("debug", "1")) + .build())) + .when(auctionRequestFactory) + .executeEntrypointHooks(any(), any(), any()); + + givenBidRequest( + builder -> builder + .ext(ExtRequest.of(ExtRequestPrebid.builder().debug(0).build())), + Imp.builder().build()); + + // when + final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); + + // then + assertThat(singletonList(request)) + .extracting(BidRequest::getExt).isNotNull() + .extracting(ExtRequest::getPrebid) + .extracting(ExtRequestPrebid::getDebug) + .containsExactly(1); + } + @Test public void shouldReturnBidRequestWithDefaultPrebidValuesIfPrebidIsNull() { // given diff --git a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java index 94cf3a36265..33cef2eb132 100644 --- a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java @@ -40,6 +40,7 @@ import org.prebid.server.exception.BlacklistedAppException; import org.prebid.server.exception.InvalidRequestException; import org.prebid.server.exception.PreBidException; +import org.prebid.server.exception.RejectedRequestException; import org.prebid.server.exception.UnauthorizedAccountException; import org.prebid.server.execution.Timeout; import org.prebid.server.execution.TimeoutFactory; @@ -379,6 +380,52 @@ public void shouldReturnFailedFutureIfRequestBodyCouldNotBeParsed() { .element(0).asString().startsWith("Error decoding bidRequest: Unrecognized token 'body'"); } + @Test + public void shouldUseBodyAndHeadersModifiedByEntrypointHooks() { + // given + given(hookStageExecutor.executeEntrypointStage(any(), any(), any(), any())) + .willAnswer(invocation -> Future.succeededFuture(HookStageExecutionResult.of( + false, + EntrypointPayloadImpl.of( + MultiMap.caseInsensitiveMultiMap(), + MultiMap.caseInsensitiveMultiMap() + .add("DNT", "0"), + bidRequestToString(BidRequest.builder() + .app(App.builder().bundle("org.company.application").build()) + .build()))))); + + givenBidRequest(BidRequest.builder() + .device(Device.builder().dnt(1).build()) + .site(Site.builder().domain("example.com").build()) + .build()); + + // when + final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); + + // then + assertThat(request.getDevice().getDnt()).isZero(); + assertThat(request.getSite()).isNull(); + assertThat(request.getApp()).isEqualTo(App.builder().bundle("org.company.application").build()); + } + + @Test + public void shouldReturnFailedFutureIfEntrypointHooksRejectRequest() { + // given + given(hookStageExecutor.executeEntrypointStage(any(), any(), any(), any())) + .willAnswer(invocation -> Future.succeededFuture(HookStageExecutionResult.of(true, null))); + + givenValidBidRequest(); + + // when + final Future future = factory.fromRequest(routingContext, 0L); + + // then + assertThat(future.failed()).isTrue(); + assertThat(future.cause()).isInstanceOf(RejectedRequestException.class); + assertThat(((RejectedRequestException) future.cause()).getHookExecutionContext()) + .isEqualTo(HookExecutionContext.of(Endpoint.openrtb2_auction)); + } + @Test public void shouldCallOrtbFieldsResolver() { // given @@ -1178,7 +1225,7 @@ public void shouldNotUpdateImpsWithSecurityOneIfRequestIsSecureAndImpSecurityIsZ final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); // then - assertThat(request.getImp()).isSameAs(imps); + assertThat(request.getImp()).isEqualTo(imps); } @Test @@ -1209,7 +1256,7 @@ public void shouldNotUpdateImpsWithSecurityOneIfRequestIsNotSecureAndImpSecurity final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); // then - assertThat(request.getImp()).isSameAs(imps); + assertThat(request.getImp()).isEqualTo(imps); } @Test @@ -1311,7 +1358,7 @@ public void shouldNotChangeImpExtWhenBidderParametersAreAtImpExtPrebidBidderOnly final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); // then - assertThat(request.getImp()).isSameAs(imps); + assertThat(request.getImp()).isEqualTo(imps); } @Test @@ -1339,7 +1386,7 @@ public void shouldNotSetFieldsFromHeadersIfRequestFieldsNotEmpty() { final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); // then - assertThat(request).isSameAs(bidRequest); + assertThat(request).isEqualTo(bidRequest); } @Test @@ -1995,7 +2042,7 @@ public void shouldNotSetCacheWinningonlyFromConfigWhenCacheWinningonlyIsNullAndC final BidRequest request = factory.fromRequest(routingContext, 0L).result().getBidRequest(); // then - assertThat(request.getExt()).isSameAs(extBidRequest); + assertThat(request.getExt()).isEqualTo(extBidRequest); } @Test @@ -2525,18 +2572,22 @@ private void givenImplicitParams(String referer, String domain, String ip, IpAdd } private void givenBidRequest(BidRequest bidRequest) { - try { - given(routingContext.getBodyAsString()).willReturn(mapper.writeValueAsString(bidRequest)); - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } + given(routingContext.getBodyAsString()).willReturn(bidRequestToString(bidRequest)); given(storedRequestProcessor.processStoredRequests(any(), any())) - .willReturn(Future.succeededFuture(bidRequest)); + .willAnswer(invocation -> Future.succeededFuture(invocation.getArgument(1))); given(requestValidator.validate(any())).willReturn(ValidationResult.success()); } + private static String bidRequestToString(BidRequest bidRequest) { + try { + return mapper.writeValueAsString(bidRequest); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + private void givenValidBidRequest() { givenBidRequest(BidRequest.builder().build()); } diff --git a/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java b/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java index 7b75159a19f..a6ca16580a8 100644 --- a/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java +++ b/src/test/java/org/prebid/server/auction/ImplicitParametersExtractorTest.java @@ -2,6 +2,7 @@ import de.malkusch.whoisServerList.publicSuffixList.PublicSuffixList; import de.malkusch.whoisServerList.publicSuffixList.PublicSuffixListFactory; +import io.vertx.core.MultiMap; import io.vertx.core.http.CaseInsensitiveHeaders; import org.junit.Before; import org.junit.Rule; @@ -171,6 +172,7 @@ public void secureFromShouldReturnOneIfXForwardedProtoIsHttps() { public void secureFromShouldReturnOneIfConnectedViaSSL() { // given httpRequest = HttpRequestWrapper.builder() + .headers(MultiMap.caseInsensitiveMultiMap()) .scheme("https") .build(); diff --git a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java index 64728400045..c24013f48e3 100644 --- a/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/VideoRequestFactoryTest.java @@ -50,6 +50,7 @@ import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.same; import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; public class VideoRequestFactoryTest extends VertxTest { @@ -167,6 +168,39 @@ public void shouldReturnFailedFutureIfRequestBodyCouldNotBeParsed() { .element(0).asString().startsWith("Failed to decode:"); } + @Test + public void shouldUseHeadersModifiedByEntrypointHooks() throws JsonProcessingException { + // given + final BidRequestVideo requestVideo = BidRequestVideo.builder().build(); + final String body = mapper.writeValueAsString(requestVideo); + given(routingContext.getBodyAsString()).willReturn(body); + + given(routingContext.request().headers()).willReturn(MultiMap.caseInsensitiveMultiMap() + .add((HttpUtil.USER_AGENT_HEADER), "user-agent-123")); + + doAnswer(invocation -> Future.succeededFuture(HttpRequestWrapper.builder() + .headers(MultiMap.caseInsensitiveMultiMap() + .add(HttpUtil.USER_AGENT_HEADER, "user-agent-456")) + .body(body) + .build())) + .when(auctionRequestFactory) + .executeEntrypointHooks(any(), any(), any()); + + final WithPodErrors emptyMergeObject = WithPodErrors.of(null, null); + given(videoStoredRequestProcessor.processVideoRequest(any(), any(), any(), any())) + .willReturn(Future.succeededFuture(emptyMergeObject)); + + // when + factory.fromRequest(routingContext, 0L); + + // then + verify(videoStoredRequestProcessor).processVideoRequest(any(), any(), any(), eq(BidRequestVideo.builder() + .device(Device.builder() + .ua("user-agent-456") + .build()) + .build())); + } + @Test public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingException { // given From 59450f18aa555f81375153c7a9001414cdee1d8c Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Tue, 30 Mar 2021 15:42:51 +0300 Subject: [PATCH 11/12] Fix cookie handling --- .../server/auction/AuctionRequestFactory.java | 3 +- .../server/cookie/UidsCookieService.java | 5 +++ .../server/model/HttpRequestWrapper.java | 5 +++ .../java/org/prebid/server/util/HttpUtil.java | 6 +++ .../auction/AuctionRequestFactoryTest.java | 3 +- .../server/handler/CookieSyncHandlerTest.java | 30 +++++++-------- .../server/handler/GetuidsHandlerTest.java | 4 +- .../server/handler/OptoutHandlerTest.java | 2 +- .../server/handler/SetuidHandlerTest.java | 38 +++++++++---------- .../org/prebid/server/util/HttpUtilTest.java | 16 ++++++++ 10 files changed, 73 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java index 58f68d6f9cb..71130a5ae3c 100644 --- a/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java +++ b/src/main/java/org/prebid/server/auction/AuctionRequestFactory.java @@ -224,6 +224,7 @@ private HttpRequestWrapper toHttpRequest(HookStageExecutionResult toAuctionContext(HttpRequestWrapper httpRequest, bidRequest, account, requestTypeMetric, timeout, errors) .map(privacyContext -> AuctionContext.builder() .httpRequest(httpRequest) - .uidsCookie(uidsCookieService.parseFromRequest(null)) + .uidsCookie(uidsCookieService.parseFromRequest(httpRequest)) .bidRequest(enrichBidRequestWithAccountAndPrivacyData( bidRequest, account, privacyContext)) .requestTypeMetric(requestTypeMetric) diff --git a/src/main/java/org/prebid/server/cookie/UidsCookieService.java b/src/main/java/org/prebid/server/cookie/UidsCookieService.java index 1fa3f1d0364..934c2123afc 100644 --- a/src/main/java/org/prebid/server/cookie/UidsCookieService.java +++ b/src/main/java/org/prebid/server/cookie/UidsCookieService.java @@ -11,6 +11,7 @@ import org.prebid.server.cookie.proto.Uids; import org.prebid.server.json.DecodeException; import org.prebid.server.json.JacksonMapper; +import org.prebid.server.model.HttpRequestWrapper; import org.prebid.server.util.HttpUtil; import java.time.Clock; @@ -85,6 +86,10 @@ public UidsCookie parseFromRequest(RoutingContext context) { return parseFromCookies(HttpUtil.cookiesAsMap(context)); } + public UidsCookie parseFromRequest(HttpRequestWrapper httpRequest) { + return parseFromCookies(HttpUtil.cookiesAsMap(httpRequest)); + } + /** * Retrieves UIDs cookie (base64 encoded) value from cookies map and transforms it into {@link UidsCookie}. */ diff --git a/src/main/java/org/prebid/server/model/HttpRequestWrapper.java b/src/main/java/org/prebid/server/model/HttpRequestWrapper.java index 39a2d3d31c6..d4d62f3855e 100644 --- a/src/main/java/org/prebid/server/model/HttpRequestWrapper.java +++ b/src/main/java/org/prebid/server/model/HttpRequestWrapper.java @@ -1,9 +1,12 @@ package org.prebid.server.model; import io.vertx.core.MultiMap; +import io.vertx.core.http.Cookie; import lombok.Builder; import lombok.Value; +import java.util.Map; + @Builder @Value public class HttpRequestWrapper { @@ -14,6 +17,8 @@ public class HttpRequestWrapper { MultiMap headers; + Map cookies; + String body; String scheme; diff --git a/src/main/java/org/prebid/server/util/HttpUtil.java b/src/main/java/org/prebid/server/util/HttpUtil.java index 3344f8d0e04..b07c221e178 100644 --- a/src/main/java/org/prebid/server/util/HttpUtil.java +++ b/src/main/java/org/prebid/server/util/HttpUtil.java @@ -9,6 +9,7 @@ import io.vertx.core.http.HttpServerResponse; import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.StringUtils; +import org.prebid.server.model.HttpRequestWrapper; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; @@ -137,6 +138,11 @@ public static String getDomainFromUrl(String url) { } } + public static Map cookiesAsMap(HttpRequestWrapper httpRequest) { + return httpRequest.getCookies().entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); + } + public static Map cookiesAsMap(RoutingContext context) { return context.cookieMap().entrySet().stream() .collect(Collectors.toMap(Map.Entry::getKey, entry -> entry.getValue().getValue())); diff --git a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java index 33cef2eb132..a44d8807932 100644 --- a/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java +++ b/src/test/java/org/prebid/server/auction/AuctionRequestFactoryTest.java @@ -86,6 +86,7 @@ import java.util.Map; import static java.util.Arrays.asList; +import static java.util.Arrays.copyOf; import static java.util.Collections.emptyList; import static java.util.Collections.singleton; import static java.util.Collections.singletonList; @@ -2256,7 +2257,7 @@ public void shouldReturnAuctionContextWithUidsCookie() { final UidsCookie givenUidsCookie = new UidsCookie(Uids.builder() .uids(singletonMap("bidder", UidWithExpiry.live("uid"))) .build(), jacksonMapper); - given(uidsCookieService.parseFromRequest(any())).willReturn(givenUidsCookie); + given(uidsCookieService.parseFromRequest(any(HttpRequestWrapper.class))).willReturn(givenUidsCookie); // when final UidsCookie uidsCookie = factory.fromRequest(routingContext, 0L).result().getUidsCookie(); diff --git a/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java b/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java index 6ebc7a31c0c..c4554eaa426 100644 --- a/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/CookieSyncHandlerTest.java @@ -116,7 +116,7 @@ public class CookieSyncHandlerTest extends VertxTest { @Before public void setUp() { - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(routingContext.response()).willReturn(httpResponse); @@ -195,7 +195,7 @@ public void shouldRespondWithErrorAndSendToAnalyticsWithTcfWhenOptedOut() { // given given(routingContext.getBody()) .willReturn(givenRequestBody(CookieSyncRequest.builder().bidders(emptyList()).gdpr(1).build())); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).optout(true).build(), jacksonMapper)); given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); @@ -321,7 +321,7 @@ public void shouldPassAccountToPrivacyEnforcementServiceWhenAccountIsNotFound() @Test public void shouldRespondWithSomeBidderStatusesIfSomeUidsMissingInCookies() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); @@ -539,7 +539,7 @@ public void shouldRespondWithNoBidderStatusesIfAllUidsPresentInCookies() throws final Map uids = new HashMap<>(); uids.put(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT")); uids.put(APPNEXUS_COOKIE, UidWithExpiry.live("12345")); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(uids).build(), jacksonMapper)); given(bidderCatalog.isActive(anyString())).willReturn(true); @@ -565,7 +565,7 @@ public void shouldRespondWithNoBidderStatusesIfAllUidsPresentInCookies() throws @Test public void shouldTolerateUnsupportedBidder() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); @@ -595,7 +595,7 @@ public void shouldTolerateUnsupportedBidder() throws IOException { @Test public void shouldTolerateDisabledBidder() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); @@ -631,7 +631,7 @@ public void shouldTolerateDisabledBidder() throws IOException { @Test public void shouldTolerateRejectedBidderByTcf() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); @@ -666,7 +666,7 @@ public void shouldTolerateRejectedBidderByTcf() throws IOException { @Test public void shouldTolerateBiddersWithoutUsersyncUrl() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap("notRelevantBidder", UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); @@ -698,7 +698,7 @@ bidderCatalog, tcfDefinerService, privacyEnforcementService, null, false, emptyL analyticsReporterDelegator, metrics, timeoutFactory, jacksonMapper); final Uids uids = Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(uids, jacksonMapper)); given(routingContext.getBody()) @@ -760,7 +760,7 @@ public void shouldUpdateCookieSyncSetAndRejectByTcfMetricForEachRejectedAndSynce @Test public void shouldUpdateCookieSyncMatchesMetricForEachAlreadySyncedBidder() { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); @@ -792,7 +792,7 @@ public void shouldRespondWithNoCookieStatusIfHostVendorRejectedByTcf() throws IO bidderCatalog, tcfDefinerService, privacyEnforcementService, 1, false, emptyList(), analyticsReporterDelegator, metrics, timeoutFactory, jacksonMapper); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(routingContext.getBody()) @@ -824,7 +824,7 @@ public void shouldRespondWithNoCookieStatusIfHostVendorRejectedByTcf() throws IO @Test public void shouldRespondWithNoCookieStatusIfNoLiveUids() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(APPNEXUS_COOKIE, UidWithExpiry.expired("12345"))).build(), jacksonMapper)); @@ -1182,7 +1182,7 @@ public void shouldLimitBidderStatusesWithLiveUids() throws IOException { // given Map liveUids = doubleMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"), APPNEXUS_COOKIE, UidWithExpiry.live("1234567890")); - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(liveUids).build(), jacksonMapper)); given(routingContext.getBody()).willReturn(givenRequestBody( @@ -1252,7 +1252,7 @@ public void shouldIncrementMetrics() { @Test public void shouldPassSuccessfulEventToAnalyticsReporter() { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); @@ -1286,7 +1286,7 @@ public void shouldPassSuccessfulEventToAnalyticsReporter() { @Test public void handleShouldRespondWithNoCookieWhenBothCcpaAndGdprRejectBidders() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(routingContext.getBody()) diff --git a/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java b/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java index 9c34321dc99..9e5088981c2 100644 --- a/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/GetuidsHandlerTest.java @@ -65,7 +65,7 @@ public void shouldReturnBuyerUidsJsonWithoutExpirationDate() { uids.put("adnxs", new UidWithExpiry("Appnexus-uid", ZonedDateTime.parse("2019-04-01T12:30:40.123456789Z"))); - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(uids).bday(ZonedDateTime.parse("2019-04-01T13:28:40.123456789Z")).build(), jacksonMapper)); @@ -82,7 +82,7 @@ public void shouldReturnBuyerUidsJsonWithoutExpirationDate() { @Test public void shouldReturnEmptyBuyerUids() { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(Collections.emptyMap()).build(), jacksonMapper)); diff --git a/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java b/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java index 30b88e086b9..c78b53d88b3 100644 --- a/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/OptoutHandlerTest.java @@ -60,7 +60,7 @@ public void setUp() { given(googleRecaptchaVerifier.verify(anyString())).willReturn(Future.succeededFuture()); given(uidsCookieService.toCookie(any())).willReturn(Cookie.cookie("cookie", "value")); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); optoutHandler = new OptoutHandler(googleRecaptchaVerifier, uidsCookieService, diff --git a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java index e703ff2d0a4..e00a25cb854 100644 --- a/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java +++ b/src/test/java/org/prebid/server/handler/SetuidHandlerTest.java @@ -131,7 +131,7 @@ public void setUp() { @Test public void shouldRespondWithErrorAndTriggerMetricsAndAnalyticsWhenOptedOut() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).optout(true).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -152,7 +152,7 @@ public void shouldRespondWithErrorAndTriggerMetricsAndAnalyticsWhenOptedOut() { @Test public void shouldRespondWithErrorIfBidderParamIsMissing() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpResponse.setStatusCode(anyInt())).willReturn(httpResponse); @@ -172,7 +172,7 @@ public void shouldRespondWithErrorIfBidderParamIsMissing() { @Test public void shouldRespondWithErrorIfBidderParamIsInvalid() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam(eq("bidder"))).willReturn("invalid_or_disabled"); @@ -190,7 +190,7 @@ public void shouldRespondWithErrorIfBidderParamIsInvalid() { @Test public void shouldPassUnsuccessfulEventToAnalyticsReporterIfUidMissingInRequest() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -215,7 +215,7 @@ public void shouldRespondWithoutCookieIfGdprProcessingPreventsCookieSetting() { .willReturn(Future.succeededFuture( TcfResponse.of(true, singletonMap(null, privacyEnforcementAction), null))); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -240,7 +240,7 @@ public void shouldRespondWithBadRequestStatusIfGdprProcessingFailsWithInvalidReq given(tcfDefinerService.resultForVendorIds(anySet(), any())) .willReturn(Future.failedFuture(new InvalidRequestException("gdpr exception"))); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -264,7 +264,7 @@ public void shouldRespondWithInternalServerErrorStatusIfGdprProcessingFailsWithU given(tcfDefinerService.resultForVendorIds(anySet(), any())) .willReturn(Future.failedFuture("unexpected error TCF")); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -283,7 +283,7 @@ public void shouldRespondWithInternalServerErrorStatusIfGdprProcessingFailsWithU @Test public void shouldPassAccountToPrivacyEnforcementServiceWhenAccountIsFound() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -309,7 +309,7 @@ public void shouldPassAccountToPrivacyEnforcementServiceWhenAccountIsFound() { @Test public void shouldPassAccountToPrivacyEnforcementServiceWhenAccountIsNotFound() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -333,7 +333,7 @@ public void shouldRemoveUidFromCookieIfMissingInRequest() throws IOException { final Map uids = new HashMap<>(); uids.put(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT")); uids.put(ADNXS, UidWithExpiry.live("12345")); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(uids).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -359,7 +359,7 @@ public void shouldRemoveUidFromCookieIfMissingInRequest() throws IOException { @Test public void shouldIgnoreFacebookSentinel() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(FACEBOOK, UidWithExpiry.live("facebookUid"))).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(FACEBOOK); @@ -403,7 +403,7 @@ public void shouldIgnoreFacebookSentinel() throws IOException { @Test public void shouldRespondWithCookieFromRequestParam() throws IOException { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); // {"tempUIDs":{"rubicon":{"uid":"J5VLCWQP-26-CWFT"}}} @@ -435,7 +435,7 @@ public void shouldUpdateUidInCookieWithRequestValue() throws IOException { final Map uids = new HashMap<>(); uids.put(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT")); uids.put(ADNXS, UidWithExpiry.live("12345")); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(uids).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -466,7 +466,7 @@ public void shouldRespondWithCookieIfUserIsNotInGdprScope() throws IOException { given(tcfDefinerService.resultForVendorIds(anySet(), any())) .willReturn(Future.succeededFuture(TcfResponse.of(false, emptyMap(), null))); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); // {"tempUIDs":{"rubicon":{"uid":"J5VLCWQP-26-CWFT"}}} @@ -501,7 +501,7 @@ public void shouldSkipTcfChecksAndRespondWithCookieIfHostVendorIdNotDefined() th given(tcfDefinerService.resultForVendorIds(anySet(), any())) .willReturn(Future.succeededFuture(TcfResponse.of(false, emptyMap(), null))); - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); // {"tempUIDs":{"rubicon":{"uid":"J5VLCWQP-26-CWFT"}}} @@ -530,7 +530,7 @@ public void shouldSkipTcfChecksAndRespondWithCookieIfHostVendorIdNotDefined() th @Test public void shouldNotSendResponseIfClientClosedConnection() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -548,7 +548,7 @@ public void shouldNotSendResponseIfClientClosedConnection() { @Test public void shouldUpdateSetsMetric() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(RUBICON); @@ -564,7 +564,7 @@ public void shouldUpdateSetsMetric() { @Test public void shouldPassUnsuccessfulEventToAnalyticsReporterIfFacebookSentinel() { // given - given(uidsCookieService.parseFromRequest(any())) + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))) .willReturn(new UidsCookie(Uids.builder().uids(emptyMap()).build(), jacksonMapper)); given(httpRequest.getParam("bidder")).willReturn(FACEBOOK); @@ -603,7 +603,7 @@ public void shouldPassUnsuccessfulEventToAnalyticsReporterIfFacebookSentinel() { @Test public void shouldPassSuccessfulEventToAnalyticsReporter() { // given - given(uidsCookieService.parseFromRequest(any())).willReturn(new UidsCookie( + given(uidsCookieService.parseFromRequest(any(RoutingContext.class))).willReturn(new UidsCookie( Uids.builder().uids(singletonMap(RUBICON, UidWithExpiry.live("J5VLCWQP-26-CWFT"))).build(), jacksonMapper)); diff --git a/src/test/java/org/prebid/server/util/HttpUtilTest.java b/src/test/java/org/prebid/server/util/HttpUtilTest.java index 889b402b4f6..12f325c110b 100644 --- a/src/test/java/org/prebid/server/util/HttpUtilTest.java +++ b/src/test/java/org/prebid/server/util/HttpUtilTest.java @@ -8,6 +8,7 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; +import org.prebid.server.model.HttpRequestWrapper; import java.util.Map; @@ -124,6 +125,21 @@ public void cookiesAsMapShouldReturnExpectedResult() { .containsOnly(entry("name", "value")); } + @Test + public void cookiesAsMapFromRequestShouldReturnExpectedResult() { + // given + final HttpRequestWrapper httpRequest = HttpRequestWrapper.builder() + .cookies(singletonMap("name", Cookie.cookie("name", "value"))) + .build(); + + // when + final Map cookies = HttpUtil.cookiesAsMap(httpRequest); + + // then + assertThat(cookies).hasSize(1) + .containsOnly(entry("name", "value")); + } + @Test public void toSetCookieHeaderValueShouldReturnExpectedString() { // given From be46b7bd090e9ba2ecde590dab00ec323e9b69b6 Mon Sep 17 00:00:00 2001 From: Sergii Chernysh Date: Wed, 31 Mar 2021 13:14:59 +0300 Subject: [PATCH 12/12] Update hook stages --- .../org/prebid/server/hooks/execution/model/Stage.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/hooks/execution/model/Stage.java b/src/main/java/org/prebid/server/hooks/execution/model/Stage.java index 11fb33bf3b2..0f2c803d21d 100644 --- a/src/main/java/org/prebid/server/hooks/execution/model/Stage.java +++ b/src/main/java/org/prebid/server/hooks/execution/model/Stage.java @@ -2,5 +2,11 @@ public enum Stage { - entrypoint, auction_request, bidder_request, bidder_response, auction_response + entrypoint, + raw_auction_request, + processed_auction_request, + bidder_request, + raw_bidder_response, + processed_bidder_response, + auction_response }