|
10 | 10 | import io.vertx.core.http.HttpServerRequest; |
11 | 11 | import io.vertx.core.http.HttpServerResponse; |
12 | 12 | import io.vertx.ext.web.RoutingContext; |
13 | | -import org.apache.commons.collections4.CollectionUtils; |
14 | 13 | import org.apache.commons.lang3.BooleanUtils; |
15 | 14 | import org.apache.commons.lang3.ObjectUtils; |
16 | 15 | import org.apache.commons.lang3.StringUtils; |
|
55 | 54 | import org.prebid.server.settings.model.AccountGdprConfig; |
56 | 55 | import org.prebid.server.settings.model.AccountPrivacyConfig; |
57 | 56 | import org.prebid.server.util.HttpUtil; |
| 57 | +import org.prebid.server.util.StreamUtil; |
58 | 58 | import org.prebid.server.vertx.verticles.server.HttpEndpoint; |
59 | 59 | import org.prebid.server.vertx.verticles.server.application.ApplicationResource; |
60 | 60 |
|
|
65 | 65 | import java.util.Optional; |
66 | 66 | import java.util.function.Consumer; |
67 | 67 | import java.util.function.Function; |
68 | | -import java.util.function.Supplier; |
| 68 | +import java.util.function.Predicate; |
69 | 69 | import java.util.stream.Collectors; |
70 | | -import java.util.stream.Stream; |
71 | 70 |
|
72 | 71 | public class SetuidHandler implements ApplicationResource { |
73 | 72 |
|
@@ -113,48 +112,54 @@ public SetuidHandler(long defaultTimeout, |
113 | 112 | this.analyticsDelegator = Objects.requireNonNull(analyticsDelegator); |
114 | 113 | this.metrics = Objects.requireNonNull(metrics); |
115 | 114 | this.timeoutFactory = Objects.requireNonNull(timeoutFactory); |
116 | | - this.cookieNameToBidderAndSyncType = collectMap(bidderCatalog); |
| 115 | + this.cookieNameToBidderAndSyncType = collectUsersyncers(bidderCatalog); |
117 | 116 | } |
118 | 117 |
|
119 | | - private static Map<String, Pair<String, UsersyncMethodType>> collectMap(BidderCatalog bidderCatalog) { |
| 118 | + private static Map<String, Pair<String, UsersyncMethodType>> collectUsersyncers(BidderCatalog bidderCatalog) { |
| 119 | + validateUsersyncersDuplicates(bidderCatalog); |
120 | 120 |
|
121 | | - final Supplier<Stream<Pair<String, Usersyncer>>> usersyncers = () -> bidderCatalog.names() |
122 | | - .stream() |
123 | | - .filter(bidderCatalog::isActive) |
124 | | - .filter(bidderName -> bidderCatalog.resolveBaseBidder(bidderName).equals(bidderName)) |
| 121 | + return bidderCatalog.usersyncReadyBidders().stream() |
| 122 | + .filter(bidderName -> !isAliasWithRootCookieFamilyName(bidderCatalog, bidderName)) |
| 123 | + .filter(StreamUtil.distinctBy(bidderCatalog::cookieFamilyName)) |
125 | 124 | .map(bidderName -> bidderCatalog.usersyncerByName(bidderName) |
126 | 125 | .map(usersyncer -> Pair.of(bidderName, usersyncer))) |
127 | | - .flatMap(Optional::stream); |
128 | | - |
129 | | - validateUsersyncers(usersyncers.get().map(Pair::getRight)); |
130 | | - |
131 | | - return usersyncers.get() |
| 126 | + .flatMap(Optional::stream) |
132 | 127 | .collect(Collectors.toMap( |
133 | 128 | pair -> pair.getRight().getCookieFamilyName(), |
134 | 129 | pair -> Pair.of(pair.getLeft(), preferredUserSyncType(pair.getRight())))); |
135 | 130 | } |
136 | 131 |
|
137 | | - private static UsersyncMethodType preferredUserSyncType(Usersyncer usersyncer) { |
138 | | - // when usersyncer is present, it will contain at least one method |
139 | | - return ObjectUtils.firstNonNull(usersyncer.getIframe(), usersyncer.getRedirect()).getType(); |
140 | | - } |
141 | | - |
142 | | - private static void validateUsersyncers(Stream<Usersyncer> usersyncers) { |
143 | | - final List<String> cookieFamilyNameDuplicates = usersyncers.map(Usersyncer::getCookieFamilyName) |
144 | | - .collect(Collectors.groupingBy(Function.identity(), Collectors.counting())) |
145 | | - .entrySet() |
146 | | - .stream() |
147 | | - .filter(name -> name.getValue() > 1) |
148 | | - .map(Map.Entry::getKey) |
| 132 | + private static void validateUsersyncersDuplicates(BidderCatalog bidderCatalog) { |
| 133 | + final List<String> duplicatedCookieFamilyNames = bidderCatalog.usersyncReadyBidders().stream() |
| 134 | + .filter(bidderName -> !isAliasWithRootCookieFamilyName(bidderCatalog, bidderName)) |
| 135 | + .map(bidderCatalog::usersyncerByName) |
| 136 | + .flatMap(Optional::stream) |
| 137 | + .map(Usersyncer::getCookieFamilyName) |
| 138 | + .filter(Predicate.not(StreamUtil.distinctBy(Function.identity()))) |
149 | 139 | .distinct() |
150 | 140 | .toList(); |
151 | | - if (CollectionUtils.isNotEmpty(cookieFamilyNameDuplicates)) { |
| 141 | + |
| 142 | + if (!duplicatedCookieFamilyNames.isEmpty()) { |
152 | 143 | throw new IllegalArgumentException( |
153 | 144 | "Duplicated \"cookie-family-name\" found, values: " |
154 | | - + String.join(", ", cookieFamilyNameDuplicates)); |
| 145 | + + String.join(", ", duplicatedCookieFamilyNames)); |
155 | 146 | } |
156 | 147 | } |
157 | 148 |
|
| 149 | + private static boolean isAliasWithRootCookieFamilyName(BidderCatalog bidderCatalog, String bidder) { |
| 150 | + final String bidderCookieFamilyName = bidderCatalog.cookieFamilyName(bidder).orElse(StringUtils.EMPTY); |
| 151 | + final String parentCookieFamilyName = |
| 152 | + bidderCatalog.cookieFamilyName(bidderCatalog.resolveBaseBidder(bidder)).orElse(null); |
| 153 | + |
| 154 | + return bidderCatalog.isAlias(bidder) |
| 155 | + && parentCookieFamilyName != null |
| 156 | + && parentCookieFamilyName.equals(bidderCookieFamilyName); |
| 157 | + } |
| 158 | + |
| 159 | + private static UsersyncMethodType preferredUserSyncType(Usersyncer usersyncer) { |
| 160 | + return ObjectUtils.firstNonNull(usersyncer.getIframe(), usersyncer.getRedirect()).getType(); |
| 161 | + } |
| 162 | + |
158 | 163 | @Override |
159 | 164 | public List<HttpEndpoint> endpoints() { |
160 | 165 | return Collections.singletonList(HttpEndpoint.of(HttpMethod.GET, Endpoint.setuid.value())); |
@@ -232,9 +237,9 @@ private void handleSetuidContextResult(AsyncResult<SetuidContext> setuidContextR |
232 | 237 | final String bidderName = cookieNameToBidderAndSyncType.get(bidderCookieFamily).getLeft(); |
233 | 238 |
|
234 | 239 | Future.all( |
235 | | - tcfDefinerService.isAllowedForHostVendorId(tcfContext), |
236 | | - tcfDefinerService.resultForBidderNames( |
237 | | - Collections.singleton(bidderName), tcfContext, accountGdprConfig)) |
| 240 | + tcfDefinerService.isAllowedForHostVendorId(tcfContext), |
| 241 | + tcfDefinerService.resultForBidderNames( |
| 242 | + Collections.singleton(bidderName), tcfContext, accountGdprConfig)) |
238 | 243 | .onComplete(hostTcfResponseResult -> respondByTcfResponse( |
239 | 244 | hostTcfResponseResult, |
240 | 245 | bidderName, |
|
0 commit comments