-
Notifications
You must be signed in to change notification settings - Fork 187
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Core: Add
Sec-Browsing-Topics
support. (#2750)
- Loading branch information
Showing
23 changed files
with
1,380 additions
and
145 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
src/main/java/org/prebid/server/auction/SecBrowsingTopicsResolver.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package org.prebid.server.auction; | ||
|
||
import org.apache.commons.lang3.StringUtils; | ||
import org.prebid.server.auction.model.SecBrowsingTopic; | ||
import org.prebid.server.exception.PreBidException; | ||
import org.prebid.server.model.CaseInsensitiveMultiMap; | ||
import org.prebid.server.util.HttpUtil; | ||
|
||
import java.util.Arrays; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
import java.util.function.Predicate; | ||
import java.util.regex.Matcher; | ||
import java.util.regex.Pattern; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.Stream; | ||
|
||
public class SecBrowsingTopicsResolver { | ||
|
||
private static final String FIELDS_SEPARATOR = ","; | ||
private static final String PADDING_FIELD_PREFIX = "();p="; | ||
private static final Pattern FIELD_PATTERN = | ||
Pattern.compile("\\((\\s*\\d+[\\d\\s]*)\\);v=chrome\\.[^:\\s]+:([1-9]|10):([^:\\s]+)$"); | ||
private static final int FIELDS_LIMIT = 10; | ||
|
||
private static final String SEGMENTS_SEPARATOR = " "; | ||
|
||
private final String topicsDomain; | ||
|
||
public SecBrowsingTopicsResolver(String topicsDomain) { | ||
this.topicsDomain = topicsDomain; | ||
} | ||
|
||
public List<SecBrowsingTopic> resolve(CaseInsensitiveMultiMap headers, | ||
boolean debugEnabled, | ||
List<String> warnings) { | ||
|
||
final String secBrowserTopics = headers.get(HttpUtil.SEC_BROWSING_TOPICS_HEADER); | ||
if (StringUtils.isBlank(secBrowserTopics)) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
return fields(secBrowserTopics, debugEnabled, warnings) | ||
.filter(field -> !field.startsWith(PADDING_FIELD_PREFIX)) | ||
.map(field -> toSecBrowsingTopic(field, debugEnabled, warnings)) | ||
.filter(Objects::nonNull) | ||
.toList(); | ||
} | ||
|
||
private static Stream<String> fields(String fields, boolean debugEnabled, List<String> warnings) { | ||
final Stream<String> baseStream = !debugEnabled | ||
? Arrays.stream(fields.split(FIELDS_SEPARATOR, FIELDS_LIMIT + 1)).limit(FIELDS_LIMIT) | ||
: Arrays.stream(fields.split(FIELDS_SEPARATOR)).filter(limitAndLogDiscarded(warnings)); | ||
|
||
return baseStream.map(StringUtils::trimToEmpty); | ||
} | ||
|
||
private static Predicate<String> limitAndLogDiscarded(List<String> warnings) { | ||
final AtomicInteger limit = new AtomicInteger(FIELDS_LIMIT); | ||
return field -> { | ||
final boolean skipFurther = limit.getAndDecrement() > 0; | ||
if (!skipFurther) { | ||
logWarning(warnings, true, field + " discarded due to limit reached."); | ||
} | ||
return skipFurther; | ||
}; | ||
} | ||
|
||
private static void logWarning(List<String> warnings, boolean debugEnabled, String reason) { | ||
if (debugEnabled) { | ||
warnings.add("Invalid field in %s header: %s".formatted(HttpUtil.SEC_BROWSING_TOPICS_HEADER, reason)); | ||
} | ||
} | ||
|
||
private SecBrowsingTopic toSecBrowsingTopic(String field, boolean debugEnabled, List<String> warnings) { | ||
final Matcher matcher = FIELD_PATTERN.matcher(field); | ||
if (!matcher.matches()) { | ||
logWarning(warnings, debugEnabled, field); | ||
return null; | ||
} | ||
|
||
try { | ||
return SecBrowsingTopic.of( | ||
topicsDomain, | ||
parseSegments(matcher.group(1)), | ||
parseInt(matcher.group(2)), | ||
matcher.group(3)); | ||
} catch (PreBidException e) { | ||
logWarning(warnings, debugEnabled, field); | ||
return null; | ||
} | ||
} | ||
|
||
private static Set<String> parseSegments(String segments) { | ||
return Arrays.stream(StringUtils.trim(segments).split(SEGMENTS_SEPARATOR)) | ||
.map(StringUtils::trim) | ||
.filter(StringUtils::isNotEmpty) | ||
.map(SecBrowsingTopicsResolver::parseInt) | ||
.map(Object::toString) | ||
.collect(Collectors.toSet()); | ||
} | ||
|
||
private static int parseInt(String integer) { | ||
try { | ||
return Integer.parseInt(integer); | ||
} catch (NumberFormatException e) { | ||
throw new PreBidException(e.getMessage()); | ||
} | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
src/main/java/org/prebid/server/auction/model/SecBrowsingTopic.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package org.prebid.server.auction.model; | ||
|
||
import lombok.Value; | ||
|
||
import java.util.Set; | ||
|
||
@Value(staticConstructor = "of") | ||
public class SecBrowsingTopic { | ||
|
||
String domain; | ||
|
||
Set<String> segments; | ||
|
||
int taxonomyVersion; | ||
|
||
String modelVersion; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.