<?xml version="1.0" encoding="utf-8"?>
<!-- name="GENERATOR" content="github.com/mmarkdown/mmark Mmark Markdown Processor - mmark.nl" -->
<rfc version="3" ipr="trust200902" submissionType="IETF" category="info" xml:lang="en" consensus="true" xmlns:xi="http://www.w3.org/2001/XInclude" docName="draft-dunglas-mercure-02">

<front>
<title>The Mercure Protocol</title><seriesInfo value="draft-dunglas-mercure-02" stream="IETF" status="informational" name="Internet-Draft"></seriesInfo>
<author initials="K." surname="Dunglas" fullname="Kévin Dunglas"><organization abbrev="Les-Tilleuls.coop">Les-Tilleuls.coop</organization><address><postal><street>5 rue Hegel</street>
<city>Lille</city>
<code>59000</code>
<country>France</country>
<region></region>
</postal><phone></phone>
<email>kevin@les-tilleuls.coop</email>
<uri></uri>
</address></author>
<date/>
<area>Internet</area>
<workgroup>Network Working Group</workgroup>

<abstract>
<t>Mercure is a protocol allowing to push data updates to web browsers and other HTTP clients in a fast, reliable and battery-efficient way. It is especially useful to publish real-time updates of resources served through web APIs, to reactive web and mobile apps.</t>
</abstract>

</front>

<middle>

<section anchor="terminology"><name>Terminology</name>
<t>The keywords <bcp14>MUST</bcp14>, <bcp14>MUST NOT</bcp14>, <bcp14>REQUIRED</bcp14>, <bcp14>SHALL</bcp14>, <bcp14>SHALL NOT</bcp14>, <bcp14>SHOULD</bcp14>, <bcp14>SHOULD NOT</bcp14>, <bcp14>RECOMMENDED</bcp14>, <bcp14>MAY</bcp14>, and <bcp14>OPTIONAL</bcp14>, when they appear in this document, are to be interpreted as described in <xref target="RFC2119"></xref>.</t>

<ul>
<li><t>Topic: An HTTP <xref target="RFC7230"></xref> or HTTPS <xref target="RFC2818"></xref> topic URL. The unit to which one can subscribe to changes.</t>
</li>
<li><t>Publisher: An owner of a topic. Notifies the hub when the topic feed has been updated. As in almost all pubsub systems, the publisher is unaware of the subscribers, if any. Other pubsub systems might call the publisher the &quot;source&quot;. Typically a website or a web API, but can also be a web browser.</t>
</li>
<li><t>Subscriber: A client application that subscribes to real-time updates of topics. Typically a Progressive Web App or a Mobile App, but can also be a server.</t>
</li>
<li><t>Target: A subscriber, or a group of subscribers. A publisher is able to securely dispatch updates to specific targets. Using an HTTP <xref target="RFC7230"></xref> or HTTPS <xref target="RFC2818"></xref> URL to identify targets is <bcp14>RECOMMENDED</bcp14>.</t>
</li>
<li><t>Hub: A server that handles subscription requests and distributes the content to subscribers when the corresponding topics have been updated (a Hub implementation is provided in this repository). Any hub <bcp14>MAY</bcp14> implement its own policies on who can use it.</t>
</li>
</ul>
</section>

<section anchor="discovery"><name>Discovery</name>
<t>If the publisher is a server, it <bcp14>SHOULD</bcp14> advertise the URL of one or more hubs to the subscriber, allowing it to receive live updates when topics are updated.
If more than one hub URL is specified, it is expected that the publisher notifies each hub, so the subscriber <bcp14>MAY</bcp14> subscribe to one or more of them.</t>
<t>The publisher <bcp14>SHOULD</bcp14> include at least one Link Header <xref target="RFC5988"></xref> with <tt>rel=mercure</tt> (a hub link header).
The target URL of these links <bcp14>MUST</bcp14> be a hub implementing the Mercure protocol.</t>
<t>Note: this relation type has not been registered yet <xref target="RFC5988"></xref>.
During the meantime, the relation type <tt>https://git.io/mercure</tt> can be used instead.</t>
<t>The publisher <bcp14>MAY</bcp14> provide the following target attributes in the Link headers:</t>

