Skip to content

Commit 2fd0b40

Browse files
committed
Cookie Size Calculation Optimization
1 parent db75507 commit 2fd0b40

File tree

1 file changed

+40
-32
lines changed

1 file changed

+40
-32
lines changed

src/main/java/org/prebid/server/cookie/UidsCookieService.java

Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ public class UidsCookieService {
4242
private static final int MIN_NUMBER_OF_UID_COOKIES = 1;
4343
private static final int MAX_NUMBER_OF_UID_COOKIES = 30;
4444

45+
// {"tempUIDs":{},"optout":false}
46+
private static final int TEMP_UIDS_BASE64_BYTES = "eyJ0ZW1wVUlEcyI6e30sIm9wdG91dCI6ZmFsc2V9".length();
47+
// "":{"uid":"","expires":"1970-01-01T00:00:00.000000000Z"},
48+
private static final int UID_BASE64_BYTES = ("IiI6eyJ1aWQiOiIiLCJleHBpcmVzI"
49+
+ "joiMTk3MC0wMS0wMVQwMDowMDowMC4wMDAwMDAwMDBaIn0s").length();
50+
4551
private final String optOutCookieName;
4652
private final String optOutCookieValue;
4753
private final String hostCookieFamily;
@@ -163,26 +169,24 @@ private Uids parseUids(Map<String, String> cookies) {
163169
* as a value.
164170
*/
165171
public Cookie aliveCookie(String cookieName, UidsCookie uidsCookie) {
166-
return Cookie
167-
.cookie(cookieName, Base64.getUrlEncoder().encodeToString(uidsCookie.toJson().getBytes()))
168-
.setPath("/")
169-
.setSameSite(CookieSameSite.NONE)
170-
.setSecure(true)
171-
.setMaxAge(ttlSeconds)
172-
.setDomain(hostCookieDomain);
172+
final String value = Base64.getUrlEncoder().encodeToString(uidsCookie.toJson().getBytes());
173+
return makeCookie(cookieName, value, ttlSeconds);
173174
}
174175

175176
public Cookie aliveCookie(UidsCookie uidsCookie) {
176177
return aliveCookie(COOKIE_NAME, uidsCookie);
177178
}
178179

179180
public Cookie expiredCookie(String cookieName) {
180-
return Cookie
181-
.cookie(cookieName, StringUtils.EMPTY)
181+
return makeCookie(cookieName, StringUtils.EMPTY, 0);
182+
}
183+
184+
private Cookie makeCookie(String cookieName, String value, long maxAge) {
185+
return Cookie.cookie(cookieName, value)
182186
.setPath("/")
183187
.setSameSite(CookieSameSite.NONE)
184188
.setSecure(true)
185-
.setMaxAge(0)
189+
.setMaxAge(maxAge)
186190
.setDomain(hostCookieDomain);
187191
}
188192

@@ -283,33 +287,38 @@ public List<Cookie> splitUidsIntoCookies(UidsCookie uidsCookie) {
283287
final Iterator<String> cookieFamilies = cookieFamilyNamesByDescPriorityAndExpiration(uidsCookie);
284288
final List<Cookie> splitCookies = new ArrayList<>();
285289

286-
int uidsIndex = 0;
290+
final int staticCookieDataBytes = makeCookie(COOKIE_NAME, StringUtils.EMPTY, ttlSeconds).encode().length();
291+
287292
String nextCookieFamily = null;
288293

289-
while (uidsIndex < numberOfUidCookies) {
290-
final String uidsName = uidsIndex == 0 ? COOKIE_NAME : COOKIE_NAME_FORMAT.formatted(uidsIndex + 1);
291-
UidsCookie tempUidsCookie = new UidsCookie(
292-
Uids.builder().uids(new HashMap<>()).optout(hasOptout).build(),
293-
mapper);
294+
for (int uidsIndex = 0; uidsIndex < numberOfUidCookies; uidsIndex++) {
295+
int actualCookieSize = staticCookieDataBytes + TEMP_UIDS_BASE64_BYTES;
296+
final Map<String, UidWithExpiry> tempUids = new HashMap<>();
294297

295298
while (nextCookieFamily != null || cookieFamilies.hasNext()) {
296299
nextCookieFamily = nextCookieFamily == null ? cookieFamilies.next() : nextCookieFamily;
297-
tempUidsCookie = tempUidsCookie.updateUid(nextCookieFamily, uids.get(nextCookieFamily));
298-
if (cookieExceededMaxLength(uidsName, tempUidsCookie)) {
299-
tempUidsCookie = tempUidsCookie.deleteUid(nextCookieFamily);
300+
301+
final UidWithExpiry uidWithExpiry = uids.get(nextCookieFamily);
302+
actualCookieSize += UID_BASE64_BYTES
303+
+ calculateCookieSize(uidsIndex, nextCookieFamily, uidWithExpiry.getUid());
304+
305+
if (maxCookieSizeBytes > 0 && actualCookieSize > maxCookieSizeBytes) {
300306
break;
301307
}
302308

309+
tempUids.put(nextCookieFamily, uidWithExpiry);
303310
nextCookieFamily = null;
304311
}
305312

306-
if (tempUidsCookie.getCookieUids().getUids().isEmpty()) {
313+
final String uidsName = uidsIndex == 0 ? COOKIE_NAME : COOKIE_NAME_FORMAT.formatted(uidsIndex + 1);
314+
315+
if (tempUids.isEmpty()) {
307316
splitCookies.add(expiredCookie(uidsName));
308317
} else {
309-
splitCookies.add(aliveCookie(uidsName, tempUidsCookie));
318+
splitCookies.add(aliveCookie(
319+
uidsName,
320+
new UidsCookie(Uids.builder().uids(tempUids).optout(hasOptout).build(), mapper)));
310321
}
311-
312-
uidsIndex++;
313322
}
314323

315324
if (nextCookieFamily != null) {
@@ -321,11 +330,18 @@ public List<Cookie> splitUidsIntoCookies(UidsCookie uidsCookie) {
321330
return splitCookies;
322331
}
323332

333+
private static int calculateCookieSize(int uidsIndex, String cookieFamily, String uid) {
334+
final int approximateBase64CookieFamilySize = (int) Math.ceil(cookieFamily.length() * 1.33);
335+
final int approximateBase64UidSize = (int) Math.ceil(uid.length() * 1.33);
336+
final int uidsIndexSize = uidsIndex == 0 ? 0 : 2;
337+
338+
return uidsIndexSize + approximateBase64CookieFamilySize + approximateBase64UidSize;
339+
}
340+
324341
private Iterator<String> cookieFamilyNamesByDescPriorityAndExpiration(UidsCookie uidsCookie) {
325342
return uidsCookie.getCookieUids().getUids().entrySet().stream()
326343
.sorted(this::compareCookieFamilyNames)
327344
.map(Map.Entry::getKey)
328-
.toList()
329345
.iterator();
330346
}
331347

@@ -352,14 +368,6 @@ private void updateSyncSizeMetrics(String nextCookieFamily) {
352368
}
353369
}
354370

355-
private boolean cookieExceededMaxLength(String name, UidsCookie uidsCookie) {
356-
return maxCookieSizeBytes > 0 && cookieBytesLength(name, uidsCookie) > maxCookieSizeBytes;
357-
}
358-
359-
private int cookieBytesLength(String cookieName, UidsCookie uidsCookie) {
360-
return aliveCookie(cookieName, uidsCookie).encode().getBytes().length;
361-
}
362-
363371
public String hostCookieUidToSync(RoutingContext routingContext, String cookieFamilyName) {
364372
if (!StringUtils.equals(cookieFamilyName, hostCookieFamily)) {
365373
return null;

0 commit comments

Comments
 (0)