diff --git a/spec.bs b/spec.bs index 35b51ef42..d58c2bd0d 100644 --- a/spec.bs +++ b/spec.bs @@ -20,6 +20,10 @@ Assume Explicit For: yes
+urlPrefix: https://fetch.spec.whatwg.org/; spec: Fetch + type: dfn + text: HTTP-network-or-cache fetch; url: #concept-http-network-or-cache-fetch + text: task destination; for: fetch params; url: fetch-params-task-destination urlPrefix: https://www.ietf.org/rfc/rfc4122.txt type: dfn; text: urn uuid urlPrefix: https://github.com/WICG/turtledove/blob/main/FLEDGE_k_anonymity_server.md @@ -42,6 +46,7 @@ spec: RFC8941; urlPrefix: https://httpwg.org/specs/rfc8941.html for: structured header text: boolean; url: boolean text: integer; url: integer + text: boolean; url: boolean spec: WebAssembly; urlPrefix: https://webassembly.github.io/spec/core/ type: dfn urlPrefix: appendix/embedding.html @@ -519,6 +524,8 @@ bid in the auction for the chance to display their advertisement.runAdAuction()
+TODO: Promise wiring, pass results to worklets. This is being done in +https://github.com/WICG/turtledove/pull/774.[SecureContext] partial interface Navigator { @@ -533,6 +540,7 @@ dictionary AuctionAdConfig { Promise auctionSignals; Promise sellerSignals; Promise directFromSellerSignals; + Promise directFromSellerSignalsHeaderAdSlot; unsigned long long sellerTimeout; unsigned short sellerExperimentGroupId; USVString sellerCurrency; @@ -2932,6 +2940,202 @@ This specification defines two [=policy-controlled features=] identified by the Issue(WICG/turtledove#522): Move from "`*`" to "`self`". +# Handling Direct from Seller Signals # {#handling-direct-from-seller-signals} + +This section specifies a manner by which signals may be provided to auctions such that the signals +are only used within their intended auction. + +Any {{Document}} in a [=traversable navigable=] may run a Protected Audience auction (with +{{Window/navigator}}.{{Navigator/runAdAuction()}}) whose worklet functions receive signal objects +derived from JSON from an [:Ad-Auction-Signals:] header captured by a +{{WindowOrWorkerGlobalScope/fetch()}} call (using the {{RequestInit/adAuctionHeaders}} option) +initiated by any *other* {{Document}} in the *same* [=traversable navigable=]. + + +Modify the definition of a [=request=]: + +A [=request=] has an associated boolean capture-ad-auction-headers. +Unless stated otherwise it is false. ++ ++Modify [[FETCH]]'s {{RequestInit}} dictionary to add an adAuctionHeaders attribute: + ++ ++partial dictionary RequestInit { + boolean adAuctionHeaders; +}; +++The following step will be added to the+ ++new Request (input, init)
constructor steps, before +step "Set [=this=]'s [=Request/request=] to |request|": + +1. If init["{{RequestInit/adAuctionHeaders}}"] [=map/exists=], then set + |request|'s [=request/capture-ad-auction-headers=] to it. + ++The following step will be added to the [=HTTP-network-or-cache fetch=] algorithm, before step +"Modify |httpRequest|'s [=request/header list=] per HTTP. ...": + +1. If [=request=]'s [=request/capture-ad-auction-headers=] is true, then [=header list/set a + structured field value=] given «[:Sec-Ad-Auction-Fetch:], the [=structured header/boolean=] `?1`» + in |httpRequest|'s [=header list=]. + ++ ++Modify [[FETCH]]'s [[FETCH#infrastructure]] to add a new section called "Per Traversable Navigable +Structures", with the following content: + ++ +Direct from seller signals key
+A direct from seller signals key is a [=struct=] with the following [=struct/items=]: + +NOTE: This is only captured during a [=request=] whose [=request/initiator type=] is `"fetch"`, made +with the {{RequestInit/adAuctionHeaders}} option set to `true`, as described in the +[:Ad-Auction-Signals:] header description. + ++: seller +:: An [=origin=]. Matches the origin that served the captured [:Ad-Auction-Signals:] header. +: ad slot +:: A [=string=]. Matches the `adSlot` key of the JSON dictionaries in the top-level array of the + [:Ad-Auction-Signals:] value. + +
+ +Direct from seller signals
+A direct from seller signals is a [=struct=] with the following [=struct/items=]: + +NOTE: This is only captured during a [=request=] whose [=request/initiator type=] is `"fetch"`, made +with the {{RequestInit/adAuctionHeaders}} option set to `true`, as described in the +[:Ad-Auction-Signals:] header description. + ++: auction signals +:: Null or a [=string=]. + Opaque JSON data passed to both buyers' and the seller's [=script runners=]. +: seller signals +:: Null or a [=string=]. + Opaque JSON data passed to the seller's [=script runner=]. +: per buyer signals +:: A [=map=] whose [=map/keys=] are [=origins=] and whose [=map/values=] are [=strings=]. + [=map/Keys=] are buyers and must be valid HTTPS origins. [=map/Values=] are opaque JSON data + passed to corresponding buyer's [=script runner=]. + +
+ +Each [=traversable navigable=] has a captured ad auction headers +, which is a [=map=] whose [=map/keys=] are [=direct from seller signals keys=] and whose +[=map/values=] are [=direct from seller signals=]. ++The following will be added to [[Fetch#http-extensions]]: + ++ +The \`
+ +The \`Sec-Ad-Auction-Fetch
\` HTTP +request headerSec-Ad-Auction-Fetch
\` request header is an optional +[=structured header=] with of type [=structured header/boolean=]. [:Sec-Ad-Auction-Fetch:] will only +be set on a [=request=] whose [=request/initiator type=] is `"fetch"`, made with the +{{RequestInit/adAuctionHeaders}} option set to `true`. If [:Sec-Ad-Auction-Fetch:] is equal to `?1`, +the user agent will remove any [:Ad-Auction-Signals:] from the returned [=response=] -- the +[:Ad-Auction-Signals:] value will instead only be used in Protected Audiences auctions. + +The \`
+ +The \`Ad-Auction-Signals
\` HTTP +response headerAd-Auction-Signals
\` response header provides value +of a JSON array of dictionaries, each with an `adSlot` key. Protected Audience non-component, +component, and top-level auctions may specify which signals to load by the `adSlot` key. ++The following step will be added to the [=HTTP fetch=] algorithm, immediately under the step "If +internalResponse’s [=status=] is a [=redirect status=]:" + +1. [=header list/Delete=] "[:Ad-Auction-Signals:]" from response's + [=response/header list=]. + ++ ++The following step will be added to the [=HTTP fetch=] algorithm, before step +"Return |response|.": + +1. If |response| is not null, |response|'s [=status=] is not a [=redirect status=], |fetchParams|'s + [=fetch params/task destination=] is a [=global object=] that's a {{Window}} object, and + |request|'s [=request/capture-ad-auction-headers=] is `true`, then run [=update captured headers=] + with |fetchParams|'s [=fetch params/task destination=]'s [=associated Document's=] [=node + navigable's=] [=traversable navigable's=] [=traversable navigable/captured ad auction headers=], + |response|'s [=response/header list=], and |request|'s [=request/URL=]'s [=url/origin=]. + ++ ++The following algorithm will be added to the [[FETCH#fetching]] section: + ++ + # Structures # {#structures}Update captured headers
+ + To update captured headers with a [=traversable + navigable/captured ad auction headers=] |storedHeaders|, [=header list=] |responseHeaders|, and + [=origin=] |requestOrigin|: + 1. Let |adAuctionSignals| be the result of [=header list/getting=] [:Ad-Auction-Signals:] from + |responseHeaders|. + 1. If |adAuctionSignals| is null, return. + 1. [=header list/Delete=] "[:Ad-Auction-Signals:]" from |responseHeaders|. + + NOTE: This step prevents the header value from being used outside the intended auctions -- + that is, scripts making the {{WindowOrWorkerGlobalScope/fetch()}} request aren't able to load + the header value. + 1. Let |parsedSignals| be the result of [=parsing JSON bytes to an Infra value=], given + |adAuctionSignals|. + 1. If |parsedSignals| is failure, return. + 1. If |parsedSignals| is not a [=list=], return. + 1. [=list/For each=] |signal| in |parsedSignals|: + 1. If |signal| is not an [=ordered map=], [=iteration/continue=]. + 1. If |signal|["`adSlot`"] doesn't exist, [=iteration/continue=]. + 1. Create a new [=direct from seller signals key=] |signalsKey|, with its + [=direct from seller signals key/seller=] set to |requestOrigin| and its + [=direct from seller signals key/ad slot=] set to |signal|["`adSlot`"]. + 1. Create a new [=direct from seller signals=] |processedSignals|. + 1. [=map/Remove=] |signal|["`adSlot`"]. + 1. [=map/For each=] |key| → |value| of |signal|: + 1. Switch on |key|: ++
+ + 1. Set |storedHeaders|[|signalsKey|] to |processedSignals|. + +- "`sellerSignals`" +
- + 1. Set |processedSignals|'s [=direct from seller signals/seller signals=] to the result + of [=serializing an Infra value to a JSON string=], given |value|. + +
- "`auctionSignals`" +
- + 1. Set |processedSignals|'s [=direct from seller signals/auction signals=] to the result + of [=serializing an Infra value to a JSON string=], given |value|. + +
- "`perBuyerSignals`" +
- + 1. If |value| is not an [=ordered map=], [=iteration/continue=]. + 1. For each |buyer| → |buyerSignals| of |value|: + 1. Let |buyerOrigin| be the result of [=parsing an https origin=] on |buyer|. If this + [=exception/throws=], [=iteration/continue=]. + 1. Let |buyerSignalsString| be the result of + [=serializing an Infra value to a JSON string=], given |buyerSignals|. + 1. Set |processedSignals|'s + [=direct from seller signals/per buyer signals=][|buyerOrigin|] to |buyerSignalsString|. + +