6
6
import io .vertx .ext .web .RoutingContext ;
7
7
import org .apache .commons .lang3 .StringUtils ;
8
8
import org .prebid .server .cookie .model .UidWithExpiry ;
9
- import org .prebid .server .cookie .model .UidsCookieUpdateResult ;
10
9
import org .prebid .server .cookie .proto .Uids ;
11
10
import org .prebid .server .json .DecodeException ;
12
11
import org .prebid .server .json .JacksonMapper ;
13
12
import org .prebid .server .log .Logger ;
14
13
import org .prebid .server .log .LoggerFactory ;
15
14
import org .prebid .server .metric .Metrics ;
16
15
import org .prebid .server .model .HttpRequestContext ;
16
+ import org .prebid .server .model .UpdateResult ;
17
17
import org .prebid .server .util .HttpUtil ;
18
18
19
19
import java .time .Duration ;
20
+ import java .util .ArrayList ;
20
21
import java .util .Base64 ;
21
22
import java .util .Collections ;
22
23
import java .util .HashMap ;
23
24
import java .util .Iterator ;
25
+ import java .util .List ;
24
26
import java .util .Map ;
25
27
import java .util .Objects ;
26
28
import java .util .Optional ;
@@ -137,17 +139,19 @@ private Uids parseUids(Map<String, String> cookies) {
137
139
138
140
for (Map .Entry <String , String > cookie : cookies .entrySet ()) {
139
141
final String cookieKey = cookie .getKey ();
140
- if (cookieKey .startsWith (COOKIE_NAME )) {
141
- try {
142
- final Uids parsedUids = mapper . decodeValue (
143
- Buffer . buffer ( Base64 . getUrlDecoder (). decode ( cookie . getValue ())), Uids . class );
144
- if ( parsedUids != null && parsedUids . getUids () != null ) {
145
- parsedUids . getUids (). forEach (( key , value ) -> uids . merge ( key , value , ( newValue , oldValue ) ->
146
- newValue . getExpires (). compareTo ( oldValue . getExpires ()) > 0 ? newValue : oldValue ) );
147
- }
148
- } catch ( IllegalArgumentException | DecodeException e ) {
149
- logger . debug ( "Could not decode or parse {} cookie value {}" , e , COOKIE_NAME , cookie . getValue ( ));
142
+ if (! cookieKey .startsWith (COOKIE_NAME )) {
143
+ continue ;
144
+ }
145
+
146
+ try {
147
+ final Uids parsedUids = mapper . decodeValue (
148
+ Buffer . buffer ( Base64 . getUrlDecoder (). decode ( cookie . getValue ())), Uids . class );
149
+ if ( parsedUids != null && parsedUids . getUids () != null ) {
150
+ parsedUids . getUids (). forEach (( key , value ) -> uids . merge ( key , value , ( newValue , oldValue ) ->
151
+ newValue . getExpires (). compareTo ( oldValue . getExpires ()) > 0 ? newValue : oldValue ));
150
152
}
153
+ } catch (IllegalArgumentException | DecodeException e ) {
154
+ logger .debug ("Could not decode or parse {} cookie value {}" , e , COOKIE_NAME , cookie .getValue ());
151
155
}
152
156
}
153
157
@@ -158,7 +162,7 @@ private Uids parseUids(Map<String, String> cookies) {
158
162
* Creates a {@link Cookie} with 'uids' as a name and encoded JSON string representing supplied {@link UidsCookie}
159
163
* as a value.
160
164
*/
161
- public Cookie makeCookie (String cookieName , UidsCookie uidsCookie ) {
165
+ public Cookie aliveCookie (String cookieName , UidsCookie uidsCookie ) {
162
166
return Cookie
163
167
.cookie (cookieName , Base64 .getUrlEncoder ().encodeToString (uidsCookie .toJson ().getBytes ()))
164
168
.setPath ("/" )
@@ -168,11 +172,11 @@ public Cookie makeCookie(String cookieName, UidsCookie uidsCookie) {
168
172
.setDomain (hostCookieDomain );
169
173
}
170
174
171
- public Cookie makeCookie (UidsCookie uidsCookie ) {
172
- return makeCookie (COOKIE_NAME , uidsCookie );
175
+ public Cookie aliveCookie (UidsCookie uidsCookie ) {
176
+ return aliveCookie (COOKIE_NAME , uidsCookie );
173
177
}
174
178
175
- public Cookie removeCookie (String cookieName ) {
179
+ public Cookie expiredCookie (String cookieName ) {
176
180
return Cookie
177
181
.cookie (cookieName , StringUtils .EMPTY )
178
182
.setPath ("/" )
@@ -245,17 +249,17 @@ private static boolean facebookSentinelOrEmpty(Map.Entry<String, UidWithExpiry>
245
249
/***
246
250
* Removes expired {@link Uids}, updates {@link UidsCookie} with new uid for family name according to priority
247
251
*/
248
- public UidsCookieUpdateResult updateUidsCookie (UidsCookie uidsCookie , String familyName , String uid ) {
252
+ public UpdateResult < UidsCookie > updateUidsCookie (UidsCookie uidsCookie , String familyName , String uid ) {
249
253
final UidsCookie initialCookie = removeExpiredUids (uidsCookie );
250
254
251
255
// At the moment, Facebook calls /setuid with a UID of 0 if the user isn't logged into Facebook.
252
256
// They shouldn't be sending us a sentinel value... but since they are, we're refusing to save that ID.
253
257
if (StringUtils .isBlank (uid ) || UidsCookie .isFacebookSentinel (familyName , uid )) {
254
- return UidsCookieUpdateResult . failure ( splitUids ( initialCookie ) );
258
+ return UpdateResult . unaltered ( initialCookie );
255
259
}
256
260
257
261
final UidsCookie updatedCookie = initialCookie .updateUid (familyName , uid );
258
- return UidsCookieUpdateResult . success ( splitUids ( updatedCookie ) );
262
+ return UpdateResult . updated ( updatedCookie );
259
263
}
260
264
261
265
private static UidsCookie removeExpiredUids (UidsCookie uidsCookie ) {
@@ -271,49 +275,49 @@ private static UidsCookie removeExpiredUids(UidsCookie uidsCookie) {
271
275
return updatedCookie ;
272
276
}
273
277
274
- public Map < String , UidsCookie > splitUids (UidsCookie uidsCookie ) {
278
+ public List < Cookie > splitUidsIntoCookies (UidsCookie uidsCookie ) {
275
279
final Uids cookieUids = uidsCookie .getCookieUids ();
276
280
final Map <String , UidWithExpiry > uids = cookieUids .getUids ();
277
281
final boolean hasOptout = !uidsCookie .allowsSync ();
278
282
279
- final Iterator <String > cookieFamilyIterator = cookieFamilyNamesByDescPriorityAndExpiration (uidsCookie );
280
- final Map < String , UidsCookie > splitCookies = new HashMap <>();
283
+ final Iterator <String > cookieFamilies = cookieFamilyNamesByDescPriorityAndExpiration (uidsCookie );
284
+ final List < Cookie > splitCookies = new ArrayList <>();
281
285
282
286
int uidsIndex = 0 ;
283
287
String nextCookieFamily = null ;
284
288
285
289
while (uidsIndex < numberOfUidCookies ) {
286
290
final String uidsName = uidsIndex == 0 ? COOKIE_NAME : COOKIE_NAME_FORMAT .formatted (uidsIndex + 1 );
287
- final UidsCookie tempUidsCookie = splitCookies .computeIfAbsent (
288
- uidsName ,
289
- key -> new UidsCookie (Uids .builder ().uids (new HashMap <>()).optout (hasOptout ).build (), mapper ));
290
- final Map <String , UidWithExpiry > tempUids = tempUidsCookie .getCookieUids ().getUids ();
291
-
292
- while (nextCookieFamily != null || cookieFamilyIterator .hasNext ()) {
293
- nextCookieFamily = nextCookieFamily == null ? cookieFamilyIterator .next () : nextCookieFamily ;
294
- tempUids .put (nextCookieFamily , uids .get (nextCookieFamily ));
291
+ UidsCookie tempUidsCookie = new UidsCookie (
292
+ Uids .builder ().uids (new HashMap <>()).optout (hasOptout ).build (),
293
+ mapper );
294
+
295
+ while (nextCookieFamily != null || cookieFamilies .hasNext ()) {
296
+ nextCookieFamily = nextCookieFamily == null ? cookieFamilies .next () : nextCookieFamily ;
297
+ tempUidsCookie = tempUidsCookie .updateUid (nextCookieFamily , uids .get (nextCookieFamily ));
295
298
if (cookieExceededMaxLength (uidsName , tempUidsCookie )) {
296
- tempUids . remove (nextCookieFamily );
299
+ tempUidsCookie = tempUidsCookie . deleteUid (nextCookieFamily );
297
300
break ;
298
301
}
299
302
300
303
nextCookieFamily = null ;
301
304
}
302
305
303
- uidsIndex ++;
304
- }
305
-
306
- while (nextCookieFamily != null || cookieFamilyIterator .hasNext ()) {
307
- nextCookieFamily = nextCookieFamily == null ? cookieFamilyIterator .next () : nextCookieFamily ;
308
- if (prioritizedCoopSyncProvider .isPrioritizedFamily (nextCookieFamily )) {
309
- metrics .updateUserSyncSizedOutMetric (nextCookieFamily );
306
+ if (tempUidsCookie .getCookieUids ().getUids ().isEmpty ()) {
307
+ splitCookies .add (expiredCookie (uidsName ));
310
308
} else {
311
- metrics . updateUserSyncSizeBlockedMetric ( nextCookieFamily );
309
+ splitCookies . add ( aliveCookie ( uidsName , tempUidsCookie ) );
312
310
}
313
311
314
- nextCookieFamily = null ;
312
+ uidsIndex ++ ;
315
313
}
316
314
315
+ if (nextCookieFamily != null ) {
316
+ updateSyncSizeMetrics (nextCookieFamily );
317
+ }
318
+
319
+ cookieFamilies .forEachRemaining (this ::updateSyncSizeMetrics );
320
+
317
321
return splitCookies ;
318
322
}
319
323
@@ -340,12 +344,20 @@ private int compareCookieFamilyNames(Map.Entry<String, UidWithExpiry> left,
340
344
}
341
345
}
342
346
347
+ private void updateSyncSizeMetrics (String nextCookieFamily ) {
348
+ if (prioritizedCoopSyncProvider .isPrioritizedFamily (nextCookieFamily )) {
349
+ metrics .updateUserSyncSizedOutMetric (nextCookieFamily );
350
+ } else {
351
+ metrics .updateUserSyncSizeBlockedMetric (nextCookieFamily );
352
+ }
353
+ }
354
+
343
355
private boolean cookieExceededMaxLength (String name , UidsCookie uidsCookie ) {
344
356
return maxCookieSizeBytes > 0 && cookieBytesLength (name , uidsCookie ) > maxCookieSizeBytes ;
345
357
}
346
358
347
359
private int cookieBytesLength (String cookieName , UidsCookie uidsCookie ) {
348
- return makeCookie (cookieName , uidsCookie ).encode ().getBytes ().length ;
360
+ return aliveCookie (cookieName , uidsCookie ).encode ().getBytes ().length ;
349
361
}
350
362
351
363
public String hostCookieUidToSync (RoutingContext routingContext , String cookieFamilyName ) {
0 commit comments