Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse Ad-Auction-Additional-Bid response header #888

Merged
merged 9 commits into from
Nov 14, 2023
Merged
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
194 changes: 111 additions & 83 deletions spec.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1128,8 +1128,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](#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
Expand Down Expand Up @@ -1405,7 +1404,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 @@ -3731,16 +3730,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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

captured by a {{WindowOrWorkerGlobalScope/fetch()}} call (using the {{RequestInit/adAuctionHeaders}} option)

There is also pending support for an iframe attribute mechanism.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we'll need to handle the merge of this PR with #883, depending on which one lands first.

(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 @@ -3779,52 +3801,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
qingxinwu marked this conversation as resolved.
Show resolved Hide resolved
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
qingxinwu marked this conversation as resolved.
Show resolved Hide resolved
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 @@ -3850,15 +3826,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 @@ -3869,40 +3847,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 @@ -3921,17 +3924,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 @@ -4580,6 +4581,33 @@ Width and height of an ad.

</dl>

<h3 id=direct-from-seller-signals-header>Direct from seller signals</h3>
qingxinwu marked this conversation as resolved.
Show resolved Hide resolved

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>

qingxinwu marked this conversation as resolved.
Show resolved Hide resolved
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