diff --git a/api.bs b/api.bs index 3e8b23f..11f4b46 100644 --- a/api.bs +++ b/api.bs @@ -1876,18 +1876,26 @@ if the user has opted out of collection of diagnostic data. # HTTP API # {#http-api} +## Saving impressions ## {#http-api-impressions} + \`Save-Impression\` is a [=structured header/dictionary|Dictionary Structured Header=] set on a response requesting that the user agent invoke the saveImpression() API. -
-Save-Impression: conversion-sites=("advertiser.example"), conversion-callers=("intermediary.example"), histogram-index=2, match-value=12, lifetime-days=7
-
+
+This is the HTTP equivalent of the JavaScript `saveImpression` example: + +Save-Impression: histogram-index=3, match-value=2, conversion-sites=("advertiser.example"), lifetime-days=7 + +
The following keys are defined, corresponding to the members of the {{AttributionImpressionOptions}} dictionary passed to -saveImpression(). +saveImpression(). Default values for omitted +optional keys are populated the same way as the corresponding +{{AttributionImpressionOptions}} field. +
conversion-sites
@@ -1896,7 +1904,7 @@ the {{AttributionImpressionOptions}} dictionary passed to an [=structured header/inner list=] containing [=structured header/string|strings=]. Each string value includes a domain name using A-labels only; [[RFC5890|Internationalized Domain Names]] therefore need to use [[RFC3492|punycode]]. - This key is optional. If not supplied, an empty set is saved for [=impression/Conversion Sites=]. + This key is optional.
conversion-callers
@@ -1904,7 +1912,7 @@ the {{AttributionImpressionOptions}} dictionary passed to an [=structured header/inner list=] containing [=structured header/string|strings=]. Each string value includes a domain name using A-labels only; [[RFC5890|Internationalized Domain Names]] therefore need to use [[RFC3492|punycode]]. - This key is optional. If not supplied, an empty set is saved for [=impression/Conversion Callers=]. + This key is optional.
histogram-index
@@ -1920,13 +1928,11 @@ the {{AttributionImpressionOptions}} dictionary passed to
Value of matchValue, a non-negative [=structured header/integer=]. This key is optional. - If not supplied, a value of 0 is saved for [=impression/Match Value=].
lifetime-days
Value of lifetimeDays, a positive [=structured header/integer=]. This key is optional. - If not supplied, 30 days is saved for [=impression/Lifetime=].
@@ -1938,37 +1944,196 @@ To parse a `Save-Impression` header given a [=header value=] with input_bytes set to |input| and field_type set to "`dictionary`". 1. If parsing failed, return an error. -1. If |dict|["[=save-impression/histogram-index=]"] does not [=map/exist=] or - is not an [=structured header/integer=] or is less than 0, return an error. -1. Let |histogramIndex| be |dict|["[=save-impression/histogram-index=]"]. -1. Let |conversionSites| be |dict|["[=save-impression/conversion-sites=]"] - [=map/with default=] an empty [=structured header/inner list=]. -1. If |conversionSites| is not an [=structured header/inner list=], or if any of |conversionSites|' [=list/items=] is not a [=structured header/string=], return an error. -1. Let |conversionCallers| be |dict|["[=save-impression/conversion-callers=]"] - [=map/with default=] an empty [=structured header/inner list=]. -1. If |conversionCallers| is not an [=structured header/inner list=], or if any of |conversionCallers|' [=list/items=] is not a [=structured header/string=], return an error. -1. Let |matchValue| be |dict|["[=save-impression/match-value=]"] [=map/with default=] 0. -1. If |matchValue| is not an [=structured header/integer=] or is less than 0, return an error. -1. Let |lifetimeDays| be |dict|["[=save-impression/lifetime-days=]"] [=map/with default=] 30. -1. If |lifetimeDays| is not an [=structured header/integer=] or is less than or equal to 0, return an error. -1. Let |priority| be |dict|["[=save-impression/priority=]"] [=map/with default=] 0. -1. If |priority| is not an [=structured header/integer=], return an error. -1. Return a new {{AttributionImpressionOptions}} with the following items: +1. Let |histogramIndex| be |dict|["[=save-impression/histogram-index=]"] [=map/with default=] `undefined`. +1. If |histogramIndex| is not a non-negative [=structured header/integer=], return an error. +1. Let |opts| be a new {{AttributionImpressionOptions}} with the following items: : {{AttributionImpressionOptions/histogramIndex}} :: |histogramIndex| - : {{AttributionImpressionOptions/matchValue}} - :: |matchValue| - : {{AttributionImpressionOptions/conversionSites}} - :: |conversionSites| - : {{AttributionImpressionOptions/conversionCallers}} - :: |conversionCallers| - : {{AttributionImpressionOptions/lifetimeDays}} - :: |lifetimeDays| - : {{AttributionImpressionOptions/priority}} - :: |priority| +1. If |dict|["[=save-impression/conversion-sites=]"] [=map/exists=]: + 1. Let |conversionSites| be its [=map/value=]. + 1. If |conversionSites| is not an [=structured header/inner list=], or if any of + |conversionSites|' [=list/items=] is not a [=structured header/string=], + return an error. + 1. Set |opts|.{{AttributionImpressionOptions/conversionSites}} to |conversionSites|. +1. If |dict|["[=save-impression/conversion-callers=]"] [=map/exists=]: + 1. Let |conversionCallers| be its [=map/value=]. + 1. If |conversionCallers| is not an [=structured header/inner list=], or if any of + |conversionCallers|' [=list/items=] is not a [=structured header/string=], + return an error. + 1. Set |opts|.{{AttributionImpressionOptions/conversionCallers}} to |conversionCallers|. +1. If |dict|["[=save-impression/match-value=]"] [=map/exists=]: + 1. Let |matchValue| be its [=map/value=]. + 1. If |matchValue| is not a non-negative [=structured header/integer=], return an error. + 1. Set |opts|.{{AttributionImpressionOptions/matchValue}} to |matchValue|. +1. If |dict|["[=save-impression/lifetime-days=]"] [=map/exists=]: + 1. Let |lifetimeDays| be its [=map/value=]. + 1. If |lifetimeDays| is not a positive [=structured header/integer=], return an error. + 1. Set |opts|.{{AttributionImpressionOptions/lifetimeDays}} to |lifetimeDays|. +1. If |dict|["[=save-impression/priority=]"] [=map/exists=]: + 1. Let |priority| be its [=map/value=]. + 1. If |priority| is not an [=structured header/integer=], return an error. + 1. Set |opts|.{{AttributionImpressionOptions/priority}} to |priority|. +1. Return |opts|. +## Measuring Conversions ## {#http-api-conversions} + +\`Measure-Conversion\` is a +[=structured header/dictionary|Dictionary Structured Header=] +set on a response requesting that the user agent invoke the +measureConversion() API. + +
+This is the HTTP equivalent of the JavaScript `measureConversion` example, +with the addition of a `report-url` to which the resulting report will be `POST`ed: + +Measure-Conversion: aggregation-service="https://aggregator.example/tee", histogram-size=20, epsilon=1.0, lookback-days=14, impression-sites=("publisher.example" "other.example"), impression-callers=("ad-tech.example"), match-values=(2), credit=(0.25 0.25 0.5), value=3, max-value=7, report-url="https://report-handler.example/foo" + +
+ +The following keys are defined, corresponding to the members of +the {{AttributionConversionOptions}} dictionary passed to +measureConversion(). Default values for omitted +optional keys are populated the same way as the corresponding +{{AttributionConversionOptions}} field. + +
+
aggregation-service
+
+ Value of aggregationService, + a [=structured header/string=]. This key is required. +
+
epsilon
+
+ Value of epsilon, + a positive [=structured header/decimal=]. This key is optional. +
+
histogram-size
+
+ Value of histogramSize, + a positive [=structured header/integer=]. This key is required. +
+
lookback-days
+
+ Value of lookbackDays, + a positive [=structured header/integer=]. This key is optional. +
+
match-values
+
+ Value of matchValues, + an [=structured header/inner list=] containing non-negative [=structured header/integer|integers=]. + This key is optional. +
+
impression-sites
+
+ Value of impressionSites, + an [=structured header/inner list=] containing [=structured header/string|strings=]. + Each string value includes a domain name using A-labels only; + [[RFC5890|Internationalized Domain Names]] therefore need to use [[RFC3492|punycode]]. + This key is optional. +
+
impression-callers
+
+ Value of impressionCallers, + an [=structured header/inner list=] containing [=structured header/string|strings=]. + Each string value includes a domain name using A-labels only; + [[RFC5890|Internationalized Domain Names]] therefore need to use [[RFC3492|punycode]]. + This key is optional. +
+
credit
+
+ Value of credit, + an [=structured header/inner list=] containing positive [=structured header/decimal|decimals=] + or positive [=structured header/integer|integers=]. This key is optional. +
+
value
+
+ Value of value, + a positive [=structured header/integer=]. This key is optional. +
+
max-value
+
+ Value of maxValue, + a positive [=structured header/integer=]. This key is optional. +
+
report-url
+
+ A [=structured header/string=] containing the [=potentially trustworthy URL=] + to which the resulting report, if any, will be `POST`ed. The URL may be + relative to the request URL, and its [=url/scheme=] must be "`http`" or "`https`". + This key is required. +
+
+ +
+To parse a `Measure-Conversion` header given a [=header value=] +|input| and [=URL=] |baseUrl|, run these steps: + +1. Let |dict| be the result of [=structured header/parsing structured fields=] + with input_bytes set to |input| and + field_type set to "`dictionary`". +1. If parsing failed, return an error. +1. Let |aggregationService| be |dict|["[=measure-conversion/aggregation-service=]"] [=map/with default=] `undefined`. +1. If |aggregationService| is not a [=structured header/string=], return an error. +1. Let |histogramSize| be |dict|["[=measure-conversion/histogram-size=]"] [=map/with default=] `undefined`. +1. If |histogramSize| is not a positive [=structured header/integer=], return an error. +1. Let |reportUrlString| be |dict|["[=measure-conversion/report-url=]"] [=map/with default=] `undefined`. +1. If |reportUrlString| is not a [=structured header/string=], return an error. +1. Let |reportUrl| be the result of applying the [=URL parser=] to |reportUrlString|, with |baseUrl|. +1. If |reportUrl| is failure, return an error. +1. If |reportUrl| is not a [=potentially trustworthy URL=], return an error. +1. If |reportUrl|'s [=url/scheme=] is not "`http`" or "`https`", return an error. +1. Let |opts| be a new {{AttributionConversionOptions}} with the following items: + : {{AttributionConversionOptions/aggregationService}} + :: |aggregationService| + : {{AttributionConversionOptions/histogramSize}} + :: |histogramSize| +1. If |dict|["[=measure-conversion/epsilon=]"] [=map/exists=]: + 1. Let |epsilon| be its [=map/value=]. + 1. If |epsilon| is not a [=structured header/decimal=], return an error. + 1. Set |opts|.{{AttributionConversionOptions/epsilon}} to |epsilon|. +1. If |dict|["[=measure-conversion/lookback-days=]"] [=map/exists=]: + 1. Let |lookbackDays| be its [=map/value=]. + 1. If |lookbackDays| is not a positive [=structured header/integer=], return an error. + 1. Set |opts|.{{AttributionConversionOptions/lookbackDays}} to |lookbackDays|. +1. If |dict|["[=measure-conversion/match-values=]"] [=map/exists=]: + 1. Let |matchValues| be its [=map/value=]. + 1. If |matchValues| is not an [=structured header/inner list=], or if any of + |matchValues|' [=list/items=] is not a non-negative [=structured header/integer=], + return an error. + 1. Set |opts|.{{AttributionConversionOptions/matchValues}} to |matchValues|. +1. If |dict|["[=measure-conversion/impression-sites=]"] [=map/exists=]: + 1. Let |impressionSites| be its [=map/value=]. + 1. If |impressionSites| is not an [=structured header/inner list=], or if any of + |impressionSites|' [=list/items=] is not a [=structured header/string=], + return an error. + 1. Set |opts|.{{AttributionConversionOptions/impressionSites}} to |impressionSites|. +1. If |dict|["[=measure-conversion/impression-callers=]"] [=map/exists=]: + 1. Let |impressionCallers| be its [=map/value=]. + 1. If |impressionCallers| is not an [=structured header/inner list=], or if any of + |impressionCallers|' [=list/items=] is not a [=structured header/string=], + return an error. + 1. Set |opts|.{{AttributionConversionOptions/impressionCallers}} to |impressionCallers|. +1. If |dict|["[=measure-conversion/credit=]"] [=map/exists=]: + 1. Let |credit| be its [=map/value=]. + 1. If |credit| is not an [=structured header/inner list=], or if any of + |credit|'s [=list/items=] is not a [=structured header/decimal=] or + [=structured header/integer=], return an error. + 1. Set |opts|.{{AttributionConversionOptions/credit}} to |credit|. +1. If |dict|["[=measure-conversion/value=]"] [=map/exists=]: + 1. Let |value| be its [=map/value=]. + 1. If |value| is not a positive [=structured header/integer=], return an error. + 1. Set |opts|.{{AttributionConversionOptions/value}} to |value|. +1. If |dict|["[=measure-conversion/max-value=]"] [=map/exists=]: + 1. Let |maxValue| be its [=map/value=]. + 1. If |maxValue| is not a positive [=structured header/integer=], return an error. + 1. Set |opts|.{{AttributionConversionOptions/maxValue}} to |maxValue|. +1. Return (|opts|, |reportUrl|). + +
+ + # Implementation Considerations # {#implementation-considerations} * Management and distribution of values for the following: @@ -3049,6 +3214,7 @@ urlPrefix: https://www.w3.org/TR/fingerprinting-guidance/; type: dfn; spec:structured header; type:dfn; urlPrefix: https://httpwg.org/specs/rfc9651; text: structured header; url: #name-introduction for: structured header + text: decimal; url: #decimal text: dictionary; url: #dictionary text: parse structured fields; url: #text-parse text: string; url: #string