From de5b81c0a8360d61e38248b721484afb39500422 Mon Sep 17 00:00:00 2001 From: Danylo Date: Wed, 29 Jan 2025 07:45:18 +0100 Subject: [PATCH 1/2] Refactor --- .../org/prebid/server/cookie/CookieSize.java | 57 +++++++++++++++++++ .../server/cookie/UidsCookieService.java | 31 +++------- 2 files changed, 64 insertions(+), 24 deletions(-) create mode 100644 src/main/java/org/prebid/server/cookie/CookieSize.java diff --git a/src/main/java/org/prebid/server/cookie/CookieSize.java b/src/main/java/org/prebid/server/cookie/CookieSize.java new file mode 100644 index 00000000000..f5512979fa6 --- /dev/null +++ b/src/main/java/org/prebid/server/cookie/CookieSize.java @@ -0,0 +1,57 @@ +package org.prebid.server.cookie; + +import io.vertx.core.http.Cookie; +import org.apache.commons.lang3.StringUtils; + +public class CookieSize { + + // {"tempUIDs":{},"optout":false} + private static final int TEMP_UIDS_BASE64_BYTES = "eyJ0ZW1wVUlEcyI6e30sIm9wdG91dCI6ZmFsc2V9".length(); + private static final int UID_TEMPLATE_BYTES = + "\"\":{\"uid\":\"\",\"expires\":\"1970-01-01T00:00:00.000000Z\"},".length(); + + private final int cookieSchemaSize; + private final int maxSize; + private int encodedUidsSize; + + public CookieSize(int cookieSchemaSize, int maxSize) { + this.cookieSchemaSize = cookieSchemaSize; + this.maxSize = maxSize; + + encodedUidsSize = 0; + } + + public static int schemaSize(Cookie cookieSchema) { + return cookieSchema.setValue(StringUtils.EMPTY).encode().length(); + } + + public boolean isValid() { + return maxSize <= 0 || totalSize() <= maxSize; + } + + public int totalSize() { + return cookieSchemaSize + + TEMP_UIDS_BASE64_BYTES + + Base64Size.base64Size(encodedUidsSize); + } + + public void addUid(String cookieFamily, String uid) { + final int uidSize = UID_TEMPLATE_BYTES + cookieFamily.length() + uid.length(); + encodedUidsSize = Base64Size.encodeSize(Base64Size.decodeSize(encodedUidsSize) + uidSize); + } + + private static class Base64Size { + + public static int encodeSize(int size) { + return size / 3 * 4 + size % 3; + } + + public static int decodeSize(int encodedSize) { + return encodedSize / 4 * 3 + encodedSize % 4; + } + + private static int base64Size(int encodedSize) { + return (encodedSize & -4) + 4 * Integer.signum(encodedSize % 4); + } + } +} diff --git a/src/main/java/org/prebid/server/cookie/UidsCookieService.java b/src/main/java/org/prebid/server/cookie/UidsCookieService.java index 12f1a7d631e..d9e6da04b16 100644 --- a/src/main/java/org/prebid/server/cookie/UidsCookieService.java +++ b/src/main/java/org/prebid/server/cookie/UidsCookieService.java @@ -42,12 +42,6 @@ public class UidsCookieService { private static final int MIN_NUMBER_OF_UID_COOKIES = 1; private static final int MAX_NUMBER_OF_UID_COOKIES = 30; - // {"tempUIDs":{},"optout":false} - private static final int TEMP_UIDS_BASE64_BYTES = "eyJ0ZW1wVUlEcyI6e30sIm9wdG91dCI6ZmFsc2V9".length(); - // "":{"uid":"","expires":"1970-01-01T00:00:00.000000000Z"}, - private static final int UID_BASE64_BYTES = ("IiI6eyJ1aWQiOiIiLCJleHBpcmVzI" - + "joiMTk3MC0wMS0wMVQwMDowMDowMC4wMDAwMDAwMDBaIn0s").length(); - private final String optOutCookieName; private final String optOutCookieValue; private final String hostCookieFamily; @@ -287,22 +281,19 @@ public List splitUidsIntoCookies(UidsCookie uidsCookie) { final Iterator cookieFamilies = cookieFamilyNamesByDescPriorityAndExpiration(uidsCookie); final List splitCookies = new ArrayList<>(); - final int staticCookieDataBytes = makeCookie(COOKIE_NAME, StringUtils.EMPTY, ttlSeconds).encode().length(); - + final int cookieSchemaSize = CookieSize.schemaSize(makeCookie(COOKIE_NAME, StringUtils.EMPTY, ttlSeconds)); String nextCookieFamily = null; + for (int i = 0; i < numberOfUidCookies; i++) { + final int digits = i < 10 ? Integer.signum(i) : 2; + final CookieSize cookieSize = new CookieSize(cookieSchemaSize + digits, maxCookieSizeBytes); - for (int uidsIndex = 0; uidsIndex < numberOfUidCookies; uidsIndex++) { - int actualCookieSize = staticCookieDataBytes + TEMP_UIDS_BASE64_BYTES; final Map tempUids = new HashMap<>(); - while (nextCookieFamily != null || cookieFamilies.hasNext()) { nextCookieFamily = nextCookieFamily == null ? cookieFamilies.next() : nextCookieFamily; - final UidWithExpiry uidWithExpiry = uids.get(nextCookieFamily); - actualCookieSize += UID_BASE64_BYTES - + calculateCookieSize(uidsIndex, nextCookieFamily, uidWithExpiry.getUid()); - if (maxCookieSizeBytes > 0 && actualCookieSize > maxCookieSizeBytes) { + cookieSize.addUid(nextCookieFamily, uidWithExpiry.getUid()); + if (!cookieSize.isValid()) { break; } @@ -310,7 +301,7 @@ public List splitUidsIntoCookies(UidsCookie uidsCookie) { nextCookieFamily = null; } - final String uidsName = uidsIndex == 0 ? COOKIE_NAME : COOKIE_NAME_FORMAT.formatted(uidsIndex + 1); + final String uidsName = i == 0 ? COOKIE_NAME : COOKIE_NAME_FORMAT.formatted(i + 1); if (tempUids.isEmpty()) { splitCookies.add(expiredCookie(uidsName)); @@ -330,14 +321,6 @@ public List splitUidsIntoCookies(UidsCookie uidsCookie) { return splitCookies; } - private static int calculateCookieSize(int uidsIndex, String cookieFamily, String uid) { - final int approximateBase64CookieFamilySize = (int) Math.ceil(cookieFamily.length() * 1.33); - final int approximateBase64UidSize = (int) Math.ceil(uid.length() * 1.33); - final int uidsIndexSize = uidsIndex == 0 ? 0 : 2; - - return uidsIndexSize + approximateBase64CookieFamilySize + approximateBase64UidSize; - } - private Iterator cookieFamilyNamesByDescPriorityAndExpiration(UidsCookie uidsCookie) { return uidsCookie.getCookieUids().getUids().entrySet().stream() .sorted(this::compareCookieFamilyNames) From 7fb9c6ba7d38e4def3e007a251feb0716d7a0b6e Mon Sep 17 00:00:00 2001 From: Danylo Date: Wed, 29 Jan 2025 11:54:05 +0100 Subject: [PATCH 2/2] Rename to UidsCookieService and add platform dependent Instant. --- .../server/cookie/UidsCookieService.java | 8 +++---- .../{CookieSize.java => UidsCookieSize.java} | 24 +++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) rename src/main/java/org/prebid/server/cookie/{CookieSize.java => UidsCookieSize.java} (67%) diff --git a/src/main/java/org/prebid/server/cookie/UidsCookieService.java b/src/main/java/org/prebid/server/cookie/UidsCookieService.java index d9e6da04b16..8bfe414884c 100644 --- a/src/main/java/org/prebid/server/cookie/UidsCookieService.java +++ b/src/main/java/org/prebid/server/cookie/UidsCookieService.java @@ -281,19 +281,19 @@ public List splitUidsIntoCookies(UidsCookie uidsCookie) { final Iterator cookieFamilies = cookieFamilyNamesByDescPriorityAndExpiration(uidsCookie); final List splitCookies = new ArrayList<>(); - final int cookieSchemaSize = CookieSize.schemaSize(makeCookie(COOKIE_NAME, StringUtils.EMPTY, ttlSeconds)); + final int cookieSchemaSize = UidsCookieSize.schemaSize(makeCookie(COOKIE_NAME, StringUtils.EMPTY, ttlSeconds)); String nextCookieFamily = null; for (int i = 0; i < numberOfUidCookies; i++) { final int digits = i < 10 ? Integer.signum(i) : 2; - final CookieSize cookieSize = new CookieSize(cookieSchemaSize + digits, maxCookieSizeBytes); + final UidsCookieSize uidsCookieSize = new UidsCookieSize(cookieSchemaSize + digits, maxCookieSizeBytes); final Map tempUids = new HashMap<>(); while (nextCookieFamily != null || cookieFamilies.hasNext()) { nextCookieFamily = nextCookieFamily == null ? cookieFamilies.next() : nextCookieFamily; final UidWithExpiry uidWithExpiry = uids.get(nextCookieFamily); - cookieSize.addUid(nextCookieFamily, uidWithExpiry.getUid()); - if (!cookieSize.isValid()) { + uidsCookieSize.addUid(nextCookieFamily, uidWithExpiry.getUid()); + if (!uidsCookieSize.isValid()) { break; } diff --git a/src/main/java/org/prebid/server/cookie/CookieSize.java b/src/main/java/org/prebid/server/cookie/UidsCookieSize.java similarity index 67% rename from src/main/java/org/prebid/server/cookie/CookieSize.java rename to src/main/java/org/prebid/server/cookie/UidsCookieSize.java index f5512979fa6..c98d74297b2 100644 --- a/src/main/java/org/prebid/server/cookie/CookieSize.java +++ b/src/main/java/org/prebid/server/cookie/UidsCookieSize.java @@ -1,20 +1,36 @@ package org.prebid.server.cookie; +import com.fasterxml.jackson.core.JsonProcessingException; import io.vertx.core.http.Cookie; import org.apache.commons.lang3.StringUtils; +import org.prebid.server.json.ObjectMapperProvider; -public class CookieSize { +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +public class UidsCookieSize { // {"tempUIDs":{},"optout":false} private static final int TEMP_UIDS_BASE64_BYTES = "eyJ0ZW1wVUlEcyI6e30sIm9wdG91dCI6ZmFsc2V9".length(); - private static final int UID_TEMPLATE_BYTES = - "\"\":{\"uid\":\"\",\"expires\":\"1970-01-01T00:00:00.000000Z\"},".length(); + private static final int UID_TEMPLATE_BYTES; + + static { + try { + UID_TEMPLATE_BYTES = "\"\":{\"uid\":\"\",\"expires\":\"%s\"}," + .formatted(ObjectMapperProvider.mapper().writeValueAsString( + ZonedDateTime.ofInstant(Instant.ofEpochSecond(0, 1), ZoneId.of("UTC")))) + .length(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } private final int cookieSchemaSize; private final int maxSize; private int encodedUidsSize; - public CookieSize(int cookieSchemaSize, int maxSize) { + public UidsCookieSize(int cookieSchemaSize, int maxSize) { this.cookieSchemaSize = cookieSchemaSize; this.maxSize = maxSize;