From 032f1592ce26b837d0772eb7e4b7e725cf9b3694 Mon Sep 17 00:00:00 2001 From: Maks Orlovich Date: Mon, 22 Jul 2024 09:30:07 -0400 Subject: [PATCH] More explicit representation of script fetch parallelism (#1225) * 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. * Improve some phrasing as suggested * Fix wrong indentation level, now I can see in a preview diff. * Fix missing comma. --------- Co-authored-by: Maks Orlovich --- spec.bs | 224 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 136 insertions(+), 88 deletions(-) diff --git a/spec.bs b/spec.bs index c7998a789..27398236d 100644 --- a/spec.bs +++ b/spec.bs @@ -1493,8 +1493,10 @@ a {{DirectFromSellerSignalsForBuyer}} |directFromSellerSignalsForBuyer|, a [=dur 1. [=map/Set=] |prevWinIDL|["{{PreviousWin/adJSON}}"] to |prevWin|'s [=previous win/ad json=]. 1. [=list/Append=] |prevWinIDL| to |prevWins|. 1. [=map/Set=] |browserSignals|["{{BiddingBrowserSignals/prevWinsMs}}"] to |prevWins|. - 1. Let « |biddingScript|, ignored » be the result of [=fetching script=] with + 1. Let |biddingScriptFetcher| be the result of [=creating a new script fetcher=] with |ig|'s [=interest group/bidding url=]. + 1. Let |biddingScript| be the result of [=waiting for script body from a fetcher=] given + |biddingScriptFetcher|. 1. If |biddingScript| is failure, return failure. 1. If |ig|'s [=interest group/bidding wasm helper url=] is not null: 1. Let |wasmModuleObject| be the result of [=fetching WebAssembly=] with |ig|'s @@ -1534,9 +1536,8 @@ To generate and score bids given an [=auction config=] |auctionConfig |bidDebugReportInfoList|: 1. [=Assert=] that these steps are running [=in parallel=]. 1. Let |auctionStartTime| be the [=current wall time=]. -1. Let « |decisionLogicScript|, |allowCrossOriginTrustedScoringSignalsFrom| » be the result of - [=fetching script=] with |auctionConfig|'s [=auction config/decision logic url=]. -1. If |decisionLogicScript| is failure, return null. +1. Let |decisionLogicFetcher| be the result of [=creating a new script fetcher=] with + |auctionConfig|'s [=auction config/decision logic url=]. 1. Let |seller| be |auctionConfig|'s [=auction config/seller=]. 1. Let « |bidGenerators|, |negativeTargetInfo| » be the result of running [=build bid generators map=] with |auctionConfig|. @@ -1566,12 +1567,12 @@ To generate and score bids given an [=auction config=] |auctionConfig 1. Set |topLevelDirectFromSellerSignalsRetrieved| to true. 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|, |decisionLogicScript|, - |allowCrossOriginTrustedScoringSignalsFrom|, null, "top-level-auction", null, and |topLevelOrigin|. + [=leading bid info/leading bid=], |leadingBidInfo|, |decisionLogicFetcher|, + 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|, |decisionLogicScript|, |allowCrossOriginTrustedScoringSignalsFrom|, null, + |leadingBidInfo|, |decisionLogicFetcher|, null, "top-level-auction", null, and |topLevelOrigin|. 1. Decrement |pendingComponentAuctions| by 1. 1. Wait until |pendingComponentAuctions| is 0. @@ -1638,7 +1639,7 @@ To generate and score bids given an [=auction config=] |auctionConfig 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|, - |decisionLogicScript|, |allowCrossOriginTrustedScoringSignalsFrom|, null, |auctionLevel|, + |decisionLogicFetcher|, null, |auctionLevel|, |componentAuctionExpectedCurrency|, and |topLevelOrigin|. 1. Decrement |pendingAdditionalBids| by 1. 1. Let |settings| be |global|'s [=relevant settings object=]. @@ -1796,9 +1797,8 @@ To generate and score bids given an [=auction config=] |auctionConfig 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|, - |decisionLogicScript|, |allowCrossOriginTrustedScoringSignalsFrom|, - |directFromSellerSignalsForSeller|, |dataVersion|, |auctionLevel|, - |componentAuctionExpectedCurrency|, and |topLevelOrigin|. + |decisionLogicFetcher|, |directFromSellerSignalsForSeller|, |dataVersion|, + |auctionLevel|, |componentAuctionExpectedCurrency|, and |topLevelOrigin|. 1. Decrement |pendingBuyers| by 1. 1. Wait until both |pendingBuyers| and |pendingAdditionalBids| are 0. 1. If |leadingBidInfo|'s [=leading bid info/leading bid=] is null, return null. @@ -1883,8 +1883,8 @@ 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 [=list=] of [=origins=] -|allowCrossOriginTrustedScoringSignalsFrom|, and an [=origin=] |topLevelOrigin|: +a [=generated bid=] |generatedBid|, a [=script fetcher=] |decisionLogicFetcher|, and an [=origin=] +|topLevelOrigin|: 1. Let |crossOriginTrustedScoringSignalsOrigin| be null. 1. Let |sameOriginTrustedScoringSignals| be null. @@ -1923,6 +1923,8 @@ a [=generated bid=] |generatedBid|, a [=list=] of [=origins=] 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. @@ -1962,7 +1964,7 @@ a [=generated bid=] |generatedBid|, a [=list=] of [=origins=]
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 [=string=] |decisionLogicScript|, a [=list=] or [=origins=] |allowCrossOriginTrustedScoringSignalsFrom|, +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|, and an [=origin=] @@ -1970,8 +1972,8 @@ or "component-auction", a [=currency tag=] |componentAuctionExpectedCurrency|, a 1. Let «|crossOriginTrustedScoringSignalsOrigin|, |sameOriginTrustedScoringSignals|, |crossOriginTrustedScoringSignals|, |scoringDataVersion|» be the result of [=fetch and - decode trusted scoring signals=] given |auctionConfig|, |generatedBid|, - |allowCrossOriginTrustedScoringSignalsFrom|, |topLevelOrigin|. + decode trusted scoring signals=] given |auctionConfig|, |generatedBid|, |decisionLogicFetcher|, + |topLevelOrigin|. 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 @@ -2007,6 +2009,9 @@ or "component-auction", a [=currency tag=] |componentAuctionExpectedCurrency|, a
The result of running [=is debugging only in cooldown or lockout=] with |seller| +1. Let |decisionLogicScript| be the result of [=wait for script body from a fetcher=] given + |decisionLogicFetcher|. +1. If |decisionLogicScript| is falure, return. 1. Let « |scoreAdResult|, |debugWinReportUrl|, |debugLossReportUrl| » be the result of [=evaluating a scoring script=] with |decisionLogicScript|, |adMetadata|, |bidValue|'s [=bid with currency/value=], |auctionConfig|'s [=auction config/config idl=], @@ -2187,74 +2192,6 @@ To validate fetching response given a [=response=] |response|, null, 1. Return true.
-The Ad-Auction-Allow-Trusted-Scoring-Signals-From HTTP response header is a -[=structured header=] whose value must be a [=structured header/list=] of [=structured header/strings=]. - -
-To parse allowed trusted scoring signals origins given a [=header list=] |headerList|: - - 1. Let |parsedHeader| be the result of [=header list/getting a structured field value=] - given [:Ad-Auction-Allow-Trusted-Scoring-Signals-From:] and "`list`" from |headerList|. - 1. If |parsedHeader| is null, return an empty [=list=]. - 1. Let |result| be a new [=list=] of [=origins=]. - 1. [=list/For each=] |entry| in |parsedHeader|: - 1. If |entry| is not a [=string=], return an empty [=list=]. - 1. Let |parsedEntry| be the result of [=parsing an https origin=] on |entry|. - 1. If |parsedEntry| is failure, return an empty [=list=]. - 1. [=list/Append=] |parsedEntry| to |result|. - 1. Return |result|. -
- -
-To fetch script given a [=URL=] |url|: - 1. Let |request| be a new [=request=] with the following properties: - : [=request/URL=] - :: |url| - : [=request/header list=] - :: «`Accept`: `text/javascript`» - : [=request/client=] - :: `null` - : [=request/mode=] - :: "`no-cors`" - : [=request/referrer=] - :: "`no-referrer`" - : [=request/credentials mode=] - :: "`omit`" - : [=request/redirect mode=] - :: "`error`" - - Issue: One of the side-effects of a `null` client for this subresource request is it neuters all - service worker interceptions, despite not having to set the service workers mode. - - Issue: Stop using "`no-cors`" mode where possible - (WICG/turtledove#667). - 1. Let |script| be null. - 1. Let |allowCrossOriginTrustedScoringSignalsFrom| be an empty [=list=]. - 1. Let |fetchController| be the result of [=fetching=] |request| with [=fetch/useParallelQueue=] - set to true, and [=fetch/processResponse=] set to the following steps given - a [=response=] |response|: - 1. If the result of [=validating fetching response headers=] given |response| is false: - 1. [=fetch controller/Abort=] |fetchController|. - 1. Set |script| to failure. - 1. Return. - 1. Set |allowCrossOriginTrustedScoringSignalsFrom| to the result of [=parsing allowed trusted - scoring signals origins=] given |response|'s [=response/header list=]. - 1. Let |bodyStream| be |response|’s [=response/body=]’s [=body/stream=]. - 1. Let |bodyReader| be result of [=ReadableStream/getting a reader=] from |bodyStream|. - 1. Let |successSteps| be a set of steps that take a [=byte sequence=] |responseBody|, and - perform the following: - 1. If [=validate fetching response mime and body=] with |response|, |responseBody| and - "`text/javascript`" returns false, set |script| to failure. - 1. Otherwise, set |script| to |responseBody|. - 1. Let |failureSteps| be a set of steps that take an [=exception=] e, and - perform the following: - 1. Set |script| to failure. - 1. [=ReadableStreamDefaultReader/Read all bytes=] from |bodyReader|, given |successSteps| - and |failureSteps|. - 1. Wait for |script| to be set. - 1. Return « |script|, |allowCrossOriginTrustedScoringSignalsFrom| ». -
-
To fetch WebAssembly given a [=URL=] |url|: @@ -2628,8 +2565,10 @@ To report result given a [=leading bid info=] |leadingBidInfo|, a given |winner|'s [=generated bid/interest group=] and |igAd| is true, then [=map/set=] |browserSignals|["{{ReportingBrowserSignals/buyerAndSellerReportingId}}"] to |igAd|'s [=interest group ad/buyer and seller reporting ID=]. - 1. Let « |sellerReportingScript|, ignored » be the result of [=fetching script=] - with |config|'s [=auction config/decision logic url=]. + 1. Let |sellerReportingScriptFetcher| be the result of [=creating a new script fetcher=] with + |config|'s [=auction config/decision logic url=]. + 1. Let |sellerReportingScript| be the result of [=waiting for script body from a fetcher=] given + |sellerReportingScriptFetcher|. 1. Let « |sellerSignals|, |reportUrl|, |reportingBeaconMap|, ignored » be the result of [=evaluating a reporting script=] with |sellerReportingScript|, "`reportResult`", |config|'s [=auction config/config idl=]'s {{AuctionAdConfig/reportingTimeout}}, and @@ -2697,8 +2636,10 @@ a {{ReportingBrowserSignals}} |browserSignals|, and a [=direct from seller signa |igAd|'s [=interest group ad/buyer reporting ID=]. 1. Otherwise, [=map/Set=] |reportWinBrowserSignals|["{{ReportWinBrowserSignals/interestGroupName}}"] to |winner|'s [=generated bid/interest group=] [=interest group/name=]. - 1. Let « |buyerReportingScript|, ignored » be the result of [=fetching script=] - with |winner|'s [=generated bid/interest group=]'s [=interest group/bidding url=]. + 1. Let |buyerReportingScriptFetcher| be the result of [=creating a new script fetcher=] with + |winner|'s [=generated bid/interest group=]'s [=interest group/bidding url=]. + 1. Let |buyerReportingScript| be the result of [=waiting for script body from a fetcher=] given + |buyerReportingScriptFetcher|. 1. Let |reportFunctionName| be "`reportWin`". 1. If |winner|'s [=generated bid/provided as additional bid=] is true: 1. Set |reportFunctionName| be "`reportAdditionalBidWin`". @@ -5662,6 +5603,113 @@ A per signals url bid generator is an [=ordered map=] whose [=map/key representing [=interest group/joining origins=], and whose [=map/values=] are [=lists=] of [=interest groups=]. +

Script fetcher

+ +A script fetcher helps manage asynchronous fetching of scripts and handling of their +headers. It's a [=struct=] with the following [=struct/items=]: + +
+ : script body + :: A [=byte sequence=], null, or failure. Initially null. The body of the script. + : origins authorized for cross origin trusted signals + :: A [=list=] of [=origins=] or null. Initially null. Parsed value of + [:Ad-Auction-Allow-Trusted-Scoring-Signals-From:]. +
+ +
+To create a new script fetcher given a [=URL=] |url|: + + 1. Let |fetcher| be a new [=script fetcher=]. + 1. Let |queue| be the result of [=starting a new parallel queue=]. + 1. [=parallel queue/enqueue steps|Enqueue the following steps=] to |queue|: + 1. [=Fetch script=] given |url| and |fetcher|. + 1. Return |fetcher|. +
+ +
+To wait for script body from a fetcher given a [=script fetcher=] |fetcher|: + + 1. Wait until |fetcher|'s [=script fetcher/script body=] is not null. + 1. Return |fetcher|'s [=script fetcher/script body=]. +
+ +
+To wait for cross origin trusted scoring signals authorization from a fetcher given a +[=script fetcher=] |fetcher|: + + 1. Wait until |fetcher|'s [=script fetcher/origins authorized for cross origin trusted signals=]. + is not null. + 1. Return |fetcher|'s [=script fetcher/origins authorized for cross origin trusted signals=]. +
+ +The Ad-Auction-Allow-Trusted-Scoring-Signals-From HTTP response +header is a [=structured header=] whose value must be a [=structured header/list=] of [=structured +header/strings=]. + +
+To parse allowed trusted scoring signals origins given a [=header list=] |headerList|: + + 1. Let |parsedHeader| be the result of [=header list/getting a structured field value=] + given [:Ad-Auction-Allow-Trusted-Scoring-Signals-From:] and "`list`" from |headerList|. + 1. If |parsedHeader| is null, return an empty [=list=]. + 1. Let |result| be a new [=list=] of [=origins=]. + 1. [=list/For each=] |entry| in |parsedHeader|: + 1. If |entry| is not a [=string=], return an empty [=list=]. + 1. Let |parsedEntry| be the result of [=parsing an https origin=] on |entry|. + 1. If |parsedEntry| is failure, return an empty [=list=]. + 1. [=list/Append=] |parsedEntry| to |result|. + 1. Return |result|. +
+ +
+To fetch script given a [=URL=] |url| and a [=script fetcher=] |fetcher|: + 1. Let |request| be a new [=request=] with the following properties: + : [=request/URL=] + :: |url| + : [=request/header list=] + :: «`Accept`: `text/javascript`» + : [=request/client=] + :: `null` + : [=request/mode=] + :: "`no-cors`" + : [=request/referrer=] + :: "`no-referrer`" + : [=request/credentials mode=] + :: "`omit`" + : [=request/redirect mode=] + :: "`error`" + + Issue: One of the side-effects of a `null` client for this subresource request is it neuters all + service worker interceptions, despite not having to set the service workers mode. + + Issue: Stop using "`no-cors`" mode where possible + (WICG/turtledove#667). + 1. Let |fetchController| be the result of [=fetching=] |request| with [=fetch/useParallelQueue=] + set to true, and [=fetch/processResponse=] set to the following steps given + a [=response=] |response|: + 1. If the result of [=validating fetching response headers=] given |response| is false: + 1. [=fetch controller/Abort=] |fetchController|. + 1. Set |fetcher|'s [=script fetcher/origins authorized for cross origin trusted signals=] to + an empty [=list=] of [=origins=]. + 1. Set |fetcher|'s [=script fetcher/script body=] to failure. + 1. Set |fetcher|'s [=script fetcher/origins authorized for cross origin trusted signals=] to the + result of [=parsing allowed trusted scoring signals origins=] given |response|'s [=response/ + header list=]. + 1. Let |bodyStream| be |response|’s [=response/body=]’s [=body/stream=]. + 1. Let |bodyReader| be result of [=ReadableStream/getting a reader=] from |bodyStream|. + 1. Let |successSteps| be a set of steps that take a [=byte sequence=] |responseBody|, and + perform the following: + 1. If [=validate fetching response mime and body=] with |response|, |responseBody| and + "`text/javascript`" returns false, set |fetcher|'s [=script fetcher/script body=] to + failure. + 1. Otherwise, set set |fetcher|'s [=script fetcher/script body=] to |responseBody|. + 1. Let |failureSteps| be a set of steps that take an [=exception=] e, and + perform the following: + 1. Set set |fetcher|'s [=script fetcher/script body=] to failure. + 1. [=ReadableStreamDefaultReader/Read all bytes=] from |bodyReader|, given |successSteps| + and |failureSteps|. +
+

Trusted bidding signals batcher

A trusted bidding signals batcher helps manage merging multiple trusted bidding signals