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

Structured headers #197

Merged
merged 8 commits into from
Mar 3, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ TARGET_BRANCH="gh-pages"

# List of long-lived topic branch names to be published on github.io as a
# subdirectory
TOPIC_BRANCHES=("split-persistence")
TOPIC_BRANCHES=("split-persistence" "structured-headers")

containsElement () {
local e match="$1"
Expand Down
116 changes: 54 additions & 62 deletions index.src.html
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ <h1>Reporting API</h1>
text: session; url: dfn-session
text: success; url: dfn-success
text: trying; url: dfn-try
spec: STRUCTURED-HEADERS; urlPrefix: https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html#
type: grammar
text: sh-dictionary; url: rfc.section.3.2
</pre>
<pre class="biblio">
{
Expand All @@ -123,6 +126,12 @@ <h1>Reporting API</h1>
"href": "https://w3c.github.io/webappsec-secure-contexts/",
"title": "Secure Contexts",
"publisher": "W3C"
},
"STRUCTURED-HEADERS": {
"authors": [ "Mark Nottingham", "Poul-Henning Kamp" ],
"href": "https://httpwg.org/http-extensions/draft-ietf-httpbis-header-structure.html",
"title": "Structured Headers for HTTP",
"publisher": "IETF"
}
}

Expand Down Expand Up @@ -167,8 +176,7 @@ <h3 id="examples">Examples</h3>
define a set of reporting endpoints named "`endpoint-1`":

<pre>
<a>Report-To</a>: { "<a for="ReportTo">name</a>": "endpoint-1",
"<a for="ReportTo">url</a>": "https://example.com/reports" }
<a>Reporting-Endpoints</a>: endpoint-1="https://example.com/reports"
</pre>

And the following headers, which direct CSP and HPKP reports to that
Expand All @@ -187,10 +195,8 @@ <h3 id="examples">Examples</h3>
the following header to define two reporting endpoints:

<pre>
<a>Report-To</a>: { "<a for="ReportTo">name</a>": "csp-endpoint",
"<a for="ReportTo">url</a>": "https://example.com/csp-reports" },
{ "<a for="ReportTo">name</a>": "hpkp-endpoint",
"<a for="ReportTo">url</a>": "https://example.com/hpkp-reports" }
<a>Reporting-Endpoints</a>: csp-endpoint="https://example.com/csp-reports",
hpkp-endpoint="https://example.com/hpkp-reports"
</pre>

