diff --git a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java index 1ed572e0c7c..f6adfff4867 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -7,6 +7,7 @@ import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Device; +import com.iab.openrtb.request.User; import com.iab.openrtb.request.Format; import com.iab.openrtb.request.Imp; import com.iab.openrtb.response.Bid; @@ -16,6 +17,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.http.client.utils.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -35,6 +37,7 @@ import org.prebid.server.util.HttpUtil; import java.math.BigDecimal; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -74,6 +77,13 @@ public Result>> makeHttpRequests(BidRequest request return Result.withError(BidderError.badInput("Device IP is required")); } + final String optimalEndpointUrl; + try { + optimalEndpointUrl = getOptimalEndpointUrl(request); + } catch (PreBidException e) { + return Result.withError(BidderError.badInput(e.getMessage())); + } + final String displayManagerVer = buildDisplayManagerVersion(request); final MultiMap headers = resolveHeaders(device); @@ -85,7 +95,7 @@ public Result>> makeHttpRequests(BidRequest request final ExtImpConnatix extImpConnatix = parseExtImp(imp); final Imp modifiedImp = modifyImp(imp, extImpConnatix, displayManagerVer, request); - httpRequests.add(makeHttpRequest(request, modifiedImp, headers)); + httpRequests.add(makeHttpRequest(request, modifiedImp, headers, optimalEndpointUrl)); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); } @@ -94,6 +104,42 @@ public Result>> makeHttpRequests(BidRequest request return Result.of(httpRequests, errors); } + private String getOptimalEndpointUrl(BidRequest request) { + final Optional dataCenterCode = getUserId(request).map(ConnatixBidder::getDataCenterCode); + + if (dataCenterCode.isEmpty()) { + return endpointUrl; + } + + try { + return new URIBuilder(endpointUrl) + .addParameter("dc", dataCenterCode.get()) + .build() + .toString(); + } catch (URISyntaxException e) { + throw new PreBidException(e.getMessage()); + } + } + + private static Optional getUserId(BidRequest request) { + return Optional.ofNullable(request.getUser()) + .map(User::getBuyeruid) + .filter(StringUtils::isNotBlank) + .map(String::trim); + } + + private static String getDataCenterCode(String usedId) { + if (usedId.startsWith("1-")) { + return "us-east-2"; + } else if (usedId.startsWith("2-")) { + return "us-west-2"; + } else if (usedId.startsWith("3-")) { + return "eu-west-1"; + } + + return null; + } + private static String buildDisplayManagerVersion(BidRequest request) { return Optional.ofNullable(request.getApp()) .map(App::getExt) @@ -171,12 +217,13 @@ private Banner modifyImpBanner(Banner banner) { return banner; } - private HttpRequest makeHttpRequest(BidRequest request, Imp imp, MultiMap headers) { - final BidRequest outgoingRequest = request.toBuilder() - .imp(List.of(imp)) - .build(); + private HttpRequest makeHttpRequest(BidRequest request, + Imp imp, + MultiMap headers, + String optimalEndpointUrl) { - return BidderUtil.defaultRequest(outgoingRequest, headers, endpointUrl, mapper); + final BidRequest outgoingRequest = request.toBuilder().imp(List.of(imp)).build(); + return BidderUtil.defaultRequest(outgoingRequest, headers, optimalEndpointUrl, mapper); } @Override diff --git a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java index 82b3d1faad8..7dfc8bdcd12 100644 --- a/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/connatix/ConnatixBidderTest.java @@ -8,6 +8,7 @@ import com.iab.openrtb.request.Device; import com.iab.openrtb.request.Format; import com.iab.openrtb.request.Imp; +import com.iab.openrtb.request.User; import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; @@ -268,6 +269,86 @@ public void makeHttpRequestsShouldIncludeResolvedHttpHeadersFromDevice() { tuple(HttpUtil.ACCEPT_HEADER.toString(), HttpHeaderValues.APPLICATION_JSON.toString())); } + @Test + public void makeHttpRequestsShouldUseDataCenterUsEast2WhenUserIdStartsWith1() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.user(User.builder().buyeruid("1-UserId").build()), + givenImp(impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtImpConnatix.of("placementId", null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(HttpRequest::getUri).containsOnly("https://test-url.com/?dc=us-east-2"); + } + + @Test + public void makeHttpRequestsShouldUseDataCenterUsWest2WhenUserIdStartsWith2() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.user(User.builder().buyeruid("2-UserId").build()), + givenImp(impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtImpConnatix.of("placementId", null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(HttpRequest::getUri).containsOnly("https://test-url.com/?dc=us-west-2"); + } + + @Test + public void makeHttpRequestsShouldUseDataCenterEuWest1WhenUserIdStartsWith3() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.user(User.builder().buyeruid("3-UserId").build()), + givenImp(impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtImpConnatix.of("placementId", null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(HttpRequest::getUri).containsOnly("https://test-url.com/?dc=eu-west-1"); + } + + @Test + public void makeHttpRequestsShouldExcludeDataCenterWhenUserIdPrefixDoesNotMatch() { + // given + final BidRequest bidRequest = givenBidRequest( + request -> request.user(User.builder().buyeruid("4-UserId").build()), + givenImp(impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtImpConnatix.of("placementId", null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(HttpRequest::getUri).containsOnly(CONNATIX_ENDPOINT); + } + + @Test + public void makeHttpRequestsShouldExcludeDataCenterWhenUserIdIsMissing() { + // given + final BidRequest bidRequest = givenBidRequest( + UnaryOperator.identity(), + givenImp(impBuilder -> impBuilder + .ext(mapper.valueToTree(ExtImpConnatix.of("placementId", null))))); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).extracting(HttpRequest::getUri).containsOnly(CONNATIX_ENDPOINT); + } + @Test public void makeBidsShouldErrorIfResponseBodyCannotBeParsed() { // given