From 704ab67b15b2f43cf2b9d4383242fd9f0136f035 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Fri, 8 Aug 2025 08:35:19 +0200 Subject: [PATCH 1/8] Bidder Configuration Fixes --- .../server/bidder/adkernel/AdkernelBidder.java | 13 +++++++------ .../audiencenetwork/AudienceNetworkBidder.java | 15 ++++++++++----- src/main/resources/bidder-config/adkernel.yaml | 2 +- .../resources/bidder-config/audiencenetwork.yaml | 2 +- src/main/resources/bidder-config/ix.yaml | 2 +- .../bidder/adkernel/AdkernelBidderTest.java | 2 +- .../AudienceNetworkBidderTest.java | 3 ++- .../huaweiads/HuaweiEndpointResolverTest.java | 5 +---- .../file/supplier/RemoteFileSupplierTest.java | 2 +- .../config/bidder/util/UsersyncerCreatorTest.java | 4 +--- .../prebid/server/it/test-application.properties | 6 +++--- 11 files changed, 29 insertions(+), 27 deletions(-) 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 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/resources/bidder-config/adkernel.yaml b/src/main/resources/bidder-config/adkernel.yaml index 2e521696c36..d58ecae8017 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/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/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/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/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/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/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/test-application.properties b/src/test/resources/org/prebid/server/it/test-application.properties index 3851b37e2d4..c01e1abf611 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 @@ -34,7 +36,7 @@ adapters.adhese.endpoint=http://localhost:8090/adhese-exchange adapters.adkerneladn.enabled=true adapters.adkerneladn.endpoint=http://localhost:8090/adkerneladn-exchange?account={{PublisherID}} adapters.adkernel.enabled=true -adapters.adkernel.endpoint=http://localhost:8090/adkernel-exchange?zone=%s +adapters.adkernel.endpoint=http://localhost:8090/adkernel-exchange?zone={{ZoneId}} adapters.adman.enabled=true adapters.adman.endpoint=http://localhost:8090/adman-exchange adapters.admatic.enabled=true @@ -632,8 +634,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 From c6c7305c8ec9c1804064b530f69ac0e7071f2feb Mon Sep 17 00:00:00 2001 From: antonbabak Date: Thu, 4 Sep 2025 11:43:26 +0200 Subject: [PATCH 2/8] Upgrade URL Validation --- extra/pom.xml | 6 -- pom.xml | 4 -- .../bidder/eplanning/EplanningBidder.java | 2 +- .../server/bidder/missena/MissenaBidder.java | 2 +- .../richaudience/RichaudienceBidder.java | 2 +- .../server/cache/utils/CacheServiceUtil.java | 26 ++++---- .../prebid/server/handler/OptoutHandler.java | 12 ++-- .../settings/HttpApplicationSettings.java | 8 +-- .../ApplicationServerConfiguration.java | 2 +- .../java/org/prebid/server/util/HttpUtil.java | 22 +++---- .../vertx/httpclient/BasicHttpClient.java | 3 +- .../CircuitBreakerSecuredHttpClient.java | 3 +- .../cache/BasicPbcStorageServiceTest.java | 7 ++- .../server/cache/CoreCacheServiceTest.java | 59 ++++++++++--------- 14 files changed, 83 insertions(+), 75 deletions(-) diff --git a/extra/pom.xml b/extra/pom.xml index 8daf0b92121..b7f64c1ff05 100644 --- a/extra/pom.xml +++ b/extra/pom.xml @@ -39,7 +39,6 @@ 4.4 1.27.1 3.6.1 - 1.10.0 2.1 4.5.14 5.5.1 @@ -136,11 +135,6 @@ commons-math3 ${commons-math3.version} - - commons-validator - commons-validator - ${commons-validator.version} - org.apache.httpcomponents diff --git a/pom.xml b/pom.xml index dcaaf60e464..2e9783ea0c1 100644 --- a/pom.xml +++ b/pom.xml @@ -114,10 +114,6 @@ org.apache.httpcomponents httpclient - - commons-validator - commons-validator - com.github.seancfoley ipaddress 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 09c607d7451..aa4534f2512 100644 --- a/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java +++ b/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java @@ -286,7 +286,7 @@ private String resolveRequestUri(BidRequest request, List requestsString 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/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/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/cache/utils/CacheServiceUtil.java b/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java index fdde5f610c0..d22d5f3fae2 100644 --- a/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java +++ b/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java @@ -1,9 +1,12 @@ package org.prebid.server.cache.utils; import io.vertx.core.MultiMap; +import org.apache.http.client.utils.URIBuilder; +import org.apache.http.client.utils.URLEncodedUtils; import org.prebid.server.util.HttpUtil; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; public class CacheServiceUtil { @@ -17,28 +20,31 @@ private CacheServiceUtil() { public static URL getCacheEndpointUrl(String cacheSchema, String cacheHost, String path) { try { - final URL baseUrl = getCacheBaseUrl(cacheSchema, cacheHost); - return new URL(baseUrl, path); - } catch (MalformedURLException e) { + final URIBuilder uriBuilder = cacheBaseUriBuilder(cacheSchema, cacheHost); + return uriBuilder.setPath(path).build().toURL(); + } catch (MalformedURLException | URISyntaxException | IllegalArgumentException 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(); - } catch (MalformedURLException e) { + return HttpUtil.validateUrl(cacheBaseUriBuilder(cacheSchema, cacheHost) + .setPath(path) + .setParameters(URLEncodedUtils.parse(cacheQuery, null)) + .build() + .toString()); + } catch (URISyntaxException e) { throw new IllegalArgumentException("Could not get cached asset url template for prebid cache service", e); } } + private static URIBuilder cacheBaseUriBuilder(String cacheSchema, String cacheHost) { + return new URIBuilder().setScheme(cacheSchema).setHost(cacheHost); + } + } 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 3dce1bcc12d..d9f5607f17b 100644 --- a/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java @@ -94,10 +94,10 @@ public HttpApplicationSettings(HttpClient httpClient, this.httpClient = Objects.requireNonNull(httpClient); this.mapper = Objects.requireNonNull(mapper); - 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.isRfc3986Compatible = isRfc3986Compatible; } 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 88f1ef32f92..029460a57cc 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 @@ -402,7 +402,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..47a2b17bb80 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,33 +86,34 @@ 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)) { 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"); } - throw new IllegalArgumentException("URL supplied is not valid: " + url); + 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())); + } } // TODO: We need our own way to work with url macrosses @@ -161,7 +163,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/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/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java b/src/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java index c7b09518ae7..a135433ff74 100644 --- a/src/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java +++ b/src/test/java/org/prebid/server/cache/BasicPbcStorageServiceTest.java @@ -20,7 +20,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 static org.assertj.core.api.AssertionsForClassTypes.assertThat; import static org.mockito.ArgumentMatchers.any; @@ -39,10 +40,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 6ce3836a695..d0b9c325e8e 100644 --- a/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java +++ b/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java @@ -48,7 +48,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; @@ -102,12 +103,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, @@ -253,13 +254,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, @@ -434,11 +435,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, @@ -875,12 +876,12 @@ public void cachePutObjectsShould() throws IOException { } @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, @@ -927,11 +928,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, @@ -969,11 +970,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, @@ -1039,11 +1040,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, @@ -1076,7 +1079,7 @@ public void cacheBidsOpenrtbShouldPrependTraceInfoWithDatacenterWhenEnabled() th .build(); // when - final Future future = target.cacheBidsOpenrtb( + target.cacheBidsOpenrtb( asList(bidInfo1, bidInfo2), givenAuctionContext(), CacheContext.builder() @@ -1109,11 +1112,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, @@ -1140,7 +1143,7 @@ public void cacheBidsOpenrtbShouldNotPrependTraceInfoToLowEntoryCacheIds() throw .build(); // when - final Future future = target.cacheBidsOpenrtb( + target.cacheBidsOpenrtb( singletonList(bidInfo), givenAuctionContext(), CacheContext.builder() @@ -1160,11 +1163,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, @@ -1208,11 +1211,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, @@ -1256,11 +1261,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, From a756d9831b80715cc161aca10e427ce946db5f53 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Thu, 4 Sep 2025 13:22:31 +0200 Subject: [PATCH 3/8] Upgrade URL Validation --- ...iveIntentOmniChannelIdentityProcessedAuctionRequestHook.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5c3e43f9952..ef7bc24b185 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 @@ -47,7 +47,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; From e1d20673960ac6c41b2d1a3eae06c1cdb434d2a6 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Fri, 26 Sep 2025 17:12:51 +0200 Subject: [PATCH 4/8] Make URL encoding RFC 3986 compliant --- .../model/WURFLEngineUtils.java | 3 ++- extra/pom.xml | 13 +++------ pom.xml | 4 +-- .../server/auction/IpAddressHelper.java | 2 +- .../adgeneration/AdgenerationBidder.java | 2 +- .../bidder/adnuntius/AdnuntiusBidder.java | 2 +- .../server/bidder/adocean/AdoceanBidder.java | 11 +++----- .../prebid/server/bidder/amx/AmxBidder.java | 2 +- .../bidder/appnexus/AppnexusBidder.java | 2 +- .../server/bidder/bluesea/BlueSeaBidder.java | 2 +- .../bidder/connatix/ConnatixBidder.java | 2 +- .../bidder/dxkulture/DxKultureBidder.java | 2 +- .../bidder/eplanning/EplanningBidder.java | 2 +- .../server/bidder/flipp/FlippBidder.java | 27 ++++++++++++------- .../server/bidder/mobkoi/MobkoiBidder.java | 8 +++--- .../server/bidder/nexx360/Nexx360Bidder.java | 2 +- .../server/bidder/rubicon/RubiconBidder.java | 2 +- .../smartadserver/SmartadserverBidder.java | 4 +-- .../server/bidder/sspbc/SspbcBidder.java | 2 +- .../server/bidder/tappx/TappxBidder.java | 2 +- .../bidder/videobyte/VideobyteBidder.java | 2 +- .../server/bidder/yandex/YandexBidder.java | 2 +- .../bidder/yieldlab/YieldlabBidder.java | 2 +- .../server/cache/utils/CacheServiceUtil.java | 23 +++++----------- .../server/floors/PriceFloorFetcher.java | 2 +- .../settings/HttpApplicationSettings.java | 2 +- .../config/bidder/ExcoConfiguration.java | 2 +- .../java/org/prebid/server/util/HttpUtil.java | 18 ++++++++----- .../bidder/adnuntius/AdnuntiusBidderTest.java | 4 +-- .../bidder/adocean/AdoceanBidderTest.java | 6 ++--- .../bidder/appnexus/AppnexusBidderTest.java | 2 +- .../server/bidder/sovrn/SovrnBidderTest.java | 2 +- .../bidder/yieldlab/YieldlabBidderTest.java | 6 ++--- .../settings/HttpApplicationSettingsTest.java | 4 +-- .../sovrn/test-sovrn-bid-response.json | 4 +-- 35 files changed, 86 insertions(+), 91 deletions(-) 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..979dfe58487 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 @@ -4,6 +4,7 @@ import com.scientiamobile.wurfl.core.WURFLEngine; import com.scientiamobile.wurfl.core.cache.LRUMapCacheProvider; import com.scientiamobile.wurfl.core.cache.NullCacheProvider; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.config.WURFLDeviceDetectionConfigProperties; import org.prebid.server.hooks.modules.com.scientiamobile.wurfl.devicedetection.exc.WURFLDeviceDetectionException; @@ -56,7 +57,7 @@ private static String wurflFilePathFromConfig(WURFLDeviceDetectionConfigProperti public static String extractWURFLFileName(String wurflSnapshotUrl) { try { - final URI uri = new URI(wurflSnapshotUrl); + final URI uri = new URIBuilder(wurflSnapshotUrl).build(); final String path = uri.getPath(); return path.substring(path.lastIndexOf('/') + 1); } catch (Exception e) { diff --git a/extra/pom.xml b/extra/pom.xml index 5401ac55362..8e3fdbd525f 100644 --- a/extra/pom.xml +++ b/extra/pom.xml @@ -40,7 +40,7 @@ 1.27.1 3.6.1 2.1 - 4.5.14 + 5.5 5.5.1 6.8.0 1.5.6 @@ -135,17 +135,10 @@ commons-math3 ${commons-math3.version} - - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 ${httpclient.version} - - - commons-logging - commons-logging - - com.github.seancfoley diff --git a/pom.xml b/pom.xml index 81eb751024e..29a3787a88c 100644 --- a/pom.xml +++ b/pom.xml @@ -111,8 +111,8 @@ commons-math3 - org.apache.httpcomponents - httpclient + org.apache.httpcomponents.client5 + httpclient5 com.github.seancfoley diff --git a/src/main/java/org/prebid/server/auction/IpAddressHelper.java b/src/main/java/org/prebid/server/auction/IpAddressHelper.java index 523219fd511..8032f950548 100644 --- a/src/main/java/org/prebid/server/auction/IpAddressHelper.java +++ b/src/main/java/org/prebid/server/auction/IpAddressHelper.java @@ -5,7 +5,7 @@ import inet.ipaddr.IPAddressString; import inet.ipaddr.IPAddressStringParameters; import org.apache.commons.lang3.StringUtils; -import org.apache.http.conn.util.InetAddressUtils; +import org.apache.hc.core5.net.InetAddressUtils; import org.prebid.server.auction.model.IpAddress; import org.prebid.server.log.Logger; import org.prebid.server.log.LoggerFactory; 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..9af347f7928 100644 --- a/src/main/java/org/prebid/server/bidder/adgeneration/AdgenerationBidder.java +++ b/src/main/java/org/prebid/server/bidder/adgeneration/AdgenerationBidder.java @@ -14,7 +14,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adgeneration.model.AdgenerationResponse; import org.prebid.server.bidder.model.BidderBid; diff --git a/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java b/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java index 1603cdc855b..b13aba3a6ff 100644 --- a/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java +++ b/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java @@ -22,7 +22,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusMetaData; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusNativeRequest; 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..78e25b3e2a7 100644 --- a/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java +++ b/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java @@ -16,10 +16,9 @@ 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.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.message.BasicNameValuePair; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adocean.model.AdoceanResponseAdUnit; import org.prebid.server.bidder.model.BidderBid; @@ -37,9 +36,7 @@ import java.io.IOException; import java.math.BigDecimal; -import java.net.URI; import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -300,7 +297,7 @@ private static MultiMap getHeaders(BidRequest request) { public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { final List params; try { - params = URLEncodedUtils.parse(new URI(httpCall.getRequest().getUri()), StandardCharsets.UTF_8); + params = new URIBuilder(httpCall.getRequest().getUri()).getQueryParams(); } catch (URISyntaxException e) { return Result.withError(BidderError.badInput(e.getMessage())); } 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..9e01bf82d7d 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,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.amx.model.AmxBidExt; import org.prebid.server.bidder.model.BidderBid; 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..246849dc429 100644 --- a/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java +++ b/src/main/java/org/prebid/server/bidder/appnexus/AppnexusBidder.java @@ -19,7 +19,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.auction.model.Endpoint; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.appnexus.proto.AppnexusBidExt; 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..d4a0a0b5831 100644 --- a/src/main/java/org/prebid/server/bidder/bluesea/BlueSeaBidder.java +++ b/src/main/java/org/prebid/server/bidder/bluesea/BlueSeaBidder.java @@ -9,7 +9,7 @@ import com.iab.openrtb.response.BidResponse; import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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..0d041911fe1 100644 --- a/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java +++ b/src/main/java/org/prebid/server/bidder/connatix/ConnatixBidder.java @@ -17,7 +17,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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..8a484b2829c 100644 --- a/src/main/java/org/prebid/server/bidder/dxkulture/DxKultureBidder.java +++ b/src/main/java/org/prebid/server/bidder/dxkulture/DxKultureBidder.java @@ -10,7 +10,7 @@ import com.iab.openrtb.response.SeatBid; import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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 aa4534f2512..a11ef764320 100644 --- a/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java +++ b/src/main/java/org/prebid/server/bidder/eplanning/EplanningBidder.java @@ -18,7 +18,7 @@ import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.eplanning.model.CleanStepName; import org.prebid.server.bidder.eplanning.model.HbResponse; 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..a9c383171c3 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,8 @@ 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.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.net.URIBuilder; 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 +47,7 @@ import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; -import java.nio.charset.StandardCharsets; +import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -168,12 +168,21 @@ 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() - .orElse(null); + if (pageUrl == null) { + return null; + } + + try { + return new URIBuilder(pageUrl) + .getQueryParams() + .stream() + .filter(nameValuePair -> nameValuePair.getName().contains("flipp-content-code")) + .map(NameValuePair::getValue) + .findFirst() + .orElse(null); + } catch (URISyntaxException e) { + return null; + } } private static List resolveKeywords(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java b/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java index 97cd481b235..f7101fe427f 100644 --- a/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java +++ b/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java @@ -8,6 +8,7 @@ import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -24,7 +25,6 @@ import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; -import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; @@ -97,8 +97,10 @@ private String resolveEndpoint(String customUri) { return endpointUrl; } try { - final URI uri = new URI(customUri); - return uri.resolve("/bid").toString(); + return new URIBuilder(customUri) + .setPath("/bid") + .clearParameters() + .toString(); } catch (IllegalArgumentException | URISyntaxException e) { return endpointUrl; } 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..90a696ac4e2 100644 --- a/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java +++ b/src/main/java/org/prebid/server/bidder/nexx360/Nexx360Bidder.java @@ -8,7 +8,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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..4fd8e7ca741 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,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.ViewabilityVendors; import org.prebid.server.bidder.model.BidderBid; 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..e6a72a06b2a 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,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -122,7 +122,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 URI uri = new URIBuilder(url).build(); final String path = isProgrammaticGuaranteed ? "/ortb" : "/api/bid"; final URIBuilder uriBuilder = new URIBuilder(uri) .setPath(StringUtils.removeEnd(uri.getPath(), "/") + path); 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..0b0342cb541 100644 --- a/src/main/java/org/prebid/server/bidder/sspbc/SspbcBidder.java +++ b/src/main/java/org/prebid/server/bidder/sspbc/SspbcBidder.java @@ -6,7 +6,7 @@ import com.iab.openrtb.response.SeatBid; import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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..e51dc2f4ef6 100644 --- a/src/main/java/org/prebid/server/bidder/tappx/TappxBidder.java +++ b/src/main/java/org/prebid/server/bidder/tappx/TappxBidder.java @@ -7,7 +7,7 @@ import com.iab.openrtb.response.SeatBid; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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..d3f2c05dc00 100644 --- a/src/main/java/org/prebid/server/bidder/videobyte/VideobyteBidder.java +++ b/src/main/java/org/prebid/server/bidder/videobyte/VideobyteBidder.java @@ -10,7 +10,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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 46ed20a06f1..5d914fe6651 100644 --- a/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java +++ b/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java @@ -14,7 +14,7 @@ import io.vertx.core.http.HttpMethod; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.http.client.utils.URIBuilder; +import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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..b799147c15a 100644 --- a/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java +++ b/src/main/java/org/prebid/server/bidder/yieldlab/YieldlabBidder.java @@ -23,7 +23,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; 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 d22d5f3fae2..fc9540b787f 100644 --- a/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java +++ b/src/main/java/org/prebid/server/cache/utils/CacheServiceUtil.java @@ -1,12 +1,9 @@ package org.prebid.server.cache.utils; import io.vertx.core.MultiMap; -import org.apache.http.client.utils.URIBuilder; -import org.apache.http.client.utils.URLEncodedUtils; import org.prebid.server.util.HttpUtil; import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.net.URL; public class CacheServiceUtil { @@ -20,9 +17,8 @@ private CacheServiceUtil() { public static URL getCacheEndpointUrl(String cacheSchema, String cacheHost, String path) { try { - final URIBuilder uriBuilder = cacheBaseUriBuilder(cacheSchema, cacheHost); - return uriBuilder.setPath(path).build().toURL(); - } catch (MalformedURLException | URISyntaxException | IllegalArgumentException e) { + return HttpUtil.parseUrl(cacheSchema + "://" + cacheHost + (path.startsWith("/") ? "" : "/") + path); + } catch (MalformedURLException e) { throw new IllegalArgumentException("Could not get cache endpoint for prebid cache service", e); } } @@ -33,18 +29,11 @@ public static String getCachedAssetUrlTemplate(String cacheSchema, String cacheQuery) { try { - return HttpUtil.validateUrl(cacheBaseUriBuilder(cacheSchema, cacheHost) - .setPath(path) - .setParameters(URLEncodedUtils.parse(cacheQuery, null)) - .build() - .toString()); - } catch (URISyntaxException e) { + 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); } } - - private static URIBuilder cacheBaseUriBuilder(String cacheSchema, String cacheHost) { - return new URIBuilder().setScheme(cacheSchema).setHost(cacheHost); - } - } diff --git a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java index b1cc8c257b2..30c2e90c6f4 100644 --- a/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java +++ b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java @@ -11,7 +11,7 @@ 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.apache.hc.core5.http.HttpStatus; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.timeout.TimeoutFactory; import org.prebid.server.floors.model.PriceFloorData; diff --git a/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java b/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java index 13f20d2c4f9..2df2a84a865 100644 --- a/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java +++ b/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java @@ -8,7 +8,7 @@ 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.apache.hc.core5.net.URIBuilder; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.timeout.Timeout; import org.prebid.server.json.DecodeException; 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/util/HttpUtil.java b/src/main/java/org/prebid/server/util/HttpUtil.java index 47a2b17bb80..3e3e075f0c6 100644 --- a/src/main/java/org/prebid/server/util/HttpUtil.java +++ b/src/main/java/org/prebid/server/util/HttpUtil.java @@ -93,7 +93,7 @@ private HttpUtil() { * Checks the input string for using as URL. */ public static String validateUrl(String url) { - if (containsMacrosses(url)) { + if (containsMacros(url)) { return url; } @@ -116,28 +116,32 @@ public static URL parseUrl(String url) throws MalformedURLException { } } - // 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); } /** 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..91166391532 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; 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..ff6c740a6da 100644 --- a/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java @@ -182,9 +182,9 @@ public void makeHttpRequestsShouldCreateRequestForEveryValidImp() { .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=" + + "~300x250_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"); + + "&hcuserid=testBuyerUid&aosspsizes=slaveId~577x333"); } @Test @@ -280,7 +280,7 @@ public void makeHttpRequestsShouldUpdateRequestsForSimilarSlaveIds() { .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"); + + "&aosspsizes=slaveId~300x250_600x320&aid=slaveId2%3Ai2-test&aosspsizes=slaveId2~577x333"); } @Test 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/sovrn/SovrnBidderTest.java b/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java index 68d4df4d00d..a8043fbfd5f 100644 --- a/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/sovrn/SovrnBidderTest.java @@ -459,7 +459,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/yieldlab/YieldlabBidderTest.java b/src/test/java/org/prebid/server/bidder/yieldlab/YieldlabBidderTest.java index c33b0c9835b..2bf9b30d039 100644 --- a/src/test/java/org/prebid/server/bidder/yieldlab/YieldlabBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/yieldlab/YieldlabBidderTest.java @@ -149,7 +149,7 @@ public void makeHttpRequestsShouldSendRequestToModifiedUrlWithHeaders() { 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" + + "schain=1.0%2C1%21exchange1.com%2C1234%2521abcd%2C1%2Cbid%2520request%2526%25251%2C" + "publisher%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=")); @@ -356,7 +356,7 @@ public void makeHttpRequestsShouldAddDsaRequestParamsToRequestWhenDsaIsPresent() "&dsarequired=1", "&dsapubrender=2", "&dsadatatopub=3", - "&dsatransparency=testDomain%7E1_2_3" + "&dsatransparency=testDomain~1_2_3" ); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue().getFirst().getUri()) @@ -393,7 +393,7 @@ public void makeHttpRequestsEncodesDsaTransparencyCorrectlyWhenBidRequestContain "&dsarequired=1", "&dsapubrender=2", "&dsadatatopub=3", - "&dsatransparency=testDomain%7E1_2_3%7E%7EtestDomain2%7E4_5_6" + "&dsatransparency=testDomain~1_2_3~~testDomain2~4_5_6" ); assertThat(result.getErrors()).isEmpty(); assertThat(result.getValue().getFirst().getUri()) 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/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 +} From e5b02da02b4d1d764e050704fd8875aa28fc8bbe Mon Sep 17 00:00:00 2001 From: antonbabak Date: Tue, 7 Oct 2025 06:47:25 +0200 Subject: [PATCH 5/8] Small bidder updates --- .../bidder/emxdigital/EmxDigitalBidder.java | 13 +- .../prebid/server/bidder/oms/OmsBidder.java | 14 +- .../bidder/EmxDigitalConfiguration.java | 4 +- .../resources/bidder-config/emxdigital.yaml | 2 +- src/main/resources/bidder-config/oms.yaml | 2 +- .../emxdigital/EmxDigitalBidderTest.java | 35 +++-- .../server/bidder/oms/OmsBidderTest.java | 120 +++--------------- 7 files changed, 62 insertions(+), 128 deletions(-) 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/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/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/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/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/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/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); } From 8743663ae7b5de468e0d46aaa1e3dede48c61308 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Tue, 7 Oct 2025 11:20:49 +0200 Subject: [PATCH 6/8] Fix pom.xml --- extra/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/extra/pom.xml b/extra/pom.xml index 8e3fdbd525f..a7a1a17bb67 100644 --- a/extra/pom.xml +++ b/extra/pom.xml @@ -135,11 +135,6 @@ commons-math3 ${commons-math3.version} - - org.apache.httpcomponents.client5 - httpclient5 - ${httpclient.version} - com.github.seancfoley ipaddress From c0446ecb4d1512d24c583e0b81d391f5588c85ee Mon Sep 17 00:00:00 2001 From: antonbabak Date: Tue, 7 Oct 2025 11:23:34 +0200 Subject: [PATCH 7/8] Fix pom.xml --- extra/pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/extra/pom.xml b/extra/pom.xml index a7a1a17bb67..b63daaf8161 100644 --- a/extra/pom.xml +++ b/extra/pom.xml @@ -40,7 +40,6 @@ 1.27.1 3.6.1 2.1 - 5.5 5.5.1 6.8.0 1.5.6 From 5c4edf92a8b801fafe1ac87674de69a658b7dbf1 Mon Sep 17 00:00:00 2001 From: antonbabak Date: Mon, 13 Oct 2025 11:35:51 +0200 Subject: [PATCH 8/8] Remove httpcomponents.client5 --- .../model/WURFLEngineUtils.java | 8 +- pom.xml | 8 +- .../server/auction/IpAddressHelper.java | 6 +- .../adgeneration/AdgenerationBidder.java | 62 +++--- .../bidder/adnuntius/AdnuntiusBidder.java | 46 +++-- .../server/bidder/adocean/AdoceanBidder.java | 116 +++++------ .../prebid/server/bidder/amx/AmxBidder.java | 14 +- .../bidder/appnexus/AppnexusBidder.java | 9 +- .../server/bidder/bluesea/BlueSeaBidder.java | 22 +-- .../bidder/connatix/ConnatixBidder.java | 14 +- .../bidder/dxkulture/DxKultureBidder.java | 21 +- .../bidder/eplanning/EplanningBidder.java | 39 ++-- .../server/bidder/flipp/FlippBidder.java | 23 +-- .../server/bidder/mobkoi/MobkoiBidder.java | 16 +- .../server/bidder/nexx360/Nexx360Bidder.java | 21 +- .../server/bidder/rubicon/RubiconBidder.java | 36 +++- .../smartadserver/SmartadserverBidder.java | 31 ++- .../server/bidder/sspbc/SspbcBidder.java | 14 +- .../server/bidder/tappx/TappxBidder.java | 35 ++-- .../bidder/videobyte/VideobyteBidder.java | 34 ++-- .../server/bidder/yandex/YandexBidder.java | 29 +-- .../bidder/yieldlab/YieldlabBidder.java | 101 ++++------ .../server/floors/PriceFloorFetcher.java | 4 +- .../settings/HttpApplicationSettings.java | 65 ++++--- .../java/org/prebid/server/util/HttpUtil.java | 14 ++ .../adgeneration/AdgenerationBidderTest.java | 181 +++++++++++++++--- .../bidder/adnuntius/AdnuntiusBidderTest.java | 171 +++++++---------- .../bidder/adocean/AdoceanBidderTest.java | 145 +++++++++++--- .../bidder/bluesea/BlueSeaBidderTest.java | 17 +- .../bidder/dxkulture/DxKultureBidderTest.java | 8 +- .../bidder/eplanning/EplanningBidderTest.java | 147 +++++++++----- .../bidder/nexx360/Nexx360BidderTest.java | 11 +- .../SmartadserverBidderTest.java | 4 +- .../server/bidder/tappx/TappxBidderTest.java | 59 +++--- .../bidder/videobyte/VideobyteBidderTest.java | 31 ++- .../bidder/yandex/YandexBidderTest.java | 12 +- .../bidder/yieldlab/YieldlabBidderTest.java | 169 ++++++++-------- 37 files changed, 1014 insertions(+), 729 deletions(-) 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 979dfe58487..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 @@ -4,11 +4,11 @@ import com.scientiamobile.wurfl.core.WURFLEngine; import com.scientiamobile.wurfl.core.cache.LRUMapCacheProvider; import com.scientiamobile.wurfl.core.cache.NullCacheProvider; -import org.apache.hc.core5.net.URIBuilder; 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; @@ -57,8 +57,8 @@ private static String wurflFilePathFromConfig(WURFLDeviceDetectionConfigProperti public static String extractWURFLFileName(String wurflSnapshotUrl) { try { - final URI uri = new URIBuilder(wurflSnapshotUrl).build(); - 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/pom.xml b/pom.xml index 24639858d4f..416fe4aefc1 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,10 +114,6 @@ org.apache.commons commons-math3 - - org.apache.httpcomponents.client5 - httpclient5 - com.github.seancfoley ipaddress diff --git a/src/main/java/org/prebid/server/auction/IpAddressHelper.java b/src/main/java/org/prebid/server/auction/IpAddressHelper.java index 8032f950548..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.hc.core5.net.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 9af347f7928..cf30b294947 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adgeneration.model.AdgenerationResponse; import org.prebid.server.bidder.model.BidderBid; @@ -32,9 +33,10 @@ import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; -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; @@ -96,47 +98,43 @@ 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 UriTemplate uriTemplate = UriTemplate.of(endpointUrl + + (endpointUrl.contains("?") ? "{&queryParams*}" : "{?queryParams*}")); + 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 uriTemplate.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/adnuntius/AdnuntiusBidder.java b/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java index b13aba3a6ff..1a282fb3b17 100644 --- a/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java +++ b/src/main/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidder.java @@ -17,12 +17,13 @@ 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.ListUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusMetaData; import org.prebid.server.bidder.adnuntius.model.request.AdnuntiusNativeRequest; @@ -59,7 +60,6 @@ import org.prebid.server.util.ObjectUtil; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.time.Clock; import java.time.OffsetDateTime; import java.util.ArrayList; @@ -248,35 +248,33 @@ 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 String url = StringUtils.isNotBlank(gdpr) ? euEndpoint : endpointUrl; - if (url == null) { - throw new PreBidException("an EU endpoint is required but invalid"); - } + if (url == 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 UriTemplate.of(url + (url.contains("?") ? "{&queryParams*}" : "{?queryParams*}")) + .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 78e25b3e2a7..21cfbda8b51 100644 --- a/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java +++ b/src/main/java/org/prebid/server/bidder/adocean/AdoceanBidder.java @@ -12,13 +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.hc.core5.http.NameValuePair; -import org.apache.hc.core5.http.message.BasicNameValuePair; -import org.apache.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.adocean.model.AdoceanResponseAdUnit; import org.prebid.server.bidder.model.BidderBid; @@ -36,7 +35,8 @@ import java.io.IOException; import java.math.BigDecimal; -import java.net.URISyntaxException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -112,40 +112,41 @@ 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) { + for (HttpRequest request : httpRequests) { try { - final URIBuilder uriBuilder = new URIBuilder(request.getUri()); - final List queryParams = uriBuilder.getQueryParams(); + final URL url = HttpUtil.parseUrl(request.getUri()); + final Map> queryParams = HttpUtil.parseQuery(url.getQuery()); + final String masterId = queryParams.get("id").stream().findFirst().orElse(null); - final String masterId = queryParams.stream() - .filter(param -> "id".equals(param.getName())) - .findFirst() - .map(NameValuePair::getValue) - .orElse(null); + final Map params = new HashMap<>(); if (masterId != null && masterId.equals(extImpAdocean.getMasterId())) { - final boolean isExistingSlaveId = queryParams.stream() - .filter(param -> "aid".equals(param.getName())) - .map(param -> param.getValue().split(":")[0]) + final boolean isExistingSlaveId = queryParams.get("aid").stream() + .map(param -> param.split(":")[0]) .anyMatch(slaveId -> slaveId.equals(extImpAdocean.getSlaveId())); + if (isExistingSlaveId) { continue; } - queryParams.add(new BasicNameValuePair("aid", extImpAdocean.getSlaveId() + ":" + impid)); + params.put("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))); + params.put("aosspsizes", String.join("-", sizeValues)); } - uriBuilder.setParameters(queryParams); - final String url = uriBuilder.toString(); - if (url.length() < MAX_URI_LENGTH) { + final String finalUrl = UriTemplate.of(url + "{?params*}") + .expandToString(Variables.variables().set("params", params)); + if (finalUrl.length() < MAX_URI_LENGTH) { final HttpRequest updatedRequest = HttpRequest.builder() .method(HttpMethod.GET) - .uri(url) + .uri(finalUrl) .headers(request.getHeaders()) .build(); httpRequests.remove(request); @@ -153,7 +154,7 @@ private boolean addRequestAndCheckIfDuplicates(List> httpReque return true; } } - } catch (URISyntaxException e) { + } catch (MalformedURLException e) { throw new PreBidException(e.getMessage()); } } @@ -203,59 +204,67 @@ private String buildUrl(String impId, ExtImpAdocean extImpAdocean, String consen final Integer test = bidRequest.getTest(); final String resolvedUrl = resolveEndpointUrl(extImpAdocean, test); - final URIBuilder uriBuilder; + final UriTemplate uriTemplate; try { - uriBuilder = new URIBuilder(resolvedUrl); - } catch (URISyntaxException e) { + final String paramsTemplate = resolvedUrl.contains("?") ? "{&queryParams*}" : "{?queryParams*}"; + uriTemplate = UriTemplate.of(resolvedUrl + paramsTemplate); + } catch (IllegalArgumentException 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); + final Map queryParams = new HashMap<>(); + + 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 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(); + return uriTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); + } + + private static void addParameterIfNotEmpty(Map queryParams, String parameter, String value) { + if (StringUtils.isNotEmpty(value)) { + queryParams.put(parameter, value); + } } private String resolveEndpointUrl(ExtImpAdocean extImpAdocean, Integer test) { @@ -295,16 +304,15 @@ private static MultiMap getHeaders(BidRequest request) { @Override public Result> makeBids(BidderCall httpCall, BidRequest bidRequest) { - final List params; + final Map> params; try { - params = new URIBuilder(httpCall.getRequest().getUri()).getQueryParams(); - } 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; 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 9e01bf82d7d..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.hc.core5.net.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 246849dc429..29e1175e6bc 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.hc.core5.net.URIBuilder; import org.prebid.server.auction.model.Endpoint; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.appnexus.proto.AppnexusBidExt; @@ -56,7 +57,6 @@ import jakarta.validation.ValidationException; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -309,9 +309,10 @@ private String readKeywordsFromArray(JsonNode keywords) { private String makeUrl(String member) { try { return member != null - ? new URIBuilder(endpointUrl).addParameter("member_id", member).build().toString() + ? UriTemplate.of(endpointUrl + (endpointUrl.contains("?") ? "{&member_id}" : "{?member_id}")) + .expandToString(Variables.variables().set("member_id", member)) : endpointUrl; - } catch (URISyntaxException e) { + } catch (IllegalArgumentException e) { throw new PreBidException(e.getMessage()); } } 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 d4a0a0b5831..26d53ca6dc5 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -25,11 +26,11 @@ 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; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; @@ -78,17 +79,14 @@ 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 UriTemplate uriTemplate = UriTemplate.of(endpointUrl + + (endpointUrl.contains("?") ? "{&queryParams*}" : "{?queryParams*}")); + + final Map queryParams = Map.of( + "pubid", extImpBlueSea.getPubId(), + "token", extImpBlueSea.getToken()); - return uriBuilder - .addParameter("pubid", extImpBlueSea.getPubId()) - .addParameter("token", extImpBlueSea.getToken()) - .toString(); + return uriTemplate.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 0d041911fe1..089e3f7ca81 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -37,7 +38,6 @@ import org.prebid.server.util.HttpUtil; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -112,14 +112,8 @@ private String getOptimalEndpointUrl(BidRequest request) { return endpointUrl; } - try { - return new URIBuilder(endpointUrl) - .addParameter("dc", dataCenterCode.get()) - .build() - .toString(); - } catch (URISyntaxException e) { - throw new PreBidException(e.getMessage()); - } + return UriTemplate.of(endpointUrl + (endpointUrl.contains("?") ? "{&dc}" : "{?dc}")) + .expandToString(Variables.variables().set("dc", dataCenterCode.get())); } 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 8a484b2829c..2688adf0e2f 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -27,11 +28,11 @@ import org.prebid.server.util.HttpUtil; import org.prebid.server.util.ObjectUtil; -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 { @@ -78,18 +79,14 @@ 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())); - } + final UriTemplate uriTemplate = UriTemplate.of(endpointUrl + + (endpointUrl.contains("?") ? "{&queryParams*}" : "{?queryParams*}")); - 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 uriTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } private static MultiMap resolveHeaders(BidRequest bidRequest) { 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 a11ef764320..d2ab5c1e6ae 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.eplanning.model.CleanStepName; import org.prebid.server.bidder.eplanning.model.HbResponse; @@ -40,7 +41,6 @@ import java.math.BigDecimal; import java.net.MalformedURLException; -import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; @@ -232,56 +232,51 @@ 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 UriTemplate uriTemplate = UriTemplate.of(endpointUrl + "{/path*}{?queryParams*}"); - 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 uriTemplate.expandToString(Variables.variables().set("path", path).set("queryParams", queryParams)); } private static URL parseUrl(String url) { 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 a9c383171c3..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.hc.core5.http.NameValuePair; -import org.apache.hc.core5.net.URIBuilder; 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.net.URISyntaxException; +import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -172,17 +170,14 @@ private static String resolveContentCode(Site site, ExtImpFlipp extImp) { return null; } - try { - return new URIBuilder(pageUrl) - .getQueryParams() - .stream() - .filter(nameValuePair -> nameValuePair.getName().contains("flipp-content-code")) - .map(NameValuePair::getValue) - .findFirst() - .orElse(null); - } catch (URISyntaxException e) { - 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); } private static List resolveKeywords(BidRequest bidRequest) { diff --git a/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java b/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java index f7101fe427f..a3aadd1bc88 100644 --- a/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java +++ b/src/main/java/org/prebid/server/bidder/mobkoi/MobkoiBidder.java @@ -6,9 +6,10 @@ import com.iab.openrtb.request.User; 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -25,7 +26,8 @@ import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; -import java.net.URISyntaxException; +import java.net.MalformedURLException; +import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -97,11 +99,11 @@ private String resolveEndpoint(String customUri) { return endpointUrl; } try { - return new URIBuilder(customUri) - .setPath("/bid") - .clearParameters() - .toString(); - } catch (IllegalArgumentException | URISyntaxException e) { + final URL url = HttpUtil.parseUrl(customUri); + final String origin = url.getProtocol() + "://" + url.getAuthority(); + return UriTemplate.of("{+origin}/bid") + .expandToString(Variables.variables().set("origin", origin)); + } catch (IllegalArgumentException | MalformedURLException e) { return endpointUrl; } } 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 90a696ac4e2..27107065847 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -26,11 +27,12 @@ import org.prebid.server.util.HttpUtil; 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; @@ -97,21 +99,18 @@ 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 UriTemplate uriTemplate = UriTemplate.of(endpointUrl + + (endpointUrl.contains("?") ? "{&queryParams*}" : "{?queryParams*}")); + 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 uriTemplate.expandToString(Variables.variables().set("queryParams", queryParams)); } @Override 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 4fd8e7ca741..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.hc.core5.net.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 e6a72a06b2a..3e0a8379bba 100644 --- a/src/main/java/org/prebid/server/bidder/smartadserver/SmartadserverBidder.java +++ b/src/main/java/org/prebid/server/bidder/smartadserver/SmartadserverBidder.java @@ -8,9 +8,10 @@ import com.iab.openrtb.request.Site; 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -26,8 +27,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; @@ -120,21 +121,19 @@ private static Publisher modifyPublisher(Publisher publisher, Integer networkId) } private String makeUrl(boolean isProgrammaticGuaranteed) { - final String url = isProgrammaticGuaranteed ? secondaryEndpointUrl : endpointUrl; - try { - final URI uri = new URIBuilder(url).build(); - 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"); - } + final String endpoint = isProgrammaticGuaranteed ? secondaryEndpointUrl : endpointUrl; + final URL url; - return uriBuilder.toString(); - } catch (URISyntaxException e) { - throw new PreBidException("Malformed URL: %s.".formatted(url)); + try { + url = HttpUtil.parseUrl(endpoint); + } catch (MalformedURLException e) { + throw new PreBidException("Malformed URL: %s.".formatted(endpoint)); } + final List paths = isProgrammaticGuaranteed ? Collections.singletonList("ortb") : List.of("api", "bid"); + final String query = isProgrammaticGuaranteed ? "?" + url.getQuery() : "{?callerId}"; + final String baseUrl = url.getProtocol() + "://" + url.getAuthority() + StringUtils.removeEnd(url.getPath(), "/"); + return UriTemplate.of(baseUrl + "{/path*}" + query).expandToString( + Variables.variables().set("path", paths).set("callerId", isProgrammaticGuaranteed ? null : "5")); } @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 0b0342cb541..26587e609bf 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -20,7 +21,6 @@ import org.prebid.server.util.BidderUtil; import org.prebid.server.util.HttpUtil; -import java.net.URISyntaxException; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -56,14 +56,8 @@ private HttpRequest createHttpRequest(BidRequest request) { } 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)); - } + return UriTemplate.of(endpointUrl + (endpointUrl.contains("?") ? "{&bdver}" : "{?bdver}")) + .expandToString(Variables.variables().set("bdver", 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 e51dc2f4ef6..78c5068e1b1 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.hc.core5.net.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; @@ -25,12 +26,13 @@ import org.prebid.server.util.BidderUtil; 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; @@ -92,27 +94,22 @@ private String resolveUrl(ExtImpTappx extImpTappx, Integer test) { final boolean isNewEndpoint = NEW_ENDPOINT_PATTERN.matcher(subdomain).matches(); 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))); - } + final UriTemplate uriTemplate = UriTemplate.of(baseUri + + (isNewEndpoint ? StringUtils.EMPTY : "{/subdomain}") + + "{?queryParams*}"); + final Map queryParams = new HashMap<>(); - uriBuilder.addParameter("tappxkey", extImpTappx.getTappxkey()); - uriBuilder.addParameter("v", VERSION); - uriBuilder.addParameter("type_cnn", TYPE_CNN); + 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(); + return uriTemplate.expandToString(Variables.variables() + .set("subdomain", subdomain) + .set("queryParams", queryParams)); } private String resolveNewHost(String subdomain) { 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 d3f2c05dc00..6f5541aee2c 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -25,11 +26,12 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; -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 { @@ -86,26 +88,22 @@ 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 UriTemplate uriTemplate = UriTemplate.of(endpointUrl + + (endpointUrl.contains("?") ? "{&queryParams*}" : "{?queryParams*}")); + 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 uriTemplate.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 5d914fe6651..cfa7e7f2fa5 100644 --- a/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java +++ b/src/main/java/org/prebid/server/bidder/yandex/YandexBidder.java @@ -12,9 +12,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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -29,11 +30,12 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.util.HttpUtil; -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; @@ -138,21 +140,20 @@ private String modifyUrl(ExtImpYandex extImpYandex, String referer, String curre 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 UriTemplate uriTemplate = UriTemplate.of(resolvedUrl + + (resolvedUrl.contains("?") ? "{&queryParams*}" : "{?queryParams*}")); + 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 uriTemplate.expandToString(Variables.variables().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 b799147c15a..bef24f602c0 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.hc.core5.net.URIBuilder; import org.prebid.server.bidder.Bidder; import org.prebid.server.bidder.model.BidderBid; import org.prebid.server.bidder.model.BidderCall; @@ -47,7 +48,6 @@ import org.prebid.server.util.HttpUtil; import java.math.BigDecimal; -import java.net.URISyntaxException; import java.time.Clock; import java.util.ArrayList; import java.util.Calendar; @@ -153,73 +153,61 @@ private ExtImpYieldlab parseImpExt(Imp imp) { } private String makeUrl(ExtImpYieldlab extImpYieldlab, BidRequest request, Map extImps) { - final String updatedPath = "%s/%s".formatted(endpointUrl, extImpYieldlab.getAdslotId()); + final UriTemplate uriTemplate = UriTemplate.of(endpointUrl + "{/adslotId}{?queryParams*}"); + 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 uriTemplate.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 +236,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 UriTemplate.of("{?queryParams*}") + .expandToString(Variables.variables().set("queryParams", extImpYieldlab.getTargeting())) + .replace("?", StringUtils.EMPTY); } private static String getGdprParameter(Regs regs) { @@ -527,29 +511,26 @@ 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 UriTemplate.of("https://ad.yieldlab.net/d{/path*}{?queryParams*}") + .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/floors/PriceFloorFetcher.java b/src/main/java/org/prebid/server/floors/PriceFloorFetcher.java index 30c2e90c6f4..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.hc.core5.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/settings/HttpApplicationSettings.java b/src/main/java/org/prebid/server/settings/HttpApplicationSettings.java index 2df2a84a865..8d213076170 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.hc.core5.net.URIBuilder; import org.prebid.server.exception.PreBidException; import org.prebid.server.execution.timeout.Timeout; import org.prebid.server.json.DecodeException; @@ -27,7 +28,6 @@ import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; -import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -127,19 +127,19 @@ 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))); - } + if (accountIds.isEmpty()) { + return endpoint; + } + + if (isRfc3986Compatible) { + String url = endpoint; + for (String id : accountIds) { + url = appendQuery(url, Map.of("account-id", id)); } - return uriBuilder.build().toString(); - } catch (URISyntaxException e) { - throw new PreBidException("URL %s has bad syntax".formatted(endpoint)); + return url; } + + return appendQuery(endpoint, Map.of("account-ids", "[\"%s\"]".formatted(joinIds(accountIds)))); } private Set processAccountsResponse(HttpClientResponse httpClientResponse, Set accountIds) { @@ -232,26 +232,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; + } + + if (isRfc3986Compatible) { + String url = endpoint; if (!requestIds.isEmpty()) { - if (isRfc3986Compatible) { - requestIds.forEach(requestId -> uriBuilder.addParameter("request-id", requestId)); - } else { - uriBuilder.addParameter("request-ids", "[\"%s\"]".formatted(joinIds(requestIds))); + for (String id : requestIds) { + url = appendQuery(url, Map.of("request-id", id)); } } if (!impIds.isEmpty()) { - if (isRfc3986Compatible) { - impIds.forEach(impId -> uriBuilder.addParameter("imp-id", impId)); - } else { - uriBuilder.addParameter("imp-ids", "[\"%s\"]".formatted(joinIds(impIds))); + for (String id : requestIds) { + url = appendQuery(url, Map.of("imp-id", id)); } } - return uriBuilder.build().toString(); - } catch (URISyntaxException e) { - throw new PreBidException("URL %s has bad syntax".formatted(endpoint)); + return url; + } + + final Map queryParams = new HashMap<>(); + if (!requestIds.isEmpty()) { + queryParams.put("request-ids", "[\"%s\"]".formatted(joinIds(requestIds))); } + if (!impIds.isEmpty()) { + queryParams.put("imp-ids", "[\"%s\"]".formatted(joinIds(impIds))); + } + return appendQuery(endpoint, queryParams); } private StoredDataResult processStoredDataResponse(HttpClientResponse httpClientResponse, @@ -390,4 +397,10 @@ private PreBidException makeFailedCategoryFetchException(String url, String reas private static String joinIds(Set ids) { return String.join("\",\"", ids); } + + private static String appendQuery(String url, Map params) { + final String tpl = url + (url.contains("?") ? "{&queryParams*}" : "{?queryParams*}"); + return UriTemplate.of(tpl) + .expandToString(Variables.variables().set("queryParams", params)); + } } diff --git a/src/main/java/org/prebid/server/util/HttpUtil.java b/src/main/java/org/prebid/server/util/HttpUtil.java index 3e3e075f0c6..f65522f3456 100644 --- a/src/main/java/org/prebid/server/util/HttpUtil.java +++ b/src/main/java/org/prebid/server/util/HttpUtil.java @@ -116,6 +116,20 @@ public static URL parseUrl(String url) throws MalformedURLException { } } + 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 macros private static boolean containsMacros(String url) { return StringUtils.contains(url, MACROS_OPEN) && StringUtils.contains(url, MACROS_CLOSE); 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/adnuntius/AdnuntiusBidderTest.java b/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java index 91166391532..970c9258dc0 100644 --- a/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adnuntius/AdnuntiusBidderTest.java @@ -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 ff6c740a6da..6d14c00735f 100644 --- a/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/adocean/AdoceanBidderTest.java @@ -177,14 +177,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" - + "~300x250_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~577x333"); + .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 +264,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 +309,25 @@ 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~300x250_600x320&aid=slaveId2%3Ai2-test&aosspsizes=slaveId2~577x333"); + .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("aosspsizes=slaveId~300x250_600x320"); + assertThat(url).contains("gdpr_consent=consent"); + assertThat(url).contains("id=masterId"); + assertThat(url).contains("aid=slaveId%3Aao-test"); + 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 +498,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 +541,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 +585,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/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/eplanning/EplanningBidderTest.java b/src/test/java/org/prebid/server/bidder/eplanning/EplanningBidderTest.java index 8b94f14c737..0c7d65f649b 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/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/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/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 dbc3cf23856..fd13bc0a306 100644 --- a/src/test/java/org/prebid/server/bidder/yandex/YandexBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/yandex/YandexBidderTest.java @@ -404,9 +404,15 @@ public void makeHttpRequestsShouldCreateCorrectURL() { // then assertThat(result.getErrors()).isEmpty(); - assertThat(result.getValue()).extracting(HttpRequest::getUri) - .containsExactly("https://test.endpoint.com/?" - + "target-ref=https%3A%2F%2Fdomain.com%2F&ssp-cur=EUR"); + assertThat(result.getValue()) + .first() + .extracting(HttpRequest::getUri) + .satisfies(url -> { + assertThat(url).startsWith("https://test.endpoint.com/"); + assertThat(url).contains("target-ref=https%3A%2F%2Fdomain.com%2F"); + assertThat(url).contains("ssp-cur=EUR"); + }); + } 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 2bf9b30d039..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%2520request%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~1_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~1_2_3~~testDomain2~4_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);