diff --git a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java index 005ac13b223..93fc7836e11 100644 --- a/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java +++ b/extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java @@ -63,7 +63,7 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniCh double logSamplingRate) { this.config = Objects.requireNonNull(config); - HttpUtil.validateUrlSyntax(config.getIdentityResolutionEndpoint()); + HttpUtil.validateUrl(config.getIdentityResolutionEndpoint()); this.mapper = Objects.requireNonNull(mapper); this.httpClient = Objects.requireNonNull(httpClient); this.logSamplingRate = logSamplingRate; diff --git a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtils.java b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtils.java index a1593e89131..4ffccb352a4 100644 --- a/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtils.java +++ b/extra/modules/wurfl-devicedetection/src/main/java/org/prebid/server/hooks/modules/com/scientiamobile/wurfl/devicedetection/model/WURFLEngineUtils.java @@ -6,8 +6,9 @@ import com.scientiamobile.wurfl.core.cache.NullCacheProvider; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.config.WURFLDeviceDetectionConfigProperties; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.exc.WURFLDeviceDetectionException; +import org.prebid.server.util.HttpUtil; -import java.net.URI; +import java.net.URL; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collections; @@ -56,8 +57,8 @@ private static String wurflFilePathFromConfig(WURFLDeviceDetectionConfigProperti public static String extractWURFLFileName(String wurflSnapshotUrl) { try { - final URI uri = new URI(wurflSnapshotUrl); - final String path = uri.getPath(); + final URL url = HttpUtil.parseUrl(wurflSnapshotUrl); + final String path = url.getPath(); return path.substring(path.lastIndexOf('/') + 1); } catch (Exception e) { throw new IllegalArgumentException("Invalid WURFL snapshot URL: " + wurflSnapshotUrl, e); diff --git a/extra/pom.xml b/extra/pom.xml index aaa92aef135..ac95e2497bf 100644 --- a/extra/pom.xml +++ b/extra/pom.xml @@ -39,9 +39,7 @@ 4.4 1.27.1 3.6.1 - 1.10.0 2.1 - 4.5.14 5.5.1 6.8.0 1.5.6 @@ -136,23 +134,6 @@ commons-math3 ${commons-math3.version} - - commons-validator - commons-validator - ${commons-validator.version} - - - - org.apache.httpcomponents - httpclient - ${httpclient.version} - - - commons-logging - commons-logging - - - com.github.seancfoley ipaddress diff --git a/pom.xml b/pom.xml index 9d754d76295..787de955b9c 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,10 @@ io.vertx vertx-auth-common + + io.vertx + vertx-uri-template + com.ongres.scram client @@ -110,14 +114,6 @@ org.apache.commons commons-math3 - - org.apache.httpcomponents - httpclient - - - commons-validator - commons-validator - com.github.seancfoley ipaddress diff --git a/src/main/java/org/prebid/server/analytics/reporter/liveintent/LiveIntentAnalyticsReporter.java b/src/main/java/org/prebid/server/analytics/reporter/liveintent/LiveIntentAnalyticsReporter.java index d404a12397e..e7a45f63f32 100644 --- a/src/main/java/org/prebid/server/analytics/reporter/liveintent/LiveIntentAnalyticsReporter.java +++ b/src/main/java/org/prebid/server/analytics/reporter/liveintent/LiveIntentAnalyticsReporter.java @@ -5,8 +5,10 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.Future; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.commons.lang3.StringUtils; import org.prebid.server.analytics.AnalyticsReporter; import org.prebid.server.analytics.model.AuctionEvent; import org.prebid.server.analytics.model.NotificationEvent; @@ -27,9 +29,12 @@ import org.prebid.server.log.LoggerFactory; import org.prebid.server.proto.openrtb.ext.request.ExtRequest; import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebid; +import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import org.prebid.server.vertx.httpclient.HttpClient; -import java.net.URISyntaxException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -44,6 +49,7 @@ public class LiveIntentAnalyticsReporter implements AnalyticsReporter { private final HttpClient httpClient; private final LiveIntentAnalyticsProperties properties; private final JacksonMapper jacksonMapper; + private final UriTemplate uriTemplate; public LiveIntentAnalyticsReporter( LiveIntentAnalyticsProperties properties, @@ -53,6 +59,21 @@ public LiveIntentAnalyticsReporter( this.httpClient = Objects.requireNonNull(httpClient); this.properties = Objects.requireNonNull(properties); this.jacksonMapper = Objects.requireNonNull(jacksonMapper); + + final URL url; + try { + url = HttpUtil.parseUrl(properties.getAnalyticsEndpoint()); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(e); + } + + final String query = url.getQuery() != null ? "?" + url.getQuery() : StringUtils.EMPTY; + this.uriTemplate = UriTemplateUtil.createTemplate( + url.getProtocol() + "://" + url.getAuthority() + "/analytic-events{/path}" + query, + query.contains("?"), + "b", + "bidId"); + } @Override @@ -96,10 +117,7 @@ private Future processAuctionEvent(AuctionContext auctionContext) { try { return httpClient.post( - new URIBuilder(properties.getAnalyticsEndpoint()) - .setPath("/analytic-events/pbsj-bids") - .build() - .toString(), + uriTemplate.expandToString(Variables.variables().set("path", "pbsj-bids")), jacksonMapper.encodeToString(pbsjBids), properties.getTimeoutMs()) .mapEmpty(); @@ -169,18 +187,11 @@ private Optional buildPbsjBid( } private Future processNotificationEvent(NotificationEvent notificationEvent) { - try { - final String url = new URIBuilder(properties.getAnalyticsEndpoint()) - .setPath("/analytic-events/pbsj-winning-bid") - .setParameter("b", notificationEvent.getBidder()) - .setParameter("bidId", notificationEvent.getBidId()) - .build() - .toString(); - return httpClient.get(url, properties.getTimeoutMs()).mapEmpty(); - } catch (URISyntaxException e) { - logger.error("Error composing url for notification event: {}", e.getMessage()); - return Future.failedFuture(e); - } + final String url = uriTemplate.expandToString(Variables.variables() + .set("path", "pbsj-winning-bid") + .set("b", notificationEvent.getBidder()) + .set("bidId", notificationEvent.getBidId())); + return httpClient.get(url, properties.getTimeoutMs()).mapEmpty(); } @Override diff --git a/src/main/java/org/prebid/server/auction/IpAddressHelper.java b/src/main/java/org/prebid/server/auction/IpAddressHelper.java index 523219fd511..8ffaf144111 100644 --- a/src/main/java/org/prebid/server/auction/IpAddressHelper.java +++ b/src/main/java/org/prebid/server/auction/IpAddressHelper.java @@ -5,17 +5,19 @@ import inet.ipaddr.IPAddressString; import inet.ipaddr.IPAddressStringParameters; import org.apache.commons.lang3.StringUtils; -import org.apache.http.conn.util.InetAddressUtils; import org.prebid.server.auction.model.IpAddress; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; import java.util.List; +import java.util.regex.Pattern; public class IpAddressHelper { private static final Logger logger = LoggerFactory.getLogger(IpAddressHelper.class); + private static final Pattern IP_V4_PATTERN = + Pattern.compile("^(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\\.(?!$)|$)){4}$"); private static final IPAddressStringParameters IP_ADDRESS_VALIDATION_OPTIONS = IPAddressString.DEFAULT_VALIDATION_OPTIONS.toBuilder() .allowSingleSegment(false) @@ -73,7 +75,7 @@ public IpAddress toIpAddress(String ip) { } public String maskIpv4(String ip) { - if (StringUtils.isBlank(ip) || !InetAddressUtils.isIPv4Address(ip)) { + if (StringUtils.isBlank(ip) || !IP_V4_PATTERN.matcher(ip).matches()) { return ip; } diff --git a/src/main/java/org/prebid/server/bidder/adgeneration/AdgenerationBidder.java b/src/main/java/org/prebid/server/bidder/adgeneration/AdgenerationBidder.java index 22fc3dc5309..a79743281be 100644 --- a/src/main/java/org/prebid/server/bidder/adgeneration/AdgenerationBidder.java +++ b/src/main/java/org/prebid/server/bidder/adgeneration/AdgenerationBidder.java @@ -12,9 +12,10 @@ import com.iab.openrtb.response.Bid; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adgeneration.model.AdgenerationResponse; import org.prebid.server.bidder.model.BidderBid; @@ -31,10 +32,12 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; +import org.prebid.server.util.UriTemplateUtil; -import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -51,11 +54,12 @@ public class AdgenerationBidder implements Bidder { new TypeReference<>() { }; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; public AdgenerationBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "queryParams"); this.mapper = Objects.requireNonNull(mapper); } @@ -96,47 +100,41 @@ private ExtImpAdgeneration parseAndValidateImpExt(Imp imp) { } private String getUri(String adSize, String id, String currency, BidRequest bidRequest) { - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(endpointUrl); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(endpointUrl, e.getMessage())); - } - - uriBuilder - .addParameter("posall", "SSPLOC") - .addParameter("id", id) - .addParameter("hb", "true") - .addParameter("t", "json3") - .addParameter("currency", currency) - .addParameter("sdkname", "prebidserver") - .addParameter("adapterver", VERSION); - - addParameterIfNotEmpty(uriBuilder, "sizes", adSize); - addParameterIfNotEmpty(uriBuilder, "tp", ObjectUtil.getIfNotNull(bidRequest.getSite(), Site::getPage)); - addParameterIfNotEmpty(uriBuilder, "appbundle", ObjectUtil.getIfNotNull(bidRequest.getApp(), App::getBundle)); - addParameterIfNotEmpty(uriBuilder, "appname", ObjectUtil.getIfNotNull(bidRequest.getApp(), App::getName)); - addParameterIfNotEmpty( - uriBuilder, "transactionid", ObjectUtil.getIfNotNull(bidRequest.getSource(), Source::getTid)); + final Map queryParams = new HashMap<>(); + + queryParams.put("posall", "SSPLOC"); + queryParams.put("id", id); + queryParams.put("hb", "true"); + queryParams.put("t", "json3"); + queryParams.put("currency", currency); + queryParams.put("sdkname", "prebidserver"); + queryParams.put("adapterver", VERSION); + + addParameterIfNotEmpty(queryParams, "sizes", adSize); + addParameterIfNotEmpty(queryParams, "tp", ObjectUtil.getIfNotNull(bidRequest.getSite(), Site::getPage)); + addParameterIfNotEmpty(queryParams, "appbundle", ObjectUtil.getIfNotNull(bidRequest.getApp(), App::getBundle)); + addParameterIfNotEmpty(queryParams, "appname", ObjectUtil.getIfNotNull(bidRequest.getApp(), App::getName)); + addParameterIfNotEmpty(queryParams, "transactionid", + ObjectUtil.getIfNotNull(bidRequest.getSource(), Source::getTid)); final Device device = bidRequest.getDevice(); final String deviceOs = device != null ? device.getOs() : null; if ("android".equals(deviceOs)) { - uriBuilder.addParameter("sdktype", "1"); - addParameterIfNotEmpty(uriBuilder, "advertising_id", device.getIfa()); + queryParams.put("sdktype", "1"); + addParameterIfNotEmpty(queryParams, "advertising_id", device.getIfa()); } else if ("ios".equals(deviceOs)) { - uriBuilder.addParameter("sdktype", "2"); - addParameterIfNotEmpty(uriBuilder, "idfa", device.getIfa()); + queryParams.put("sdktype", "2"); + addParameterIfNotEmpty(queryParams, "idfa", device.getIfa()); } else { - uriBuilder.addParameter("sdktype", "0"); + queryParams.put("sdktype", "0"); } - return uriBuilder.toString(); + return endpointUrlTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } - private static void addParameterIfNotEmpty(URIBuilder uriBuilder, String parameter, String value) { + private static void addParameterIfNotEmpty(Map queryParams, String parameter, String value) { if (StringUtils.isNotEmpty(value)) { - uriBuilder.addParameter(parameter, value); + queryParams.put(parameter, value); } } diff --git a/src/main/java/org/prebid/server/bidder/adkernel/AdkernelBidder.java b/src/main/java/org/prebid/server/bidder/adkernel/AdkernelBidder.java index c50b89b3417..6b7712f00ae 100644 --- a/src/main/java/org/prebid/server/bidder/adkernel/AdkernelBidder.java +++ b/src/main/java/org/prebid/server/bidder/adkernel/AdkernelBidder.java @@ -41,6 +41,8 @@ public class AdkernelBidder implements Bidder { new TypeReference<>() { }; + private static final String ZONE_ID_MACRO = "{{ZoneId}}"; + private static final String MF_SUFFIX = "__mf"; private static final String MF_SUFFIX_BANNER = "b" + MF_SUFFIX; private static final String MF_SUFFIX_VIDEO = "v" + MF_SUFFIX; @@ -49,11 +51,11 @@ public class AdkernelBidder implements Bidder { private static final int MF_SUFFIX_LENGTH = MF_SUFFIX.length() + 1; - private final String endpointTemplate; + private final String endpointUrl; private final JacksonMapper mapper; - public AdkernelBidder(String endpointTemplate, JacksonMapper mapper) { - this.endpointTemplate = HttpUtil.validateUrl(Objects.requireNonNull(endpointTemplate)); + public AdkernelBidder(String endpointUrl, JacksonMapper mapper) { + this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); this.mapper = Objects.requireNonNull(mapper); } @@ -183,10 +185,9 @@ private HttpRequest createHttpRequest(Map.Entry { private static final int BANNER_MTYPE = 1; private static final int NATIVE_MTYPE = 4; - private final String endpointUrl; - private final String euEndpoint; + private final UriTemplate endpointUrlTemplate; + private final UriTemplate euEndpointUrlTemplate; private final Clock clock; private final JacksonMapper mapper; @@ -92,8 +93,12 @@ public AdnuntiusBidder(String endpointUrl, Clock clock, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); - this.euEndpoint = euEndpoint == null ? null : HttpUtil.validateUrl(euEndpoint); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "queryParams"); + final String euUrl = euEndpoint == null ? null : HttpUtil.validateUrl(euEndpoint); + this.euEndpointUrlTemplate = euUrl == null + ? null + : UriTemplateUtil.createTemplate(euUrl, "queryParams"); this.clock = Objects.requireNonNull(clock); this.mapper = Objects.requireNonNull(mapper); } @@ -248,35 +253,32 @@ private List> createHttpRequests( } private String makeEndpoint(BidRequest bidRequest, Boolean noCookies) { - try { - final String gdpr = extractGdpr(bidRequest.getRegs()); - final String url = StringUtils.isNotBlank(gdpr) ? euEndpoint : endpointUrl; + final String gdpr = extractGdpr(bidRequest.getRegs()); + final UriTemplate urlTemplate = StringUtils.isNotBlank(gdpr) ? euEndpointUrlTemplate : endpointUrlTemplate; - if (url == null) { - throw new PreBidException("an EU endpoint is required but invalid"); - } + if (urlTemplate == null) { + throw new PreBidException("an EU endpoint is required but invalid"); + } - final URIBuilder uriBuilder = new URIBuilder(url) - .addParameter("format", "prebidServer") - .addParameter("tzo", getTimeZoneOffset()); + final Map queryParams = new HashMap<>(); - if (StringUtils.isNotEmpty(gdpr)) { - uriBuilder.addParameter("gdpr", gdpr); - } + queryParams.put("format", "prebidServer"); + queryParams.put("tzo", getTimeZoneOffset()); - final String consent = extractConsent(bidRequest.getUser()); - if (StringUtils.isNotEmpty(consent)) { - uriBuilder.addParameter("consentString", consent); - } + if (StringUtils.isNotEmpty(gdpr)) { + queryParams.put("gdpr", gdpr); + } - if (noCookies || extractNoCookies(bidRequest.getDevice())) { - uriBuilder.addParameter("noCookies", "true"); - } + final String consent = extractConsent(bidRequest.getUser()); + if (StringUtils.isNotEmpty(consent)) { + queryParams.put("consentString", consent); + } - return uriBuilder.build().toString(); - } catch (URISyntaxException | IllegalArgumentException e) { - throw new PreBidException(e.getMessage()); + if (noCookies || extractNoCookies(bidRequest.getDevice())) { + queryParams.put("noCookies", "true"); } + + return urlTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } private String getTimeZoneOffset() { diff --git a/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java b/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java index 63ad320ca4e..1e142b62c06 100644 --- a/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java +++ b/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java @@ -12,14 +12,12 @@ import com.iab.openrtb.response.Bid; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adocean.model.AdoceanResponseAdUnit; import org.prebid.server.bidder.model.BidderBid; @@ -34,12 +32,11 @@ import org.prebid.server.proto.openrtb.ext.request.adocean.ExtImpAdocean; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import java.io.IOException; import java.math.BigDecimal; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; +import java.net.MalformedURLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -64,11 +61,16 @@ public class AdoceanBidder implements Bidder { if (su && !(navigator.sendBeacon && navigator.sendBeacon(su))) { (new Image(1,1)).src = su } }(); """; - private final String endpointUrl; + private static final String HOST_MACRO_NAME = "Host"; + private final JacksonMapper mapper; + private final UriTemplate uriTemplate; public AdoceanBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.uriTemplate = UriTemplateUtil.createTemplate( + "%s/_%s/ad.json".formatted(endpointUrl, "{randomizedPart}"), + List.of(HOST_MACRO_NAME)); this.mapper = Objects.requireNonNull(mapper); } @@ -78,6 +80,7 @@ public Result>> makeHttpRequests(BidRequest request) { final User user = request.getUser(); final ExtUser extUser = user != null ? user.getExt() : null; final String consentString = extUser != null ? extUser.getConsent() : ""; + final Map, HttpRequestWrapper> httpRequestWrapperMap = new HashMap<>(); final List> httpRequests = new ArrayList<>(); for (Imp imp : request.getImp()) { @@ -87,11 +90,22 @@ public Result>> makeHttpRequests(BidRequest request) { final Map slaveSizes = new HashMap<>(); slaveSizes.put(extImpAdocean.getSlaveId(), getImpSizes(imp)); - if (addRequestAndCheckIfDuplicates(httpRequests, extImpAdocean, imp.getId(), slaveSizes, - request.getTest())) { + if (addRequestAndCheckIfDuplicates( + httpRequests, + extImpAdocean, + imp.getId(), + slaveSizes, + request.getTest(), + httpRequestWrapperMap)) { continue; } - httpRequests.add(createSingleRequest(request, imp, extImpAdocean, consentString, slaveSizes)); + httpRequests.add(createSingleRequest( + request, + imp, + extImpAdocean, + consentString, + slaveSizes, + httpRequestWrapperMap)); } catch (PreBidException e) { errors.add(BidderError.badInput(e.getMessage())); } @@ -115,49 +129,51 @@ private static void validateImpExt(ExtImpAdocean impExt) { } } - private boolean addRequestAndCheckIfDuplicates(List> httpRequests, ExtImpAdocean extImpAdocean, - String impid, Map slaveSizes, Integer test) { + private boolean addRequestAndCheckIfDuplicates(List> httpRequests, + ExtImpAdocean extImpAdocean, + String impid, + Map slaveSizes, + Integer test, + Map, HttpRequestWrapper> httpRequestWrapperMap) { + for (HttpRequest request : httpRequests) { - try { - final URIBuilder uriBuilder = new URIBuilder(request.getUri()); - final List queryParams = uriBuilder.getQueryParams(); - - final String masterId = queryParams.stream() - .filter(param -> "id".equals(param.getName())) - .findFirst() - .map(NameValuePair::getValue) - .orElse(null); - - if (masterId != null && masterId.equals(extImpAdocean.getMasterId())) { - final boolean isExistingSlaveId = queryParams.stream() - .filter(param -> "aid".equals(param.getName())) - .map(param -> param.getValue().split(":")[0]) - .anyMatch(slaveId -> slaveId.equals(extImpAdocean.getSlaveId())); - if (isExistingSlaveId) { - continue; - } - - queryParams.add(new BasicNameValuePair("aid", extImpAdocean.getSlaveId() + ":" + impid)); - final List sizeValues = setSlaveSizesParam(slaveSizes, Objects.equals(test, 1)); - if (CollectionUtils.isNotEmpty(sizeValues)) { - queryParams.add(new BasicNameValuePair("aosspsizes", String.join("-", sizeValues))); - } - uriBuilder.setParameters(queryParams); - - final String url = uriBuilder.toString(); - if (url.length() < MAX_URI_LENGTH) { - final HttpRequest updatedRequest = HttpRequest.builder() - .method(HttpMethod.GET) - .uri(url) - .headers(request.getHeaders()) - .build(); - httpRequests.remove(request); - httpRequests.add(updatedRequest); - return true; - } + final HttpRequestWrapper httpRequestWrapper = httpRequestWrapperMap.get(request); + final Map queryParams = new HashMap<>(httpRequestWrapper.queryParams()); + final String masterId = queryParams.get("id"); + + if (masterId != null && masterId.equals(extImpAdocean.getMasterId())) { + final boolean isExistingSlaveId = Objects.equals( + queryParams.get("aid").split(":")[0], + extImpAdocean.getSlaveId()); + + if (isExistingSlaveId) { + continue; + } + + queryParams.put("aid", extImpAdocean.getSlaveId() + ":" + impid); + final List sizeValues = setSlaveSizesParam(slaveSizes, Objects.equals(test, 1)); + if (CollectionUtils.isNotEmpty(sizeValues)) { + queryParams.put("aosspsizes", String.join("-", sizeValues)); + } + + final String finalUrl = UriTemplateUtil.createTemplate( + httpRequestWrapper.url(), + false, + "queryParams") + .expandToString(Variables.variables() + .set("url", httpRequestWrapper.url()) + .set("queryParams", queryParams)); + + if (finalUrl.length() < MAX_URI_LENGTH) { + final HttpRequest updatedRequest = HttpRequest.builder() + .method(HttpMethod.GET) + .uri(finalUrl) + .headers(request.getHeaders()) + .build(); + httpRequests.remove(request); + httpRequests.add(updatedRequest); + return true; } - } catch (URISyntaxException e) { - throw new PreBidException(e.getMessage()); } } return false; @@ -190,81 +206,94 @@ private int getIntOrElseZero(Integer number) { return number != null ? number : 0; } - private HttpRequest createSingleRequest(BidRequest request, Imp imp, ExtImpAdocean extImpAdocean, - String consentString, Map slaveSizes) { + private HttpRequest createSingleRequest(BidRequest request, + Imp imp, + ExtImpAdocean extImpAdocean, + String consentString, + Map slaveSizes, + Map, HttpRequestWrapper> httpRequestWrapperMap) { - return HttpRequest.builder() + final HttpRequestWrapper httpRequestWrapper = buildHttpRequestWrapper( + imp.getId(), extImpAdocean, consentString, request, slaveSizes); + + final HttpRequest httpRequest = HttpRequest.builder() .method(HttpMethod.GET) - .uri(buildUrl(imp.getId(), extImpAdocean, consentString, request, slaveSizes)) + .uri(httpRequestWrapper.url() + httpRequestWrapper.query()) .headers(getHeaders(request)) .build(); + + httpRequestWrapperMap.put(httpRequest, httpRequestWrapper); + return httpRequest; } - private String buildUrl(String impId, ExtImpAdocean extImpAdocean, String consentString, BidRequest bidRequest, - Map slaveSizes) { + private HttpRequestWrapper buildHttpRequestWrapper(String impId, + ExtImpAdocean extImpAdocean, + String consentString, + BidRequest bidRequest, + Map slaveSizes) { - final Integer test = bidRequest.getTest(); - final String resolvedUrl = resolveEndpointUrl(extImpAdocean, test); + final Map queryParams = new HashMap<>(); - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(resolvedUrl); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(resolvedUrl, e.getMessage())); - } - - uriBuilder - .addParameter("pbsrv_v", VERSION) - .addParameter("id", extImpAdocean.getMasterId()) - .addParameter("nc", "1") - .addParameter("nosecure", "1") - .addParameter("aid", extImpAdocean.getSlaveId() + ":" + impId); + queryParams.put("pbsrv_v", VERSION); + queryParams.put("id", extImpAdocean.getMasterId()); + queryParams.put("nc", "1"); + queryParams.put("nosecure", "1"); + queryParams.put("aid", extImpAdocean.getSlaveId() + ":" + impId); if (StringUtils.isNotEmpty(consentString)) { - uriBuilder.addParameter("gdpr_consent", consentString); - uriBuilder.addParameter("gdpr", "1"); + queryParams.put("gdpr_consent", consentString); + queryParams.put("gdpr", "1"); } final User user = bidRequest.getUser(); if (user != null && StringUtils.isNotEmpty(user.getBuyeruid())) { - uriBuilder.addParameter("hcuserid", user.getBuyeruid()); + queryParams.put("hcuserid", user.getBuyeruid()); } final App app = bidRequest.getApp(); if (app != null) { - uriBuilder.addParameter("app", "1"); - uriBuilder.addParameter("appname", app.getName()); - uriBuilder.addParameter("appbundle", app.getBundle()); - uriBuilder.addParameter("appdomain", app.getDomain()); + addParameterIfNotEmpty(queryParams, "app", "1"); + addParameterIfNotEmpty(queryParams, "appname", app.getName()); + addParameterIfNotEmpty(queryParams, "appbundle", app.getBundle()); + addParameterIfNotEmpty(queryParams, "appdomain", app.getDomain()); } final Device device = bidRequest.getDevice(); if (device != null) { if (StringUtils.isNotEmpty(device.getIfa())) { - uriBuilder.addParameter("ifa", device.getIfa()); - } else { - uriBuilder.addParameter("dpidmd5", device.getDpidmd5()); + queryParams.put("ifa", device.getIfa()); + } else if (StringUtils.isNotEmpty(device.getDpidmd5())) { + queryParams.put("dpidmd5", device.getDpidmd5()); } - uriBuilder.addParameter("devos", device.getOs()); - uriBuilder.addParameter("devosv", device.getOsv()); - uriBuilder.addParameter("devmodel", device.getModel()); - uriBuilder.addParameter("devmake", device.getMake()); + addParameterIfNotEmpty(queryParams, "devos", device.getOs()); + addParameterIfNotEmpty(queryParams, "devosv", device.getOsv()); + addParameterIfNotEmpty(queryParams, "devmodel", device.getModel()); + addParameterIfNotEmpty(queryParams, "devmake", device.getMake()); } + final Integer test = bidRequest.getTest(); final List sizeValues = setSlaveSizesParam(slaveSizes, Objects.equals(test, 1)); if (CollectionUtils.isNotEmpty(sizeValues)) { - uriBuilder.addParameter("aosspsizes", String.join("-", sizeValues)); + queryParams.put("aosspsizes", String.join("-", sizeValues)); } - return uriBuilder.toString(); + final int randomizedPart = Objects.equals(test, 1) ? 10000000 : 10000000 + (int) (Math.random() * 89999999); + final String resolvedUrl = uriTemplate.expandToString(Variables.variables() + .set(HOST_MACRO_NAME, extImpAdocean.getEmitterPrefix()) + .set("randomizedPart", String.valueOf(randomizedPart))); + + final String urlQuery = UriTemplateUtil.ONLY_QUERY_URI_TEMPLATE.expandToString(Variables.variables() + .set("queryParams", queryParams)); + + return new HttpRequestWrapper(resolvedUrl, urlQuery, queryParams); } - private String resolveEndpointUrl(ExtImpAdocean extImpAdocean, Integer test) { - final String url = endpointUrl.replace("{{Host}}", extImpAdocean.getEmitterPrefix()); - final int randomizedPart = Objects.equals(test, 1) ? 10000000 : 10000000 + (int) (Math.random() * 89999999); - return "%s/_%s/ad.json".formatted(url, randomizedPart); + private static void addParameterIfNotEmpty(Map queryParams, String parameter, String value) { + if (StringUtils.isNotEmpty(value)) { + queryParams.put(parameter, value); + } } private List setSlaveSizesParam(Map slaveSizes, boolean orderByKey) { @@ -298,16 +327,15 @@ private static MultiMap getHeaders(BidRequest request) { @Override public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { - final List params; + final Map> params; try { - params = URLEncodedUtils.parse(new URI(httpCall.getRequest().getUri()), StandardCharsets.UTF_8); - } catch (URISyntaxException e) { + params = HttpUtil.parseQuery(HttpUtil.parseUrl(httpCall.getRequest().getUri()).getQuery()); + } catch (MalformedURLException e) { return Result.withError(BidderError.badInput(e.getMessage())); } - final Map auctionIds = params != null ? params.stream() - .filter(param -> "aid".equals(param.getName())) - .map(param -> param.getValue().split(":")) + final Map auctionIds = params != null ? params.get("aid").stream() + .map(value -> value.split(":")) .collect(Collectors.toMap(name -> name[0], value -> value[1])) : null; final List adoceanResponses; @@ -355,4 +383,8 @@ private List getAdoceanResponseAdUnitList(String response throw new PreBidException(e.getMessage()); } } + + private record HttpRequestWrapper(String url, String query, Map queryParams) { + + } } diff --git a/src/main/java/org/prebid/server/bidder/amx/AmxBidder.java b/src/main/java/org/prebid/server/bidder/amx/AmxBidder.java index f9d309a3495..f28e616383d 100644 --- a/src/main/java/org/prebid/server/bidder/amx/AmxBidder.java +++ b/src/main/java/org/prebid/server/bidder/amx/AmxBidder.java @@ -13,7 +13,6 @@ import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.amx.model.AmxBidExt; import org.prebid.server.bidder.model.BidderBid; @@ -32,7 +31,6 @@ import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -57,15 +55,9 @@ public AmxBidder(String endpointUrl, JacksonMapper mapper) { } private static String resolveEndpointUrl(String url) { - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(HttpUtil.validateUrl(Objects.requireNonNull(url))); - } catch (URISyntaxException e) { - throw new IllegalArgumentException("Invalid url: %s, error: %s".formatted(url, e.getMessage())); - } - return uriBuilder - .addParameter(VERSION_PARAM, ADAPTER_VERSION) - .toString(); + return HttpUtil.validateUrl(Objects.requireNonNull(url)) + + (url.contains("?") ? "&" : "?") + + VERSION_PARAM + "=" + ADAPTER_VERSION; } @Override diff --git a/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java b/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java index 06a37460655..f0f8c8f315f 100644 --- a/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java +++ b/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java @@ -14,12 +14,13 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; import org.prebid.server.auction.model.Endpoint; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.appnexus.proto.AppnexusBidExt; @@ -53,10 +54,10 @@ import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; +import org.prebid.server.util.UriTemplateUtil; import jakarta.validation.ValidationException; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -83,7 +84,7 @@ public class AppnexusBidder implements Bidder { new TypeReference<>() { }; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final Integer headerBiddingSource; private final Map iabCategories; private final JacksonMapper mapper; @@ -93,7 +94,8 @@ public AppnexusBidder(String endpointUrl, Map iabCategories, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "member_id"); this.headerBiddingSource = ObjectUtils.defaultIfNull(platformId, DEFAULT_PLATFORM_ID); this.iabCategories = ObjectUtils.defaultIfNull(iabCategories, Collections.emptyMap()); this.mapper = Objects.requireNonNull(mapper); @@ -307,13 +309,7 @@ private String readKeywordsFromArray(JsonNode keywords) { } private String makeUrl(String member) { - try { - return member != null - ? new URIBuilder(endpointUrl).addParameter("member_id", member).build().toString() - : endpointUrl; - } catch (URISyntaxException e) { - throw new PreBidException(e.getMessage()); - } + return endpointUrlTemplate.expandToString(Variables.variables().set("member_id", member)); } private static String extractEndpointName(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidder.java b/src/main/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidder.java index 8266b55934e..54f2ccbc03c 100644 --- a/src/main/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidder.java +++ b/src/main/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidder.java @@ -53,23 +53,26 @@ public class AudienceNetworkBidder implements Bidder { private static final List SUPPORTED_BANNER_HEIGHT = Arrays.asList(250, 50); + private static final String PLATFORM_MACRO = "{{PlatformId}}"; + private static final String REQUEST_MACRO = "{{RequestId}}"; + private static final String PUBLISHER_MACRO = "{{PublisherId}}"; + private final String endpointUrl; private final String platformId; private final String appSecret; - private final String timeoutNotificationUrlTemplate; + private final String timeoutNotificationUrl; private final JacksonMapper mapper; public AudienceNetworkBidder(String endpointUrl, String platformId, String appSecret, - String timeoutNotificationUrlTemplate, + String timeoutNotificationUrl, JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); this.platformId = checkBlankString(Objects.requireNonNull(platformId), "platform-id"); this.appSecret = checkBlankString(Objects.requireNonNull(appSecret), "app-secret"); - this.timeoutNotificationUrlTemplate = HttpUtil.validateUrl( - Objects.requireNonNull(timeoutNotificationUrlTemplate)); + this.timeoutNotificationUrl = HttpUtil.validateUrl(Objects.requireNonNull(timeoutNotificationUrl)); this.mapper = Objects.requireNonNull(mapper); } @@ -343,7 +346,9 @@ public HttpRequest makeTimeoutNotification(HttpRequest httpReq return HttpRequest.builder() .method(HttpMethod.GET) - .uri(timeoutNotificationUrlTemplate.formatted(platformId, publisherId, requestId)) + .uri(timeoutNotificationUrl.replace(PLATFORM_MACRO, HttpUtil.encodeUrl(platformId)) + .replace(PUBLISHER_MACRO, HttpUtil.encodeUrl(publisherId)) + .replace(REQUEST_MACRO, HttpUtil.encodeUrl(requestId))) .build(); } } diff --git a/src/main/java/org/prebid/server/bidder/bluesea/BlueSeaBidder.java b/src/main/java/org/prebid/server/bidder/bluesea/BlueSeaBidder.java index 8c93ba9f73d..e0ec45efb79 100644 --- a/src/main/java/org/prebid/server/bidder/bluesea/BlueSeaBidder.java +++ b/src/main/java/org/prebid/server/bidder/bluesea/BlueSeaBidder.java @@ -8,8 +8,9 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; -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; @@ -24,12 +25,13 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -39,11 +41,12 @@ public class BlueSeaBidder implements Bidder { new TypeReference<>() { }; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; public BlueSeaBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "queryParams"); this.mapper = Objects.requireNonNull(mapper); } @@ -78,17 +81,11 @@ private HttpRequest makeRequest(BidRequest bidRequest, ExtImpBlueSea } private String resolveUrl(ExtImpBlueSea extImpBlueSea) { - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(endpointUrl); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(endpointUrl, e.getMessage())); - } + final Map queryParams = Map.of( + "pubid", extImpBlueSea.getPubId(), + "token", extImpBlueSea.getToken()); - return uriBuilder - .addParameter("pubid", extImpBlueSea.getPubId()) - .addParameter("token", extImpBlueSea.getToken()) - .toString(); + return endpointUrlTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } @Override 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 aef2abcaf61..eb15d4457de 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -14,10 +14,11 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; 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,9 +36,9 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -53,9 +54,8 @@ public class ConnatixBidder implements Bidder { private static final String BIDDER_CURRENCY = "USD"; private static final String FORMATTING = "%s-%s"; - private static final String GPID_KEY = "gpid"; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; private final CurrencyConversionService currencyConversionService; @@ -64,7 +64,8 @@ public ConnatixBidder(String endpointUrl, CurrencyConversionService currencyConversionService, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "dc"); this.currencyConversionService = Objects.requireNonNull(currencyConversionService); this.mapper = Objects.requireNonNull(mapper); } @@ -106,20 +107,8 @@ public Result>> makeHttpRequests(BidRequest request } 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()); - } + final String dataCenterCode = getUserId(request).map(ConnatixBidder::getDataCenterCode).orElse(null); + return endpointUrlTemplate.expandToString(Variables.variables().set("dc", dataCenterCode)); } private static Optional getUserId(BidRequest request) { diff --git a/src/main/java/org/prebid/server/bidder/dxkulture/DxKultureBidder.java b/src/main/java/org/prebid/server/bidder/dxkulture/DxKultureBidder.java index ad3c146795d..90f93aa8190 100644 --- a/src/main/java/org/prebid/server/bidder/dxkulture/DxKultureBidder.java +++ b/src/main/java/org/prebid/server/bidder/dxkulture/DxKultureBidder.java @@ -9,8 +9,9 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; -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; @@ -26,12 +27,13 @@ import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; +import org.prebid.server.util.UriTemplateUtil; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; public class DxKultureBidder implements Bidder { @@ -41,11 +43,12 @@ public class DxKultureBidder implements Bidder { }; private static final String X_OPENRTB_VERSION = "2.5"; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; public DxKultureBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "queryParams"); this.mapper = Objects.requireNonNull(mapper); } @@ -78,18 +81,11 @@ private ExtImpDxKulture parseImpExt(Imp imp) { } private String getUri(ExtImpDxKulture extImpDxKulture) { - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(endpointUrl); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(endpointUrl, e.getMessage())); - } - - uriBuilder - .addParameter("publisher_id", extImpDxKulture.getPublisherId()) - .addParameter("placement_id", extImpDxKulture.getPlacementId()); + final Map queryParams = Map.of( + "publisher_id", extImpDxKulture.getPublisherId(), + "placement_id", extImpDxKulture.getPlacementId()); - return uriBuilder.toString(); + return endpointUrlTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } private static MultiMap resolveHeaders(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java b/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java index 0c3ce43b489..e2bddbb0ad0 100644 --- a/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java +++ b/src/main/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidder.java @@ -31,7 +31,7 @@ import org.prebid.server.util.HttpUtil; import java.math.BigDecimal; -import java.time.Instant; +import java.time.Clock; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -41,16 +41,20 @@ public class EmxDigitalBidder implements Bidder { private static final String USD_CURRENCY = "USD"; private static final Integer PROTOCOL_VAST_40 = 7; + private static final String URL_TIMEOUT_MACRO = "{{URL_TIMEOUT}}"; + private static final String TIMESTAMP_MACRO = "{{TIMESTAMP}}"; private static final TypeReference> EMXDIGITAL_EXT_TYPE_REFERENCE = new TypeReference<>() { }; private final String endpointUrl; + private final Clock clock; private final JacksonMapper mapper; - public EmxDigitalBidder(String endpointUrl, JacksonMapper mapper) { + public EmxDigitalBidder(String endpointUrl, Clock clock, JacksonMapper mapper) { this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.clock = Objects.requireNonNull(clock); this.mapper = Objects.requireNonNull(mapper); } @@ -231,8 +235,9 @@ private String makeUrl(BidRequest bidRequest) { final Long tmax = bidRequest.getTmax(); final int urlTimeout = tmax == 0 ? 1000 : tmax.intValue(); - return "%s?t=%s&ts=%s&src=pbserver" - .formatted(endpointUrl, urlTimeout, (int) Instant.now().getEpochSecond()); + return endpointUrl + .replace(URL_TIMEOUT_MACRO, String.valueOf(urlTimeout)) + .replace(TIMESTAMP_MACRO, String.valueOf((int) clock.millis())); } @Override diff --git a/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java b/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java index 99beb0538bf..174379ad34c 100644 --- a/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java +++ b/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java @@ -15,10 +15,11 @@ import com.iab.openrtb.response.Bid; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; 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.eplanning.model.CleanStepName; import org.prebid.server.bidder.eplanning.model.HbResponse; @@ -37,10 +38,10 @@ import org.prebid.server.proto.openrtb.ext.request.eplanning.ExtImpEplanning; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import java.math.BigDecimal; import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -79,11 +80,12 @@ public class EplanningBidder implements Bidder { new TypeReference<>() { }; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; public EplanningBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl + "{/path*}", false, "queryParams"); this.mapper = Objects.requireNonNull(mapper); } @@ -232,61 +234,57 @@ private String resolveRequestUri(BidRequest request, List requestsString ? app.getBundle() : pageDomain; - final String uri = "%s/%s/%s/%s/%s".formatted(endpointUrl, clientId, DFP_CLIENT_ID, requestTarget, SEC); + final List path = List.of(clientId, DFP_CLIENT_ID, requestTarget, SEC); - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(uri); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(uri, e.getMessage())); - } + final Map queryParams = new HashMap<>(); - uriBuilder - .addParameter("r", "pbs") - .addParameter("ncb", "1"); + queryParams.put("r", "pbs"); + queryParams.put("ncb", "1"); if (app == null) { - uriBuilder.addParameter("ur", pageUrl); + queryParams.put("ur", pageUrl); } - uriBuilder.addParameter("e", String.join("+", requestsStrings)); + queryParams.put("e", String.join("+", requestsStrings)); final User user = request.getUser(); final String buyeruid = user != null ? user.getBuyeruid() : null; if (StringUtils.isNotBlank(buyeruid)) { - uriBuilder.addParameter("uid", buyeruid); + queryParams.put("uid", buyeruid); } final Device device = request.getDevice(); final String ip = device != null ? device.getIp() : null; if (StringUtils.isNotBlank(ip)) { - uriBuilder.addParameter("ip", ip); + queryParams.put("ip", ip); } if (app != null) { if (StringUtils.isNotBlank(app.getName())) { - uriBuilder.addParameter("appn", app.getName()); + queryParams.put("appn", app.getName()); } if (StringUtils.isNotBlank(app.getId())) { - uriBuilder.addParameter("appid", app.getId()); + queryParams.put("appid", app.getId()); } if (request.getDevice() != null && StringUtils.isNotBlank(request.getDevice().getIfa())) { - uriBuilder.addParameter("ifa", request.getDevice().getIfa()); + queryParams.put("ifa", request.getDevice().getIfa()); } - uriBuilder.addParameter("app", REQUEST_TARGET_INVENTORY); + queryParams.put("app", REQUEST_TARGET_INVENTORY); } String schain = getSchainParameter(request.getSource()); if (schain != null) { schain = schain.replace(" ", "%20"); - uriBuilder.addParameter("sch", schain); + queryParams.put("sch", schain); } - return uriBuilder.toString(); + return endpointUrlTemplate.expandToString(Variables.variables() + .set("path", path) + .set("queryParams", queryParams)); } private static URL parseUrl(String url) { try { - return new URL(url); + return HttpUtil.parseUrl(url); } catch (MalformedURLException e) { throw new PreBidException("Invalid url: " + url, e); } diff --git a/src/main/java/org/prebid/server/bidder/flipp/FlippBidder.java b/src/main/java/org/prebid/server/bidder/flipp/FlippBidder.java index dedd8399f1b..f1e1813149e 100644 --- a/src/main/java/org/prebid/server/bidder/flipp/FlippBidder.java +++ b/src/main/java/org/prebid/server/bidder/flipp/FlippBidder.java @@ -16,8 +16,6 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URLEncodedUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.flipp.model.request.CampaignRequestBody; import org.prebid.server.bidder.flipp.model.request.CampaignRequestBodyUser; @@ -47,7 +45,7 @@ import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; -import java.nio.charset.StandardCharsets; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -168,11 +166,17 @@ private static String resolveContentCode(Site site, ExtImpFlipp extImp) { .map(Site::getPage) .orElse(null); - return URLEncodedUtils.parse(pageUrl, StandardCharsets.UTF_8) - .stream() - .filter(nameValuePair -> nameValuePair.getName().contains("flipp-content-code")) - .map(NameValuePair::getValue) - .findFirst() + if (pageUrl == null) { + return null; + } + + return Optional.of(site) + .map(Site::getPage) + .map(URI::create) + .map(URI::getQuery) + .map(HttpUtil::parseQuery) + .map(params -> params.get("flipp-content-code")) + .flatMap(values -> values.stream().findFirst()) .orElse(null); } diff --git a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java index eacc3a49541..27e12e1670d 100644 --- a/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java +++ b/src/main/java/org/prebid/server/bidder/missena/MissenaBidder.java @@ -169,7 +169,7 @@ private MultiMap makeHeaders(Device device, Site site) { if (site != null && StringUtils.isNotBlank(site.getPage())) { HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.REFERER_HEADER, site.getPage()); try { - final URL url = new URL(site.getPage()); + final URL url = HttpUtil.parseUrl(site.getPage()); final String origin = url.getProtocol() + "://" + url.getHost(); HttpUtil.addHeaderIfValueIsNotEmpty(headers, HttpUtil.ORIGIN_HEADER, origin); } catch (MalformedURLException e) { diff --git a/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java b/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java index 180f545bf47..c90ea153b4c 100644 --- a/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java +++ b/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java @@ -6,9 +6,10 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; 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; @@ -24,13 +25,15 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import org.prebid.server.version.PrebidVersionProvider; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.stream.Collectors; @@ -40,12 +43,13 @@ public class Nexx360Bidder implements Bidder { }; private static final String BIDDER_NAME = "nexx360"; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; private final PrebidVersionProvider prebidVersionProvider; public Nexx360Bidder(String endpointUrl, JacksonMapper mapper, PrebidVersionProvider prebidVersionProvider) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "queryParams"); this.mapper = Objects.requireNonNull(mapper); this.prebidVersionProvider = Objects.requireNonNull(prebidVersionProvider); } @@ -97,21 +101,16 @@ private BidRequest makeRequest(BidRequest request, List imps) { } private String makeUrl(String tagId, String placement) { - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(endpointUrl); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(endpointUrl, e.getMessage())); - } + final Map queryParams = new HashMap<>(); if (StringUtils.isNotBlank(placement)) { - uriBuilder.addParameter("placement", placement); + queryParams.put("placement", placement); } if (StringUtils.isNotBlank(tagId)) { - uriBuilder.addParameter("tag_id", tagId); + queryParams.put("tag_id", tagId); } - return uriBuilder.toString(); + return endpointUrlTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } @Override diff --git a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java index 81e1c8091f5..75150aa958e 100644 --- a/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java +++ b/src/main/java/org/prebid/server/bidder/oms/OmsBidder.java @@ -34,6 +34,9 @@ public class OmsBidder implements Bidder { private static final TypeReference> EXT_TYPE_REFERENCE = new TypeReference<>() { }; + + private static final String PUBLISHER_ID_MACRO = "{{PublisherId}}"; + private final String endpointUrl; private final JacksonMapper mapper; @@ -47,8 +50,7 @@ public Result>> makeHttpRequests(BidRequest request try { final ExtImpOms impExt = parseImpExt(request.getImp().getFirst()); final String publisherId = resolverPublisherId(impExt.getPid(), impExt.getPublisherId()); - final String encodedPublisherId = HttpUtil.encodeUrl(publisherId); - final String url = "%s?publisherId=%s".formatted(endpointUrl, encodedPublisherId); + final String url = endpointUrl.replace(PUBLISHER_ID_MACRO, HttpUtil.encodeUrl(publisherId)); return Result.withValue(BidderUtil.defaultRequest(request, url, mapper)); } catch (PreBidException e) { return Result.withError(BidderError.badInput(e.getMessage())); @@ -63,11 +65,8 @@ private ExtImpOms parseImpExt(Imp imp) throws PreBidException { } } - private String resolverPublisherId(String pid, Integer publisherId) { - if (StringUtils.isEmpty(pid) && publisherId != null && publisherId > 0) { - return String.valueOf(publisherId); - } - return pid; + private static String resolverPublisherId(String pid, Integer publisherId) { + return StringUtils.isEmpty(pid) ? String.valueOf(publisherId) : pid; } @Override @@ -93,6 +92,7 @@ private static List bidsFromResponse(BidResponse bidResponse) { .map(SeatBid::getBid) .filter(Objects::nonNull) .flatMap(Collection::stream) + .filter(Objects::nonNull) .map(bid -> createBidderBid(bid, bidResponse.getCur())) .toList(); } diff --git a/src/main/java/org/prebid/server/bidder/richaudience/RichaudienceBidder.java b/src/main/java/org/prebid/server/bidder/richaudience/RichaudienceBidder.java index a156be6c94e..5930e33d855 100644 --- a/src/main/java/org/prebid/server/bidder/richaudience/RichaudienceBidder.java +++ b/src/main/java/org/prebid/server/bidder/richaudience/RichaudienceBidder.java @@ -165,7 +165,7 @@ private static App modifyApp(App originalApp, String tagId) { private static Optional extractUrl(Site site) { return Optional.ofNullable(site).map(Site::getPage).map(page -> { try { - return new URL(page); + return HttpUtil.parseUrl(page); } catch (MalformedURLException e) { return null; } diff --git a/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java b/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java index 5760b9f4242..736a47e06ca 100644 --- a/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java +++ b/src/main/java/org/prebid/server/bidder/rubicon/RubiconBidder.java @@ -32,7 +32,6 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.math.NumberUtils; -import org.apache.http.client.utils.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.ViewabilityVendors; import org.prebid.server.bidder.model.BidderBid; @@ -109,7 +108,8 @@ import org.prebid.server.version.PrebidVersionProvider; import java.math.BigDecimal; -import java.net.URISyntaxException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; @@ -449,16 +449,32 @@ private BidRequest createSingleRequest(BidRequest bidRequest, private String makeUri(BidRequest bidRequest) { final String tkXint = tkXintValue(bidRequest); - if (StringUtils.isNotBlank(tkXint)) { - try { - return new URIBuilder(endpointUrl) - .setParameter(TK_XINT_QUERY_PARAMETER, tkXint) - .build().toString(); - } catch (URISyntaxException e) { - throw new PreBidException("Cant add the tk_xint value for url: " + tkXint, e); + if (StringUtils.isBlank(tkXint)) { + return endpointUrl; + } + + try { + final URL url = HttpUtil.parseUrl(endpointUrl); + final String baseUrl = url.getProtocol() + "://" + url.getAuthority() + (url.getPath() == null ? "" : url.getPath()); + final String query = url.getQuery(); + + final List queryParams = new ArrayList<>(); + if (query != null && !query.isEmpty()) { + for (String keyValue : query.split("&")) { + final int i = keyValue.indexOf('='); + final String key = (i >= 0) ? keyValue.substring(0, i) : keyValue; + if (!TK_XINT_QUERY_PARAMETER.equals(key)) { + queryParams.add(keyValue); + } + } } + + queryParams.add(TK_XINT_QUERY_PARAMETER + "=" + HttpUtil.encodeUrl(tkXint)); + return baseUrl + "?" + String.join("&", queryParams); + + } catch (MalformedURLException e) { + throw new PreBidException("Cant add the tk_xint value for url: " + tkXint, e); } - return endpointUrl; } private String tkXintValue(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/bidder/smartadserver/SmartadserverBidder.java b/src/main/java/org/prebid/server/bidder/smartadserver/SmartadserverBidder.java index 150c37fd255..f4770e0e06d 100644 --- a/src/main/java/org/prebid/server/bidder/smartadserver/SmartadserverBidder.java +++ b/src/main/java/org/prebid/server/bidder/smartadserver/SmartadserverBidder.java @@ -10,7 +10,6 @@ import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; 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; @@ -26,8 +25,8 @@ import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; -import java.net.URI; -import java.net.URISyntaxException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -46,11 +45,31 @@ public class SmartadserverBidder implements Bidder { private final JacksonMapper mapper; public SmartadserverBidder(String endpointUrl, String secondaryEndpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); - this.secondaryEndpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(secondaryEndpointUrl)); + this.endpointUrl = prepareEndpoint(endpointUrl); + this.secondaryEndpointUrl = prepareSecondaryEndpoint(secondaryEndpointUrl); this.mapper = Objects.requireNonNull(mapper); } + private static String prepareEndpoint(String endpointUrl) { + try { + final URL url = HttpUtil.parseUrl(endpointUrl); + final String baseUrl = url.getProtocol() + "://" + url.getAuthority() + StringUtils.removeEnd(url.getPath(), "/"); + return baseUrl + "/api/bid?callerId=5"; + } catch (MalformedURLException e) { + throw new IllegalArgumentException("URL supplied is not valid: " + endpointUrl, e); + } + } + + private static String prepareSecondaryEndpoint(String endpointUrl) { + try { + final URL url = HttpUtil.parseUrl(endpointUrl); + final String baseUrl = url.getProtocol() + "://" + url.getAuthority() + StringUtils.removeEnd(url.getPath(), "/"); + return baseUrl + "/ortb?" + url.getQuery(); + } catch (MalformedURLException e) { + throw new IllegalArgumentException("URL supplied is not valid: " + endpointUrl, e); + } + } + @Override public Result>> makeHttpRequests(BidRequest request) { final List errors = new ArrayList<>(); @@ -120,21 +139,7 @@ private static Publisher modifyPublisher(Publisher publisher, Integer networkId) } private String makeUrl(boolean isProgrammaticGuaranteed) { - final String url = isProgrammaticGuaranteed ? secondaryEndpointUrl : endpointUrl; - try { - final URI uri = new URI(url); - final String path = isProgrammaticGuaranteed ? "/ortb" : "/api/bid"; - final URIBuilder uriBuilder = new URIBuilder(uri) - .setPath(StringUtils.removeEnd(uri.getPath(), "/") + path); - - if (!isProgrammaticGuaranteed) { - uriBuilder.addParameter("callerId", "5"); - } - - return uriBuilder.toString(); - } catch (URISyntaxException e) { - throw new PreBidException("Malformed URL: %s.".formatted(url)); - } + return isProgrammaticGuaranteed ? secondaryEndpointUrl : endpointUrl; } @Override diff --git a/src/main/java/org/prebid/server/bidder/sspbc/SspbcBidder.java b/src/main/java/org/prebid/server/bidder/sspbc/SspbcBidder.java index 47419fb21a7..2802226d9c8 100644 --- a/src/main/java/org/prebid/server/bidder/sspbc/SspbcBidder.java +++ b/src/main/java/org/prebid/server/bidder/sspbc/SspbcBidder.java @@ -5,8 +5,9 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import io.vertx.core.http.HttpMethod; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; -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; @@ -19,8 +20,8 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; -import java.net.URISyntaxException; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -29,12 +30,14 @@ public class SspbcBidder implements Bidder { private static final String ADAPTER_VERSION = "6.0"; + private static final String BDVER_QUERY_PARAM = "bdver"; - private final String endpointUrl; private final JacksonMapper mapper; + private final UriTemplate uriTemplate; public SspbcBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.uriTemplate = UriTemplateUtil.createTemplate(endpointUrl, BDVER_QUERY_PARAM); this.mapper = Objects.requireNonNull(mapper); } @@ -47,7 +50,7 @@ private HttpRequest createHttpRequest(BidRequest request) { final SspbcRequest outgoingRequest = SspbcRequest.of(request); return HttpRequest.builder() .method(HttpMethod.POST) - .uri(makeUrl(endpointUrl)) + .uri(makeUrl()) .headers(HttpUtil.headers()) .impIds(BidderUtil.impIds(outgoingRequest.getBidRequest())) .body(mapper.encodeToBytes(outgoingRequest)) @@ -55,15 +58,8 @@ private HttpRequest createHttpRequest(BidRequest request) { .build(); } - private static String makeUrl(String endpointUrl) { - try { - return new URIBuilder(endpointUrl) - .addParameter("bdver", ADAPTER_VERSION) - .build() - .toString(); - } catch (URISyntaxException e) { - throw new PreBidException("Malformed URL: %s.".formatted(endpointUrl)); - } + private String makeUrl() { + return uriTemplate.expandToString(Variables.variables().set(BDVER_QUERY_PARAM, ADAPTER_VERSION)); } @Override diff --git a/src/main/java/org/prebid/server/bidder/tappx/TappxBidder.java b/src/main/java/org/prebid/server/bidder/tappx/TappxBidder.java index 67224479693..901e2a0c85e 100644 --- a/src/main/java/org/prebid/server/bidder/tappx/TappxBidder.java +++ b/src/main/java/org/prebid/server/bidder/tappx/TappxBidder.java @@ -5,9 +5,10 @@ import com.iab.openrtb.request.Imp; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.collections4.ListUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.commons.lang3.StringUtils; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -23,14 +24,17 @@ import org.prebid.server.proto.openrtb.ext.request.tappx.ExtImpTappx; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.BidderUtil; +import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.time.Clock; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.regex.Pattern; @@ -43,14 +47,19 @@ public class TappxBidder implements Bidder { new TypeReference<>() { }; private static final Pattern NEW_ENDPOINT_PATTERN = Pattern.compile("^(zz|vz)[0-9]{3,}([a-z]{2,3}|test)$"); - private static final String SUBDOMAIN_MACRO = "{{subdomain}}"; + private static final String SUBDOMAIN_MACRO = "subdomain"; - private final String endpointUrl; + private final UriTemplate newEndpointUrlTemplate; + private final UriTemplate oldEndpointUrlTemplate; private final Clock clock; private final JacksonMapper mapper; public TappxBidder(String endpointUrl, Clock clock, JacksonMapper mapper) { - this.endpointUrl = Objects.requireNonNull(endpointUrl); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.newEndpointUrlTemplate = UriTemplateUtil.createTemplate( + endpointUrl + "/rtb/", false, "queryParams", List.of(SUBDOMAIN_MACRO)); + this.oldEndpointUrlTemplate = UriTemplateUtil.createTemplate( + endpointUrl + "/rtb/v2/{path}", false, "queryParams", List.of(SUBDOMAIN_MACRO)); this.clock = Objects.requireNonNull(clock); this.mapper = Objects.requireNonNull(mapper); } @@ -90,37 +99,21 @@ private static List modifyImps(List imps, ExtImpTappx extImpTappx) { private String resolveUrl(ExtImpTappx extImpTappx, Integer test) { final String subdomain = extImpTappx.getEndpoint(); final boolean isNewEndpoint = NEW_ENDPOINT_PATTERN.matcher(subdomain).matches(); + final UriTemplate urlTemplate = isNewEndpoint ? newEndpointUrlTemplate : oldEndpointUrlTemplate; - final String baseUri = isNewEndpoint ? resolveNewHost(subdomain) : resolveOldHost(); - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(baseUri); - } catch (URISyntaxException e) { - throw new PreBidException("Failed to build endpoint URL: " + e.getMessage()); - } - - if (!isNewEndpoint) { - final List pathSegments = uriBuilder.getPathSegments(); - uriBuilder.setPathSegments(ListUtils.union(pathSegments, Collections.singletonList(subdomain))); - } - - uriBuilder.addParameter("tappxkey", extImpTappx.getTappxkey()); - uriBuilder.addParameter("v", VERSION); - uriBuilder.addParameter("type_cnn", TYPE_CNN); + final Map queryParams = new HashMap<>(); + queryParams.put("tappxkey", extImpTappx.getTappxkey()); + queryParams.put("v", VERSION); + queryParams.put("type_cnn", TYPE_CNN); if (!BidderUtil.isNullOrZero(test)) { - uriBuilder.addParameter("ts", String.valueOf(clock.millis())); + queryParams.put("ts", String.valueOf(clock.millis())); } - return uriBuilder.toString(); - } - - private String resolveNewHost(String subdomain) { - return endpointUrl.replace(SUBDOMAIN_MACRO, subdomain + ".pub") + "/rtb/"; - } - - private String resolveOldHost() { - return endpointUrl.replace(SUBDOMAIN_MACRO, "ssp.api") + "/rtb/v2"; + return urlTemplate.expandToString(Variables.variables() + .set(SUBDOMAIN_MACRO, isNewEndpoint ? subdomain + ".pub" : "ssp.api") + .set("path", isNewEndpoint ? StringUtils.EMPTY : subdomain) + .set("queryParams", queryParams)); } private static Imp modifyImp(Imp imp, ExtImpTappx extImpTappx) { diff --git a/src/main/java/org/prebid/server/bidder/videobyte/VideobyteBidder.java b/src/main/java/org/prebid/server/bidder/videobyte/VideobyteBidder.java index cdbac176521..4ba2b267ab4 100644 --- a/src/main/java/org/prebid/server/bidder/videobyte/VideobyteBidder.java +++ b/src/main/java/org/prebid/server/bidder/videobyte/VideobyteBidder.java @@ -8,9 +8,10 @@ import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; 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; @@ -24,12 +25,14 @@ import org.prebid.server.proto.openrtb.ext.request.videobyte.ExtImpVideobyte; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; public class VideobyteBidder implements Bidder { @@ -39,11 +42,12 @@ public class VideobyteBidder implements Bidder { new TypeReference<>() { }; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; public VideobyteBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl, "queryParams"); this.mapper = Objects.requireNonNull(mapper); } @@ -86,26 +90,20 @@ private HttpRequest createRequest(BidRequest bidRequest, Imp imp, Ex } private String createUri(ExtImpVideobyte extImpVideobyte) { - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(endpointUrl); - } catch (URISyntaxException e) { - throw new PreBidException(e.getMessage()); - } - - uriBuilder.addParameter("source", "pbs") - .addParameter("pid", extImpVideobyte.getPublisherId()); + final Map queryParams = new HashMap<>(); - addUriParameterIfNotEmpty(uriBuilder, "placementId", extImpVideobyte.getPlacementId()); - addUriParameterIfNotEmpty(uriBuilder, "nid", extImpVideobyte.getNetworkId()); + queryParams.put("source", "pbs"); + queryParams.put("pid", extImpVideobyte.getPublisherId()); - return uriBuilder.toString(); - } + if (StringUtils.isNotEmpty(extImpVideobyte.getPlacementId())) { + queryParams.put("placementId", extImpVideobyte.getPlacementId()); + } - private static void addUriParameterIfNotEmpty(URIBuilder uriBuilder, String parameter, String value) { - if (StringUtils.isNotEmpty(value)) { - uriBuilder.addParameter(parameter, value); + if (StringUtils.isNotEmpty(extImpVideobyte.getNetworkId())) { + queryParams.put("nid", extImpVideobyte.getNetworkId()); } + + return endpointUrlTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } private static MultiMap headers(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java b/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java index d3851455d1d..f5ae6bd8820 100644 --- a/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java +++ b/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java @@ -13,9 +13,10 @@ import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; 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; @@ -29,12 +30,14 @@ import org.prebid.server.proto.openrtb.ext.request.yandex.ExtImpYandex; import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; @@ -45,16 +48,20 @@ public class YandexBidder implements Bidder { new TypeReference<>() { }; - private static final String PAGE_ID_MACRO = "{{PageId}}"; - private static final String IMP_ID_MACRO = "{{ImpId}}"; + private static final String PAGE_ID_MACRO = "PageId"; + private static final String IMP_ID_MACRO = "ImpId"; private static final String DISPLAY_MANAGER = "prebid.java"; private static final String DISPLAY_MANAGER_VERSION = "1.1"; - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final JacksonMapper mapper; public YandexBidder(String endpointUrl, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate( + endpointUrl, + "queryParams", + List.of(PAGE_ID_MACRO, IMP_ID_MACRO)); this.mapper = Objects.requireNonNull(mapper); } @@ -171,24 +178,20 @@ private static Video modifyVideo(Video video) { } private String modifyUrl(ExtImpYandex extImpYandex, String referer, String currency) { - final String resolvedUrl = endpointUrl - .replace(PAGE_ID_MACRO, HttpUtil.encodeUrl(extImpYandex.getPageId().toString())) - .replace(IMP_ID_MACRO, HttpUtil.encodeUrl(extImpYandex.getImpId().toString())); - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(resolvedUrl); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(endpointUrl, e.getMessage())); + final Map queryParams = new HashMap<>(); + + if (StringUtils.isNotBlank(referer)) { + queryParams.put("target-ref", referer); } - addParameterIfNotBlank(uriBuilder, "target-ref", referer); - addParameterIfNotBlank(uriBuilder, "ssp-cur", currency); - return uriBuilder.toString(); - } - private static void addParameterIfNotBlank(URIBuilder uriBuilder, String parameter, String value) { - if (StringUtils.isNotBlank(value)) { - uriBuilder.addParameter(parameter, value); + if (StringUtils.isNotBlank(currency)) { + queryParams.put("ssp-cur", currency); } + + return endpointUrlTemplate.expandToString(Variables.variables() + .set(PAGE_ID_MACRO, extImpYandex.getPageId().toString()) + .set(IMP_ID_MACRO, extImpYandex.getImpId().toString()) + .set("queryParams", queryParams)); } private HttpRequest buildHttpRequest(BidRequest outgoingRequest, String url) { diff --git a/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java b/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java index 47f6cd44523..ea1b3ec5380 100644 --- a/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java +++ b/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java @@ -19,11 +19,12 @@ import io.netty.handler.codec.http.HttpHeaderValues; import io.vertx.core.MultiMap; import io.vertx.core.http.HttpMethod; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; -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; @@ -45,9 +46,9 @@ import org.prebid.server.proto.openrtb.ext.response.ExtBidDsa; import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.time.Clock; import java.util.ArrayList; import java.util.Calendar; @@ -76,7 +77,6 @@ public class YieldlabBidder implements Bidder { private static final String AD_SIZE_SEPARATOR = "x"; private static final String CREATIVE_ID = "%s%s%s"; private static final String AD_SOURCE_BANNER = ""; - private static final String AD_SOURCE_URL = "https://ad.yieldlab.net/d/%s/%s/%s?%s"; private static final String TRANSPARENCY_TEMPLATE = "%s~%s"; private static final String TRANSPARENCY_TEMPLATE_PARAMS_DELIMITER = "_"; private static final String TRANSPARENCY_TEMPLATE_DELIMITER = "~~"; @@ -87,13 +87,16 @@ public class YieldlabBidder implements Bidder { """; + private static final UriTemplate NURL_TEMPLATE = UriTemplateUtil.createTemplate( + "https://ad.yieldlab.net/d{/path*}", false, "queryParams"); - private final String endpointUrl; + private final UriTemplate endpointUrlTemplate; private final Clock clock; private final JacksonMapper mapper; public YieldlabBidder(String endpointUrl, Clock clock, JacksonMapper mapper) { - this.endpointUrl = HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + HttpUtil.validateUrl(Objects.requireNonNull(endpointUrl)); + this.endpointUrlTemplate = UriTemplateUtil.createTemplate(endpointUrl + "{/adslotId}", false, "queryParams"); this.clock = Objects.requireNonNull(clock); this.mapper = Objects.requireNonNull(mapper); } @@ -153,73 +156,60 @@ private ExtImpYieldlab parseImpExt(Imp imp) { } private String makeUrl(ExtImpYieldlab extImpYieldlab, BidRequest request, Map extImps) { - final String updatedPath = "%s/%s".formatted(endpointUrl, extImpYieldlab.getAdslotId()); + final Map queryParams = new HashMap<>(); - final URIBuilder uriBuilder; - try { - uriBuilder = new URIBuilder(updatedPath); - } catch (URISyntaxException e) { - throw new PreBidException("Invalid url: %s, error: %s".formatted(updatedPath, e.getMessage())); - } - - uriBuilder - .addParameter("content", "json") - .addParameter("pvid", "true") - .addParameter("ts", resolveNumberParameter(clock.instant().getEpochSecond())) - .addParameter("t", getTargetingValues(extImpYieldlab)); + queryParams.put("content", "json"); + queryParams.put("pvid", "true"); + queryParams.put("ts", resolveNumberParameter(clock.instant().getEpochSecond())); + queryParams.put("t", getTargetingValues(extImpYieldlab)); final String formats = makeFormats(request, extImps); if (formats != null) { - uriBuilder.addParameter("sizes", formats); + queryParams.put("sizes", formats); } final User user = request.getUser(); if (user != null && StringUtils.isNotBlank(user.getBuyeruid())) { - uriBuilder.addParameter("ids", "ylid:" + StringUtils.defaultString(user.getBuyeruid())); + queryParams.put("ids", "ylid:" + StringUtils.defaultString(user.getBuyeruid())); } final Device device = request.getDevice(); if (device != null) { - uriBuilder.addParameter("yl_rtb_ifa", device.getIfa()); - - uriBuilder.addParameter("yl_rtb_devicetype", resolveNumberParameter(device.getDevicetype())); + addUriParameterIfNotBlank(queryParams, "yl_rtb_ifa", device.getIfa()); + addUriParameterIfNotBlank(queryParams, "yl_rtb_devicetype", resolveNumberParameter(device.getDevicetype())); final Integer connectionType = device.getConnectiontype(); if (connectionType != null) { - uriBuilder.addParameter("yl_rtb_connectiontype", device.getConnectiontype().toString()); + queryParams.put("yl_rtb_connectiontype", device.getConnectiontype().toString()); } final Geo geo = device.getGeo(); if (geo != null) { - uriBuilder.addParameter("lat", ObjectUtils.defaultIfNull(geo.getLat(), 0f).toString()); - uriBuilder.addParameter("lon", ObjectUtils.defaultIfNull(geo.getLon(), 0f).toString()); + addUriParameterIfNotBlank(queryParams, "lat", ObjectUtils.defaultIfNull(geo.getLat(), 0f).toString()); + addUriParameterIfNotBlank(queryParams, "lon", ObjectUtils.defaultIfNull(geo.getLon(), 0f).toString()); } } final App app = request.getApp(); if (app != null) { - uriBuilder.addParameter("pubappname", app.getName()) - .addParameter("pubbundlename", app.getBundle()); - } + addUriParameterIfNotBlank(queryParams, "pubappname", app.getName()); + addUriParameterIfNotBlank(queryParams, "pubbundlename", app.getBundle()); - final String gdpr = getGdprParameter(request.getRegs()); - if (StringUtils.isNotBlank(gdpr)) { - uriBuilder.addParameter("gdpr", gdpr); } + addUriParameterIfNotBlank(queryParams, "gdpr", getGdprParameter(request.getRegs())); + addUriParameterIfNotBlank(queryParams, "gdpr_consent", getConsentParameter(request.getUser())); + addUriParameterIfNotBlank(queryParams, "schain", getSchainParameter(request.getSource())); + queryParams.putAll(extractDsaRequestParamsFromBidRequest(request)); - final String consent = getConsentParameter(request.getUser()); - if (StringUtils.isNotBlank(consent)) { - uriBuilder.addParameter("gdpr_consent", consent); - } + return endpointUrlTemplate.expandToString(Variables.variables() + .set("adslotId", extImpYieldlab.getAdslotId()) + .set("queryParams", queryParams)); + } - final String schain = getSchainParameter(request.getSource()); - if (schain != null) { - uriBuilder.addParameter("schain", schain); + private static void addUriParameterIfNotBlank(Map queryParams, String parameter, String value) { + if (StringUtils.isNotBlank(value)) { + queryParams.put(parameter, value); } - - extractDsaRequestParamsFromBidRequest(request).forEach(uriBuilder::addParameter); - - return uriBuilder.toString(); } private String makeFormats(BidRequest request, Map extImps) { @@ -248,13 +238,9 @@ private boolean isBanner(Imp imp) { } private String getTargetingValues(ExtImpYieldlab extImpYieldlab) { - final URIBuilder uriBuilder = new URIBuilder(); - - for (Map.Entry targeting : extImpYieldlab.getTargeting().entrySet()) { - uriBuilder.addParameter(targeting.getKey(), targeting.getValue()); - } - - return uriBuilder.toString().replace("?", ""); + return UriTemplateUtil.ONLY_QUERY_URI_TEMPLATE + .expandToString(Variables.variables().set("queryParams", extImpYieldlab.getTargeting())) + .replace("?", StringUtils.EMPTY); } private static String getGdprParameter(Regs regs) { @@ -527,29 +513,27 @@ private String makeVast(BidRequest bidRequest, ExtImpYieldlab extImp, YieldlabBi } private String makeNurl(BidRequest bidRequest, ExtImpYieldlab extImp, YieldlabBid yieldlabBid) { - final URIBuilder uriBuilder = new URIBuilder() - .addParameter("ts", resolveNumberParameter(clock.instant().getEpochSecond())) - .addParameter("id", extImp.getExtId()) - .addParameter("pvid", yieldlabBid.getPvid()); + final Map queryParams = new HashMap<>(); + queryParams.put("ts", resolveNumberParameter(clock.instant().getEpochSecond())); + queryParams.put("id", extImp.getExtId()); + queryParams.put("pvid", yieldlabBid.getPvid()); final User user = bidRequest.getUser(); if (user != null && StringUtils.isNotBlank(user.getBuyeruid())) { - uriBuilder.addParameter("ids", "ylid:" + StringUtils.defaultString(user.getBuyeruid())); + queryParams.put("ids", "ylid:" + StringUtils.defaultString(user.getBuyeruid())); } final String gdpr = getGdprParameter(bidRequest.getRegs()); final String consent = getConsentParameter(bidRequest.getUser()); if (StringUtils.isNotBlank(gdpr) && StringUtils.isNotBlank(consent)) { - uriBuilder - .addParameter("gdpr", gdpr) - .addParameter("gdpr_consent", consent); + queryParams.put("gdpr", gdpr); + queryParams.put("gdpr_consent", consent); } - return AD_SOURCE_URL.formatted( - extImp.getAdslotId(), - extImp.getSupplyId(), - yieldlabBid.getAdSize(), - uriBuilder.toString().replace("?", "")); + final List pathSegments = List.of(extImp.getAdslotId(), extImp.getSupplyId(), yieldlabBid.getAdSize()); + return NURL_TEMPLATE.expandToString(Variables.variables() + .set("path", pathSegments) + .set("queryParams", queryParams)); } private ObjectNode resolveBidExt(YieldlabBid bid, List errors) { diff --git a/src/main/java/org/prebid/server/cache/CoreCacheService.java b/src/main/java/org/prebid/server/cache/CoreCacheService.java index e3769216570..84460ef6f74 100644 --- a/src/main/java/org/prebid/server/cache/CoreCacheService.java +++ b/src/main/java/org/prebid/server/cache/CoreCacheService.java @@ -6,10 +6,11 @@ import com.iab.openrtb.response.Bid; import io.vertx.core.Future; import io.vertx.core.MultiMap; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; 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.auction.model.AuctionContext; import org.prebid.server.auction.model.BidInfo; import org.prebid.server.auction.model.CachedDebugLog; @@ -43,11 +44,11 @@ import org.prebid.server.settings.model.AccountAuctionConfig; import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; +import org.prebid.server.util.UriTemplateUtil; import org.prebid.server.vast.VastModifier; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; -import java.net.URISyntaxException; import java.net.URL; import java.time.Clock; import java.util.ArrayList; @@ -70,8 +71,6 @@ public class CoreCacheService { private static final String BID_WURL_ATTRIBUTE = "wurl"; private static final String TRACE_INFO_SEPARATOR = "-"; private static final int MAX_DATACENTER_REGION_LENGTH = 4; - private static final String UUID_QUERY_PARAMETER = "uuid"; - private static final String CH_QUERY_PARAMETER = "ch"; private final HttpClient httpClient; private final URL externalEndpointUrl; @@ -90,6 +89,7 @@ public class CoreCacheService { private final boolean appendTraceInfoToCacheId; private final String datacenterRegion; + private final UriTemplate cacheGetEndpointTemplate; public CoreCacheService( HttpClient httpClient, @@ -127,6 +127,9 @@ public CoreCacheService( this.appendTraceInfoToCacheId = appendTraceInfoToCacheId; this.datacenterRegion = normalizeDatacenterRegion(datacenterRegion); + + final String endpointUrl = ObjectUtils.firstNonNull(internalEndpointUrl, externalEndpointUrl).toString(); + this.cacheGetEndpointTemplate = UriTemplateUtil.createTemplate(endpointUrl, "uuid", "ch"); } public String getEndpointHost() { @@ -648,19 +651,15 @@ public Future getCachedObject(String key, String ch, Timeout return Future.failedFuture(new TimeoutException("Timeout has been exceeded")); } - final URL endpointUrl = ObjectUtils.firstNonNull(internalEndpointUrl, externalEndpointUrl); - final String url; - try { - final URIBuilder uriBuilder = new URIBuilder(endpointUrl.toString()); - uriBuilder.addParameter(UUID_QUERY_PARAMETER, key); - if (StringUtils.isNotBlank(ch)) { - uriBuilder.addParameter(CH_QUERY_PARAMETER, ch); - } - url = uriBuilder.build().toString(); - } catch (URISyntaxException e) { - return Future.failedFuture(new IllegalArgumentException("Configured cache url is malformed", e)); + final Variables queryParams = Variables.variables(); + + queryParams.set("uuid", key); + if (StringUtils.isNotBlank(ch)) { + queryParams.set("ch", ch); } + final String url = cacheGetEndpointTemplate.expandToString(queryParams); + final long startTime = clock.millis(); return httpClient.get(url, cacheHeaders, remainingTimeout) .map(response -> processVtrackReadResponse(response, startTime)) diff --git a/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java b/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java index fdde5f610c0..fc9540b787f 100644 --- a/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java +++ b/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java @@ -17,28 +17,23 @@ private CacheServiceUtil() { public static URL getCacheEndpointUrl(String cacheSchema, String cacheHost, String path) { try { - final URL baseUrl = getCacheBaseUrl(cacheSchema, cacheHost); - return new URL(baseUrl, path); + return HttpUtil.parseUrl(cacheSchema + "://" + cacheHost + (path.startsWith("/") ? "" : "/") + path); } catch (MalformedURLException e) { throw new IllegalArgumentException("Could not get cache endpoint for prebid cache service", e); } } - private static URL getCacheBaseUrl(String cacheSchema, String cacheHost) throws MalformedURLException { - return new URL(cacheSchema + "://" + cacheHost); - } - public static String getCachedAssetUrlTemplate(String cacheSchema, String cacheHost, String path, String cacheQuery) { try { - final URL baseUrl = getCacheBaseUrl(cacheSchema, cacheHost); - return new URL(baseUrl, path + "?" + cacheQuery).toString(); + return HttpUtil.parseUrl(cacheSchema + "://" + cacheHost + + (path.startsWith("/") ? "" : "/") + path + + (cacheQuery.startsWith("?") ? "" : "?") + cacheQuery).toString(); } catch (MalformedURLException e) { throw new IllegalArgumentException("Could not get cached asset url template for prebid cache service", e); } } - } diff --git a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java index b1cc8c257b2..4db7d31d0e7 100644 --- a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java +++ b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java @@ -2,6 +2,7 @@ import com.github.benmanes.caffeine.cache.Caffeine; import io.netty.channel.ConnectTimeoutException; +import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Future; import io.vertx.core.Vertx; import io.vertx.core.http.HttpHeaders; @@ -11,7 +12,6 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.apache.http.HttpStatus; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.timeout.TimeoutFactory; import org.prebid.server.floors.model.PriceFloorData; @@ -165,7 +165,7 @@ private ResponseCacheInfo parseFloorResponse(HttpClientResponse httpClientRespon AccountPriceFloorsFetchConfig fetchConfig) { final int statusCode = httpClientResponse.getStatusCode(); - if (statusCode != HttpStatus.SC_OK) { + if (statusCode != HttpResponseStatus.OK.code()) { throw new PreBidException("Failed to request, provider respond with status %s".formatted(statusCode)); } final String body = httpClientResponse.getBody(); diff --git a/src/main/java/org/prebid/server/handler/OptoutHandler.java b/src/main/java/org/prebid/server/handler/OptoutHandler.java index 5d9885c70ec..184d96fedac 100644 --- a/src/main/java/org/prebid/server/handler/OptoutHandler.java +++ b/src/main/java/org/prebid/server/handler/OptoutHandler.java @@ -18,7 +18,6 @@ import org.prebid.server.vertx.verticles.server.application.ApplicationResource; import java.net.MalformedURLException; -import java.net.URL; import java.util.List; import java.util.Objects; @@ -35,8 +34,12 @@ public class OptoutHandler implements ApplicationResource { private final String optoutUrl; private final String optinUrl; - public OptoutHandler(GoogleRecaptchaVerifier googleRecaptchaVerifier, UidsCookieService uidsCookieService, - String optoutRedirectUrl, String optoutUrl, String optinUrl) { + public OptoutHandler(GoogleRecaptchaVerifier googleRecaptchaVerifier, + UidsCookieService uidsCookieService, + String optoutRedirectUrl, + String optoutUrl, + String optinUrl) { + this.googleRecaptchaVerifier = Objects.requireNonNull(googleRecaptchaVerifier); this.uidsCookieService = Objects.requireNonNull(uidsCookieService); this.optoutRedirectUrl = Objects.requireNonNull(optoutRedirectUrl); @@ -121,8 +124,7 @@ private static String getRequestParam(RoutingContext routingContext, String para public static String getOptoutRedirectUrl(String externalUrl) { try { - final URL url = new URL(externalUrl); - return new URL(url.toExternalForm() + "/static/optout.html").toString(); + return HttpUtil.parseUrl(externalUrl + "/static/optout.html").toString(); } catch (MalformedURLException e) { throw new IllegalArgumentException("Could not get optout redirect url", e); } diff --git a/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java b/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java index c0d899508c4..15e4fcdd008 100644 --- a/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java @@ -5,10 +5,11 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import io.netty.handler.codec.http.HttpResponseStatus; import io.vertx.core.Future; +import io.vertx.uritemplate.UriTemplate; +import io.vertx.uritemplate.Variables; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.MapUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.timeout.Timeout; import org.prebid.server.json.DecodeException; @@ -24,10 +25,11 @@ import org.prebid.server.settings.proto.response.HttpAccountsResponse; import org.prebid.server.settings.proto.response.HttpFetcherResponse; import org.prebid.server.util.HttpUtil; +import org.prebid.server.util.UriTemplateUtil; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; -import java.net.URISyntaxException; +import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -77,6 +79,10 @@ public class HttpApplicationSettings implements ApplicationSettings { private static final TypeReference> CATEGORY_RESPONSE_REFERENCE = new TypeReference<>() { }; + private static final long TIMESTAMP = Instant.now().toEpochMilli(); + private static final String ACCOUNT_ID_PARAMETER = "accountId%s".formatted(TIMESTAMP); + private static final String REQUEST_ID_PARAMETER = "requestId%s".formatted(TIMESTAMP); + private static final String IMP_ID_PARAMETER = "impId%s".formatted(TIMESTAMP); private final boolean isRfc3986Compatible; private final String endpoint; @@ -85,6 +91,8 @@ public class HttpApplicationSettings implements ApplicationSettings { private final String categoryEndpoint; private final HttpClient httpClient; private final JacksonMapper mapper; + private final UriTemplate storedDataUrlTemplate; + private final UriTemplate accountUrlTemplate; public HttpApplicationSettings(boolean isRfc3986Compatible, String endpoint, @@ -95,12 +103,15 @@ public HttpApplicationSettings(boolean isRfc3986Compatible, JacksonMapper mapper) { this.isRfc3986Compatible = isRfc3986Compatible; - this.endpoint = HttpUtil.validateUrlSyntax(Objects.requireNonNull(endpoint)); - this.ampEndpoint = HttpUtil.validateUrlSyntax(Objects.requireNonNull(ampEndpoint)); - this.videoEndpoint = HttpUtil.validateUrlSyntax(Objects.requireNonNull(videoEndpoint)); - this.categoryEndpoint = HttpUtil.validateUrlSyntax(Objects.requireNonNull(categoryEndpoint)); + this.endpoint = HttpUtil.validateUrl(Objects.requireNonNull(endpoint)); + this.ampEndpoint = HttpUtil.validateUrl(Objects.requireNonNull(ampEndpoint)); + this.videoEndpoint = HttpUtil.validateUrl(Objects.requireNonNull(videoEndpoint)); + this.categoryEndpoint = HttpUtil.validateUrl(Objects.requireNonNull(categoryEndpoint)); this.httpClient = Objects.requireNonNull(httpClient); this.mapper = Objects.requireNonNull(mapper); + + this.storedDataUrlTemplate = UriTemplateUtil.createTemplate(endpoint, REQUEST_ID_PARAMETER, IMP_ID_PARAMETER); + this.accountUrlTemplate = UriTemplateUtil.createTemplate(endpoint, ACCOUNT_ID_PARAMETER); } @Override @@ -127,19 +138,17 @@ private Future> fetchAccountsByIds(Set accountIds, Timeout } private String accountsRequestUrlFrom(String endpoint, Set accountIds) { - try { - final URIBuilder uriBuilder = new URIBuilder(endpoint); - if (!accountIds.isEmpty()) { - if (isRfc3986Compatible) { - accountIds.forEach(accountId -> uriBuilder.addParameter("account-id", accountId)); - } else { - uriBuilder.addParameter("account-ids", "[\"%s\"]".formatted(joinIds(accountIds))); - } - } - return uriBuilder.build().toString(); - } catch (URISyntaxException e) { - throw new PreBidException("URL %s has bad syntax".formatted(endpoint)); + if (accountIds.isEmpty()) { + return endpoint; } + + final String resolvedUrl = isRfc3986Compatible + ? accountUrlTemplate.expandToString(Variables.variables() + .set(ACCOUNT_ID_PARAMETER, new ArrayList<>(accountIds))) + : accountUrlTemplate.expandToString(Variables.variables() + .set(ACCOUNT_ID_PARAMETER, "[\"%s\"]".formatted(joinIds(accountIds)))); + + return resolvedUrl.replace(ACCOUNT_ID_PARAMETER, isRfc3986Compatible ? "account-id" : "account-ids"); } private Set processAccountsResponse(HttpClientResponse httpClientResponse, Set accountIds) { @@ -232,26 +241,33 @@ private static StoredDataResult toFailedStoredDataResult(Set req } private String storeRequestUrlFrom(String endpoint, Set requestIds, Set impIds) { - try { - final URIBuilder uriBuilder = new URIBuilder(endpoint); + if (requestIds.isEmpty() && impIds.isEmpty()) { + return endpoint; + } + + final Variables variables = Variables.variables(); + if (isRfc3986Compatible) { if (!requestIds.isEmpty()) { - if (isRfc3986Compatible) { - requestIds.forEach(requestId -> uriBuilder.addParameter("request-id", requestId)); - } else { - uriBuilder.addParameter("request-ids", "[\"%s\"]".formatted(joinIds(requestIds))); - } + variables.set(REQUEST_ID_PARAMETER, new ArrayList<>(requestIds)); } if (!impIds.isEmpty()) { - if (isRfc3986Compatible) { - impIds.forEach(impId -> uriBuilder.addParameter("imp-id", impId)); - } else { - uriBuilder.addParameter("imp-ids", "[\"%s\"]".formatted(joinIds(impIds))); - } + variables.set(IMP_ID_PARAMETER, new ArrayList<>(impIds)); } - return uriBuilder.build().toString(); - } catch (URISyntaxException e) { - throw new PreBidException("URL %s has bad syntax".formatted(endpoint)); + + return storedDataUrlTemplate.expandToString(variables) + .replace(REQUEST_ID_PARAMETER, "request-id") + .replace(IMP_ID_PARAMETER, "imp-id"); + } + + if (!requestIds.isEmpty()) { + variables.set(REQUEST_ID_PARAMETER, "[\"%s\"]".formatted(joinIds(requestIds))); + } + if (!impIds.isEmpty()) { + variables.set(IMP_ID_PARAMETER, "[\"%s\"]".formatted(joinIds(impIds))); } + return storedDataUrlTemplate.expandToString(variables) + .replace(REQUEST_ID_PARAMETER, "request-ids") + .replace(IMP_ID_PARAMETER, "imp-ids"); } private StoredDataResult processStoredDataResponse(HttpClientResponse httpClientResponse, diff --git a/src/main/java/org/prebid/server/spring/config/bidder/EmxDigitalConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/EmxDigitalConfiguration.java index dbeccd07032..c3f1e18e6f7 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/EmxDigitalConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/EmxDigitalConfiguration.java @@ -14,6 +14,7 @@ import org.springframework.context.annotation.PropertySource; import jakarta.validation.constraints.NotBlank; +import java.time.Clock; @Configuration @PropertySource(value = "classpath:/bidder-config/emxdigital.yaml", factory = YamlPropertySourceFactory.class) @@ -30,12 +31,13 @@ BidderConfigurationProperties configurationProperties() { @Bean BidderDeps emxdigitalBidderDeps(BidderConfigurationProperties emxdigitalConfigurationProperties, @NotBlank @Value("${external-url}") String externalUrl, + Clock clock, JacksonMapper mapper) { return BidderDepsAssembler.forBidder(BIDDER_NAME) .withConfig(emxdigitalConfigurationProperties) .usersyncerCreator(UsersyncerCreator.create(externalUrl)) - .bidderCreator(config -> new EmxDigitalBidder(config.getEndpoint(), mapper)) + .bidderCreator(config -> new EmxDigitalBidder(config.getEndpoint(), clock, mapper)) .assemble(); } } diff --git a/src/main/java/org/prebid/server/spring/config/bidder/ExcoConfiguration.java b/src/main/java/org/prebid/server/spring/config/bidder/ExcoConfiguration.java index 9e079821d2e..920fdb1af21 100644 --- a/src/main/java/org/prebid/server/spring/config/bidder/ExcoConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/bidder/ExcoConfiguration.java @@ -13,7 +13,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; -import javax.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotBlank; @Configuration @PropertySource(value = "classpath:/bidder-config/exco.yaml", factory = YamlPropertySourceFactory.class) diff --git a/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java b/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java index c6ae167ae94..fc9fda7dc9c 100644 --- a/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/server/application/ApplicationServerConfiguration.java @@ -411,7 +411,7 @@ OptoutHandler optoutHandler( return new OptoutHandler( googleRecaptchaVerifier, uidsCookieService, - OptoutHandler.getOptoutRedirectUrl(externalUrl), + OptoutHandler.getOptoutRedirectUrl(HttpUtil.validateUrl(externalUrl)), HttpUtil.validateUrl(optoutUrl), HttpUtil.validateUrl(optinUrl)); } diff --git a/src/main/java/org/prebid/server/util/HttpUtil.java b/src/main/java/org/prebid/server/util/HttpUtil.java index e08a276c6fa..f65522f3456 100644 --- a/src/main/java/org/prebid/server/util/HttpUtil.java +++ b/src/main/java/org/prebid/server/util/HttpUtil.java @@ -8,7 +8,6 @@ import io.vertx.core.http.HttpServerResponse; import io.vertx.ext.web.RoutingContext; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.validator.routines.UrlValidator; import org.prebid.server.log.ConditionalLogger; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; @@ -16,6 +15,8 @@ import org.prebid.server.model.HttpRequestContext; import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import java.net.URLEncoder; @@ -85,57 +86,76 @@ public final class HttpUtil { public static final String MACROS_OPEN = "{{"; public static final String MACROS_CLOSE = "}}"; - private static final UrlValidator URL_VALIDAROR = UrlValidator.getInstance(); - private HttpUtil() { } /** * Checks the input string for using as URL. */ - @Deprecated public static String validateUrl(String url) { - if (containsMacrosses(url)) { + if (containsMacros(url)) { return url; } try { - return new URL(url).toString(); + return parseUrl(url).toString(); } catch (MalformedURLException e) { throw new IllegalArgumentException("URL supplied is not valid: " + url, e); } } - public static String validateUrlSyntax(String url) { - if (containsMacrosses(url) || URL_VALIDAROR.isValid(url)) { - return url; + public static URL parseUrl(String url) throws MalformedURLException { + if (StringUtils.isBlank(url)) { + throw new MalformedURLException("URL supplied is not valid: null"); + } + + try { + return new URI(url).toURL(); + } catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) { + throw new MalformedURLException("URL supplied is not valid: %s. Reason: %s".formatted(url, e.getMessage())); } + } - throw new IllegalArgumentException("URL supplied is not valid: " + url); + public static Map> parseQuery(String query) { + if (query == null || query.isEmpty()) { + return Collections.emptyMap(); + } + return Arrays.stream(query.split("&")) + .map(param -> param.split("=", 2)) + .filter(parts -> StringUtils.isNotBlank(parts[0]) && StringUtils.isNotBlank(parts[1])) + .collect(Collectors.groupingBy( + parts -> HttpUtil.decodeUrl(parts[0]), + Collectors.mapping( + parts -> HttpUtil.decodeUrl(parts[1]), + Collectors.toList()))); } - // TODO: We need our own way to work with url macrosses - private static boolean containsMacrosses(String url) { + // TODO: We need our own way to work with url macros + private static boolean containsMacros(String url) { return StringUtils.contains(url, MACROS_OPEN) && StringUtils.contains(url, MACROS_CLOSE); } /** - * Returns encoded URL for the given value. + * Returns encoded URL for the given value. The result is RFC 3986 compliant. *

* The result can be safety used as the query string. */ public static String encodeUrl(String value) { - return URLEncoder.encode(value, StandardCharsets.UTF_8); + return URLEncoder.encode(value, StandardCharsets.UTF_8) + .replace("+", "%20") + .replace("%7E", "~") + .replace("*", "%2A"); } /** - * Returns decoded value if supplied is not null, otherwise returns null. + * Returns decoded value if supplied is not null, otherwise returns null. The result is RFC 3986 compliant. */ public static String decodeUrl(String value) { if (StringUtils.isBlank(value)) { return null; } - return URLDecoder.decode(value, StandardCharsets.UTF_8); + + return URLDecoder.decode(value.replace("+", "%2B"), StandardCharsets.UTF_8); } /** @@ -161,7 +181,7 @@ public static String getHostFromUrl(String url) { return null; } try { - return new URL(url).getHost(); + return parseUrl(url).getHost(); } catch (MalformedURLException e) { return null; } diff --git a/src/main/java/org/prebid/server/util/UriTemplateUtil.java b/src/main/java/org/prebid/server/util/UriTemplateUtil.java new file mode 100644 index 00000000000..fb97dad4caf --- /dev/null +++ b/src/main/java/org/prebid/server/util/UriTemplateUtil.java @@ -0,0 +1,53 @@ +package org.prebid.server.util; + +import io.vertx.uritemplate.UriTemplate; + +import java.util.List; + +public class UriTemplateUtil { + + public static final UriTemplate ONLY_QUERY_URI_TEMPLATE = UriTemplate.of("{?queryParams*}"); + + private UriTemplateUtil() { + + } + + public static UriTemplate createTemplate(String url, List macros) { + String resolvedUrl = url; + for (String macro : macros) { + resolvedUrl = resolvedUrl.replace("{{%s}}".formatted(macro), "{%s}".formatted(macro)); + } + + return UriTemplate.of(resolvedUrl); + } + + public static UriTemplate createTemplate(String url, String... params) { + return createTemplate(url, url.contains("?"), params); + } + + public static UriTemplate createTemplate(String url, boolean hasQueryParameters, String... params) { + final StringBuilder parametersTemplate = new StringBuilder(); + for (int i = 0; i < params.length; i++) { + final String paramTemplate = i == 0 && !hasQueryParameters ? "{?%s*}" : "{&%s*}"; + parametersTemplate.append(paramTemplate.formatted(params[i])); + } + + return UriTemplate.of(url + parametersTemplate); + } + + public static UriTemplate createTemplate(String url, String param, List macros) { + return createTemplate(url, url.contains("?"), param, macros); + } + + public static UriTemplate createTemplate(String url, + boolean hasQueryParameters, + String param, + List macros) { + String resolvedUrl = url; + for (String macro : macros) { + resolvedUrl = resolvedUrl.replace("{{%s}}".formatted(macro), "{%s}".formatted(macro)); + } + return createTemplate(resolvedUrl, hasQueryParameters, param); + } + +} diff --git a/src/main/java/org/prebid/server/vertx/httpclient/BasicHttpClient.java b/src/main/java/org/prebid/server/vertx/httpclient/BasicHttpClient.java index 35dd808c97d..51bd4405efc 100644 --- a/src/main/java/org/prebid/server/vertx/httpclient/BasicHttpClient.java +++ b/src/main/java/org/prebid/server/vertx/httpclient/BasicHttpClient.java @@ -10,6 +10,7 @@ import io.vertx.core.http.HttpMethod; import io.vertx.core.http.RequestOptions; import org.prebid.server.exception.PreBidException; +import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; import java.net.MalformedURLException; @@ -54,7 +55,7 @@ private Future request(HttpMethod method, String url, MultiM final URL absoluteUrl; try { - absoluteUrl = new URL(url); + absoluteUrl = HttpUtil.parseUrl(url); } catch (MalformedURLException e) { return Future.failedFuture(e); } diff --git a/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java b/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java index 0843a04de12..5a32235c2d5 100644 --- a/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java +++ b/src/main/java/org/prebid/server/vertx/httpclient/CircuitBreakerSecuredHttpClient.java @@ -10,6 +10,7 @@ import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; import org.prebid.server.metric.Metrics; +import org.prebid.server.util.HttpUtil; import org.prebid.server.vertx.CircuitBreaker; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; @@ -146,7 +147,7 @@ private static String idFrom(String urlAsString) { private static URL parseUrl(String url) { try { - return new URL(url); + return HttpUtil.parseUrl(url); } catch (MalformedURLException e) { throw new PreBidException("Invalid url: " + url, e); } diff --git a/src/main/resources/bidder-config/adkernel.yaml b/src/main/resources/bidder-config/adkernel.yaml index dbc1afb26a7..2251768c7a4 100644 --- a/src/main/resources/bidder-config/adkernel.yaml +++ b/src/main/resources/bidder-config/adkernel.yaml @@ -1,6 +1,6 @@ adapters: adkernel: - endpoint: http://pbs.adksrv.com/hb?zone=%s + endpoint: http://pbs.adksrv.com/hb?zone={{ZoneId}} endpoint-compression: gzip aliases: rxnetwork: ~ diff --git a/src/main/resources/bidder-config/audiencenetwork.yaml b/src/main/resources/bidder-config/audiencenetwork.yaml index a77b12cd6d3..7ffa93f078b 100644 --- a/src/main/resources/bidder-config/audiencenetwork.yaml +++ b/src/main/resources/bidder-config/audiencenetwork.yaml @@ -11,4 +11,4 @@ adapters: vendor-id: 0 platform-id: app-secret: - timeout-notification-url-template: https://www.facebook.com/audiencenetwork/nurl/?partner=%s&app=%s&auction=%s&ortb_loss_code=2 + timeout-notification-url-template: https://www.facebook.com/audiencenetwork/nurl/?partner={{PlatformId}}&app={{PublisherId}}&auction={{RequestId}}&ortb_loss_code=2 diff --git a/src/main/resources/bidder-config/emxdigital.yaml b/src/main/resources/bidder-config/emxdigital.yaml index 34080708c3e..502c3188db5 100644 --- a/src/main/resources/bidder-config/emxdigital.yaml +++ b/src/main/resources/bidder-config/emxdigital.yaml @@ -1,6 +1,6 @@ adapters: emxdigital: - endpoint: https://hb.emxdgt.com + endpoint: https://hb.emxdgt.com?t={{URL_TIMEOUT}}&ts={{TIMESTAMP}}&src=pbserver aliases: cadent_aperture_mx: enabled: false diff --git a/src/main/resources/bidder-config/ix.yaml b/src/main/resources/bidder-config/ix.yaml index 725c2494701..f7adfea67ee 100644 --- a/src/main/resources/bidder-config/ix.yaml +++ b/src/main/resources/bidder-config/ix.yaml @@ -1,7 +1,7 @@ adapters: ix: # Please contact the maintainer to obtain endpoint details - endpoint: https:// + endpoint: https://localhost ortb-version: "2.6" meta-info: maintainer-email: pdu-supply-prebid@indexexchange.com diff --git a/src/main/resources/bidder-config/oms.yaml b/src/main/resources/bidder-config/oms.yaml index 16c4a4cac08..68d535168f2 100644 --- a/src/main/resources/bidder-config/oms.yaml +++ b/src/main/resources/bidder-config/oms.yaml @@ -1,6 +1,6 @@ adapters: oms: - endpoint: http://rt.marphezis.com/pbs + endpoint: http://rt.marphezis.com/pbs?publisherId={{PublisherId}} meta-info: maintainer-email: prebid@onlinemediasolutions.com app-media-types: diff --git a/src/test/java/org/prebid/server/bidder/adgeneration/AdgenerationBidderTest.java b/src/test/java/org/prebid/server/bidder/adgeneration/AdgenerationBidderTest.java index aea2695820b..7ea0b430b88 100644 --- a/src/test/java/org/prebid/server/bidder/adgeneration/AdgenerationBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adgeneration/AdgenerationBidderTest.java @@ -115,10 +115,22 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfAtLeastOneImpIsSecured() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3&" - + "currency=JPY&sdkname=prebidserver&adapterver=1.0.3&sdktype=0"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=0"); + }); + } @Test @@ -133,10 +145,22 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfDefaultCurrencyIsAbsent() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3&" - + "currency=GBR&sdkname=prebidserver&adapterver=1.0.3&sdktype=0"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=GBR"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=0"); + }); + } @Test @@ -151,10 +175,22 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfDeviceOsIsAndroid() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3&" - + "currency=JPY&sdkname=prebidserver&adapterver=1.0.3&sdktype=1"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=1"); + }); + } @Test @@ -169,10 +205,22 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfDeviceOsIsIos() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3&" - + "currency=JPY&sdkname=prebidserver&adapterver=1.0.3&sdktype=2"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=2"); + }); + } @Test @@ -188,9 +236,22 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfAppHasBundle() { // then assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3¤cy=JPY&" - + "sdkname=prebidserver&adapterver=1.0.3&appbundle=test&sdktype=0"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("appbundle=test"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=0"); + }); + } @Test @@ -206,9 +267,22 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfAppHasAppName() { // then assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3¤cy=JPY&" - + "sdkname=prebidserver&adapterver=1.0.3&appname=test&sdktype=0"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("appname=test"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=0"); + }); + } @Test @@ -223,10 +297,23 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfDeviceHasIfaAndOsIsIos() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3&" - + "currency=JPY&sdkname=prebidserver&adapterver=1.0.3&sdktype=2&idfa=51s"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("idfa=51s"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=2"); + }); + } @Test @@ -241,10 +328,23 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfDeviceHasIfaAndOsIsAndroid() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3&" - + "currency=JPY&sdkname=prebidserver&adapterver=1.0.3&sdktype=1&advertising_id=51s"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("advertising_id=51s"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=1"); + }); + } @Test @@ -260,10 +360,22 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfSitePageIsNotEmpty() { // then assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true" - + "&t=json3¤cy=JPY&sdkname=prebidserver&adapterver=1.0.3" - + "&tp=http%3A%2F%2Fwww.example.com&sdktype=0"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("tp=http%3A%2F%2Fwww.example.com"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=0"); + }); + } @Test @@ -281,10 +393,23 @@ public void makeHttpRequestsShouldReturnHttpsUrlIfAdSizeIsNotEmpty() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?posall=SSPLOC&id=123&hb=true&t=json3&" - + "currency=JPY&sdkname=prebidserver&adapterver=1.0.3&sizes=300x500&sdktype=0"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("t=json3"); + assertThat(url).contains("sizes=300x500"); + assertThat(url).contains("adapterver=1.0.3"); + assertThat(url).contains("hb=true"); + assertThat(url).contains("currency=JPY"); + assertThat(url).contains("id=123"); + assertThat(url).contains("posall=SSPLOC"); + assertThat(url).contains("sdkname=prebidserver"); + assertThat(url).contains("sdktype=0"); + }); + } @Test diff --git a/src/test/java/org/prebid/server/bidder/adkernel/AdkernelBidderTest.java b/src/test/java/org/prebid/server/bidder/adkernel/AdkernelBidderTest.java index 8759cc04679..b879662b0f6 100644 --- a/src/test/java/org/prebid/server/bidder/adkernel/AdkernelBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adkernel/AdkernelBidderTest.java @@ -46,7 +46,7 @@ public class AdkernelBidderTest extends VertxTest { - private static final String ENDPOINT_URL = "https://test.com?zone=%s"; + private static final String ENDPOINT_URL = "https://test.com?zone={{ZoneId}}"; private final AdkernelBidder target = new AdkernelBidder(ENDPOINT_URL, jacksonMapper); diff --git a/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java b/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java index 910a2b6514c..970c9258dc0 100644 --- a/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java @@ -21,10 +21,10 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.prebid.server.VertxTest; -import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusNativeRequest; -import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusRequestAdUnit; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusMetaData; +import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusNativeRequest; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusRequest; +import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusRequestAdUnit; import org.prebid.server.bidder.adnuntius.model.response.AdnuntiusAd; import org.prebid.server.bidder.adnuntius.model.response.AdnuntiusAdUnit; import org.prebid.server.bidder.adnuntius.model.response.AdnuntiusAdvertiser; @@ -518,11 +518,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfGdprAndConsentAr final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = buildExpectedUrl(ENDPOINT_URL, null, null, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, null, null, null); assertThat(result.getErrors()).isEmpty(); } @@ -540,11 +536,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfGdprIsAbsent() { final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, null, "consent"); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, null, "consent"); assertThat(result.getErrors()).isEmpty(); } @@ -560,11 +552,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfConsentIsAbsent( final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, null); assertThat(result.getErrors()).isEmpty(); } @@ -579,11 +567,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfExtImpNoCookiesI final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, null); assertThat(result.getErrors()).isEmpty(); } @@ -600,11 +584,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfExtImpNoCookiesI final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -621,11 +601,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfExtImpNoCookiesI final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -641,11 +617,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriAndPopulateExtDevi final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, null); assertThat(result.getErrors()).isEmpty(); } @@ -662,11 +634,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfExtDeviceImpNoCo final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -683,11 +651,7 @@ public void makeHttpRequestsShouldReturnRequestsWithCorrectUriIfExtDeviceImpNoCo final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -711,11 +675,7 @@ public void makeHttpRequestsShouldReturnRequestsWithBasicUriIfGdprAndConsentAreA final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = buildExpectedUrl(ENDPOINT_URL, null, null, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, null, null, null); assertThat(result.getErrors()).isEmpty(); } @@ -739,11 +699,7 @@ public void makeHttpRequestsShouldReturnRequestsWithBasicUriIfGdprIsAbsentWhenAl final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ENDPOINT_URL, null, "consent"); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ENDPOINT_URL, null, "consent"); assertThat(result.getErrors()).isEmpty(); } @@ -767,11 +723,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUriIfConsentIsAbs final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = buildExpectedUrl(ALTERNATIVE_URL, 1, null, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, 1, null, null); assertThat(result.getErrors()).isEmpty(); } @@ -821,11 +773,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUri() { final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ALTERNATIVE_URL, gdpr, consent); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, gdpr, consent); assertThat(result.getErrors()).isEmpty(); } @@ -847,11 +795,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUriIfExtImpNoCook final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = buildExpectedUrl(ALTERNATIVE_URL, 1, null, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, 1, null, null); assertThat(result.getErrors()).isEmpty(); } @@ -874,11 +818,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUriIfExtImpNoCook final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ALTERNATIVE_URL, 1, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, 1, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -901,11 +841,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUriIfExtImpNoCook final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ALTERNATIVE_URL, 1, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, 1, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -929,11 +865,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUriAndPopulateExt final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = buildExpectedUrl(ALTERNATIVE_URL, 1, null, null); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, 1, null, null); assertThat(result.getErrors()).isEmpty(); } @@ -958,11 +890,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUriIfExtDeviceImp final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ALTERNATIVE_URL, 1, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, 1, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -987,11 +915,7 @@ public void makeHttpRequestsShouldReturnRequestsWithAlternativeUriIfExtDeviceImp final Result>> result = target.makeHttpRequests(bidRequest); // then - final String expectedUrl = givenExpectedUrl(ALTERNATIVE_URL, 1, noCookies); - - assertThat(result.getValue()) - .extracting(HttpRequest::getUri) - .containsExactly(expectedUrl, expectedUrl); + assertExpectedUrl(result, ALTERNATIVE_URL, 1, noCookies); assertThat(result.getErrors()).isEmpty(); } @@ -1517,29 +1441,64 @@ private static ExtDevice givenExtDeviceNoCookies(Boolean noCookies) { return extDevice; } - private static String givenExpectedUrl(String url, Integer gdpr, String consent) { - return buildExpectedUrl(url, gdpr, consent, false); + private static void assertExpectedUrl(Result>> result, + String url, + Integer gdpr, + String consent) { + + assertExpectedUrl(result, url, gdpr, consent, false); } - private static String givenExpectedUrl(String url, Integer gdpr, Boolean noCookies) { - return buildExpectedUrl(url, gdpr, null, noCookies); + private static void assertExpectedUrl(Result>> result, + String url, + Integer gdpr, + Boolean noCookies) { + + assertExpectedUrl(result, url, gdpr, null, noCookies); } - private static String givenExpectedUrl(String url, Boolean noCookies) { - return buildExpectedUrl(url, null, null, noCookies); + private static void assertExpectedUrl(Result>> result, + String url, + Boolean noCookies) { + + assertExpectedUrl(result, url, null, null, noCookies); } - private static String buildExpectedUrl(String url, Integer gdpr, String consent, Boolean noCookies) { + private static void assertExpectedUrl(Result>> result, + String url, + Integer gdpr, + String consent, + Boolean noCookies) { + final StringBuilder expectedUri = new StringBuilder(url + "?format=prebidServer&tzo=-300"); - if (gdpr != null) { - expectedUri.append("&gdpr=").append(HttpUtil.encodeUrl(gdpr.toString())); - } if (consent != null) { expectedUri.append("&consentString=").append(HttpUtil.encodeUrl(consent)); } if (BooleanUtils.isTrue(noCookies)) { expectedUri.append("&noCookies=").append(HttpUtil.encodeUrl(noCookies.toString())); } - return expectedUri.toString(); + if (gdpr != null) { + expectedUri.append("&gdpr=").append(HttpUtil.encodeUrl(gdpr.toString())); + } + + assertThat(result.getValue()) + .extracting(HttpRequest::getUri) + .allSatisfy(uri -> { + assertThat(uri).startsWith(url); + assertThat(uri).contains("format=prebidServer"); + assertThat(uri).contains("tzo=-300"); + + if (consent != null) { + assertThat(uri).contains("consentString=%s".formatted(HttpUtil.encodeUrl(consent))); + } + + if (BooleanUtils.isTrue(noCookies)) { + assertThat(uri).contains("noCookies=%s".formatted(HttpUtil.encodeUrl(noCookies.toString()))); + } + + if (gdpr != null) { + assertThat(uri).contains("gdpr=%s".formatted(HttpUtil.encodeUrl(gdpr.toString()))); + } + }); } } diff --git a/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java b/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java index 9657dd88767..253470c3db6 100644 --- a/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java @@ -66,34 +66,6 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtCouldNotBeParsed() { .containsExactly(BidderError.badInput("Error parsing adOceanExt parameters, in imp with id : 123")); } - @Test - public void makeHttpRequestsShouldReturnErrorIfEndpointUrlComposingFails() { - // given - final BidRequest bidRequest = BidRequest.builder() - .user(User.builder() - .ext(ExtUser.builder() - .consent("consent").build()) - .build()) - .imp(singletonList(Imp.builder() - .id("ao-test") - .banner(Banner.builder().build()) - .ext(mapper.valueToTree(ExtPrebid.of(null, - ExtImpAdocean.of("invalid domain", "masterId", - "adoceanmyaozpniqismex")))).build())) - .test(1) - .build(); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).hasSize(1) - .allSatisfy(error -> { - assertThat(error.getMessage()).startsWith("Invalid url: https://invalid domain/"); - assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input); - }); - } - @Test public void makeHttpRequestsShouldReturnErrorIfExtImpEmitterPrefixIsEmpty() { // given @@ -177,14 +149,36 @@ public void makeHttpRequestsShouldCreateRequestForEveryValidImp() { assertThat(result.getErrors()) .containsExactly(BidderError.badInput("Error parsing adOceanExt parameters, " + "in imp with id : notValidImp")); - assertThat(result.getValue()).hasSize(2) + assertThat(result.getValue()) + .hasSize(2) .extracting(HttpRequest::getUri) - .containsExactly("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0&id=masterId&nc=1" - + "&nosecure=1&aid=adoceanmyaozpniqismex%3Aao-test&gdpr_consent=consent&gdpr=1" - + "&hcuserid=testBuyerUid&aosspsizes=myaozpniqismex" - + "%7E300x250_600x320", "https://em.dom/_10000000/ad.json?pbsrv_v=1.3.0&id=" - + "masterId2&nc=1&nosecure=1&aid=slaveId%3Ai2-test&gdpr_consent=consent&gdpr=1" - + "&hcuserid=testBuyerUid&aosspsizes=slaveId%7E577x333"); + .satisfiesExactly( + url -> { + assertThat(url).startsWith("https://myao.adocean.pl/_10000000/ad.json"); + assertThat(url).contains("pbsrv_v=1.3.0"); + assertThat(url).contains("nc=1"); + assertThat(url).contains("nosecure=1"); + assertThat(url).contains("aosspsizes=myaozpniqismex~300x250_600x320"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("id=masterId"); + assertThat(url).contains("aid=adoceanmyaozpniqismex%3Aao-test"); + assertThat(url).contains("gdpr=1"); + assertThat(url).contains("hcuserid=testBuyerUid"); + }, + url -> { + assertThat(url).startsWith("https://em.dom/_10000000/ad.json"); + assertThat(url).contains("pbsrv_v=1.3.0"); + assertThat(url).contains("nc=1"); + assertThat(url).contains("nosecure=1"); + assertThat(url).contains("aosspsizes=slaveId~577x333"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("id=masterId2"); + assertThat(url).contains("aid=slaveId%3Ai2-test"); + assertThat(url).contains("gdpr=1"); + assertThat(url).contains("hcuserid=testBuyerUid"); + } + ); + } @Test @@ -242,9 +236,20 @@ public void makeHttpRequestsShouldCreateRequestWithoutSizeIfBannerSizesNotPresen // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0&id=masterId&nc=1&nosecure=1" - + "&aid=adoceanmyaozpniqismex%3Aao-test&gdpr_consent=consent&gdpr=1"); + .satisfies(url -> { + assertThat(url).startsWith("https://myao.adocean.pl/_10000000/ad.json"); + assertThat(url).contains("pbsrv_v=1.3.0"); + assertThat(url).contains("nc=1"); + assertThat(url).contains("nosecure=1"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("id=masterId"); + assertThat(url).contains("aid=adoceanmyaozpniqismex%3Aao-test"); + assertThat(url).contains("gdpr=1"); + }); + } @Test @@ -276,11 +281,23 @@ public void makeHttpRequestsShouldUpdateRequestsForSimilarSlaveIds() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0&id=masterId&nc=1" - + "&nosecure=1&aid=slaveId%3Aao-test&gdpr_consent=consent&gdpr=1&hcuserid=testBuyerUid" - + "&aosspsizes=slaveId%7E300x250_600x320&aid=slaveId2%3Ai2-test&aosspsizes=slaveId2%7E577x333"); + .satisfies(url -> { + assertThat(url).startsWith("https://myao.adocean.pl/_10000000/ad.json"); + assertThat(url).contains("pbsrv_v=1.3.0"); + assertThat(url).contains("nc=1"); + assertThat(url).contains("nosecure=1"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("id=masterId"); + assertThat(url).contains("gdpr=1"); + assertThat(url).contains("hcuserid=testBuyerUid"); + assertThat(url).contains("aosspsizes=slaveId2~577x333"); + assertThat(url).contains("aid=slaveId2%3Ai2-test"); + }); + } @Test @@ -451,12 +468,25 @@ public void makeHttpRequestsShouldBuildUrlIfAppIsPresent() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0" - + "&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7&nc=1&nosecure=1" - + "&aid=adoceanmyaozpniqismex%3Aao-test&gdpr_consent=consent" - + "&gdpr=1&app=1&appname=name&appbundle=bundle&appdomain=domain"); + .satisfies(url -> { + assertThat(url).startsWith("https://myao.adocean.pl/_10000000/ad.json"); + assertThat(url).contains("app=1"); + assertThat(url).contains("pbsrv_v=1.3.0"); + assertThat(url).contains("appname=name"); + assertThat(url).contains("nc=1"); + assertThat(url).contains("nosecure=1"); + assertThat(url).contains("appbundle=bundle"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("appdomain=domain"); + assertThat(url).contains("id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"); + assertThat(url).contains("aid=adoceanmyaozpniqismex%3Aao-test"); + assertThat(url).contains("gdpr=1"); + }); + } @Test @@ -481,12 +511,26 @@ public void makeHttpRequestsShouldBuildUrlIfDeviceWithIfaIsPresent() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0" - + "&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7" - + "&nc=1&nosecure=1&aid=adoceanmyaozpniqismex%3Aao-test" - + "&gdpr_consent=consent&gdpr=1&ifa=ifa&devos=os&devosv=osv&devmodel=model&devmake=make"); + .satisfies(url -> { + assertThat(url).startsWith("https://myao.adocean.pl/_10000000/ad.json"); + assertThat(url).contains("pbsrv_v=1.3.0"); + assertThat(url).contains("nc=1"); + assertThat(url).contains("ifa=ifa"); + assertThat(url).contains("devosv=osv"); + assertThat(url).contains("nosecure=1"); + assertThat(url).contains("devos=os"); + assertThat(url).contains("devmake=make"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"); + assertThat(url).contains("aid=adoceanmyaozpniqismex%3Aao-test"); + assertThat(url).contains("devmodel=model"); + assertThat(url).contains("gdpr=1"); + }); + } @Test @@ -511,13 +555,26 @@ public void makeHttpRequestsShouldBuildUrlIfDeviceWithIfaIsNotPresent() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactlyInAnyOrder("https://myao.adocean.pl/_10000000/ad.json?pbsrv_v=1.3.0" - + "&id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7" - + "&nc=1&nosecure=1&aid=adoceanmyaozpniqismex%3Aao-test" - + "&gdpr_consent=consent&gdpr=1&dpidmd5=dpidmd5&devos=os&devosv=osv" - + "&devmodel=model&devmake=make"); + .satisfies(url -> { + assertThat(url).startsWith("https://myao.adocean.pl/_10000000/ad.json"); + assertThat(url).contains("pbsrv_v=1.3.0"); + assertThat(url).contains("dpidmd5=dpidmd5"); + assertThat(url).contains("nc=1"); + assertThat(url).contains("devosv=osv"); + assertThat(url).contains("nosecure=1"); + assertThat(url).contains("devos=os"); + assertThat(url).contains("devmake=make"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("id=tmYF.DMl7ZBq.Nqt2Bq4FutQTJfTpxCOmtNPZoQUDcL.G7"); + assertThat(url).contains("aid=adoceanmyaozpniqismex%3Aao-test"); + assertThat(url).contains("devmodel=model"); + assertThat(url).contains("gdpr=1"); + }); + } private static AdoceanResponseAdUnit adoceanResponseCreator( diff --git a/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java b/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java index 445aa552a1b..b1d01c2fa68 100644 --- a/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/appnexus/AppnexusBidderTest.java @@ -459,7 +459,7 @@ public void makeHttpRequestsShouldReturnExpectedUrlWithMemberId() { // then assertThat(result.getValue()) .extracting(HttpRequest::getUri) - .containsExactly("https://endpoint.com/?member_id=me+mber"); + .containsExactly("https://endpoint.com/?member_id=me%20mber"); assertThat(result.getErrors()).isEmpty(); } diff --git a/src/test/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidderTest.java b/src/test/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidderTest.java index 2a6081c7857..8c84d8bdd14 100644 --- a/src/test/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/audiencenetwork/AudienceNetworkBidderTest.java @@ -46,7 +46,8 @@ public class AudienceNetworkBidderTest extends VertxTest { private static final String PLATFORM_ID = "101"; private static final String APP_SECRET = "6237"; private static final String DEFAULT_BID_CURRENCY = "USD"; - public static final String TIMEOUT_NOTIFICATION_URL_TEMPLATE = "https://url/?p=%s&a=%s&auction=%s&ortb_loss_code=2"; + public static final String TIMEOUT_NOTIFICATION_URL_TEMPLATE = + "https://url/?p={{PlatformId}}&a={{PublisherId}}&auction={{RequestId}}&ortb_loss_code=2"; private final AudienceNetworkBidder target = new AudienceNetworkBidder( ENDPOINT_URL, diff --git a/src/test/java/org/prebid/server/bidder/bluesea/BlueSeaBidderTest.java b/src/test/java/org/prebid/server/bidder/bluesea/BlueSeaBidderTest.java index f26abea686e..5d57c4781c4 100644 --- a/src/test/java/org/prebid/server/bidder/bluesea/BlueSeaBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/bluesea/BlueSeaBidderTest.java @@ -97,10 +97,21 @@ public void makeHttpRequestsShouldMakeCorrectUrls() { // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(2) + assertThat(result.getValue()) + .hasSize(2) .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com?pubid=testPubId&token=testToken", - "https://test.endpoint.com?pubid=testPubId2&token=testToken2"); + .satisfiesExactly( + url -> { + assertThat(url).startsWith("https://test.endpoint.com"); + assertThat(url).contains("pubid=testPubId"); + assertThat(url).contains("token=testToken"); + }, + url -> { + assertThat(url).startsWith("https://test.endpoint.com"); + assertThat(url).contains("pubid=testPubId2"); + assertThat(url).contains("token=testToken2"); + } + ); } @Test diff --git a/src/test/java/org/prebid/server/bidder/dxkulture/DxKultureBidderTest.java b/src/test/java/org/prebid/server/bidder/dxkulture/DxKultureBidderTest.java index 15e4f869c36..7adfd183afb 100644 --- a/src/test/java/org/prebid/server/bidder/dxkulture/DxKultureBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/dxkulture/DxKultureBidderTest.java @@ -99,9 +99,13 @@ public void makeHttpRequestsShouldCreateCorrectUrl() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - assertThat(result.getValue()) + assertThat(result.getValue()).first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com?publisher_id=testPublisherId&placement_id=testPlacementId"); + .satisfies(url -> { + assertThat(url).startsWith(ENDPOINT_URL); + assertThat(url).contains("publisher_id=testPublisherId"); + assertThat(url).contains("placement_id=testPlacementId"); + }); } @Test diff --git a/src/test/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidderTest.java b/src/test/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidderTest.java index 2ecf5d9f1b5..c55f8f4c421 100644 --- a/src/test/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/emxdigital/EmxDigitalBidderTest.java @@ -12,7 +12,11 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; import org.prebid.server.VertxTest; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -24,7 +28,7 @@ import org.prebid.server.proto.openrtb.ext.request.emxdigital.ExtImpEmxDigital; import java.math.BigDecimal; -import java.time.Instant; +import java.time.Clock; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -35,19 +39,31 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.tuple; -import static org.assertj.core.api.Assertions.within; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mock.Strictness.LENIENT; import static org.prebid.server.proto.openrtb.ext.response.BidType.banner; import static org.prebid.server.proto.openrtb.ext.response.BidType.video; +@ExtendWith(MockitoExtension.class) public class EmxDigitalBidderTest extends VertxTest { - private static final String ENDPOINT_URL = "https://test.endpoint.com"; + private static final String ENDPOINT_URL = "https://test.com?t={{URL_TIMEOUT}}&ts={{TIMESTAMP}}&src=pbserver"; - private final EmxDigitalBidder target = new EmxDigitalBidder(ENDPOINT_URL, jacksonMapper); + @Mock(strictness = LENIENT) + private Clock clock; + + private EmxDigitalBidder target; + + @BeforeEach + public void before() { + given(clock.millis()).willReturn(200L); + target = new EmxDigitalBidder(ENDPOINT_URL, clock, jacksonMapper); + } @Test public void creationShouldFailOnInvalidEndpointUrl() { - assertThatIllegalArgumentException().isThrownBy(() -> new EmxDigitalBidder("invalid_url", jacksonMapper)); + assertThatIllegalArgumentException() + .isThrownBy(() -> new EmxDigitalBidder("invalid_url", clock, jacksonMapper)); } @Test @@ -465,17 +481,10 @@ public void makeHttpRequestsShouldSendRequestToModifiedUrlWithHeaders() { .makeHttpRequests(bidRequest); // then - final int expectedTime = (int) Instant.now().getEpochSecond(); - assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1) .extracting(HttpRequest::getUri) - .allSatisfy(uri -> { - assertThat(uri).startsWith("https://test.endpoint.com?t=1000&ts="); - assertThat(uri).endsWith("&src=pbserver"); - final String ts = uri.substring(36, uri.indexOf("&src")); - assertThat(Integer.parseInt(ts)).isCloseTo(expectedTime, within(10)); - }); + .containsExactly("https://test.com?t=1000&ts=200&src=pbserver"); assertThat(result.getValue()).hasSize(1) .flatExtracting(r -> r.getHeaders().entries()) diff --git a/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java b/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java index 6db871bc6bd..409320ec970 100644 --- a/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java @@ -108,26 +108,6 @@ public void makeHttpRequestsShouldReturnErrorIfImpExtClientIdIsBlank() { assertThat(result.getValue()).isEmpty(); } - @Test - public void makeHttpRequestsShouldReturnErrorIfEndpointUrlComposingFails() { - // given - final BidRequest bidRequest = givenBidRequest( - requestBuilder -> requestBuilder - .site(Site.builder().domain("invalid domain").build()), - identity()); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).hasSize(1) - .allSatisfy(error -> { - assertThat(error.getMessage()) - .startsWith("Invalid url: https://eplanning.com/clientId/1/invalid domain/ROS"); - assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input); - }); - } - @Test public void makeHttpRequestsShouldSendSingleGetRequestWithNullBody() { // given @@ -206,9 +186,15 @@ public void makeHttpRequestsShouldSetCorrectUriWithDefaults() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly( - "https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A1x1"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A1x1"); + }); } @Test @@ -225,10 +211,16 @@ public void makeHttpRequestsShouldSetCorrectUriWithSitePageAndDomain() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly( - "https://eplanning.com/clientId/1/DOMAIN/ROS?r=pbs&ncb=1&ur=https%3A%2F%2Fwww.example.com&e=" - + "testadun_itco_de%3A1x1"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/DOMAIN/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=https%3A%2F%2Fwww.example.com"); + assertThat(url).contains("e=testadun_itco_de%3A1x1"); + }); + } @Test @@ -245,9 +237,16 @@ public void makeHttpRequestsShouldSetCorrectUriIfSiteDomainIsBlank() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/www.example.com/ROS?r=pbs&ncb=1" - + "&ur=https%3A%2F%2Fwww.example.com&e=testadun_itco_de%3A1x1"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/www.example.com/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=https%3A%2F%2Fwww.example.com"); + assertThat(url).contains("e=testadun_itco_de%3A1x1"); + }); + } @Test @@ -266,9 +265,16 @@ public void makeHttpRequestsShouldSetCorrectUriWithSizeStringFromBannerWAndH() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A" - + "300x200"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A300x200"); + }); + } @Test @@ -288,9 +294,16 @@ public void makeHttpRequestsShouldSetCorrectUriWithSizeStringFromFormatForMobile // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A" - + "320x50"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A320x50"); + }); + } @Test @@ -310,9 +323,16 @@ public void makeHttpRequestsShouldSetCorrectUriWithSizeStringFromFormatForDeskto // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A" - + "728x90"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A728x90"); + }); + } @Test @@ -332,9 +352,16 @@ public void makeHttpRequestsShouldTolerateAndDropInvalidFormats() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A" - + "728x90"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A728x90"); + }); + } @Test @@ -354,9 +381,16 @@ public void makeHttpRequestsShouldSetUriWithSize1x1WhenSizeWasNotFoundInPriority // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A" - + "1x1"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A1x1"); + }); + } @Test @@ -373,9 +407,17 @@ public void makeHttpRequestsShouldSetCorrectUriWithUserId() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A" - + "1x1&uid=Buyer-ID"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A1x1"); + assertThat(url).contains("uid=Buyer-ID"); + }); + } @Test @@ -392,10 +434,17 @@ public void makeHttpRequestsShouldSetCorrectUriWithDeviceIp() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly( - "https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&ur=FILE&e=testadun_itco_de%3A1x1" - + "&ip=123.321.321.123"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("ur=FILE"); + assertThat(url).contains("e=testadun_itco_de%3A1x1"); + assertThat(url).contains("ip=123.321.321.123"); + }); + } @Test @@ -413,9 +462,19 @@ public void makeHttpRequestsShouldSetCorrectUriWithApp() { // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://eplanning.com/clientId/1/FILE/ROS?r=pbs&ncb=1&e=testadun_itco_de%3A1x1&" - + "appn=appName&appid=id&ifa=ifa&app=1"); + .satisfies(url -> { + assertThat(url).startsWith("https://eplanning.com/clientId/1/FILE/ROS"); + assertThat(url).contains("r=pbs"); + assertThat(url).contains("ncb=1"); + assertThat(url).contains("e=testadun_itco_de%3A1x1"); + assertThat(url).contains("appn=appName"); + assertThat(url).contains("appid=id"); + assertThat(url).contains("ifa=ifa"); + assertThat(url).contains("app=1"); + }); + } @Test diff --git a/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiEndpointResolverTest.java b/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiEndpointResolverTest.java index d831443d157..f468e46aecb 100644 --- a/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiEndpointResolverTest.java +++ b/src/test/java/org/prebid/server/bidder/huaweiads/HuaweiEndpointResolverTest.java @@ -3,19 +3,16 @@ import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; -@ExtendWith(MockitoExtension.class) public class HuaweiEndpointResolverTest { private static final String ENDPOINT_URL = "https://test-url.org/"; private static final String CHINESE_ENDPOINT_URL = "https://test-url.org/china"; private static final String EUROPEAN_ENDPOINT_URL = "https://test-url.org/europe"; - private static final String RUSSIAN_ENDPOINT_URL = "https://test-url.orc/russia"; + private static final String RUSSIAN_ENDPOINT_URL = "https://test-url.org/russia"; private static final String ASIAN_ENDPOINT_URL = "https://test-url.org/asian"; private HuaweiEndpointResolver target; diff --git a/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java b/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java index 09c50589e19..92632ba7fee 100644 --- a/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java +++ b/src/test/java/org/prebid/server/bidder/nexx360/Nexx360BidderTest.java @@ -104,9 +104,16 @@ public void makeHttpRequestsShouldSetCorrectUrl() { // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com?placement=placement&tag_id=tag"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com"); + assertThat(url).contains("placement=placement"); + assertThat(url).contains("tag_id=tag"); + }); + } @Test diff --git a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java index 81b3186bc71..c6886cc9dd5 100644 --- a/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/oms/OmsBidderTest.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.iab.openrtb.request.Banner; import com.iab.openrtb.request.BidRequest; import com.iab.openrtb.request.Imp; import com.iab.openrtb.response.Bid; @@ -21,21 +20,18 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebidVideo; -import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.function.Function; import java.util.function.UnaryOperator; import static java.util.Collections.singletonList; -import static java.util.function.UnaryOperator.identity; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.prebid.server.bidder.model.BidderError.badInput; public class OmsBidderTest extends VertxTest { - private static final String ENDPOINT_URL = "https://randomurl.com"; + private static final String ENDPOINT_URL = "https://randomurl.com?publisherId={{PublisherId}}"; private final OmsBidder target = new OmsBidder(ENDPOINT_URL, jacksonMapper); @@ -58,9 +54,9 @@ public void makeHttpRequestsShouldReturnErrorWhenRequestHasInvalidImpression() { } @Test - public void makeHttpRequestsShouldCreateExpectedUrl() { + public void makeHttpRequestsShouldCreateUrlWithPidWhenPidIsProvided() { // given - final ExtImpOms impExt = ExtImpOms.of("otherTagId", 12345); + final ExtImpOms impExt = ExtImpOms.of("otherTagId", null); final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); // when @@ -74,7 +70,7 @@ public void makeHttpRequestsShouldCreateExpectedUrl() { } @Test - public void makeHttpRequestsShouldCreateExpectedUrlWithPublisherId() { + public void makeHttpRequestsShouldCreateUrlWithPublisherIdWhenPublisherIdIsProvided() { // given final ExtImpOms impExt = ExtImpOms.of(null, 12345); final BidRequest bidRequest = givenBidRequest(impCustomizer -> impCustomizer.ext(givenImpExt(impExt))); @@ -89,48 +85,13 @@ public void makeHttpRequestsShouldCreateExpectedUrlWithPublisherId() { .containsExactly("https://randomurl.com?publisherId=12345"); } - @Test - public void makeHttpRequestsShouldIncludePidInRequestWhenPresent() { - // given - final ObjectNode bidderExt = mapper.createObjectNode().put("pid", "examplePid"); - final ObjectNode impExt = mapper.createObjectNode().set("bidder", bidderExt); - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(impExt)); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .extracting(Imp::getExt) - .containsExactly(impExt); - } - - @Test - public void makeHttpRequestsShouldIncludePublisherIdInRequestWhenPresent() { - // given - final ObjectNode bidderExt = mapper.createObjectNode().put("publisherId", 12345); - final ObjectNode impExt = mapper.createObjectNode().set("bidder", bidderExt); - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.ext(impExt)); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()) - .extracting(HttpRequest::getPayload) - .flatExtracting(BidRequest::getImp) - .extracting(Imp::getExt) - .containsExactly(impExt); - } - @Test public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { // given - final BidderCall httpCall = givenHttpCall(null, "invalid"); + final BidderCall httpCall = BidderCall.succeededHttp( + HttpRequest.builder().build(), + HttpResponse.of(200, null, "invalid"), + null); // when final Result> result = target.makeBids(httpCall, null); @@ -147,7 +108,7 @@ public void makeBidsShouldReturnErrorIfResponseBodyCouldNotBeParsed() { @Test public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(null)); + final BidderCall httpCall = givenHttpCall(null); // when final Result> result = target.makeBids(httpCall, null); @@ -160,8 +121,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseIsNull() throws JsonProces @Test public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall(null, - mapper.writeValueAsString(BidResponse.builder().build())); + final BidderCall httpCall = givenHttpCall(BidResponse.builder().build()); // when final Result> result = target.makeBids(httpCall, null); @@ -174,9 +134,7 @@ public void makeBidsShouldReturnEmptyListIfBidResponseSeatBidIsNull() throws Jso @Test public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall( - givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())), - mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123").mtype(1)))); + final BidderCall httpCall = givenHttpCall(givenBidResponse(impBuilder -> impBuilder.mtype(1))); // when final Result> result = target.makeBids(httpCall, null); @@ -189,9 +147,7 @@ public void makeBidsShouldReturnBannerBid() throws JsonProcessingException { @Test public void makeBidsShouldReturnVideoBid() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall( - givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())), - mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123").mtype(2)))); + final BidderCall httpCall = givenHttpCall(givenBidResponse(impBuilder -> impBuilder.mtype(2))); // when final Result> result = target.makeBids(httpCall, null); @@ -204,9 +160,7 @@ public void makeBidsShouldReturnVideoBid() throws JsonProcessingException { @Test public void makeBidsShouldReturnBannerWhenMTypeIsUnsupported() throws JsonProcessingException { // given - final BidderCall httpCall = givenHttpCall( - givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())), - mapper.writeValueAsString(givenBidResponse(impBuilder -> impBuilder.impid("123").mtype(99)))); + final BidderCall httpCall = givenHttpCall(givenBidResponse(impBuilder -> impBuilder.mtype(99))); // when final Result> result = target.makeBids(httpCall, null); @@ -216,36 +170,6 @@ public void makeBidsShouldReturnBannerWhenMTypeIsUnsupported() throws JsonProces assertThat(result.getValue()).extracting(BidderBid::getType).containsExactly(BidType.banner); } - @Test - public void makeBidsShouldExtractAllBidsFromMultipleSeatBids() throws JsonProcessingException { - // given - final Bid bid1 = Bid.builder().impid("bid1").mtype(1).build(); - final Bid bid2 = Bid.builder().impid("bid2").mtype(1).build(); - final Bid bid3 = Bid.builder().impid("bid3").mtype(2).build(); - - final SeatBid seatBid1 = SeatBid.builder().bid(Arrays.asList(bid1, bid2)).build(); - final SeatBid seatBid2 = SeatBid.builder().bid(Collections.singletonList(bid3)).build(); - - final BidResponse bidResponse = BidResponse.builder() - .seatbid(Arrays.asList(seatBid1, seatBid2)) - .cur("USD") - .build(); - final String bidResponseJson = mapper.writeValueAsString(bidResponse); - - final BidRequest bidRequest = givenBidRequest(impBuilder -> impBuilder.banner(Banner.builder().build())); - final BidderCall httpCall = givenHttpCall(bidRequest, bidResponseJson); - - // when - final Result> result = target.makeBids(httpCall, bidRequest); - - // then - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(3) - .extracting(BidderBid::getType) - .containsExactly(BidType.banner, BidType.banner, BidType.video); - assertThat(result.getValue()).extracting(BidderBid::getBidCurrency).containsOnly("USD"); - } - @Test public void makeBidsShouldReturnVideoBidWithVideoInfo() throws JsonProcessingException { // given @@ -258,7 +182,7 @@ public void makeBidsShouldReturnVideoBidWithVideoInfo() throws JsonProcessingExc .seatbid(List.of(SeatBid.builder().bid(List.of(videoBid)).build())) .cur("USD") .build(); - final BidderCall httpCall = givenHttpCall(null, mapper.writeValueAsString(bidResponse)); + final BidderCall httpCall = givenHttpCall(bidResponse); // when final Result> result = target.makeBids(httpCall, null); @@ -270,14 +194,8 @@ public void makeBidsShouldReturnVideoBidWithVideoInfo() throws JsonProcessingExc } private static BidRequest givenBidRequest(UnaryOperator impCustomizer) { - return givenBidRequest(identity(), impCustomizer); - } - - private static BidRequest givenBidRequest( - Function bidRequestCustomizer, - Function impCustomizer) { - return bidRequestCustomizer.apply(BidRequest.builder() - .imp(singletonList(impCustomizer.apply(Imp.builder().id("123")).build()))) + return BidRequest.builder() + .imp(singletonList(impCustomizer.apply(Imp.builder().id("123")).build())) .build(); } @@ -288,10 +206,10 @@ private static BidResponse givenBidResponse(Function givenHttpCall(BidRequest bidRequest, String body) { + private static BidderCall givenHttpCall(BidResponse bidResponse) throws JsonProcessingException { return BidderCall.succeededHttp( - HttpRequest.builder().payload(bidRequest).build(), - HttpResponse.of(200, null, body), + HttpRequest.builder().build(), + HttpResponse.of(200, null, mapper.writeValueAsString(bidResponse)), null); } diff --git a/src/test/java/org/prebid/server/bidder/smartadserver/SmartadserverBidderTest.java b/src/test/java/org/prebid/server/bidder/smartadserver/SmartadserverBidderTest.java index c9f64cd8a0c..1fb5a4557a4 100644 --- a/src/test/java/org/prebid/server/bidder/smartadserver/SmartadserverBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/smartadserver/SmartadserverBidderTest.java @@ -86,7 +86,7 @@ public void makeHttpRequestsShouldCreateCorrectPrimaryURLWhenProgrammaticGuarant assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); assertThat(result.getValue().getFirst().getUri()) - .isEqualTo("https://test.endpoint.com/path/api/bid?testParam=testVal&callerId=5"); + .isEqualTo("https://test.endpoint.com/path/api/bid?callerId=5"); } @Test @@ -126,7 +126,7 @@ public void makeHttpRequestsShouldCreateCorrectPrimaryURLWhenProgrammaticGuarant assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); assertThat(result.getValue().getFirst().getUri()) - .isEqualTo("https://test.endpoint.com/path/api/bid?testParam=testVal&callerId=5"); + .isEqualTo("https://test.endpoint.com/path/api/bid?callerId=5"); } @Test diff --git a/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java b/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java index 68f6bd9d0ec..9ccd6c7c969 100644 --- a/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java @@ -441,7 +441,7 @@ public void makeBidsShouldReturnDecodedUrlInAdmField() throws JsonProcessingExce // given final BidderCall httpCall = givenHttpCall(givenBidRequest(identity()), mapper.writeValueAsString(givenBidResponse(bidBuilder -> bidBuilder.impid("123") - .adm("encoded+url+test")))); + .adm("encoded%20url%20test")))); // when final Result> result = target.makeBids(httpCall, null); diff --git a/src/test/java/org/prebid/server/bidder/tappx/TappxBidderTest.java b/src/test/java/org/prebid/server/bidder/tappx/TappxBidderTest.java index 5372c135896..0ce76f07221 100644 --- a/src/test/java/org/prebid/server/bidder/tappx/TappxBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/tappx/TappxBidderTest.java @@ -7,7 +7,6 @@ import com.iab.openrtb.response.Bid; import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; -import io.vertx.core.http.HttpMethod; import org.junit.jupiter.api.Test; import org.prebid.server.VertxTest; import org.prebid.server.bidder.model.BidderBid; @@ -141,12 +140,17 @@ public void makeHttpRequestsShouldMakeRequestWithUrl() { // then assertThat(result.getErrors()).isEmpty(); - final String expectedUri = "https://ssp.api.domain/rtb/v2/endpoint?tappxkey=tappxkey&v=1.6&type_cnn=prebid"; - assertThat(result.getValue()).hasSize(1) - .allSatisfy(httpRequest -> { - assertThat(httpRequest.getUri()).isEqualTo(expectedUri); - assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.POST); + assertThat(result.getValue()) + .hasSize(1) + .first() + .extracting(HttpRequest::getUri) + .satisfies(url -> { + assertThat(url).startsWith("https://ssp.api.domain/rtb/v2/endpoint"); + assertThat(url).contains("tappxkey=tappxkey"); + assertThat(url).contains("v=1.6"); + assertThat(url).contains("type_cnn=prebid"); }); + } @Test @@ -165,11 +169,15 @@ public void makeHttpRequestShouldBuildCorrectUriWithPathInHostParameterButWithou // then assertThat(result.getErrors()).isEmpty(); - final String expectedUri = "https://ssp.api.domain/rtb/v2/endpoint?tappxkey=tappxkey&v=1.6&type_cnn=prebid"; - assertThat(result.getValue()).hasSize(1) - .allSatisfy(httpRequest -> { - assertThat(httpRequest.getUri()).isEqualTo(expectedUri); - assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.POST); + assertThat(result.getValue()) + .hasSize(1) + .first() + .extracting(HttpRequest::getUri) + .satisfies(url -> { + assertThat(url).startsWith("https://ssp.api.domain/rtb/v2/endpoint"); + assertThat(url).contains("tappxkey=tappxkey"); + assertThat(url).contains("v=1.6"); + assertThat(url).contains("type_cnn=prebid"); }); } @@ -189,12 +197,15 @@ public void makeHttpRequestShouldBuildCorrectUriWithEndPointParameterIfMatched() // then assertThat(result.getErrors()).isEmpty(); - final String expectedUri = - "https://zz855226test.pub.domain/rtb/?tappxkey=tappxkey&v=1.6&type_cnn=prebid"; - assertThat(result.getValue()).hasSize(1) - .allSatisfy(httpRequest -> { - assertThat(httpRequest.getUri()).isEqualTo(expectedUri); - assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.POST); + assertThat(result.getValue()) + .hasSize(1) + .first() + .extracting(HttpRequest::getUri) + .satisfies(url -> { + assertThat(url).startsWith("https://zz855226test.pub.domain/rtb/?"); + assertThat(url).contains("tappxkey=tappxkey"); + assertThat(url).contains("v=1.6"); + assertThat(url).contains("type_cnn=prebid"); }); } @@ -214,11 +225,15 @@ public void makeHttpRequestsShouldModifyUrl() { // then assertThat(result.getErrors()).isEmpty(); - final String expectedUri = "https://ssp.api.domain/rtb/v2/endpoint?tappxkey=tappxkey&v=1.6&type_cnn=prebid"; - assertThat(result.getValue()).hasSize(1) - .allSatisfy(httpRequest -> { - assertThat(httpRequest.getUri()).isEqualTo(expectedUri); - assertThat(httpRequest.getMethod()).isEqualTo(HttpMethod.POST); + assertThat(result.getValue()) + .hasSize(1) + .first() + .extracting(HttpRequest::getUri) + .satisfies(url -> { + assertThat(url).startsWith("https://ssp.api.domain/rtb/v2/endpoint"); + assertThat(url).contains("tappxkey=tappxkey"); + assertThat(url).contains("v=1.6"); + assertThat(url).contains("type_cnn=prebid"); }); } diff --git a/src/test/java/org/prebid/server/bidder/videobyte/VideobyteBidderTest.java b/src/test/java/org/prebid/server/bidder/videobyte/VideobyteBidderTest.java index 33f454fc055..187af211ff6 100644 --- a/src/test/java/org/prebid/server/bidder/videobyte/VideobyteBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/videobyte/VideobyteBidderTest.java @@ -90,10 +90,29 @@ public void makeHttpRequestsShouldCreateRequestsWithCorrectUri() { final Result>> result = target.makeHttpRequests(bidRequest); // then - assertThat(result.getValue()).extracting(HttpRequest::getUri) - .containsExactly(ENDPOINT_URL + "?source=pbs&pid=" + HttpUtil.encodeUrl("1 23"), - ENDPOINT_URL + "?source=pbs&pid=456&placementId=" + HttpUtil.encodeUrl("a/bc"), - ENDPOINT_URL + "?source=pbs&pid=789&placementId=dce&nid=" + HttpUtil.encodeUrl("A?a=BC")); + assertThat(result.getValue()) + .extracting(HttpRequest::getUri) + .satisfiesExactly( + url -> { + assertThat(url).startsWith(ENDPOINT_URL); + assertThat(url).contains("pid=1%2023"); + assertThat(url).contains("source=pbs"); + }, + url -> { + assertThat(url).startsWith(ENDPOINT_URL); + assertThat(url).contains("placementId=a%2Fbc"); + assertThat(url).contains("pid=456"); + assertThat(url).contains("source=pbs"); + }, + url -> { + assertThat(url).startsWith(ENDPOINT_URL); + assertThat(url).contains("placementId=dce"); + assertThat(url).contains("nid=A%3Fa%3DBC"); + assertThat(url).contains("pid=789"); + assertThat(url).contains("source=pbs"); + } + ); + assertThat(result.getErrors()).isEmpty(); } @@ -255,7 +274,9 @@ private BidRequest givenBidRequest(Site site, Imp... imps) { private Imp givenImp(UnaryOperator extCustomizer, UnaryOperator impCustomizer) { - final ExtImpVideobyte extImpVideobyte = extCustomizer.apply(ExtImpVideobyte.builder()).build(); + final ExtImpVideobyte extImpVideobyte = extCustomizer.apply(ExtImpVideobyte.builder() + .publisherId("publisherId")) + .build(); final ObjectNode ext = mapper.valueToTree(ExtPrebid.of(null, extImpVideobyte)); return impCustomizer.apply(Imp.builder().ext(ext)).build(); } diff --git a/src/test/java/org/prebid/server/bidder/yandex/YandexBidderTest.java b/src/test/java/org/prebid/server/bidder/yandex/YandexBidderTest.java index 26322943187..46bf47699ce 100644 --- a/src/test/java/org/prebid/server/bidder/yandex/YandexBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/yandex/YandexBidderTest.java @@ -606,7 +606,7 @@ public void makeBidsShouldReturnCorrectBidTypeForMultiFormatImpression() throws // then assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue()).hasSize(1); - assertThat(result.getValue().getFirst().getType()).isEqualTo(video); // Video has highest priority + assertThat(result.getValue().getFirst().getType()).isEqualTo(video); } private static BidRequest givenBidRequest( diff --git a/src/test/java/org/prebid/server/bidder/yieldlab/YieldlabBidderTest.java b/src/test/java/org/prebid/server/bidder/yieldlab/YieldlabBidderTest.java index c33b0c9835b..14e3fc0babf 100644 --- a/src/test/java/org/prebid/server/bidder/yieldlab/YieldlabBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/yieldlab/YieldlabBidderTest.java @@ -37,7 +37,6 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidDsa; -import java.math.BigDecimal; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; @@ -74,29 +73,6 @@ public void creationShouldFailOnInvalidEndpointUrl() { .withMessage("URL supplied is not valid: invalid_url"); } - @Test - public void makeHttpRequestsShouldReturnErrorIfEndpointUrlComposingFails() { - // given - final BidRequest bidRequest = BidRequest.builder() - .imp(singletonList(Imp.builder() - .ext(mapper.valueToTree(ExtPrebid.of(null, - ExtImpYieldlab.builder() - .adslotId("invalid path") - .build()))) - .build())) - .build(); - - // when - final Result>> result = target.makeHttpRequests(bidRequest); - - // then - assertThat(result.getErrors()).hasSize(1) - .allSatisfy(error -> { - assertThat(error.getMessage()).startsWith("Invalid url: https://test.endpoint.com/invalid path"); - assertThat(error.getType()).isEqualTo(BidderError.Type.bad_input); - }); - } - @Test public void makeHttpRequestsShouldSendRequestToModifiedUrlWithHeaders() { // given @@ -143,17 +119,29 @@ public void makeHttpRequestsShouldSendRequestToModifiedUrlWithHeaders() { final long expectedTime = clock.instant().getEpochSecond(); assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .allSatisfy(uri -> { - assertThat(uri).startsWith("https://test.endpoint.com/1?content=json&pvid=true&ts="); - assertThat(uri).endsWith("&t=key1%3Dvalue1%26key2%3Dvalue2&sizes=1%3A1x1%7C2x2&" - + "ids=ylid%3Abuyeruid&yl_rtb_ifa&yl_rtb_devicetype=1&gdpr=1&gdpr_consent=consent&" - + "schain=1.0%2C1%21exchange1.com%2C1234%2521abcd%2C1%2Cbid%2Brequest%2526%25251%2C" - + "publisher%2Cpublisher.com%2C%257B%2522freeFormData%2522%253A1%252C%2522" + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/1"); + assertThat(url).contains("t=key1%3Dvalue1%26key2%3Dvalue2"); + assertThat(url).contains("sizes=1%3A1x1%7C2x2"); + assertThat(url).contains("pvid=true"); + assertThat(url).contains("ids=ylid%3Abuyeruid"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("yl_rtb_devicetype=1"); + assertThat(url).contains("content=json"); + assertThat(url).contains("gdpr=1"); + assertThat(url).contains("schain=1.0%2C1%21exchange1.com%2C1234%2521abcd%2C1%2Cbid%2520request" + + "%2526%25251%2Cpublisher%2Cpublisher.com%2C%257B%2522freeFormData%2522%253A1%252C%2522" + "nested%2522%253A%257B%2522isTrue%2522%253Atrue%257D%257D"); - final String ts = uri.substring(54, uri.indexOf("&t=")); - assertThat(Long.parseLong(ts)).isEqualTo(expectedTime); + assertThat(url).contains("ts="); + + final int tsStart = url.indexOf("ts="); + final int tsEnd = url.indexOf('&', tsStart); + final String tsValue = tsEnd == -1 ? url.substring(tsStart + 3) : url.substring(tsStart + 3, tsEnd); + assertThat(Long.parseLong(tsValue)).isEqualTo(expectedTime); }); assertThat(result.getValue()).hasSize(1) @@ -209,12 +197,21 @@ public void constructExtImpShouldWorkWithDuplicateKeysTargeting() { final Result>> result = target.makeHttpRequests(bidRequest); // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1) + assertThat(result.getValue()) + .hasSize(1) + .first() .extracting(HttpRequest::getUri) - .allSatisfy(uri -> { - assertThat(uri).startsWith("https://test.endpoint.com/1,2?content=json&pvid=true&ts="); - assertThat(uri).endsWith("&t=key1%3Dvalue1&sizes=1%3A%2C2%3A&ids=ylid%3Abuyeruid&yl_rtb_ifa&" - + "yl_rtb_devicetype=1&gdpr=1&gdpr_consent=consent"); + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/1%2C2"); + assertThat(url).contains("t=key1%3Dvalue1"); + assertThat(url).contains("sizes=1%3A%2C2%3A"); + assertThat(url).contains("pvid=true"); + assertThat(url).contains("ids=ylid%3Abuyeruid"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("yl_rtb_devicetype=1"); + assertThat(url).contains("content=json"); + assertThat(url).contains("ts="); + assertThat(url).contains("gdpr=1"); }); } @@ -264,26 +261,33 @@ public void makeBidsShouldReturnCorrectBidderBid() throws JsonProcessingExceptio // then final String timestamp = String.valueOf(clock.instant().getEpochSecond()); final int weekNumber = Calendar.getInstance().get(Calendar.WEEK_OF_YEAR); - final String adm = """ - """.formatted(timestamp); - final BidderBid expected = BidderBid.of( - Bid.builder() - .id("1") - .impid("test-imp-id") - .price(BigDecimal.valueOf(2.01)) - .crid("11234" + weekNumber) - .dealid("1234") - .w(728) - .h(90) - .adm(adm) - .adomain(singletonList("yieldlab")) - .build(), - BidType.banner, "EUR"); + assertThat(result.getValue()) + .hasSize(1) + .first() + .satisfies(bb -> { + final Bid bid = bb.getBid(); + assertThat(bid.getId()).isEqualTo("1"); + assertThat(bid.getImpid()).isEqualTo("test-imp-id"); + assertThat(bid.getPrice()).isEqualByComparingTo("2.01"); + assertThat(bid.getCrid()).isEqualTo("11234" + weekNumber); + assertThat(bid.getDealid()).isEqualTo("1234"); + assertThat(bid.getW()).isEqualTo(728); + assertThat(bid.getH()).isEqualTo(90); + assertThat(bid.getAdomain()).containsExactly("yieldlab"); + assertThat(bb.getType()).isEqualTo(BidType.banner); + assertThat(bb.getBidCurrency()).isEqualTo("EUR"); + + final String admHtml = bid.getAdm(); + assertThat(admHtml).startsWith(""); + }); assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).containsExactly(expected); } @Test @@ -311,22 +315,21 @@ public void makeBidsShouldReturnCorrectAdm() throws JsonProcessingException { // then final String timestamp = String.valueOf(clock.instant().getEpochSecond()); - final String expectedAdm = """ - - Yieldlab - - - - """.formatted( - "https://ad.yieldlab.net/d/12345/123456789/728x90?ts=", - timestamp, - "&id=abc&pvid=40cb3251-1e1e-4cfd-8edc-7d32dc1a21e5"); - assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).hasSize(1) - .extracting(BidderBid::getBid) - .extracting(Bid::getAdm) - .containsExactly(expectedAdm); + assertThat(result.getValue()) + .hasSize(1) + .first() + .satisfies(bb -> { + final String adm = bb.getBid().getAdm(); + assertThat(adm).startsWith("\n" + + "Yieldlab\n\n\n\n" + + ""); + }); } @Test @@ -353,11 +356,10 @@ public void makeHttpRequestsShouldAddDsaRequestParamsToRequestWhenDsaIsPresent() //then final List expectations = List.of( - "&dsarequired=1", - "&dsapubrender=2", - "&dsadatatopub=3", - "&dsatransparency=testDomain%7E1_2_3" - ); + "dsarequired=1", + "dsapubrender=2", + "dsadatatopub=3", + "dsatransparency=testDomain~1_2_3"); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue().getFirst().getUri()) .contains(expectations); @@ -390,11 +392,10 @@ public void makeHttpRequestsEncodesDsaTransparencyCorrectlyWhenBidRequestContain //then final List expectations = List.of( - "&dsarequired=1", - "&dsapubrender=2", - "&dsadatatopub=3", - "&dsatransparency=testDomain%7E1_2_3%7E%7EtestDomain2%7E4_5_6" - ); + "dsarequired=1", + "dsapubrender=2", + "dsadatatopub=3", + "dsatransparency=testDomain~1_2_3~~testDomain2~4_5_6"); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue().getFirst().getUri()) .contains(expectations); @@ -425,8 +426,7 @@ public void makeHttpRequestsShouldNotSendDsaInfoInBidRequestWhenDsaIsMissing() { //then final List expectations = List.of( "dsarequired=2", - "dsadatatopub=3" - ); + "dsadatatopub=3"); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue().getFirst().getUri()) .contains(expectations); @@ -457,8 +457,7 @@ public void makeHttpRequestsShouldNotAddDsaTransparencyParamsToBidRequestWhenPar //then final List expectations = List.of( "dsarequired=2", - "dsadatatopub=3" - ); + "dsadatatopub=3"); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue().getFirst().getUri()) .contains(expectations); diff --git a/src/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java b/src/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java index a995429ba79..0912e9a5710 100644 --- a/src/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java +++ b/src/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java @@ -22,7 +22,8 @@ import org.prebid.server.vertx.httpclient.model.HttpClientResponse; import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; @@ -49,10 +50,10 @@ public class BasicPbcStorageServiceTest extends VertxTest { private BasicPbcStorageService target; @BeforeEach - public void setUp() throws MalformedURLException, JsonProcessingException { + public void setUp() throws MalformedURLException, JsonProcessingException, URISyntaxException { target = new BasicPbcStorageService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), "pbc-api-key", 10, jacksonMapper, diff --git a/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java b/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java index 4a9fbabc15a..aab2e5b76ef 100644 --- a/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java +++ b/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java @@ -49,7 +49,8 @@ import java.io.IOException; import java.net.MalformedURLException; -import java.net.URL; +import java.net.URI; +import java.net.URISyntaxException; import java.time.Clock; import java.time.Instant; import java.time.ZoneId; @@ -104,12 +105,12 @@ public class CoreCacheServiceTest extends VertxTest { private Timeout expiredTimeout; @BeforeEach - public void setUp() throws MalformedURLException, JsonProcessingException { + public void setUp() throws MalformedURLException, URISyntaxException, JsonProcessingException { clock = Clock.fixed(Instant.now(), ZoneId.systemDefault()); target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -255,13 +256,13 @@ public void cacheBidsOpenrtbShouldTolerateReadingHttpResponseFails() throws Json @Test public void cacheBidsOpenrtbShouldTryCallingInternalEndpointAndTolerateReadingHttpResponseFails() - throws JsonProcessingException, MalformedURLException { + throws JsonProcessingException, MalformedURLException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), - new URL("http://cache-service-internal/cache"), + new URI("http://cache-service/cache").toURL(), + new URI("http://cache-service-internal/cache").toURL(), "http://cache-service-host/cache?uuid=", 100L, null, @@ -436,11 +437,11 @@ public void cacheBidsOpenrtbShouldReturnExpectedDebugInfo() throws JsonProcessin } @Test - public void cacheBidsOpenrtbShouldUseApiKeyWhenProvided() throws MalformedURLException { + public void cacheBidsOpenrtbShouldUseApiKeyWhenProvided() throws MalformedURLException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -961,12 +962,12 @@ public void cachePutObjectsShouldNotLogErrorMetricsWhenCacheServiceIsNotConnecte } @Test - public void cachePutObjectsShouldCallInternalCacheEndpointWhenProvided() throws IOException { + public void cachePutObjectsShouldCallInternalCacheEndpointWhenProvided() throws IOException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), - new URL("http://cache-service-internal/cache"), + new URI("http://cache-service/cache").toURL(), + new URI("http://cache-service-internal/cache").toURL(), "http://cache-service-host/cache?uuid=", 100L, null, @@ -1013,11 +1014,11 @@ public void cachePutObjectsShouldCallInternalCacheEndpointWhenProvided() throws } @Test - public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLException { + public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -1055,11 +1056,11 @@ public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLExce } @Test - public void cacheBidsOpenrtbShouldPrependTraceInfoWhenEnabled() throws IOException { + public void cacheBidsOpenrtbShouldPrependTraceInfoWhenEnabled() throws IOException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -1125,11 +1126,13 @@ public void cacheBidsOpenrtbShouldPrependTraceInfoWhenEnabled() throws IOExcepti } @Test - public void cacheBidsOpenrtbShouldPrependTraceInfoWithDatacenterWhenEnabled() throws IOException { + public void cacheBidsOpenrtbShouldPrependTraceInfoWithDatacenterWhenEnabled() + throws IOException, URISyntaxException { + // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -1162,7 +1165,7 @@ public void cacheBidsOpenrtbShouldPrependTraceInfoWithDatacenterWhenEnabled() th .build(); // when - final Future future = target.cacheBidsOpenrtb( + target.cacheBidsOpenrtb( asList(bidInfo1, bidInfo2), givenAuctionContext(), CacheContext.builder() @@ -1195,11 +1198,11 @@ public void cacheBidsOpenrtbShouldPrependTraceInfoWithDatacenterWhenEnabled() th } @Test - public void cacheBidsOpenrtbShouldNotPrependTraceInfoToLowEntoryCacheIds() throws IOException { + public void cacheBidsOpenrtbShouldNotPrependTraceInfoToLowEntoryCacheIds() throws IOException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -1226,7 +1229,7 @@ public void cacheBidsOpenrtbShouldNotPrependTraceInfoToLowEntoryCacheIds() throw .build(); // when - final Future future = target.cacheBidsOpenrtb( + target.cacheBidsOpenrtb( singletonList(bidInfo), givenAuctionContext(), CacheContext.builder() @@ -1246,11 +1249,11 @@ public void cacheBidsOpenrtbShouldNotPrependTraceInfoToLowEntoryCacheIds() throw } @Test - public void cachePutObjectsShouldPrependTraceInfoWhenEnabled() throws IOException { + public void cachePutObjectsShouldPrependTraceInfoWhenEnabled() throws IOException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -1294,11 +1297,13 @@ public void cachePutObjectsShouldPrependTraceInfoWhenEnabled() throws IOExceptio } @Test - public void cachePutObjectsShouldPrependTraceInfoWithDatacenterWhenEnabled() throws IOException { + public void cachePutObjectsShouldPrependTraceInfoWithDatacenterWhenEnabled() + throws IOException, URISyntaxException { + // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -1342,11 +1347,11 @@ public void cachePutObjectsShouldPrependTraceInfoWithDatacenterWhenEnabled() thr } @Test - public void cachePutObjectsShouldNotPrependTraceInfoToPassedInKey() throws IOException { + public void cachePutObjectsShouldNotPrependTraceInfoToPassedInKey() throws IOException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), + new URI("http://cache-service/cache").toURL(), null, "http://cache-service-host/cache?uuid=", 100L, @@ -1450,8 +1455,7 @@ public void getCachedObjectShouldAddUuidAndChQueryParamsBeforeSendingWhenChIsPre MultiMap.caseInsensitiveMultiMap().add("Header", "Value"), "body"); - given(httpClient.get(eq("http://cache-service/cache?uuid=key&ch=ch"), any(), anyLong())) - .willReturn(Future.succeededFuture(response)); + given(httpClient.get(any(), any(), anyLong())).willReturn(Future.succeededFuture(response)); // when final Future result = target.getCachedObject("key", "ch", timeout); @@ -1459,6 +1463,11 @@ public void getCachedObjectShouldAddUuidAndChQueryParamsBeforeSendingWhenChIsPre // then assertThat(result.result()).isEqualTo(response); verify(metrics).updateVtrackCacheReadRequestTime(anyLong(), eq(MetricName.ok)); + final ArgumentCaptor urlCaptor = ArgumentCaptor.forClass(String.class); + verify(httpClient).get(urlCaptor.capture(), any(), anyLong()); + assertThat(urlCaptor.getValue()) + .startsWith("http://cache-service/cache?") + .contains("uuid=key", "ch=ch"); } @Test @@ -1482,13 +1491,13 @@ public void getCachedObjectShouldAddUuidQueryParamsBeforeSendingWhenChIsAbsent() @Test public void getCachedObjectShouldAddUuidQueryParamsToInternalBeforeSendingWhenChIsAbsent() - throws MalformedURLException { + throws MalformedURLException, URISyntaxException { // given target = new CoreCacheService( httpClient, - new URL("http://cache-service/cache"), - new URL("http://internal-cache-service/cache"), + new URI("http://cache-service/cache").toURL(), + new URI("http://internal-cache-service/cache").toURL(), "http://cache-service-host/cache?uuid=", 100L, "ApiKey", @@ -1520,12 +1529,7 @@ public void getCachedObjectShouldAddUuidQueryParamsToInternalBeforeSendingWhenCh @Test public void getCachedObjectShouldNotLogErrorMetricsWhenCacheIsNotReached() { // given - final HttpClientResponse response = HttpClientResponse.of( - 200, - MultiMap.caseInsensitiveMultiMap().add("Header", "Value"), - "body"); - - given(httpClient.get(eq("http://cache-service/cache?uuid=key&ch=ch"), any(), anyLong())) + given(httpClient.get(any(), any(), anyLong())) .willReturn(Future.failedFuture(new TimeoutException("Timeout"))); // when @@ -1544,8 +1548,7 @@ public void getCachedObjectShouldHandleErrorResponse() { null, jacksonMapper.encodeToString(CacheErrorResponse.builder().message("Resource not found").build())); - given(httpClient.get(eq("http://cache-service/cache?uuid=key&ch=ch"), any(), anyLong())) - .willReturn(Future.succeededFuture(response)); + given(httpClient.get(any(), any(), anyLong())).willReturn(Future.succeededFuture(response)); // when final Future result = target.getCachedObject("key", "ch", timeout); @@ -1560,8 +1563,7 @@ public void getCachedObjectShouldFailWhenErrorResponseCanNotBeParsed() { // given final HttpClientResponse response = HttpClientResponse.of(404, null, "Resource not found"); - given(httpClient.get(eq("http://cache-service/cache?uuid=key&ch=ch"), any(), anyLong())) - .willReturn(Future.succeededFuture(response)); + given(httpClient.get(any(), any(), anyLong())).willReturn(Future.succeededFuture(response)); // when final Future result = target.getCachedObject("key", "ch", timeout); diff --git a/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java b/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java index 076e03e0f03..a759e4fbae6 100644 --- a/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java +++ b/src/test/java/org/prebid/server/execution/file/supplier/RemoteFileSupplierTest.java @@ -74,7 +74,7 @@ public void setUp() { private RemoteFileSupplier target(boolean checkRemoteFileSize) { return new RemoteFileSupplier( - "https://download.url/", + "https://download.url.com/", SAVE_PATH, TMP_PATH, httpClient, diff --git a/src/test/java/org/prebid/server/settings/HttpApplicationSettingsTest.java b/src/test/java/org/prebid/server/settings/HttpApplicationSettingsTest.java index 0a46bc83d16..c4f79299a96 100644 --- a/src/test/java/org/prebid/server/settings/HttpApplicationSettingsTest.java +++ b/src/test/java/org/prebid/server/settings/HttpApplicationSettingsTest.java @@ -2,8 +2,8 @@ import com.fasterxml.jackson.core.JsonProcessingException; import io.vertx.core.Future; -import org.apache.http.NameValuePair; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.net.URIBuilder; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; diff --git a/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java b/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java index 7337d5d8b1c..c4f205c9865 100644 --- a/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java +++ b/src/test/java/org/prebid/server/spring/config/bidder/util/UsersyncerCreatorTest.java @@ -8,8 +8,6 @@ import org.prebid.server.spring.config.bidder.model.usersync.UsersyncConfigurationProperties; import org.prebid.server.spring.config.bidder.model.usersync.UsersyncMethodConfigurationProperties; -import java.net.MalformedURLException; - import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -57,7 +55,7 @@ public void createShouldValidateExternalUrl() { // given, when and then assertThatThrownBy(() -> UsersyncerCreator.create(null).apply(config, CookieFamilySource.ROOT)) - .hasCauseExactlyInstanceOf(MalformedURLException.class) + .isInstanceOf(IllegalArgumentException.class) .hasMessage("URL supplied is not valid: null"); } diff --git a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-response.json b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-response.json index c9537c8a2b2..825aeaad54d 100644 --- a/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-response.json +++ b/src/test/resources/org/prebid/server/it/openrtb2/sovrn/test-sovrn-bid-response.json @@ -7,7 +7,7 @@ "id": "bid_id", "impid": "imp_id", "price": 5.78, - "adm": "adm+13", + "adm": "adm%2013", "crid": "crid", "w": 300, "h": 250 @@ -17,4 +17,4 @@ "group": 0 } ] -} \ No newline at end of file +} diff --git a/src/test/resources/org/prebid/server/it/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index c2e136cf572..ed18a53af0f 100644 --- a/src/test/resources/org/prebid/server/it/test-application.properties +++ b/src/test/resources/org/prebid/server/it/test-application.properties @@ -16,6 +16,8 @@ adapters.generic.aliases.infytv.enabled=true adapters.generic.aliases.infytv.endpoint=http://localhost:8090/infytv-exchange adapters.generic.aliases.zeta_global_ssp.enabled=true adapters.generic.aliases.zeta_global_ssp.endpoint=http://localhost:8090/zeta_global_ssp-exchange +adapters.aax.enabled=true +adapters.aax.endpoint=http://localhost:8090/aax-exchange adapters.aceex.enabled=true adapters.aceex.endpoint=http://localhost:8090/aceex-exchange adapters.acuityads.enabled=true @@ -667,8 +669,6 @@ adapters.zentotem.enabled=true adapters.zentotem.endpoint=http://localhost:8090/zentotem-exchange adapters.zeroclickfraud.enabled=true adapters.zeroclickfraud.endpoint=http://{{Host}}/zeroclickfraud-exchange?sid={{SourceId}} -adapters.aax.enabled=true -adapters.aax.endpoint=http://localhost:8090/aax-exchange adapters.zmaticoo.enabled=true adapters.zmaticoo.endpoint=http://localhost:8090/zmaticoo-exchange adapters.yearxero.enabled=true