<ul>
<li><t><tt>last-event-id</tt>: the globally unique identifier of the last event dispatched by the publisher at the time of the generation of this resource. If provided, it <bcp14>MUST</bcp14> be passed to the hub through a query parameter called <tt>Last-Event-ID</tt> and will be used to ensure that possible updates having been made during between the resource generation time and the connection to the hub are not lost. See section #Re-Connection-and-State-Reconciliation. If this attribute is provided, the publisher <bcp14>MUST</bcp14> always set the <tt>id</tt> parameter when sending updates to the hub.</t>
</li>
<li><t><tt>content-type</tt>: the content type of the updates that will pushed by the hub. If omited, the subscriber <bcp14>MUST</bcp14> assume that the content type will be the same than the one of the original resource. Setting the <tt>content-type</tt> attribute is especially useful to hint that partial updates will be pushed, using formats such as JSON Patch <xref target="RFC6902"></xref> or JSON Merge Patch <xref target="RFC7386"></xref>.</t>
</li>
<li><t><tt>key-set=&lt;JWKS&gt;</tt>: the key(s) to decrypt updates encoded in the JWKS (JSON Web Key Set) format (see the Encryption section).</t>
</li>
</ul>
<t>All these attributes are optional.</t>
<t>The publisher <bcp14>MAY</bcp14> also include one Link Header <xref target="RFC5988"></xref> with <tt>rel=self</tt> (the self link header). It <bcp14>SHOULD</bcp14> contain the canonical URL for the topic to which subscribers are expected to use for subscriptions. If the Link with <tt>rel=self</tt> is ommitted, the current URL of the resource <bcp14>MUST</bcp14> be used as fallback.</t>
<t>Minimal example:</t>

<sourcecode type="http">GET /books/foo.jsonld HTTP/1.1
Host: example.com

HTTP/1.1 200 Ok
Content-type: application/ld+json
Link: &lt;https://example.com/hub&gt;; rel=&quot;mercure&quot;

{&quot;@id&quot;: &quot;/books/foo.jsonld&quot;, &quot;foo&quot;: &quot;bar&quot;}
</sourcecode>
<t>Links embedded in HTML or XML documents (as defined in the WebSub recommendation) <bcp14>MAY</bcp14> also be supported by subscribers.</t>
<t>Note: the discovery mechanism described in this section <eref target="https://www.w3.org/TR/websub/#discovery">is strongly inspired from the one specified in the WebSub recommendation</eref>.</t>
</section>

