From c527b8635f478f5d6d946cd7dcaf31a328f316d5 Mon Sep 17 00:00:00 2001 From: Dahale Aditya Date: Wed, 30 Sep 2026 09:46:27 +0530 Subject: [PATCH 1/3] pubmatic: return error when banner has no sizes and no format Port of Go fix from prebid-server#5008 (prebid/prebid-server#5008). In Go, assignBannerSize() returns a BadInput error when banner.Format is empty and no explicit W/H are present, preventing a panic. The Java implementation had the same logical gap: assignSizesIfMissing() silently returned the banner unchanged when format was empty, forwarding a dimensionless banner to PubMatic. This commit: - Renames assignSizesIfMissing -> fillBannerSizeFromFormat to clarify its role (only copies dims from Format[0]; does not validate) - Adds a post-enrichment check in modifyImp() that throws PreBidException when the resulting banner still has no W/H after both fillBannerSizeFromFormat and enrichWithAdSlotParameters have run - This preserves the valid case where adSlot (e.g. slot@300x250) supplies dimensions even when format is empty Closes #5002 (see also prebid/prebid-server#5002) --- .../bidder/pubmatic/PubmaticBidder.java | 18 ++++++-- .../bidder/pubmatic/PubmaticBidderTest.java | 44 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java index 857f212a209..201c68b0b5d 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -272,7 +272,7 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage final ObjectNode newExt = makeKeywords(impExt); final Imp.ImpBuilder impBuilder = imp.toBuilder() - .banner(banner != null ? assignSizesIfMissing(banner) : null) + .banner(banner != null ? fillBannerSizeFromFormat(banner) : null) .audio(null) .bidfloor(resolveBidFloor(impExtBidder.getKadfloor(), imp.getBidfloor())) .displaymanager(StringUtils.firstNonBlank(imp.getDisplaymanager(), displayManager)) @@ -281,12 +281,22 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage enrichWithAdSlotParameters(impBuilder, impExtBidder.getAdSlot(), banner); - return impBuilder.build(); + final Imp result = impBuilder.build(); + final Banner resultBanner = result.getBanner(); + if (resultBanner != null && resultBanner.getW() == null && resultBanner.getH() == null) { + throw new PreBidException("No sizes provided for Banner"); + } + + return result; } - private static Banner assignSizesIfMissing(Banner banner) { + private static Banner fillBannerSizeFromFormat(Banner banner) { final List format = banner.getFormat(); - if ((banner.getW() != null && banner.getH() != null) || CollectionUtils.isEmpty(format)) { + if (banner.getW() != null && banner.getH() != null) { + return banner; + } + + if (CollectionUtils.isEmpty(format)) { return banner; } diff --git a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java index 0d7b50e89a9..473f6770b22 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java @@ -587,6 +587,50 @@ public void makeHttpRequestsShouldSetBannerWidthAndHeightFromFormatIfMissedOrigi .containsExactly(100); } + @Test + public void makeHttpRequestsShouldReturnErrorIfBannerHasNoSizesAndNoFormat() { + // given + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder.banner(Banner.builder().build()), + extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()) + .containsExactly(BidderError.badInput("No sizes provided for Banner")); + assertThat(result.getValue()).isEmpty(); + } + + @Test + public void makeHttpRequestsShouldAllowBannerWithNoFormatWhenAdSlotProvidesSize() { + // given + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder.banner(Banner.builder().build())); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + // Default givenBidRequest adSlot is "slot@300x250", so dimensions come from adSlot + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .extracting(Banner::getW) + .containsExactly(300); + assertThat(result.getValue()) + .extracting(HttpRequest::getPayload) + .flatExtracting(BidRequest::getImp) + .extracting(Imp::getBanner) + .extracting(Banner::getH) + .containsExactly(250); + } + + + @Test public void makeHttpRequestsShouldSetTagIdForBannerImpsWithSymbolsFromAdSlotBeforeAtSign() { // given From 6eccd098426e6c59a5573dfb5ed2ac8c268d18a6 Mon Sep 17 00:00:00 2001 From: Dahale Aditya Date: Wed, 30 Sep 2026 23:06:24 +0530 Subject: [PATCH 2/3] pubmatic: exempt interstitial banners from no-sizes check Per OpenRTB 2.6 spec, banner sizes are optional for interstitial impressions (imp.instl=1), as interstitials fill the full screen. The previous fix incorrectly discarded these legitimate impressions. Skip the no-sizes PreBidException when the imp has instl=1, even if both W/H are absent and format is empty. --- .../bidder/pubmatic/PubmaticBidder.java | 4 +++- .../bidder/pubmatic/PubmaticBidderTest.java | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java index 201c68b0b5d..79fdc980cf4 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -283,7 +283,9 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage final Imp result = impBuilder.build(); final Banner resultBanner = result.getBanner(); - if (resultBanner != null && resultBanner.getW() == null && resultBanner.getH() == null) { + // Per OpenRTB 2.6 spec, banner sizes are optional for interstitial impressions. + final boolean isInterstitial = Objects.equals(result.getInstl(), 1); + if (resultBanner != null && resultBanner.getW() == null && resultBanner.getH() == null && !isInterstitial) { throw new PreBidException("No sizes provided for Banner"); } diff --git a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java index 473f6770b22..448b6b8f595 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java @@ -589,7 +589,7 @@ public void makeHttpRequestsShouldSetBannerWidthAndHeightFromFormatIfMissedOrigi @Test public void makeHttpRequestsShouldReturnErrorIfBannerHasNoSizesAndNoFormat() { - // given + // given - non-interstitial banner with no W/H and no format: should error final BidRequest bidRequest = givenBidRequest( impBuilder -> impBuilder.banner(Banner.builder().build()), extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot")); @@ -603,6 +603,23 @@ public void makeHttpRequestsShouldReturnErrorIfBannerHasNoSizesAndNoFormat() { assertThat(result.getValue()).isEmpty(); } + @Test + public void makeHttpRequestsShouldNotReturnErrorForInterstitialBannerWithNoSizes() { + // given - per OpenRTB 2.6, banner sizes are optional for interstitial imps (instl=1) + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder + .instl(1) + .banner(Banner.builder().build()), + extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()).isEmpty(); + assertThat(result.getValue()).hasSize(1); + } + @Test public void makeHttpRequestsShouldAllowBannerWithNoFormatWhenAdSlotProvidesSize() { // given From 6380b2b14907e1feeeba39e5d6d75b81e631db5e Mon Sep 17 00:00:00 2001 From: Dahale Aditya Date: Sun, 4 Oct 2026 18:37:07 +0530 Subject: [PATCH 3/3] pubmatic: reject banner if either width or height is missing Update banner dimensions validation to check if either width or height is missing ((w == null || h == null)), preventing banners with only one dimension set from passing through. --- .../server/bidder/pubmatic/PubmaticBidder.java | 2 +- .../bidder/pubmatic/PubmaticBidderTest.java | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java index 79fdc980cf4..e36c8344504 100644 --- a/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java +++ b/src/main/java/org/prebid/server/bidder/pubmatic/PubmaticBidder.java @@ -285,7 +285,7 @@ private Imp modifyImp(Imp imp, PubmaticBidderImpExt impExt, String displayManage final Banner resultBanner = result.getBanner(); // Per OpenRTB 2.6 spec, banner sizes are optional for interstitial impressions. final boolean isInterstitial = Objects.equals(result.getInstl(), 1); - if (resultBanner != null && resultBanner.getW() == null && resultBanner.getH() == null && !isInterstitial) { + if (resultBanner != null && (resultBanner.getW() == null || resultBanner.getH() == null) && !isInterstitial) { throw new PreBidException("No sizes provided for Banner"); } diff --git a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java index 448b6b8f595..a500c6be8d3 100644 --- a/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java +++ b/src/test/java/org/prebid/server/bidder/pubmatic/PubmaticBidderTest.java @@ -603,6 +603,22 @@ public void makeHttpRequestsShouldReturnErrorIfBannerHasNoSizesAndNoFormat() { assertThat(result.getValue()).isEmpty(); } + @Test + public void makeHttpRequestsShouldReturnErrorIfBannerHasOnlyOneDimensionAndNoFormat() { + // given - banner with w=300, h=null, no format, adSlot without size: should error + final BidRequest bidRequest = givenBidRequest( + impBuilder -> impBuilder.banner(Banner.builder().w(300).build()), + extImpPubmaticBuilder -> extImpPubmaticBuilder.adSlot("slot")); + + // when + final Result>> result = target.makeHttpRequests(bidRequest); + + // then + assertThat(result.getErrors()) + .containsExactly(BidderError.badInput("No sizes provided for Banner")); + assertThat(result.getValue()).isEmpty(); + } + @Test public void makeHttpRequestsShouldNotReturnErrorForInterstitialBannerWithNoSizes() { // given - per OpenRTB 2.6, banner sizes are optional for interstitial imps (instl=1)