From 5af3f7f58e719f7196fb73044c8bca2eb8a760cb Mon Sep 17 00:00:00 2001 From: Maks Orlovich Date: Fri, 6 Sep 2024 10:40:54 -0400 Subject: [PATCH] More clearly define how seller trusted signals fetching works (#1230) * Specify support for cross-origin trusted signals, and the bundled queryFeatureSupport('*'). This also includes fixes to some bugs in parsing of these URLs (some of the checks were missing). * Simpler part of feedback * Refactor trustedBiddingSignalsURL config. * Update scoring, also remove some diff noise. * Split function. * Apply feedback * Apply feedback. * Apply suggestions I didn't need to ask follow ups on * Apply a typo fix Qingxin pointed out which I missed because there was another comment about the same line. * Fix same origin checks * varify ignored placeholders * Rework the merging language. * Some first steps towards expression some fetch parallelism. * Very vague spec of proper batcher. * Fill out the algorithm and wire it through * Improve some phrasing as suggested * Fix wrong indentation level, now I can see in a preview diff. * Fix missing comma. * Apply feedback * Better wait. * Fix merge mistake * Apply feedback * Fix return capitalization, as per feedback * Apply feedback * Notes changes --------- Co-authored-by: Maks Orlovich --- spec.bs | 457 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 325 insertions(+), 132 deletions(-) diff --git a/spec.bs b/spec.bs index 8f20be548..2cfca488c 100644 --- a/spec.bs +++ b/spec.bs @@ -1653,6 +1653,8 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: 1. Let |auctionStartTime| be the [=current wall time=]. 1. Let |decisionLogicFetcher| be the result of [=creating a new script fetcher=] with |auctionConfig|'s [=auction config/decision logic url=] and |settings|. +1. Let |trustedScoringSignalsBatcher| be the result of [=creating a trusted scoring signals + batcher=] with |auctionConfig|'s [=auction config/max trusted scoring signals url length=]. 1. Let « |bidGenerators|, |negativeTargetInfo| » be the result of running [=build bid generators map=] with |auctionConfig|. 1. Let |leadingBidInfo| be a new [=leading bid info=]. @@ -1682,12 +1684,13 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: 1. If |compWinnerInfo|'s [=leading bid info/leading bid=] is not null, then run [=score and rank a bid=] with |auctionConfig|, |compWinnerInfo|'s [=leading bid info/leading bid=], |leadingBidInfo|, |decisionLogicFetcher|, - null, "top-level-auction", null, and |topLevelOrigin|. + |trustedScoringSignalsBatcher|, null, "top-level-auction", null, and |topLevelOrigin|. 1. If |compWinnerInfo|'s [=leading bid info/leading non-k-anon-enforced bid=] is not null, then run [=score and rank a bid=] with |auctionConfig|, |compWinnerInfo|'s [=leading bid info/leading non-k-anon-enforced bid=], - |leadingBidInfo|, |decisionLogicFetcher|, |topLevelDirectFromSellerSignalsForSeller|, null, - "top-level-auction", null, |topLevelOrigin|, and |realTimeContributionsMap|. + |leadingBidInfo|, |decisionLogicFetcher|, |trustedScoringSignalsBatcher|, + |topLevelDirectFromSellerSignalsForSeller|, null, "top-level-auction", null, |topLevelOrigin|, + and |realTimeContributionsMap|. 1. Decrement |pendingComponentAuctions| by 1. 1. Wait until |pendingComponentAuctions| is 0. 1. If |leadingBidInfo|'s [=leading bid info/leading bid=] is null, return null. @@ -1753,8 +1756,9 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: 1. Let |pendingAdditionalBids| be the [=list/size=] of |additionalBids|. 1. [=list/For each=] |additionalBid| of |additionalBids|, run the following steps [=in parallel=]: 1. [=Score and rank a bid=] with |auctionConfig|, |additionalBid|, |leadingBidInfo|, - |decisionLogicFetcher|, |directFromSellerSignalsForSeller|, null, |auctionLevel|, - |componentAuctionExpectedCurrency|, |topLevelOrigin|, and |realTimeContributionsMap|. + |decisionLogicFetcher|, |trustedScoringSignalsBatcher|, |directFromSellerSignalsForSeller|, + null, |auctionLevel|, |componentAuctionExpectedCurrency|, |topLevelOrigin|, and + |realTimeContributionsMap|. 1. Decrement |pendingAdditionalBids| by 1. 1. [=map/For each=] |buyer| → |perBuyerGenerator| of |bidGenerators|, [=parallel queue/enqueue steps|enqueue the following steps=] to |queue|: @@ -1928,7 +1932,8 @@ and a [=real time reporting contributions map=] |realTimeContributionsMap|: 1. If |bidToScore|'s [=generated bid/for k-anon auction=] is true, [=list/append=] |bidToScore|'s [=generated bid/interest group=] to |bidIgs|. 1. [=Score and rank a bid=] with |auctionConfig|, |bidToScore|, |leadingBidInfo|, - |decisionLogicFetcher|, |directFromSellerSignalsForSeller|, |dataVersion|, |auctionLevel|, + |decisionLogicFetcher|, |trustedScoringSignalsBatcher|, + |directFromSellerSignalsForSeller|, |dataVersion|, |auctionLevel|, |componentAuctionExpectedCurrency|, |topLevelOrigin|, and |realTimeContributionsMap|. 1. Decrement |pendingBuyers| by 1. 1. Wait until both |pendingBuyers| and |pendingAdditionalBids| are 0. @@ -2020,12 +2025,12 @@ To convert to an AuctionAd sequence given a [=list=]-or-null |ads|:
-To fetch and decode trusted scoring signals given an [=auction config=] |auctionConfig|, -a [=generated bid=] |generatedBid|, a [=script fetcher=] |decisionLogicFetcher|, an [=origin=] -|topLevelOrigin|, a [=real time reporting contributions map=] |realTimeContributionsMap|, and a -[=policy container=] |policyContainer|: +To fetch and decode trusted scoring signals given a [=trusted scoring signals batcher=] +|batcher|, an [=auction config=] |auctionConfig|, a [=generated bid=] |generatedBid|, a +[=script fetcher=] |decisionLogicFetcher|, an [=origin=] |topLevelOrigin|, a [=real time reporting +contributions map=] |realTimeContributionsMap|, and a [=policy container=] |policyContainer|: -1. Let |crossOriginTrustedScoringSignalsOrigin| be null. +1. Let |isCrossOrigin| be false. 1. Let |sameOriginTrustedScoringSignals| be null. 1. Let |crossOriginTrustedScoringSignals| be null. 1. Let |scoringDataVersion| be null. @@ -2037,48 +2042,41 @@ a [=generated bid=] |generatedBid|, a [=script fetcher=] |decisionLogicFetcher|, descriptors=]: 1. [=list/Append=] [=URL serializer|serialized=] |adComponentDescriptor|'s [=ad descriptor/url=] to |adComponentRenderURLs|. -1. Let |fullSignalsUrl| be null. 1. If |auctionConfig|'s [=auction config/trusted scoring signals url=] is not null: - 1. Set |fullSignalsUrl| be the result of [=building trusted scoring signals url=] with |auctionConfig|'s - [=auction config/trusted scoring signals url=], «|renderURL|», |adComponentRenderURLs|, - |auctionConfig|'s [=auction config/seller experiment group id=], and |topLevelOrigin|. - - Implementations may batch trusted scoring signals - requests with same [=auction config/trusted scoring signals url=], |auctionConfig|'s - [=auction config/seller experiment group id=], and |topLevelOrigin| by collecting render URLs - and ad component render URLs from multiple invocations of [=score and rank a bid=] and passing - them all to a single invocation of [=building trusted scoring signals url=] to get a - |scoringSignalsUrl|. Requests may not be combined if the resulting combination's - [=string/length=] of [=URL serializer|serialized=] |scoringSignalsUrl| exceeds the [=auction - config/max trusted scoring signals url length=] of the auction; however this limit does not - apply if no combining has taken place. - - The network response has to be parsed to pull out the pieces relevant to each - [=evaluating a scoring script|evaluation of a scoring script=]. - - These requests may also begin before the script fetch, but requests cross-origin to the - script origin must not happen until [:Ad-Auction-Allow-Trusted-Scoring-Signals-From:] header on - the script is received, parsed, and determined to authorize such a fetch. - 1. If |fullSignalsUrl|'s [=url/origin=] is not [=same origin=] with |auctionConfig|'s - [=auction config/seller=], then: - 1. Set |crossOriginTrustedScoringSignalsOrigin| to |fullSignalsUrl|'s [=url/origin=]. - 1. Let |allowCrossOriginTrustedScoringSignalsFrom| be the result of [=wait for cross origin - trusted scoring signals authorization from a fetcher=] given |decisionLogicFetcher|. - 1. If |allowCrossOriginTrustedScoringSignalsFrom| does not [=list/contain=] - |crossOriginTrustedScoringSignalsOrigin|: - 1. Set |crossOriginTrustedScoringSignalsOrigin| to null. - 1. Set |fullSignalsUrl| to null. -1. Let |seller| be |auctionConfig|'s [=auction config/seller=]. -1. If |fullSignalsUrl| is not null: - 1. Let |allTrustedScoringSignals| be null. - 1. Set «|allTrustedScoringSignals|, - ignored, |scoringDataVersion|» to the result of [=fetching trusted signals=] - with |fullSignalsUrl|, |auctionConfig|'s [=auction config/seller=], |policyContainer|, and false. - 1. If |allTrustedScoringSignals| is null, and |auctionConfig|'s - [=auction config/seller real time reporting config=] is "`default-local-reporting`",then: - 1. [=Add a platform contribution=] with [=trusted scoring signals failure bucket=], - |realTimeContributionsMap|, and |seller|. - 1. Otherwise if |allTrustedScoringSignals| is an [=ordered map=]: + 1. Let |request| be a new [=trusted scoring signals request=] with the following [=struct/items=]: + : [=trusted scoring signals request/seller=] + :: |auctionConfig|'s [=auction config/seller=] + + : [=trusted scoring signals request/seller script fetcher=] + :: |decisionLogicFetcher| + + : [=trusted scoring signals request/base url=] + :: |auctionConfig|'s [=auction config/trusted scoring signals url=] + + : [=trusted scoring signals request/seller experiment group id=] + :: |auctionConfig|'s [=auction config/seller experiment group id=] + + : [=trusted scoring signals request/top level origin=] + :: |topLevelOrigin| + + : [=trusted scoring signals request/render URL=] + :: |renderURL| + + : [=trusted scoring signals request/ad component URLs=] + :: |adComponentRenderURLs| + + : [=trusted scoring signals request/policy container=] + :: |policyContainer| + + 1. If |auctionConfig|'s [=auction config/trusted scoring signals url=]'s [=url/origin=] is not + [=same origin=] with |auctionConfig|'s [=auction config/seller=], then set |isCrossOrigin| to + true. + 1. Let |result| be the result of [=fetching trusted scoring signals with batching=] with + |batcher| and |request|. + 1. If |result| is not failure: + 1. Let |allTrustedScoringSignals| be |result|'s [=trusted scoring signals reply/all trusted + scoring signals=]: + 1. Set |scoringDataVersion| to |result|'s [=trusted scoring signals reply/data version=]. 1. Let |trustedScoringSignals| be a new empty [=map=]. 1. [=map/Set=] |trustedScoringSignals|["`renderURL`"] to a new empty [=map=]. 1. If |allTrustedScoringSignals|["`renderURLs`"] [=map/exists=] and @@ -2093,31 +2091,35 @@ a [=generated bid=] |generatedBid|, a [=script fetcher=] |decisionLogicFetcher|, [=map/exists=], then [=map/set=] |adComponentRenderURLsValue|[|adComponentRenderURL|] to |allTrustedScoringSignals|["`adComponentRenderURLs`"][|adComponentRenderURL|]. 1. [=map/Set=] |trustedScoringSignals|["`adComponentRenderURLs`"] to |adComponentRenderURLsValue|. - 1. If |crossOriginTrustedScoringSignalsOrigin| is null, set |sameOriginTrustedScoringSignals| + 1. If |isCrossOrigin| is false, set |sameOriginTrustedScoringSignals| to |trustedScoringSignals|. 1. Otherwise: 1. Set |crossOriginTrustedScoringSignals| to a new [=map=]. 1. Let |originKey| be the [=serialization of an origin|serialization=] given - |crossOriginTrustedScoringSignalsOrigin|. + |auctionConfig|'s [=auction config/trusted scoring signals url=]'s [=url/origin=]. 1. [=map/Set=] |crossOriginTrustedScoringSignals|[|originKey|] to |trustedScoringSignals|. -1. Return «|crossOriginTrustedScoringSignalsOrigin|, |sameOriginTrustedScoringSignals|, - |crossOriginTrustedScoringSignals|, |scoringDataVersion|» + 1. Otherwise if |auctionConfig|'s [=auction config/seller real time reporting config=] + is "`default-local-reporting`",then: + 1. [=Add a platform contribution=] with [=trusted scoring signals failure bucket=], + |realTimeContributionsMap|, and |auctionConfig|'s [=auction config/seller=]. +1. Return «|isCrossOrigin|, |sameOriginTrustedScoringSignals|, |crossOriginTrustedScoringSignals|, + |scoringDataVersion|»
To score and rank a bid given an [=auction config=] |auctionConfig|, a [=generated bid=] |generatedBid|, a [=bid debug reporting info=] |bidDebugReportInfo|, a [=leading bid info=] |leadingBidInfo|, -a [=script fetcher=] |decisionLogicFetcher|, a {{DirectFromSellerSignalsForSeller}} -|directFromSellerSignalsForSeller|, an {{unsigned long}}-or-null |biddingDataVersion|, an enum |auctionLevel|, -which is "single-level-auction", "top-level-auction", or "component-auction", a [=currency tag=] -|componentAuctionExpectedCurrency|, an [=origin=] |topLevelOrigin|, and a -[=real time reporting contributions map=] |realTimeContributionsMap|: +a [=script fetcher=] |decisionLogicFetcher|, a [=trusted scoring signals batcher=] |trustedScoringSignalsBatcher| +a {{DirectFromSellerSignalsForSeller}} |directFromSellerSignalsForSeller|, an {{unsigned long}}-or-null +|biddingDataVersion|, an enum |auctionLevel|, which is "single-level-auction", "top-level-auction", +or "component-auction", a [=currency tag=] |componentAuctionExpectedCurrency|, an [=origin=] +|topLevelOrigin|, and a [=real time reporting contributions map=] |realTimeContributionsMap|: -1. Let «|crossOriginTrustedScoringSignalsOrigin|, |sameOriginTrustedScoringSignals|, +1. Let «|trustedScoringSignalsAreCrossOrigin|, |sameOriginTrustedScoringSignals|, |crossOriginTrustedScoringSignals|, |scoringDataVersion|» be the result of [=fetch and - decode trusted scoring signals=] given |auctionConfig|, |generatedBid|, |decisionLogicFetcher|, - |topLevelOrigin|, and |realTimeContributionsMap|. + decode trusted scoring signals=] given |trustedScoringSignalsBatcher|, |auctionConfig|, + |generatedBid|, |decisionLogicFetcher|, |topLevelOrigin|, and |realTimeContributionsMap|. 1. Let |adMetadata| be |generatedBid|'s [=generated bid/ad=]. 1. Let |bidValue| be |generatedBid|'s [=generated bid/bid=]. 1. If |generatedBid|'s [=generated bid/modified bid=] is not null, then set |bidValue| to @@ -2141,11 +2143,11 @@ which is "single-level-auction", "top-level-auction", or "component-auction", a
The result of [=serializing a currency tag=] with |generatedBid|'s [=generated bid/bid=]'s [=bid with currency/currency=]
{{ScoringBrowserSignals/dataVersion}} -
|scoringDataVersion| if it is not null and |crossOriginTrustedScoringSignalsOrigin| is null, +
|scoringDataVersion| if it is not null and |trustedScoringSignalsAreCrossOrigin| is false, unset otherwise.
{{ScoringBrowserSignals/crossOriginDataVersion}} -
|scoringDataVersion| if it is not null and |crossOriginTrustedScoringSignalsOrigin| is not - null, unset otherwise. +
|scoringDataVersion| if it is not null and |trustedScoringSignalsAreCrossOrigin| is true, + unset otherwise.
{{ScoringBrowserSignals/adComponents}}
|generatedBid|'s [=generated bid/ad component descriptors=] [=converted to a string sequence=]
{{ScoringBrowserSignals/forDebuggingOnlyInCooldownOrLockout}} @@ -2516,71 +2518,6 @@ To calculate the ad slot size query param given an [=interest group=]
-
- -To build trusted bidding signals url given a [=URL=] |signalsUrl|, an [=ordered set=] of -[=strings=] |keys|, an [=ordered set=] of [=strings=] |igNames|, an {{unsigned short}}-or-null -|experimentGroupId|, an [=origin=] |topLevelOrigin|, and a [=string=] |slotSizeQueryParam|: -1. Let |queryParamsList| be a new empty [=list=]. - - Note: These steps create a [=url/query=] of the form "`&=`". - E.g., "`hostname=publisher1.com&keys=key1,key2&interestGroupNames=ad+platform,name2&experimentGroupId=1234`". -