And the following headers, which direct CSP and HPKP reports to those named
Expand Down Expand Up @@ -393,53 +399,41 @@ <h3 id="document-configuration">Document configuration</h3>
attribute>endpoints</dfn> list, which is a list of <a>endpoints</a>, each of
which MUST have a distinct {{endpoint/name}}. (The algorithm in
[[#process-header]] guarantees this by keeping the first entry in a
`Report-To` header with a particular name.)
`Reporting-Endpoints` header with a particular name.)

A server MAY define a set of reporting endpoints for a resource it returns,
via the <a>`Report-To`</a> HTTP response header field. This mechanism
is defined in [[#header]], and its processing in [[#process-header]].
via the <a>`Reporting-Endpoints`</a> HTTP response header field. This
mechanism is defined in [[#header]], and its processing in
[[#process-header]].

Each <a>document</a> has an <dfn for="document" export attribute>reports</dfn>
list, which is a list of <a>reports</a>.

<h3 id="header">The `Report-To` HTTP Response Header Field</h3>

The value of the <dfn export>`Report-To`</dfn> HTTP response header field is
used to construct the reporting configuration for a resource. The header is
represented by the following ABNF grammar [[!RFC5234]]:

<pre class="abnf" link-type="grammar" dfn-type="grammar">
Report-To = <a>json-field-value</a>
; See Section 2 of [[HTTP-JFV]], and Section 2 of [[RFC8259]]
</pre>
<h3 id="header">The `Reporting-Endpoints` HTTP Response Header Field</h3>

The header's value is interpreted as a JSON-formatted array of objects
without the outer `[` and `]`, as described in Section 4 of [[HTTP-JFV]].
The value of the <dfn export>`Reporting-Endpoints`</dfn> HTTP response header
field is used to construct the reporting configuration for a resource.

Each object in the array defines an <a>endpoint</a> to which reports may be
delivered, and will be parsed as defined in [[#process-header]].
<a>`Reporting-Endpoints`</a> is a Dictionary Structured Header
[[STRUCTURED-HEADERS]]. Each entry in the dictionary defines an
<a>endpoint</a> to which reports may be delivered. The entry value MUST be a
string.

The following subsections define the initial set of known members in each
JSON object the header's value defines. Future versions of this document may
define additional such members, and user agents MUST ignore unknown members
when parsing the header.
Each <a>endpoint</a> is defined by a String Item, which is interpreted as a
URI-reference. If its value is not a valid URI-reference, that <a>endpoint</a>
member MUST be ignored.

<h4 id="id-member">The `name` member</h4>
Moreover, the URL that the member's value represents MUST be <a>potentially
trustworthy</a> [[!SECURE-CONTEXTS]]. Non-secure endpoints will be ignored.

The OPTIONAL <dfn for="ReportTo">`name`</dfn> member is a string that
associates a {{endpoint/name}} with the <a>endpoint</a>.
No parameters are defined for <a>endpoints</a>, and any parameters which are
specified will be silently ignored.

If present, the member's value MUST be a string. If not present, the
<a>endpoint</a> will be given the {{endpoint/name}} "`default`".
The header is represented by the following ABNF grammar [[!RFC5234]]:

<h4 id="url-member">The `url` member</h4>

The REQUIRED <dfn for="ReportTo">`url`</dfn> member is a string that defines
the location of the <a>endpoint</a>.

The member's value MUST be a string. Moreover, the URL that the member's value
represents MUST be <a>potentially trustworthy</a> [[!SECURE-CONTEXTS]].
Non-secure endpoints will be ignored.
<pre class="abnf" link-type="grammar" dfn-type="grammar">
Reporting-Endpoints = <a>sh-dictionary</a>
</pre>

<h3 id="process-header" algorithm>
Process reporting endpoints for |response|
Expand All @@ -462,37 +456,35 @@ <h3 id="process-header" algorithm>

2. |response|'s <a for="response" attribute>header list</a> does not
contain a <a>header</a> whose <a for="header" attribute>name</a> is
"<a>`Report-To`</a>".
"<a>`Reporting-Endpoints`</a>".

2. Let |header| be the <a for="header" attribute>value</a> of the
<a>header</a> in |response|'s <a for="response" attribute>header list</a>
whose name is "<a>`Report-To`</a>".
whose name is "<a>`Reporting-Endpoints`</a>".

3. Let |list| be the result of executing the algorithm defined in Section 4
of [[HTTP-JFV]] on |header|. If that algorithm results in an error, abort
these steps.
3. Let |parsed header| be the result of executing the algorithm defined in
Section 4.2 of [[STRUCTURED-HEADERS]] on |header|, with <var
ignore>header_type</var> set to "dictionary". If that algorithm fails
parsing, abort these steps.

4. Let |endpoints| be an empty list.

5. For each |item| in |list|:
5. For each |name| → |value_and_parameters| of |parsed header|:

1. Let |name| be |item|'s "<a for="ReportTo">`name`</a>" member's value
if present, and "`default`" otherwise.

2. If there is already an <a>endpoint</a> in |endpoints| whose
{{endpoint/name}} is |name|, skip to the next |item|.
1. Let |endpoint url string| be the first element of the tuple
|value_and_parameters|. If |endpoint url string| is not a string,
then <a>continue</a>.

3. If |item| has no member named "<a for="ReportTo">`url`</a>", or that
member's value is not a string, or if that value is not an
<a>absolute-URL string</a> or a <a>path-absolute-URL string</a>, skip
to the next |item|.
2. Let |endpoint url| be the result of executing the <a>URL parser</a>
on |endpoint url string|, with <a spec="url">base URL</a> set to
|response|'s <a for="response" attribute>url</a>. If |endpoint url| is
failure, then <a>continue</a>.

4. Let |url| be the result of executing the <a>URL parser</a> on |item|'s
"<a for="ReportTo">`url`</a>" member's value, with <a spec="url">base
URL</a> set to |response|'s <a for="response" attribute>url</a>. If
|url| is failure, skip to the next |item|.
3. If |endpoint url|'s <a>origin</a> is not <a>potentially
trustworthy</a>, then <a>continue</a>.

5. Let |endpoint| be a new <a>endpoint</a> whose properties are set
4. Let |endpoint| be a new <a>endpoint</a> whose properties are set
as follows:

: {{endpoint/name}}
Expand All @@ -502,7 +494,7 @@ <h3 id="process-header" algorithm>
: {{endpoint/failures}}
:: 0

6. Add |endpoint| to |endpoints|.
5. Add |endpoint| to |endpoints|.

6. Return |endpoints|.

Expand Down Expand Up @@ -1090,13 +1082,13 @@ <h3 id="disable">Disabling Reporting</h3>
<section>
<h2 id="iana-considerations">IANA Considerations</h2>

<h3 id="header-field-registration">The `Report-To` Header</h3>
<h3 id="header-field-registration">The `Reporting-Endpoints` Header</h3>

The permanent message header field registry should be updated
with the following registration: [[!RFC3864]]

: Header field name
:: `Report-To`
:: `Reporting-Endpoints`
: Applicable protocol
:: http
: Status
Expand Down