Skip to content

Commit

Permalink
Parse Ad-Auction-Additional-Bid response header (#888)
Browse files Browse the repository at this point in the history
* work in progress.

* Finish

* Update spec.bs

Co-authored-by: caraitto <[email protected]>

* Address comments

* Address comments.

---------

Co-authored-by: Qingxin Wu <[email protected]>
Co-authored-by: caraitto <[email protected]>
  • Loading branch information
3 people authored Nov 14, 2023
1 parent a13de44 commit 3de7fde
Showing 1 changed file with 111 additions and 84 deletions.
195 changes: 111 additions & 84 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,8 +1125,7 @@ To <dfn>validate and convert auction ad config</dfn> given an {{AuctionAdConfig}
returned from an associated [=request=], whose [=request/initiator type=] is `"fetch"` and the
{{RequestInit/adAuctionHeaders}} option set to `true`, resolves or rejects. Otherwise, there
will be a race condition that the worklet can run without the direct from seller signals that
it needs. See [[#handling-direct-from-seller-signals]] for details.

it needs. See [[#fetch-patch-for-auction-headers]] for details.
* To parse the value |result|:
1. Set |auctionConfig|'s [=auction config/direct from seller signals header ad slot=] to
|result|.
Expand Down Expand Up @@ -1401,7 +1400,7 @@ To <dfn>generate and score bids</dfn> given an [=auction config=] |auctionConfig
1. Let |leadingBidInfo| be a new [=leading bid info=].
1. Let |queue| be the result of [=starting a new parallel queue=].
1. Let |capturedAuctionHeaders| be |global|'s [=associated Document's=] [=node navigable's=]
[=traversable navigable's=] [=traversable navigable/captured ad auction headers=].
[=traversable navigable's=] [=traversable navigable/captured ad auction signals headers=].
1. If |auctionConfig|'s [=auction config/component auctions=] are not [=list/is empty|empty=]:
1. [=Assert=] |topLevelAuctionConfig| is null.
1. Let |pendingComponentAuctions| be |auctionConfig|'s [=auction config/component auctions=]'s
Expand Down Expand Up @@ -3732,16 +3731,39 @@ 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}
# Fetch Patch for Auction Headers # {#fetch-patch-for-auction-headers}

This section specifies a manner by which signals may be provided to auctions such that the signals
are only used within their intended auction.
This section specifies a manner by which some data, including [=additional bids=] and
[=direct from seller signals=], may be provided to auctions such that the data is 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=].
derived from JSON from an [:Ad-Auction-Signals:] header, or [=additional bids=] derived from an
[:Ad-Auction-Additional-Bid:] header, captured by a {{WindowOrWorkerGlobalScope/fetch()}} call
(using the {{RequestInit/adAuctionHeaders}} option) initiated by any *other* {{Document}} in the
*same* [=traversable navigable=].

<div algorithm="fetch per traversable navigable structures patch">
Modify [[FETCH]]'s [[FETCH#infrastructure]] to add a new section called "Per Traversable Navigable
Structures", with the following content:

Each [=traversable navigable=] has a <dfn for="traversable navigable">captured ad auction signals
headers</dfn>, which is a [=map=] whose [=map/keys=] are [=direct from seller signals keys=] and
whose [=map/values=] are [=direct from seller signals=].

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.

Each [=traversable navigable=] has a <dfn for="traversable navigable">captured ad auction additional
bids headers</dfn>, which is a [=map=] whose [=map/keys=] are [=auction nonces=] and whose
[=map/values=] are [=strings=].

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-Additional-Bid:] header description.
</div>

<div algorithm="fetch capture adAuctionHeaders boolean patch">
Modify the definition of a [=request=]:
Expand Down Expand Up @@ -3780,52 +3802,6 @@ The following step will be added to the [=HTTP-network-or-cache fetch=] algorith

</div>

<div algorithm="fetch per traversable navigable structures patch">
Modify [[FETCH]]'s [[FETCH#infrastructure]] to add a new section called "Per Traversable Navigable
Structures", with the following content:

<h3 id=direct-from-sellers-signals-key-struct>Direct from seller signals key</h3>
A <dfn>direct from seller signals key</dfn> 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.

<dl dfn-for="direct from seller signals key">
: <dfn>seller</dfn>
:: An [=origin=]. Matches the origin that served the captured [:Ad-Auction-Signals:] header.
: <dfn>ad slot</dfn>
:: A [=string=]. Matches the `adSlot` key of the JSON dictionaries in the top-level array of the
[:Ad-Auction-Signals:] value.

</dl>

<h3 id=direct-from-sellers-signals-struct>Direct from seller signals</h3>
A <dfn>direct from seller signals</dfn> 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.

<dl dfn-for="direct from seller signals">
: <dfn>auction signals</dfn>
:: Null or a [=string=].
Opaque JSON data passed to both buyers' and the seller's [=script runners=].
: <dfn>seller signals</dfn>
:: Null or a [=string=].
Opaque JSON data passed to the seller's [=script runner=].
: <dfn>per buyer signals</dfn>
:: 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=].

</dl>

Each [=traversable navigable=] has a <dfn for="traversable navigable">captured ad auction headers
</dfn>, which is a [=map=] whose [=map/keys=] are [=direct from seller signals keys=] and whose
[=map/values=] are [=direct from seller signals=].
</div>

<div algorithm="fetch auction headers patch">
The following will be added to [[Fetch#http-extensions]]:

Expand All @@ -3851,15 +3827,17 @@ HTTP response header.</h3>

The \`<dfn http-header><code>Ad-Auction-Additional-Bid</code></dfn>\` response header provides value
of a string in the format of `<auction nonce>:<base64-encoding of the signed additional bid>`, which
corresponds to a single additional bid. The response may include more than one additional bid by
specifying multiple instances of the [:Ad-Auction-Additional-Bid:] response header.
corresponds to a single [=additional bid=]. The response may include more than one [=additional bid=]
by specifying multiple instances of the [:Ad-Auction-Additional-Bid:] response header.
</div>

<div algorithm="fetch auction signals redirect patch">
The following step will be added to the [=HTTP fetch=] algorithm, immediately under the step "If
<div algorithm="ad auction fetch redirect patch">
The following steps will be added to the [=HTTP fetch=] algorithm, immediately under the step "If
<var ignore>internalResponse</var>’s [=status=] is a [=redirect status=]:"

1. [=header list/Delete=] "[:Ad-Auction-Signals:]" from <var ignore>response</var>'s
1. [=header list/Delete=] "[:Ad-Auction-Signals:]" from |response|'s
[=response/header list=].
1. [=header list/Delete=] "[:Ad-Auction-Additional-Bid:]" from |response|'s
[=response/header list=].

</div>
Expand All @@ -3870,40 +3848,65 @@ The following step will be added to the [=HTTP fetch=] algorithm, before step

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=].
|request|'s [=request/capture-ad-auction-headers=] is `true`:
1. Let |navigable| be |fetchParams|'s [=fetch params/task destination=]'s [=associated Document=]'s
[=node navigable=]'s [=traversable navigable=].
1. Run [=update captured headers=] with |navigable|'s
[=traversable navigable/captured ad auction signals headers=], |navigable|'s
[=traversable navigable/captured ad auction additional bids headers=], |response|'s
[=response/header list=], and |request|'s [=request/URL=]'s [=url/origin=].

</div>

<div algorithm="fetch update captured headers patch">
The following algorithm will be added to the [[FETCH#fetching]] section:

<h3 id=update-captured-headers>Update captured headers</h3>

To <dfn id=concept-update-captured-headers>update captured headers</dfn> with a [=traversable
navigable/captured ad auction headers=] |storedHeaders|, [=header list=] |responseHeaders|, and
[=origin=] |requestOrigin|:
navigable/captured ad auction signals headers=] |storedSignalsHeaders|,
[=traversable navigable/captured ad auction additional bids headers=] |storedAdditionalBidsHeaders|,
[=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|.
1. If |adAuctionSignals| is not null:
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. [=Handle ad auction signals header value=] given |adAuctionSignals|, |storedSignalsHeaders| and
|requestOrigin|.
1. Let |additionalBids| be the result of [=header list/getting, decoding, and splitting=]
[:Ad-Auction-Additional-Bid:] from |responseHeaders|.
1. If |additionalBids| is not null:
1. [=header list/Delete=] "[:Ad-Auction-Additional-Bid:]" 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. [=list/For each=] |bid| of |additionalBids|:
1. Let |nonceAndAdditionalBid| be the result of [=strictly splitting=] |bid| on U+003A (:).
1. If |nonceAndAdditionalBid|'s [=list/size=] is not 2, then [=iteration/continue=].
1. Let |nonce| be |nonceAndAdditionalBid|[0].
1. If |nonce|'s [=string/length=] is not 36, then [=iteration/continue=].
1. Set |storedAdditionalBidsHeaders|[|nonce|] to |nonceAndAdditionalBid|[1].

</div>

<div algorithm>
To <dfn>handle ad auction signals header value</dfn> given a [=byte sequence=] |adAuctionSignals|,
[=traversable navigable/captured ad auction signals headers=] |storedSignalsHeaders|, and [=origin=]
|requestOrigin|:

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 |parsedSignals| is failure or not a [=list=], return.
1. [=list/For each=] |signal| of |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
1. Let |signalsKey| be a new [=direct from seller signals key=], 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. Let |processedSignals| be a new [=direct from seller signals=].
1. [=map/Remove=] |signal|["`adSlot`"].
1. [=map/For each=] |key| → |value| of |signal|:
1. Switch on |key|:
Expand All @@ -3922,17 +3925,15 @@ The following algorithm will be added to the [[FETCH#fetching]] section:
<dd>
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 |buyerOrigin| be the result of [=parsing an https origin=] on |buyer|.
1. If |buyerOrigin| is failure, [=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|.

</dl>

1. Set |storedHeaders|[|signalsKey|] to |processedSignals|.

1. Set |storedSignalsHeaders|[|signalsKey|] to |processedSignals|.
</div>


Expand Down Expand Up @@ -4550,7 +4551,6 @@ response headers.
: <dfn>provided as additional bid</dfn>
:: A [=boolean=], initially false.


</dl>

<h3 dfn-type=dfn>Ad descriptor</h3>
Expand Down Expand Up @@ -4581,6 +4581,33 @@ Width and height of an ad.

</dl>

<h3 id=direct-from-seller-signals-section>Direct from seller signals</h3>

A <dfn>direct from seller signals key</dfn> is a [=struct=] with the following [=struct/items=]:

<dl dfn-for="direct from seller signals key">
: <dfn>seller</dfn>
:: An [=origin=]. Matches the origin that served the captured [:Ad-Auction-Signals:] header.
: <dfn>ad slot</dfn>
:: A [=string=]. Matches the `adSlot` key of the JSON dictionaries in the top-level array of the
[:Ad-Auction-Signals:] value.
</dl>

A <dfn>direct from seller signals</dfn> is a [=struct=] with the following [=struct/items=]:

<dl dfn-for="direct from seller signals">
: <dfn>auction signals</dfn>
:: Null or a [=string=].
Opaque JSON data passed to both buyers' and the seller's [=script runners=].
: <dfn>seller signals</dfn>
:: Null or a [=string=].
Opaque JSON data passed to the seller's [=script runner=].
: <dfn>per buyer signals</dfn>
:: 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=].
</dl>

<h3 dfn-type=dfn>Score ad output</h3>

The output of running a Protected Audience `scoreAd()` script, is represented using the following type:
Expand Down

0 comments on commit 3de7fde

Please sign in to comment.