These steps don't use the [=urlencoded serializer|application/x-www-form-urlencoded - serializer=] to construct the query string because it repeats a key if it has multiple values - instead of a comma-demilited list (e.g., "`keys=key1&keys=key2`", instead of - "`keys=key1,key2`"), and it also uses a different percent encode set from the Chrome - implementation. - -1. [=list/Append=] "hostname=" to |queryParamsList|. -1. [=list/Append=] the result of [=string/UTF-8 percent-encoding=] the - [=serialization of an origin|serialized=] |topLevelOrigin| using [=component percent-encode set=] - to |queryParamsList|. -1. If |keys| is not [=set/is empty|empty=]: - 1. [=list/Append=] "`&keys=`" to |queryParamsList|. - 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with - |keys|. -1. If |igNames| is not [=set/is empty|empty=]: - 1. [=list/Append=] "`&interestGroupNames=`" to |queryParamsList|. - 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with - |igNames|. -1. If |experimentGroupId| is not null: - 1. [=list/Append=] "`&experimentGroupId=`" to |queryParamsList|. - 1. [=list/Append=] [=serialize an integer|serialized=] |experimentGroupId| to |queryParamsList|. -1. [=list/Append=] |slotSizeQueryParam| to |queryParamsList|. -1. Let |fullSignalsUrl| be |signalsUrl|. -1. Set |fullSignalsUrl|'s [=url/query=] to the result of [=string/concatenating=] |queryParamsList|. -1. return |fullSignalsUrl|. - -
- -
- -To build trusted scoring signals url given a [=URL=] |signalsUrl|, a [=list=] of -[=strings=] |renderURLs|, an [=ordered set=] of [=strings=] |adComponentRenderURLs|, an -{{unsigned short}} |experimentGroupId|, and an [=origin=] |topLevelOrigin|: - -Note: When trusted scoring signals fetches are not batched, |renderURLs|'s [=list/size=] is 1. - -1. Let |queryParamsList| be a new empty [=list=]. -1. [=list/Append=] "hostname=" to |queryParamsList|. -1. [=list/Append=] the result of [=string/UTF-8 percent-encoding=] |topLevelOrigin| using - [=component percent-encode set=] to |queryParamsList|. -1. If |renderURLs| is not [=set/is empty|empty=]: - 1. [=list/Append=] "`&renderURLs=`" to |queryParamsList|. - 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with - |renderURLs|. -1. If |adComponentRenderURLs| is not [=set/is empty|empty=]: - 1. [=list/Append=] "`&adComponentRenderURLs=`" to |queryParamsList|. - 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with - |adComponentRenderURLs|. -1. If |experimentGroupId| is not null: - 1. [=list/Append=] "`&experimentGroupId=`" to |queryParamsList|. - 1. [=list/Append=] [=serialize an integer|serialized=] |experimentGroupId| to |queryParamsList|. -1. Set |signalsUrl|'s [=url/query=] to the result of [=string/concatenating=] |queryParamsList|. -1. return |signalsUrl|. - -
-
To send report given a [=URL=] |url|, and an [=environment settings object=] |settings|: @@ -6562,6 +6499,42 @@ To append to a bidding signals per-interest group data map given an [
+
+ +To build trusted bidding signals url given a [=URL=] |signalsUrl|, an [=ordered set=] of +[=strings=] |keys|, an [=ordered set=] of [=strings=] |igNames|, an {{unsigned short}}-or-null +|experimentGroupId|, an [=origin=] |topLevelOrigin|, and a [=string=] |slotSizeQueryParam|: +1. Let |queryParamsList| be a new empty [=list=]. + + Note: These steps create a [=url/query=] of the form "`&=`". + E.g., "`hostname=publisher1.com&keys=key1,key2&interestGroupNames=ad+platform,name2&experimentGroupId=1234`". +

These steps don't use the [=urlencoded serializer|application/x-www-form-urlencoded + serializer=] to construct the query string because it repeats a key if it has multiple values + instead of a comma-demilited list (e.g., "`keys=key1&keys=key2`", instead of + "`keys=key1,key2`"), and it also uses a different percent encode set from the Chrome + implementation. + +1. [=list/Append=] "hostname=" to |queryParamsList|. +1. [=list/Append=] the result of [=string/UTF-8 percent-encoding=] the + [=serialization of an origin|serialized=] |topLevelOrigin| using [=component percent-encode set=] + to |queryParamsList|. +1. If |keys| is not [=set/is empty|empty=]: + 1. [=list/Append=] "`&keys=`" to |queryParamsList|. + 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with + |keys|. +1. If |igNames| is not [=set/is empty|empty=]: + 1. [=list/Append=] "`&interestGroupNames=`" to |queryParamsList|. + 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with + |igNames|. +1. If |experimentGroupId| is not null: + 1. [=list/Append=] "`&experimentGroupId=`" to |queryParamsList|. + 1. [=list/Append=] [=serialize an integer|serialized=] |experimentGroupId| to |queryParamsList|. +1. [=list/Append=] |slotSizeQueryParam| to |queryParamsList|. +1. Let |fullSignalsUrl| be |signalsUrl|. +1. Set |fullSignalsUrl|'s [=url/query=] to the result of [=string/concatenating=] |queryParamsList|. +1. Return |fullSignalsUrl|. + +
To fetch the current outstanding trusted signals batch given a @@ -6652,6 +6625,226 @@ To batch or fetch trusted bidding signals given a [=trusted bidding s
+

Trusted scoring signals batcher

+ +A trusted scoring signals batcher helps manage merging multiple trusted scoring signals +requests into smaller number of fetches. It's a [=struct=] with the following [=struct/items=]: + +
+ : request queue + :: A [=list=] of [=trusted scoring signals requests=] that hasn't yet been organized to aid + batching. + : request map + :: A [=map=] from a tuple of [=script fetcher=], a [=URL=] representating the trusted signals + base [=URL=], {{unsigned short}} or null for experiment ID, and + [=origin=], representing the top frame's [=origin], to a [=list=] of [=trusted scoring signals + requests=]. This organizes fetches that can possibly be merged together. + : url length limit + :: A {{long}} denoting a user-configured limit which should not be exceeded due to combining of + fetches. 0 denotes no limit, and is the initial value. +
+ +A trusted scoring signals request is a [=struct=] with the following [=struct/items=], +representing all information needed to produce a trusted scoring signals fetch for a single scoring +invocation: + +
+ : seller + :: An [=origin=] of the seller the fetch is on behalf of. + : seller script fetcher. + :: A [=script fetcher=] for the seller's decision logic script. + : base url + :: A [=URL=], the base URL for trusted seller signals to fetch. + : seller experiment group id + :: Null or an {{unsigned short}}, initially null. + : top level origin + :: An [=origin=]. The origin of top-level frame in the hierarchy containing the document running + the auction. + : render URL + :: A [=string=], the serialized main URL of the creative to pass in the fetch. + : ad component URLs + :: A [=set=] of [=strings=], list of serialized component URLs of the creative to pass in the + fetch. + : policy container + :: A [=policy container=] to use for the network fetch. + : reply + :: A [=trusted scoring signals reply=], null, or failure. Initially null. Set to a non-null value + when the fetch has been completed. +
+ +A trusted scoring signals reply is a [=struct=] with the following [=struct/items=] +
+ : all trusted scoring signals + :: A [=ordered map=] or failure. + : data version + :: An {{unsigned long}} or null. +
+ +
+ +To create a trusted scoring signals batcher given a {{long}} |urlLengthLimit|: + +1. Let |batcher| be a new [=trusted scoring signals batcher=]. +1. Set |batcher|'s [=trusted scoring signals batcher/url length limit=] to |urlLengthLimit|. +1. Let |queue| be the result of [=starting a new parallel queue=]. +1. [=parallel queue/enqueue steps|Enqueue the following steps=] to |queue|: + 1. [=Batch and fetch trusted scoring signals=] given |batcher|. +1. Return |batcher|. + +
+ +
+ +To fetch trusted scoring signals with batching given a [=trusted scoring signals +batcher=] |batcher| and a [=trusted scoring signals request=] |request|: +1. [=list/Append=] |request| to |batcher|'s [=trusted scoring signals batcher/request queue=]. +1. Wait until |request|'s [=trusted scoring signals request/reply=] is non-null. +1. Return |request|'s [=trusted scoring signals request/reply=]. + +
+ +
+ +To build trusted scoring signals url given a [=URL=] |signalsUrl|, a [=list=] of +[=strings=] |renderURLs|, an [=ordered set=] of [=strings=] |adComponentRenderURLs|, an +{{unsigned short}} |experimentGroupId|, and an [=origin=] |topLevelOrigin|: + +Note: When trusted scoring signals fetches are not batched, |renderURLs|'s [=list/size=] is 1. + +1. Let |queryParamsList| be a new empty [=list=]. +1. [=list/Append=] "hostname=" to |queryParamsList|. +1. [=list/Append=] the result of [=string/UTF-8 percent-encoding=] |topLevelOrigin| using + [=component percent-encode set=] to |queryParamsList|. +1. If |renderURLs| is not [=set/is empty|empty=]: + 1. [=list/Append=] "`&renderURLs=`" to |queryParamsList|. + 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with + |renderURLs|. +1. If |adComponentRenderURLs| is not [=set/is empty|empty=]: + 1. [=list/Append=] "`&adComponentRenderURLs=`" to |queryParamsList|. + 1. [=list/Extend=] |queryParamsList| with the result of [=encode trusted signals keys=] with + |adComponentRenderURLs|. +1. If |experimentGroupId| is not null: + 1. [=list/Append=] "`&experimentGroupId=`" to |queryParamsList|. + 1. [=list/Append=] [=serialize an integer|serialized=] |experimentGroupId| to |queryParamsList|. +1. Set |signalsUrl|'s [=url/query=] to the result of [=string/concatenating=] |queryParamsList|. +1. Return |signalsUrl|. + +
+ +
+To build batched trusted scoring signals url given a non-empty [=list=] of [=trusted +scoring signals requests=] |entriesToBatch|: + +1. Let |firstEntry| be |entriesToBatch|[0]. +1. Let |renderURLs| be an empty [=ordered set=] of [=strings=]. +1. Let |adComponentRenderURLs| be an empty [=ordered set=] of [=strings=] + |adComponentRenderURLs| +1. [=list/For each=] |entry| of |entriesToBatch|: + 1. [=Assert=] that |entry|'s [=trusted scoring signals request/base URL=] is equal to + |firstEntry|'s [=trusted scoring signals request/base URL=]. + 1. [=Assert=] that |entry|'s [=trusted scoring signals request/seller experiment group id=] is + equal to |firstEntry|'s [=trusted scoring signals request/seller experiment group id=]. + 1. [=Assert=] that |entry|'s [=trusted scoring signals request/top level origin=] is equal to + |firstEntry|'s [=trusted scoring signals request/top level origin=]. + 1. [=Assert=] that |entry|'s [=trusted scoring signals request/seller script fetcher=] is equal to + |firstEntry|'s [=trusted scoring signals request/seller script fetcher=]. + 1. [=Assert=] that |entry|'s [=trusted scoring signals request/policy container=] is equal to + |firstEntry|'s [=trusted scoring signals request/policy container=]. + 1. [=set/Append=] |entry|'s [=trusted scoring signals request/render URL=] to |renderURLs|. + 1. [=list/Extend=] |adComponentRenderURLs| with |entry|'s [=trusted scoring signals request/ + ad component URLs=]. +1. Return the result of [=building trusted scoring signals url=] with |firstEntry|'s [=trusted + scoring signals request/base URL=], |renderURLs|, |adComponentRenderURLs|, |firstEntry|'s + [=trusted scoring signals request/seller experiment group id=], + |firstEntry|'s [=trusted scoring signals request/top level origin=]. + +
+ +
+To check if trusted scoring signals batch honors URL length limit given a +[=trusted scoring signals batcher=] |batcher| and a non-empty [=list=] of [=trusted +scoring signals requests=] |entriesToBatch|: + +1. If the [=list/size=] of |entriesToBatch| is 1, return true. +1. If |batcher|'s [=trusted scoring signals batcher/url length limit=] is 0, return true. +1. Return whether the [=string/length=] of the result of [=building batched trusted scoring signals + url=] for |entriesToBatch| ≤ |batcher|'s [=trusted scoring signals batcher/url length + limit=]. + +
+ +
+ +To batch and fetch trusted scoring signals given a [=trusted scoring signals batcher=] +|batcher|: + +1. [=Assert=] that these steps are running [=in parallel=]. +1. Until |batcher| is no longer needed: + 1. Wait until at least one of the following is true: + * |batcher|'s [=trusted scoring signals batcher/request queue=] [=list/is not empty=]. + * |batcher|'s [=trusted scoring signals batcher/request map=] [=map/is not empty=] and some + heuristically chosen amount of time has passed. + 1. Atomically do: + 1. Let |incomingRequests| be a [=list/clone=] of |batcher|'s [=trusted scoring signals batcher/ + request queue=]. + 1. [=list/Empty=] |batcher|'s [=trusted scoring signals batcher/request queue=]. + + Note: the result of atomicity is that any concurrent attempts to modify |batcher|'s [=trusted + scoring signals batcher/request queue=] while these steps are running will not result in + different items being removed by the [=list/Empty=] operation than were cloned into + |incomingRequests|. + + 1. [=list/For each=] |request| in |incomingRequests|: + 1. Let |key| be (|request|'s [=trusted scoring signals request/seller script fetcher=], + |request|'s [=trusted scoring signals request/base url=], |request|'s [=trusted scoring + signals request/seller experiment group id=], |request|'s [=trusted scoring signals request/ + top level origin=]). + 1. If |batcher|'s [=trusted scoring signals batcher/request map=][|key|] does not [=map/exist=], + then [=map/set=] |batcher|'s [=trusted scoring signals batcher/request map=][|key|] to an + [=list/is empty|empty=] [=list=]. + 1. [=list/Append=] |request| to |batcher|'s [=trusted scoring signals batcher/request + map=][|key|]. + 1. Some number of times, heuristically, select a |key| and a non-[=list/is empty|empty=] [=set/ + subset=] of |batcher|'s [=trusted scoring signals batcher/request map=][|key|], called + |entriesToBatch|, such that [=checking if trusted scoring signals batch honors URL length + limit=] on |batcher| and |entriesToBatch| returns true: + + Note: implementations are free to wait to collect more requests to merge (by leaving things + in the |batcher|'s [=trusted scoring signals batcher/request map=]), or send them + individually, but need to take into account the configured URL length limit if they do combine + requests. All entries need to be handled eventually. + + 1. [=list/Remove=] |entriesToBatch| from |batcher|'s [=trusted scoring signals batcher/ + request map=][|key|]. + 1. If |batcher|'s [=trusted scoring signals batcher/request map=][|key|] [=list/is empty=], + then [=map/remove=] |key| from |batcher|'s [=trusted scoring signals batcher/request map=]. + 1. Let |fullSignalsUrl| be the result of [=building batched trusted scoring signals url=] for + |entriesToBatch|. + 1. Let |seller| be |entriesToBatch|[0]'s [=trusted scoring signals request/seller=]. + 1. Let |scriptFetcher| be |entriesToBatch|[0]'s [=trusted scoring signals request/seller + script fetcher=]. + 1. Let |policyContainer| be |entriesToBatch|[0]'s [=trusted scoring signals request/policy + container=]. + 1. If |fullSignalsUrl|'s [=url/origin=] is not [=same origin=] with |seller| then: + 1. Let |allowCrossOriginTrustedScoringSignalsFrom| be the result of [=wait for cross origin + trusted scoring signals authorization from a fetcher=] given |scriptFetcher|. + 1. If |allowCrossOriginTrustedScoringSignalsFrom| does not [=list/contain=] + |fullSignalsUrl|'s [=url/origin=], set |fullSignalsUrl| to null. + 1. Let |result| be failure. + 1. If |fullSignalsUrl| is not null: + 1. Let «|allTrustedScoringSignals|, ignored, |scoringDataVersion|» be + the result of [=fetching trusted signals=] with |fullSignalsUrl|, |seller|, + |policyContainer|, and false. + 1. If |allTrustedScoringSignals| is an [=ordered map=]: + 1. Set |result| to a new [=trusted scoring signals reply=] + 1. Set |result|'s [=trusted scoring signals reply/all trusted scoring signals=] to + |allTrustedScoringSignals|. + 1. Set |result|'s [=trusted scoring signals reply/data version=] to |scoringDataVersion|. + 1. [=list/For each=] |entry| in |entriesToBatch|: + 1. Set |entry|'s [=trusted scoring signals request/reply=] to |result|. + +
+

Generated bid

A generated bid is a bid that needs to be scored by the seller. The bid is either the