<section anchor="subscriptions"><name>Subscriptions</name>
<t>The subscriber subscribes to an URL exposed by a hub to receive updates of one or many topics.
To subscribe to updates, the client opens an HTTPS connection following the <eref target="https://html.spec.whatwg.org/multipage/server-sent-events.html">Server-Sent Events specification</eref> to the hub's subscription URL advertised
by the Publisher. The <tt>GET</tt> HTTP method must be used.
The connection <bcp14>SHOULD</bcp14> use HTTP/2 to leverage mutliplexing and other advanced features of this protocol.</t>
<t>The subscriber specifies the list of topics to get updates for by using one or several query parameters named <tt>topic</tt>.
The value of these query parameters <bcp14>MUST</bcp14> be URI templates <xref target="RFC6570"></xref>.</t>
<t>Note: an URL is also a valid URI template.</t>
<t>The protocol doesn't specify the maximum number of <tt>topic</tt> parameters that can be sent, but the hub <bcp14>MAY</bcp14> apply an arbitrary limit.</t>
<t>The <eref target="https://html.spec.whatwg.org/multipage/server-sent-events.html#the-eventsource-interface">EventSource JavaScript interface</eref> <bcp14>MAY</bcp14> be used to establish the connection.
Any other appropriate mechanism including but not limited to <eref target="https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams">readable streams</eref> and <eref target="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest">XMLHttpRequest</eref> (used by popular polyfills) <bcp14>MAY</bcp14> also be used.</t>
<t>The hub sends updates concerning all subscribed resources matching the provided URI templates and the provided targets (see section #Authorization). If no targets are specied, the update is dispatched to all subscribers.
The hub <bcp14>MUST</bcp14> send these updates as <eref target="https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model">text/event-stream compliant events</eref>.</t>
<t>The <tt>data</tt> property <bcp14>MUST</bcp14> contain the new version of the topic. It can be the full resource, or a partial update by using formats such as JSON Patch <tt>@RFC6902</tt> or JSON Merge Patch <tt>@RFC7386</tt>.</t>
<t>All other properties defined in the Server-Sent Events specification <bcp14>MAY</bcp14> be used and <bcp14>SHOULD</bcp14> be supported by hubs.</t>
<t>The resource <bcp14>SHOULD</bcp14> be represented in a format with hypermedia capabilities such as JSON-LD <xref target="W3C.REC-json-ld-20140116"></xref>, Atom <xref target="RFC4287"></xref>, XML <xref target="W3C.REC-xml-20081126"></xref> or HTML <xref target="W3C.REC-html52-20171214"></xref>.</t>
<t>Web Linking <xref target="RFC5988"></xref> <bcp14>SHOULD</bcp14> be used to indicate the IRI of the resource sent in the event.
When using Atom, XML or HTML as serialization format for the resource, the document <bcp14>SHOULD</bcp14> contain a <tt>link</tt> element with a <tt>self</tt> relation containing the IRI of the resource.
When using JSON-LD, the document <bcp14>SHOULD</bcp14> contain an <tt>@id</tt> property containing the IRI of the resource.</t>
<t>Example:</t>

<sourcecode type="javascript">// The subscriber subscribes to updates for the https://example.com/foo topic
// and to any topic matching https://example.com/books/{name}
const url = new URL('https://example.com/hub');
url.searchParams.append('topic', 'https://example.com/foo');
url.searchParams.append('topic', 'https://example.com/bar/{id}');

const eventSource = new EventSource(url);

// The callback will be called every time an update is published
eventSource.onmessage = function ({data}) {
    console.log(data);
};
</sourcecode>
<t>The hub <bcp14>MAY</bcp14> require that the subscribers are authorized to receive any update.</t>
</section>

<section anchor="publication"><name>Publication</name>
<t>The publisher send updates by issuing <tt>POST</tt> HTTPS requests on the hub URL.
When it receives an update, the hub dispatches it to subsribers using the established server-sent events connections.</t>
<t>An application CAN send events directly to the subscribers, without using an external hub server, if it is able to do so.
In this case, it <strong>MAY NOT</strong> implement the endpoint to publish updates.</t>
<t>The request <bcp14>MUST</bcp14> be encoded using the <tt>application/x-www-form-urlencoded</tt> format and contains the following data:</t>

<ul>
<li><t><tt>topic</tt>: IRIs of the updated topic. If this key is present several times, the first occurence is considered to be the canonical URL of the topic, and other ones are considered to be alternate URLs. The hub <bcp14>MUST</bcp14> dispatch this update to subscribers subscribed to both canonical or alternate URLs.</t>
</li>
<li><t><tt>data</tt>: the content of the new version of this topic.</t>
</li>
<li><t><tt>target</tt> (optional): target audience of this update. This key can be present several times. See section #Authorization for further information.</t>
</li>
<li><t><tt>id</tt> (optional): the topic's revision identifier, it will be used as the SSE's <tt>id</tt> property, if omited the hub <bcp14>MUST</bcp14> generate a valid globally unique id. It <tt>MAY</tt> be an UUID.</t>
</li>
<li><t><tt>type</tt> (optional): the SSE's <tt>event</tt> property (a specific event type)</t>
</li>
<li><t><tt>retry</tt> (optional): the SSE's <tt>retry</tt> property (the reconnection time)</t>
</li>
</ul>
<t>In case of success, the HTTP response's body <bcp14>MUST</bcp14> be the <tt>id</tt> associated to this update (the one generated by the hub, if it has not been provided by the client) and a success HTTP status code <bcp14>MUST</bcp14> be returned.
The publisher <bcp14>MUST</bcp14> be authorized to publish updates. See section #Authorization.</t>
</section>

<section anchor="authorization"><name>Authorization</name>
<t>To ensure that they are authorized, both publishers and subscribers must present a valid JWS <xref target="RFC7515"></xref> in compact serialization to the hub. This JWS <bcp14>SHOULD</bcp14> be short lived, especially if the subscriber is a web browser.
A different key <bcp14>MAY</bcp14> be used to sign subscribers' and publishers' tokens.</t>
<t>Two mechanisms are defined to present the JWS to the hub:</t>

<ul>
<li><t>using an <tt>Authorization</tt> HTTP header</t>
</li>
<li><t>using a cookie</t>
</li>
</ul>
<t>If a publisher or the subscriber is not a web browser, it <bcp14>SHOULD</bcp14> use an <tt>Authorization</tt> HTTP header. This <tt>Authorization</tt> header <bcp14>MUST</bcp14> contain the string <tt>Bearer</tt> followed by the JWS.
The hub will check that the JWS is conform to the rules defined later to ensure that the client is authorized to publish or subscribe to updates.</t>
<t>By the <tt>EventSource</tt> specification, web browsers can not set custom HTTP headers for such connections, and they can only be estabilished using the <tt>GET</tt> HTTP method.
However, cookies are supported, and can be included even in crossdomain requests if <eref target="https://html.spec.whatwg.org/multipage/server-sent-events.html#dom-eventsourceinit-withcredentials">the CORS credentials are set</eref>:</t>
<t>If a publisher or a subscriber is a web browser, it <bcp14>SHOULD</bcp14> send a cookie called <tt>mercureAuthorization</tt> containing the JWS when connecting to the hub.</t>
<t>When possible, to improve the overall security, the <tt>mercureAuthorization</tt> cookie <bcp14>SHOULD</bcp14> be set during the discovery. See section #Discovery.
Consequently, if the cookie is set during the discovery, both the publisher and the hub have to share the same second level domain. The <tt>Domain</tt> attribute <bcp14>MAY</bcp14> be used to allow the publisher and the hub to use different subdomains.</t>
<t>The cookie <bcp14>SHOULD</bcp14> have the <tt>Secure</tt>, <tt>HttpOnly</tt> and <tt>SameSite</tt> attributes set. Setting the cookie's <tt>Path</tt> attribute <bcp14>SHOULD</bcp14> also be set to the hub's URL. See section #Security-Considerations.</t>
<t>When using authorization mechanisms, the connection <bcp14>MUST</bcp14> use an encryption layer such as HTTPS.</t>
<t>If both an <tt>Authorization</tt> HTTP header and a cookie named <tt>mercureAuthorization</tt> are presented by the client, the cookie <bcp14>MUST</bcp14> be ignored.
If a client tries to execute an operation it is not allowed to, a 403 HTTP status code <bcp14>SHOULD</bcp14> be returned.</t>

<section anchor="publishers"><name>Publishers</name>
<t>Publishers <bcp14>MUST</bcp14> be authorized to dispatch updates to the hub, and <bcp14>MUST</bcp14> prove that they are allowed to send updates.</t>
<t>To be allowed to publish an update, the JWT presented by the publisher <bcp14>MUST</bcp14> contain a claim called <tt>mercure</tt>, and this claim <bcp14>MUST</bcp14> contain a <tt>publish</tt> key.
JWT's <tt>mercure.publish</tt> contains an array of targets the publisher is allowed to dispatch updates to.</t>
<t>If <tt>mercure.publish</tt>:</t>

<ul>
<li><t>is not defined, then the publisher <bcp14>MUST NOT</bcp14> be authorized to dispatch any update</t>
</li>
<li><t>contains an empty array, then the publisher is only allowed to dispatch public updates</t>
</li>
<li><t>contains the reserved string <tt>*</tt> as an array value, then the publisher is authorized to dispatch updates to all targets</t>
</li>
</ul>
<t>If a topic is not public, the <tt>POST</tt> request sent by the publisher to the hub <bcp14>MUST</bcp14> contain a list of keys named <tt>target</tt>. Theirs values <bcp14>MUST</bcp14> be of type <tt>string</tt>, and it is <bcp14>RECOMMENDED</bcp14> to use valid IRIs. They can be, for instance a user ID, or a list of group IDs.
If an update contains at least one target the publisher is not authorized for, the hub <bcp14>MUST NOT</bcp14> dispatch the update (even if some targets in the list are allowed) and <bcp14>SHOULD</bcp14> return a 403 HTTP status code.</t>
</section>

<section anchor="subscribers"><name>Subscribers</name>
<t>Subscribers <bcp14>MAY</bcp14> need to be authorized to connect to the hub.
To receive updates destined to specific targets, they <bcp14>MUST</bcp14> be authorized, and <bcp14>MUST</bcp14> prove they belong to at least one of the specified targets. If the subscriber is not authorized it <bcp14>MUST NOT</bcp14> receive any update having at least one target.</t>
<t>To receive updates destined to specific targets, the JWS presented by the subscriber <bcp14>MUST</bcp14> have a claim named <tt>mercure</tt> with a key named <tt>subscribe</tt> that contains an array of strings: the list of targets the user is authorized to receive updates for. The targets <bcp14>SHOULD</bcp14> be IRIs.</t>
<t>If at least one target is specified, the update <bcp14>MUST NOT</bcp14> be sent to the subscriber by the hub, unless the <tt>mercure.subscribe</tt> property of the JWS presented by the subscriber contains at least one of the specified targets.</t>
<t>If the <tt>mercure.subscribe</tt> array contains the reserved string value <tt>*</tt>, then the subscriber is authorized to receive updates destined to all targets.</t>
</section>
</section>

<section anchor="re-connection-and-state-reconciliation"><name>Re-Connection and State Reconciliation</name>
<t>To allow re-establisment in case of connection lost, events dispatched by the hub <bcp14>SHOULD</bcp14> include an <tt>id</tt> property.
The value contained in this <tt>id</tt> property <bcp14>SHOULD</bcp14> be a globally unique identifier.
To do so, UUID <xref target="RFC4122"></xref> <bcp14>MAY</bcp14> be used.</t>
<t>According to the server-sent events specification, in case of connection lost the subscriber will try to automatically reconnect. During the reconnection the subscriber <bcp14>MUST</bcp14> send the last received event id in a <eref target="https://html.spec.whatwg.org/multipage/iana.html#last-event-id">Last-Event-ID</eref> HTTP header.</t>
<t>The server-sent events specification doesn't allow to set this HTTP header during the first connection (before a re-connection occurs).
In order to fetch any update dispatched between the initial resource generation by the publisher and the connection to he hub, the subscriber <bcp14>MUST</bcp14> send the event id provided during the discovery in the <tt>last-event-id</tt> link's attribute in a query parameter named <tt>Last-Event-ID</tt> when connecting to the hub.</t>
<t>If both the <tt>Last-Event-ID</tt> HTTP header and the query parameter are present, the HTTP header <bcp14>MUST</bcp14> take precedence.</t>
<t>If the <tt>Last-Event-ID</tt> header or query parameter exists, the hub <bcp14>SHOULD</bcp14> send to the subscriber all events published since the one having this identifier.</t>
<t>The hub <bcp14>MAY</bcp14> discard some messages for operational reasons. The subscriber <bcp14>MUST NOT</bcp14> assume that no update will be lost, and <bcp14>MUST</bcp14> re-fetch the original topic to ensure this (for instance, after a long deconnection time).</t>
<t>The hub <bcp14>MAY</bcp14> also specify the reconnection time using the <tt>retry</tt> key, as specified in the server-sent events format.</t>
</section>

<section anchor="encryption"><name>Encryption</name>
<t>Using HTTPS doesn't prevent the hub to access to the update's content.
Depending of the intended privacy of informations contained in the updates, it <bcp14>MAY</bcp14> be necessary to prevent eavesdropping by the hub.</t>
<t>To make sure that the message content can not be read by the hub, the publisher <bcp14>MAY</bcp14> encode the message before sending it to the hub.
The publisher <bcp14>SHOULD</bcp14> use JSON Web Encryption <xref target="RFC7516"></xref> to encrypt the update content.
The publisher <bcp14>MAY</bcp14> provide the relevant encryption key(s) in the <tt>key-set</tt> attribute of the Link HTTP header during the discovery.
The <tt>key-set</tt> attribute <bcp14>SHOULD</bcp14> contain a key encoded using the JSON Web Key Set <xref target="RFC7517"></xref> format.
Any other out-of-band mechanism <bcp14>MAY</bcp14> be used instead to share the key between the publisher and the subscriber.</t>
<t>Updates encyption is considered a best practice to prevent mass surveillance.
This is especially relevant if the hub is managed by an external provider.</t>
</section>

<section anchor="security-considerations"><name>Security Considerations</name>
<t>The confidentiality of the secret key(s) used to generate the JWTs is a primary concern.
The secret key(s) <bcp14>MUST</bcp14> be stored securely. They <bcp14>MUST</bcp14> be revoked immediatly in case of compromission.</t>
<t>Possessing a valid JWTs allows any client to subscribe, or to publish to the hub.
Their confidentiality <bcp14>MUST</bcp14> therefore be ensured. To do so, JWTs <bcp14>MUST</bcp14> only be transmited over secure connections.</t>
<t>Also, when the client is a web browser, to be resilient to <eref target="https://www.owasp.org/index.php/Cross-site_Scripting_(XSS">Cross-site Scription (XSS) attacks</eref>), the JWT <bcp14>SHOULD</bcp14> not be made accessible to JavaScript scripts.
It's main reason why, when the client is a web browser, using <tt>HttpOnly</tt> cookies as authorization mechanism <bcp14>SHOULD</bcp14> always be prefered.</t>
<t>In case of compromission, revoking a JWT before its expiration is often difficult.
So, using short-lived token is strongly <bcp14>RECOMMENDED</bcp14>.</t>
<t>The publish endpoint of the hub may be targeted by <eref target="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF">Cross-Site Request Forgery (CSRF) attacks</eref>) when the cookie-based authorization mechanism is used.
Therefore, implementations supporting this mechanism <bcp14>MUST</bcp14> mitigate such attacks.</t>
<t>The first prevention method to implement is to set the <tt>mercureAuthorization</tt> cookie's <tt>SameSite</tt> attribute.
However, <eref target="https://caniuse.com/#feat=same-site-cookie-attribute">some web browsers still not support this attribute</eref>, and will stay vulnerable.
In addition, hub implementations <bcp14>SHOULD</bcp14> use the <tt>Origin</tt> and <tt>Referer</tt> HTTP headers set by web browsers to verify that the source origin matches the target origin. If none of these headers are available, the hub <bcp14>SHOULD</bcp14> discard the request.</t>
<t>CSRF prevention techniques, including the ones previously mentioned, are described in depth in <eref target="https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF">OWASP's Cross-Site Request Forgery (CSRF) Prevention Cheat Sheet</eref><em>Prevention</em>Cheat_Sheet).</t>
</section>

</middle>

<back>
<references><name>Normative References</name>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.5988.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.7517.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.7230.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.2818.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.7515.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.7516.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6570.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4122.xml"/>
</references>
<references><name>Informative References</name>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml-w3c/reference.W3C.REC-xml-20081126.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml-w3c/reference.W3C.REC-json-ld-20140116.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.4287.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.6902.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml-w3c/reference.W3C.REC-html52-20171214.xml"/>
<xi:include href="https://xml2rfc.ietf.org/public/rfc/bibxml/reference.RFC.7386.xml"/>
</references>

</back>

</rfc>
