<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc2629 version 1.2.7 -->
<?rfc toc="yes"?>
<?rfc tocindent="yes"?>
<?rfc sortrefs="yes"?>
<?rfc symrefs="yes"?>
<?rfc strict="yes"?>
<?rfc compact="yes"?>
<?rfc comments="yes"?>
<?rfc inline="yes"?>
<rfc xmlns:x="http://purl.org/net/xml2rfc/ext"
     category="exp"
     docName="draft-ietf-httpbis-cache-digest-03"
     ipr="trust200902"
     submissionType="IETF">
   <x:feedback template="mailto:ietf-http-wg@w3.org?subject={docname},%20%22{section}%22\&amp;amp;body=%3c{ref}%3e:"/>
   <front>
      <title>Cache Digests for HTTP/2</title>
      <author fullname="Kazuho Oku" initials="K." surname="Oku">
         <organization>Fastly</organization>
         <address>
            <email>kazuhooku@gmail.com</email>
         </address>
      </author>
      <author fullname="Mark Nottingham" initials="M." surname="Nottingham">
         <address>
            <email>mnot@mnot.net</email>
            <uri>https://www.mnot.net/</uri>
         </address>
      </author>
      <date year="2018" month="3" day="1"/>
      <area>Applications and Real-Time</area>
      <workgroup>HTTP</workgroup>
      <keyword>Internet-Draft</keyword>
      <abstract>
         <t>This specification defines a HTTP/2 frame type to allow clients to inform the server of their cache’s contents. Servers can then use this to inform their choices of what to push to clients.</t>
      </abstract>
      <note title="Note to Readers">
         <t>Discussion of this draft takes place on the HTTP working group mailing list (ietf-http-wg@w3.org), which is archived at <eref target="https://lists.w3.org/Archives/Public/ietf-http-wg/">https://lists.w3.org/Archives/Public/ietf-http-wg/</eref>.</t>
         <t>Working Group information can be found at <eref target="http://httpwg.github.io/">http://httpwg.github.io/</eref>; source code and issues list for this draft can be found at <eref target="https://github.com/httpwg/http-extensions/labels/cache-digest">https://github.com/httpwg/http-extensions/labels/cache-digest</eref>.</t>
      </note>
   </front>
   <middle>
      <section anchor="introduction" title="Introduction">
         <t>HTTP/2 <xref target="RFC7540"/> allows a server to “push” synthetic request/response pairs into a client’s cache optimistically. While there is strong interest in using this facility to improve perceived Web browsing performance, it is sometimes counterproductive because the client might already have cached the “pushed” response.</t>
         <t>When this is the case, the bandwidth used to “push” the response is effectively wasted, and represents opportunity cost, because it could be used by other, more relevant responses. HTTP/2 allows a stream to be cancelled by a client using a RST_STREAM frame in this situation, but there is still at least one round trip of potentially wasted capacity even then.</t>
         <t>This specification defines a HTTP/2 frame type to allow clients to inform the server of their cache’s contents using a Cuckoo-filter <xref target="Cuckoo"/> based digest. Servers can then use this to inform their choices of what to push to clients.</t>
         <section anchor="notational-conventions" title="Notational Conventions">
            <t>The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in <xref target="RFC2119"/>.</t>
         </section>
      </section>
      <section anchor="the-cachedigest-frame" title="The CACHE_DIGEST Frame">
         <t>The CACHE_DIGEST frame type is 0xd (decimal 13).</t>
         <figure>
            <artwork>
+-------------------------------+-------------------------------+
|         Origin-Len (16)       | Origin? (\*)                ...
+-------------------------------+-------------------------------+
|                   Digest-Value? (\*)                        ...
+---------------------------------------------------------------+
</artwork>
         </figure>
         <t>The CACHE_DIGEST frame payload has the following fields:</t>
         <t>
            <list style="hanging">
               <t hangText="Origin-Len:">An unsigned, 16-bit integer indicating the length, in octets, of the Origin field.</t>
               <t hangText="Origin:">A sequence of characters containing the ASCII serialization of an origin (<xref target="RFC6454" x:fmt="," x:sec="6.2"/>) that the Digest-Value applies to.</t>
               <t hangText="Digest-Value:">A sequence of octets containing the digest as computed in <xref target="creating"/> and <xref target="adding"/>.</t>
            </list>
         </t>
         <t>The CACHE_DIGEST frame defines the following flags:</t>
         <t>
            <list style="symbols">
               <t>
                  <spanx style="strong">RESET</spanx> (0x1): When set, indicates that any and all cache digests for the applicable origin held by the recipient MUST be considered invalid.</t>
               <t>
                  <spanx style="strong">COMPLETE</spanx> (0x2): When set, indicates that the currently valid set of cache digests held by the server constitutes a complete representation of the cache’s state regarding that origin, for the type of cached response indicated by the <spanx style="verb">STALE</spanx> flag.</t>
               <t>
                  <spanx style="strong">VALIDATORS</spanx> (0x4): When set, indicates that the <spanx style="verb">validators</spanx> boolean in <xref target="key"/> is true.</t>
               <t>
                  <spanx style="strong">STALE</spanx> (0x8): When set, indicates that all cached responses represented in the digest-value are stale <xref target="RFC7234"/> at the point in them that the digest was generated; otherwise, all are fresh.</t>
            </list>
         </t>
         <section anchor="client-behavior" title="Client Behavior">
            <t>A CACHE_DIGEST frame MUST be sent from a client to a server on stream 0, and conveys a digest of the contents of the client’s cache for the indicated origin.</t>
            <t>In typical use, a client will send one or more CACHE_DIGESTs immediately after the first request on a connection for a given origin, on the same stream, because there is usually a short period of inactivity then, and servers can benefit most when they understand the state of the cache before they begin pushing associated assets (e.g., CSS, JavaScript and images). Clients MAY send CACHE_DIGEST at other times.</t>
            <t>If the cache’s state is cleared, lost, or the client otherwise wishes the server to stop using previously sent CACHE_DIGESTs, it can send a CACHE_DIGEST with the RESET flag set.</t>
            <t>When generating CACHE_DIGEST, a client MUST NOT include cached responses whose URLs do not share origins <xref target="RFC6454"/> with the indicated origin. Clients MUST NOT send CACHE_DIGEST frames on connections that are not authoritative (as defined in <xref target="RFC7540"/>, 10.1) for the indicated origin.</t>
            <t>CACHE_DIGEST allows the client to indicate whether the set of URLs used to compute the digest represent fresh or stale stored responses, using the STALE flag. Clients MAY decide whether to only send CACHE_DIGEST frames representing their fresh stored responses, their stale stored responses, or both.</t>
            <t>Clients can choose to only send a subset of the suitable stored responses of each type (fresh or stale). However, when the CACHE_DIGEST frames sent represent the complete set of stored responses of a given type, the last such frame SHOULD have a COMPLETE flag set, to indicate to the server that it has all relevant state of that type. Note that for the purposes of COMPLETE, responses cached since the beginning of the connection or the last RESET flag on a CACHE_DIGEST frame need not be included.</t>
            <t>CACHE_DIGEST can be computed to include cached responses’ ETags, as indicated by the VALIDATORS flag. This information can be used by servers to decide what kinds of responses to push to clients; for example, a stale response that hasn’t changed could be refreshed with a 304 (Not Modified) response; one that has changed can be replaced with a 200 (OK) response, whether the cached response was fresh or stale.</t>
            <t>CACHE_DIGEST has no defined meaning when sent from servers, and SHOULD be ignored by clients.</t>
            <section anchor="creating" title="Creating a digest">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">P</spanx>, an integer smaller than 256, that indicates the probability of a false positive that is acceptable, expressed as <spanx style="verb">1/2\*\*P</spanx>.</t>
                     <t>
                        <spanx style="verb">N</spanx>, an integer that represents the number of entries - a prime number smaller than 2**32</t>
                  </list>
               </t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">f</spanx> be the number of bits per fingerprint, calculated as <spanx style="verb">P + 3</spanx>
                     </t>
                     <t>Let <spanx style="verb">b</spanx> be the bucket size, defined as 4.</t>
                     <t>Let <spanx style="verb">allocated</spanx> be the closest power of 2 that is larger than <spanx style="verb">N</spanx>.</t>
                     <t>Let <spanx style="verb">bytes</spanx> be <spanx style="verb">f</spanx>*<spanx style="verb">allocated</spanx>*<spanx style="verb">b</spanx>/8 rounded up to the nearest integer</t>
                     <t>Add 5 to <spanx style="verb">bytes</spanx>
                     </t>
                     <t>Allocate memory of <spanx style="verb">bytes</spanx> and set it to zero. Assign it to <spanx style="verb">digest-value</spanx>.</t>
                     <t>Set the first byte to <spanx style="verb">P</spanx>
                     </t>
                     <t>Set the second till fifth bytes to <spanx style="verb">N</spanx> in big endian form</t>
                     <t>Return the <spanx style="verb">digest-value</spanx>.</t>
                  </list>
               </t>
               <t>Note: <spanx style="verb">allocated</spanx> is necessary due to the nature of the way Cuckoo filters are creating the secondary hash, by XORing the initial hash and the fingerprint’s hash. The XOR operation means that secondary hash can pick an entry beyond the initial number of entries, up to the next power of 2. In order to avoid issues there, we allocate the table appropriately. For increased space efficiency, it is recommended that implementations pick a number of entries that’s close to the next power of 2.</t>
            </section>
            <section anchor="adding" title="Adding a URL to the Digest-Value">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">URL</spanx> a string corresponding to the Effective Request URI (<xref target="RFC7230" x:fmt="," x:sec="5.5"/>) of a cached response <xref target="RFC7234"/>
                     </t>
                     <t>
                        <spanx style="verb">ETag</spanx> a string corresponding to the entity-tag <xref target="RFC7232"/> of a cached response <xref target="RFC7234"/> (if the ETag is available; otherwise, null);</t>
                     <t>
                        <spanx style="verb">maxcount</spanx> - max number of cuckoo hops</t>
                     <t>
                        <spanx style="verb">digest-value</spanx>
                     </t>
                  </list>
               </t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">f</spanx> be the value of the first byte of <spanx style="verb">digest-value</spanx>.</t>
                     <t>Let <spanx style="verb">b</spanx> be the bucket size, defined as 4.</t>
                     <t>Let <spanx style="verb">N</spanx> be the value of the second to fifth bytes of <spanx style="verb">digest-value</spanx> in big endian form.</t>
                     <t>Let <spanx style="verb">key</spanx> be the return value of <xref target="key"/> with <spanx style="verb">URL</spanx> and <spanx style="verb">ETag</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">h1</spanx> be the return value of <xref target="hash"/> with <spanx style="verb">key</spanx> and <spanx style="verb">N</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">dest_fingerprint</spanx> be the return value of <xref target="fingerprint"/> with <spanx style="verb">key</spanx> and <spanx style="verb">f</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">h2</spanx> be the return value of <xref target="hash2"/> with <spanx style="verb">h1</spanx>, <spanx style="verb">dest_fingerprint</spanx> and <spanx style="verb">N</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">h</spanx> be either <spanx style="verb">h1</spanx> or <spanx style="verb">h2</spanx>, picked in random.</t>
                     <t>While <spanx style="verb">maxcount</spanx> is larger than zero: <list style="numbers">
                           <t>Let <spanx style="verb">position_start</spanx> be 40 + <spanx style="verb">h</spanx> * <spanx style="verb">f</spanx> * <spanx style="verb">b</spanx>.</t>
                           <t>Let <spanx style="verb">position_end</spanx> be <spanx style="verb">position_start</spanx> + <spanx style="verb">f</spanx> * <spanx style="verb">b</spanx>.</t>
                           <t>While <spanx style="verb">position_start</spanx> &lt; <spanx style="verb">position_end</spanx>: <list style="numbers">
                                 <t>Let <spanx style="verb">bits</spanx> be <spanx style="verb">f</spanx> bits from <spanx style="verb">digest_value</spanx> starting at <spanx style="verb">position_start</spanx>.</t>
                                 <t>If <spanx style="verb">bits</spanx> is all zeros, set <spanx style="verb">bits</spanx> to <spanx style="verb">dest_fingerprint</spanx> and terminate these steps.</t>
                                 <t>Add <spanx style="verb">f</spanx> to <spanx style="verb">position_start</spanx>.</t>
                              </list>
                           </t>
                           <t>Let <spanx style="verb">e</spanx> be a random number from 0 to <spanx style="verb">b</spanx>.</t>
                           <t>Subtract <spanx style="verb">f</spanx> * (<spanx style="verb">b</spanx> - <spanx style="verb">e</spanx>) from <spanx style="verb">position_start</spanx>.</t>
                           <t>Let <spanx style="verb">bits</spanx> be <spanx style="verb">f</spanx> bits from <spanx style="verb">digest_value</spanx> starting at <spanx style="verb">position_start</spanx>.</t>
                           <t>Let <spanx style="verb">fingerprint</spanx> be the value of bits, read as big endian.</t>
                           <t>Set <spanx style="verb">bits</spanx> to <spanx style="verb">dest_fingerprint</spanx>.</t>
                           <t>Set <spanx style="verb">dest_fingerprint</spanx> to <spanx style="verb">fingerprint</spanx>.</t>
                           <t>Let <spanx style="verb">h</spanx> be <xref target="hash2"/> with <spanx style="verb">h</spanx>, <spanx style="verb">dest_fingerprint</spanx> and <spanx style="verb">N</spanx> as inputs.</t>
                           <t>Subtract 1 from <spanx style="verb">maxcount</spanx>.</t>
                        </list>
                     </t>
                     <t>Subtract <spanx style="verb">f</spanx> from <spanx style="verb">position_start</spanx>.</t>
                     <t>Let <spanx style="verb">fingerprint</spanx> be the <spanx style="verb">f</spanx> bits starting at <spanx style="verb">position_start</spanx>.</t>
                     <t>Let <spanx style="verb">h1</spanx> be <spanx style="verb">h</spanx>
                     </t>
                     <t>Subtract 1 from <spanx style="verb">maxcount</spanx>.</t>
                     <t>If <spanx style="verb">maxcount</spanx> is zero, return an error.</t>
                     <t>Go to step 7.</t>
                  </list>
               </t>
            </section>
            <section anchor="removing" title="Removing a URL to the Digest-Value">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">URL</spanx> a string corresponding to the Effective Request URI (<xref target="RFC7230" x:fmt="," x:sec="5.5"/>) of a cached response <xref target="RFC7234"/>
                     </t>
                     <t>
                        <spanx style="verb">ETag</spanx> a string corresponding to the entity-tag <xref target="RFC7232"/> of a cached response <xref target="RFC7234"/> (if the ETag is available; otherwise, null);</t>
                     <t>
                        <spanx style="verb">digest-value</spanx>
                     </t>
                  </list>
               </t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">f</spanx> be the value of the first byte of <spanx style="verb">digest-value</spanx>.</t>
                     <t>Let <spanx style="verb">b</spanx> be the bucket size, defined as 4.</t>
                     <t>Let <spanx style="verb">N</spanx> be the value of the second to fifth bytes of <spanx style="verb">digest-value</spanx> in big endian form.</t>
                     <t>Let <spanx style="verb">key</spanx> be the return value of <xref target="key"/> with <spanx style="verb">URL</spanx> and <spanx style="verb">ETag</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">h1</spanx> be the return value of <xref target="hash"/> with <spanx style="verb">key</spanx> and <spanx style="verb">N</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">fingerprint</spanx> be the return value of <xref target="fingerprint"/> with <spanx style="verb">key</spanx> and <spanx style="verb">f</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">h2</spanx> be the return value of <xref target="hash2"/> with <spanx style="verb">h1</spanx>, <spanx style="verb">fingerprint</spanx> and <spanx style="verb">N</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">hashes</spanx> be an array containing <spanx style="verb">h1</spanx> and <spanx style="verb">h2</spanx>.</t>
                     <t>For each <spanx style="verb">h</spanx> in <spanx style="verb">hashes</spanx>: <list style="numbers">
                           <t>Let <spanx style="verb">position_start</spanx> be 40 + <spanx style="verb">h</spanx> * <spanx style="verb">f</spanx> * <spanx style="verb">b</spanx>.</t>
                           <t>Let <spanx style="verb">position_end</spanx> be <spanx style="verb">position_start</spanx> + <spanx style="verb">f</spanx> * <spanx style="verb">b</spanx>.</t>
                           <t>While <spanx style="verb">position_start</spanx> &lt; <spanx style="verb">position_end</spanx>: <list style="numbers">
                                 <t>Let <spanx style="verb">bits</spanx> be <spanx style="verb">f</spanx> bits from <spanx style="verb">digest_value</spanx> starting at <spanx style="verb">position_start</spanx>.</t>
                                 <t>If <spanx style="verb">bits</spanx> is <spanx style="verb">fingerprint</spanx>, set <spanx style="verb">bits</spanx> to all zeros and terminate these steps.</t>
                                 <t>Add <spanx style="verb">f</spanx> to <spanx style="verb">position_start</spanx>.</t>
                              </list>
                           </t>
                        </list>
                     </t>
                  </list>
               </t>
            </section>
            <section anchor="fingerprint" title="Computing a fingerprint value">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">key</spanx>, an array of characters</t>
                     <t>
                        <spanx style="verb">f</spanx>, an integer indicating the number of output bits</t>
                  </list>
               </t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">hash-value</spanx> be the SHA-256 message digest <xref target="RFC6234"/> of <spanx style="verb">key</spanx>, expressed as an integer.</t>
                     <t>Let <spanx style="verb">h</spanx> be the number of bits in <spanx style="verb">hash-value</spanx>
                     </t>
                     <t>Let <spanx style="verb">fingerprint-value</spanx> be 0</t>
                     <t>While <spanx style="verb">fingerprint-value</spanx> is 0 and <spanx style="verb">h</spanx> &gt; <spanx style="verb">f</spanx>: <list style="numbers">
                           <t>Let <spanx style="verb">fingerprint-value</spanx> be the <spanx style="verb">f</spanx> least significant bits of <spanx style="verb">hash-value</spanx>.</t>
                           <t>Let <spanx style="verb">hash-value</spanx> be the <spanx style="verb">h</spanx>-<spanx style="verb">f</spanx> most significant bits of <spanx style="verb">hash-value</spanx>.</t>
                           <t>Subtract <spanx style="verb">f</spanx> from <spanx style="verb">h</spanx>.</t>
                        </list>
                     </t>
                     <t>If <spanx style="verb">fingerprint-value</spanx> is 0, let <spanx style="verb">fingerprint-value</spanx> be 1.</t>
                     <t>Return <spanx style="verb">fingerprint-value</spanx>.</t>
                  </list>
               </t>
               <t>Note: Step 5 is to handle the extremely unlikely case where a SHA-256 digest of <spanx style="verb">key</spanx> is all zeros. The implications of it means that there’s an infitisimaly larger probability of getting a <spanx style="verb">fingerprint-value</spanx> of 1 compared to all other values. This is not a problem for any practical purpose.</t>
            </section>
            <section anchor="key" title="Computing the key">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">URL</spanx>, an array of characters</t>
                     <t>
                        <spanx style="verb">ETag</spanx>, an array of characters</t>
                     <t>
                        <spanx style="verb">validators</spanx>, a boolean indicating whether validators (<xref target="RFC7232"/>) are to be included in the digest</t>
                  </list>
               </t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">key</spanx> be <spanx style="verb">URL</spanx> converted to an ASCII string by percent-encoding as appropriate <xref target="RFC3986"/>.</t>
                     <t>If <spanx style="verb">validators</spanx> is true and <spanx style="verb">ETag</spanx> is not null: <list style="numbers">
                           <t>Append <spanx style="verb">ETag</spanx> to <spanx style="verb">key</spanx> as an ASCII string, including both the <spanx style="verb">weak</spanx> indicator (if present) and double quotes, as per <xref target="RFC7232" x:fmt="," x:sec="2.3"/>.</t>
                        </list>
                     </t>
                     <t>Return <spanx style="verb">key</spanx>
                     </t>
                  </list>
               </t>
               <t>TODO: Add an example of the ETag and the key calcuations.</t>
            </section>
            <section anchor="hash" title="Computing a Hash Value">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">key</spanx>, an array of characters.</t>
                     <t>
                        <spanx style="verb">N</spanx>, an integer</t>
                  </list>
               </t>
               <t>
                  <spanx style="verb">hash-value</spanx> can be computed using the following algorithm:</t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">hash-value</spanx> be the SHA-256 message digest <xref target="RFC6234"/> of <spanx style="verb">key</spanx>, truncated to 32 bits, expressed as an integer.</t>
                     <t>Return <spanx style="verb">hash-value</spanx> modulo N.</t>
                  </list>
               </t>
            </section>
            <section anchor="hash2" title="Computing an Alternative Hash Value">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">hash1</spanx>, an integer indicating the previous hash.</t>
                     <t>
                        <spanx style="verb">fingerprint</spanx>, an integer indicating the fingerprint value.</t>
                     <t>
                        <spanx style="verb">N</spanx>, an integer indicating the number of entries in the digest.</t>
                  </list>
               </t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">fingerprint-string</spanx> be the value of <spanx style="verb">fingerprint</spanx> in base 10, expressed as a string.</t>
                     <t>Let <spanx style="verb">hash2</spanx> be the return value of <xref target="hash"/> with <spanx style="verb">fingerprint-string</spanx> and <spanx style="verb">N</spanx> as inputs, XORed with <spanx style="verb">hash1</spanx>.</t>
                     <t>Return <spanx style="verb">hash2</spanx>.</t>
                  </list>
               </t>
            </section>
         </section>
         <section anchor="server-behavior" title="Server Behavior">
            <t>In typical use, a server will query (as per <xref target="querying"/>) the CACHE_DIGESTs received on a given connection to inform what it pushes to that client;</t>
            <t>
               <list style="symbols">
                  <t>If a given URL and ETag combination has a match in a current CACHE_DIGEST, a complete response need not be pushed; The server MAY push a 304 response for that resource, indicating the client that it hasn’t changed.</t>
                  <t>If a given URL and ETag has no match in any current CACHE_DIGEST, the client does not have a cached copy, and a complete response can be pushed.</t>
               </list>
            </t>
            <t>Servers MAY use all CACHE_DIGESTs received for a given origin as current, as long as they do not have the RESET flag set; a CACHE_DIGEST frame with the RESET flag set MUST clear any previously stored CACHE_DIGESTs for its origin. Servers MUST treat an empty Digest-Value with a RESET flag set as effectively clearing all stored digests for that origin.</t>
            <t>Clients are not likely to send updates to CACHE_DIGEST over the lifetime of a connection; it is expected that servers will separately track what cacheable responses have been sent previously on the same connection, using that knowledge in conjunction with that provided by CACHE_DIGEST.</t>
            <t>Servers MUST ignore CACHE_DIGEST frames sent on a stream other than 0.</t>
            <section anchor="querying" title="Querying the Digest for a Value">
               <t>Given the following inputs:</t>
               <t>
                  <list style="symbols">
                     <t>
                        <spanx style="verb">URL</spanx> a string corresponding to the Effective Request URI (<xref target="RFC7230" x:fmt="," x:sec="5.5"/>) of a cached response <xref target="RFC7234"/>.</t>
                     <t>
                        <spanx style="verb">ETag</spanx> a string corresponding to the entity-tag <xref target="RFC7232"/> of a cached response <xref target="RFC7234"/> (if the ETag is available; otherwise, null).</t>
                     <t>
                        <spanx style="verb">validators</spanx>, a boolean</t>
                     <t>
                        <spanx style="verb">digest-value</spanx>, an array of bits.</t>
                  </list>
               </t>
               <t>
                  <list style="numbers">
                     <t>Let <spanx style="verb">f</spanx> be the value of the first byte of <spanx style="verb">digest-value</spanx>.</t>
                     <t>Let <spanx style="verb">b</spanx> be the bucket size, defined as 4.</t>
                     <t>Let <spanx style="verb">N</spanx> be the value of the second to fifth bytes of <spanx style="verb">digest-value</spanx> in big endian form.</t>
                     <t>Let <spanx style="verb">key</spanx> be the return value of <xref target="key"/> with <spanx style="verb">URL</spanx> and <spanx style="verb">ETag</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">h1</spanx> be the return value of <xref target="hash"/> with <spanx style="verb">key</spanx> and <spanx style="verb">N</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">fingerprint</spanx> be the return value of <xref target="fingerprint"/> with <spanx style="verb">key</spanx> and <spanx style="verb">f</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">h2</spanx> be the return value of <xref target="hash2"/> with <spanx style="verb">h1</spanx>, <spanx style="verb">fingerprint</spanx> and <spanx style="verb">N</spanx> as inputs.</t>
                     <t>Let <spanx style="verb">hashes</spanx> be an array containing <spanx style="verb">h1</spanx> and <spanx style="verb">h2</spanx>.</t>
                     <t>For each <spanx style="verb">h</spanx> in <spanx style="verb">hashes</spanx>: <list style="numbers">
                           <t>Let <spanx style="verb">position_start</spanx> be 40 + <spanx style="verb">h</spanx> * <spanx style="verb">f</spanx> * <spanx style="verb">b</spanx>.</t>
                           <t>Let <spanx style="verb">position_end</spanx> be <spanx style="verb">position_start</spanx> + <spanx style="verb">f</spanx> * <spanx style="verb">b</spanx>.</t>
                           <t>While <spanx style="verb">position_start</spanx> &lt; <spanx style="verb">position_end</spanx>: <list style="numbers">
                                 <t>Let <spanx style="verb">bits</spanx> be <spanx style="verb">f</spanx> bits from <spanx style="verb">digest_value</spanx> starting at <spanx style="verb">position_start</spanx>.</t>
                                 <t>If <spanx style="verb">bits</spanx> is <spanx style="verb">fingerprint</spanx>, return true</t>
                                 <t>Add <spanx style="verb">f</spanx> to <spanx style="verb">position_start</spanx>.</t>
                              </list>
                           </t>
                        </list>
                     </t>
                     <t>Return false.</t>
                  </list>
               </t>
            </section>
         </section>
      </section>
      <section anchor="the-sendingcachedigest-settings-parameter"
               title="The SENDING_CACHE_DIGEST SETTINGS Parameter">
         <t>A Client SHOULD notify its support for CACHE_DIGEST frames by sending the SENDING_CACHE_DIGEST (0xXXX) SETTINGS parameter.</t>
         <t>The value of the parameter is a bit-field of which the following bits are defined:</t>
         <t>DIGEST_PENDING (0x1): When set it indicates that the client has a digest to send, and the server may choose to wait for a digest in order to make server push decisions.</t>
         <t>Rest of the bits MUST be ignored and MUST be left unset when sending.</t>
         <t>The initial value of the parameter is zero (0x0) meaning that the client has no digest to send the server.</t>
      </section>
      <section anchor="the-acceptcachedigest-settings-parameter"
               title="The ACCEPT_CACHE_DIGEST SETTINGS Parameter">
         <t>A server can notify its support for CACHE_DIGEST frame by sending the ACCEPT_CACHE_DIGEST (0x7) SETTINGS parameter. If the server is tempted to making optimizations based on CACHE_DIGEST frames, it SHOULD send the SETTINGS parameter immediately after the connection is established.</t>
         <t>The value of the parameter is a bit-field of which the following bits are defined:</t>
         <t>ACCEPT (0x1): When set, it indicates that the server is willing to make use of a digest of cached responses.</t>
         <t>Rest of the bits MUST be ignored and MUST be left unset when sending.</t>
         <t>The initial value of the parameter is zero (0x0) meaning that the server is not interested in seeing a CACHE_DIGEST frame.</t>
         <t>Some underlying transports allow the server’s first flight of application data to reach the client at around the same time when the client sends it’s first flight data. When such transport (e.g., TLS 1.3 <xref target="I-D.ietf-tls-tls13"/> in full-handshake mode) is used, a client can postpone sending the CACHE_DIGEST frame until it receives a ACCEPT_CACHE_DIGEST settings value.</t>
         <t>When the underlying transport does not have such property (e.g., TLS 1.3 in 0-RTT mode), a client can reuse the settings value found in previous connections to that origin <xref target="RFC6454"/> to make assumptions.</t>
      </section>
      <section anchor="iana-considerations" title="IANA Considerations">
         <t>This document registers the following entry in the Permanent Message Headers Registry, as per <xref target="RFC3864"/>:</t>
         <t>
            <list style="symbols">
               <t>Header field name: Cache-Digest</t>
               <t>Applicable protocol: http</t>
               <t>Status: experimental</t>
               <t>Author/Change controller: IESG</t>
               <t>Specification document(s): [this document]</t>
            </list>
         </t>
         <t>This document registers the following entry in the HTTP/2 Frame Type Registry, as per <xref target="RFC7540"/>:</t>
         <t>
            <list style="symbols">
               <t>Frame Type: CACHE_DIGEST</t>
               <t>Code: 0xd</t>
               <t>Specification: [this document]</t>
            </list>
         </t>
         <t>This document registers the following entry in the HTTP/2 Settings Registry, as per <xref target="RFC7540"/>:</t>
         <t>
            <list style="symbols">
               <t>Code: 0x7</t>
               <t>Name: ACCEPT_CACHE_DIGEST</t>
               <t>Initial Value: 0x0</t>
               <t>Reference: [this document]</t>
            </list>
         </t>
      </section>
      <section anchor="security-considerations" title="Security Considerations">
         <t>The contents of a User Agent’s cache can be used to re-identify or “fingerprint” the user over time, even when other identifiers (e.g., Cookies <xref target="RFC6265"/>) are cleared.</t>
         <t>CACHE_DIGEST allows such cache-based fingerprinting to become passive, since it allows the server to discover the state of the client’s cache without any visible change in server behaviour.</t>
         <t>As a result, clients MUST mitigate for this threat when the user attempts to remove identifiers (e.g., “clearing cookies”). This could be achieved in a number of ways; for example: by clearing the cache, by changing one or both of N and P, or by adding new, synthetic entries to the digest to change its contents.</t>
         <t>TODO: discuss how effective the suggested mitigations actually would be.</t>
         <t>Additionally, User Agents SHOULD NOT send CACHE_DIGEST when in “privacy mode.”</t>
      </section>
   </middle>
   <back>
      <references title="Normative References">
         <reference anchor="RFC2119">
            <front>
               <title>Key words for use in RFCs to Indicate Requirement Levels</title>
               <author fullname="S. Bradner" initials="S." surname="Bradner"/>
               <date month="March" year="1997"/>
            </front>
            <seriesInfo name="BCP" value="14"/>
            <seriesInfo name="RFC" value="2119"/>
            <seriesInfo name="DOI" value="10.17487/RFC2119"/>
         </reference>
         <reference anchor="RFC3986">
            <front>
               <title>Uniform Resource Identifier (URI): Generic Syntax</title>
               <author fullname="T. Berners-Lee" initials="T." surname="Berners-Lee"/>
               <author fullname="R. Fielding" initials="R." surname="Fielding"/>
               <author fullname="L. Masinter" initials="L." surname="Masinter"/>
               <date month="January" year="2005"/>
            </front>
            <seriesInfo name="STD" value="66"/>
            <seriesInfo name="RFC" value="3986"/>
            <seriesInfo name="DOI" value="10.17487/RFC3986"/>
         </reference>
         <reference anchor="RFC6234">
            <front>
               <title>US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)</title>
               <author fullname="D. Eastlake 3rd" initials="D." surname="Eastlake 3rd"/>
               <author fullname="T. Hansen" initials="T." surname="Hansen"/>
               <date month="May" year="2011"/>
            </front>
            <seriesInfo name="RFC" value="6234"/>
            <seriesInfo name="DOI" value="10.17487/RFC6234"/>
         </reference>
         <reference anchor="RFC7230">
            <front>
               <title>Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing</title>
               <author fullname="R. Fielding"
                       initials="R."
                       role="editor"
                       surname="Fielding"/>
               <author fullname="J. Reschke"
                       initials="J."
                       role="editor"
                       surname="Reschke"/>
               <date month="June" year="2014"/>
            </front>
            <seriesInfo name="RFC" value="7230"/>
            <seriesInfo name="DOI" value="10.17487/RFC7230"/>
         </reference>
         <reference anchor="RFC7232">
            <front>
               <title>Hypertext Transfer Protocol (HTTP/1.1): Conditional Requests</title>
               <author fullname="R. Fielding"
                       initials="R."
                       role="editor"
                       surname="Fielding"/>
               <author fullname="J. Reschke"
                       initials="J."
                       role="editor"
                       surname="Reschke"/>
               <date month="June" year="2014"/>
            </front>
            <seriesInfo name="RFC" value="7232"/>
            <seriesInfo name="DOI" value="10.17487/RFC7232"/>
         </reference>
         <reference anchor="RFC7234">
            <front>
               <title>Hypertext Transfer Protocol (HTTP/1.1): Caching</title>
               <author fullname="R. Fielding"
                       initials="R."
                       role="editor"
                       surname="Fielding"/>
               <author fullname="M. Nottingham"
                       initials="M."
                       role="editor"
                       surname="Nottingham"/>
               <author fullname="J. Reschke"
                       initials="J."
                       role="editor"
                       surname="Reschke"/>
               <date month="June" year="2014"/>
            </front>
            <seriesInfo name="RFC" value="7234"/>
            <seriesInfo name="DOI" value="10.17487/RFC7234"/>
         </reference>
         <reference anchor="RFC7540">
            <front>
               <title>Hypertext Transfer Protocol Version 2 (HTTP/2)</title>
               <author fullname="M. Belshe" initials="M." surname="Belshe"/>
               <author fullname="R. Peon" initials="R." surname="Peon"/>
               <author fullname="M. Thomson"
                       initials="M."
                       role="editor"
                       surname="Thomson"/>
               <date month="May" year="2015"/>
            </front>
            <seriesInfo name="RFC" value="7540"/>
            <seriesInfo name="DOI" value="10.17487/RFC7540"/>
         </reference>
         <reference anchor="RFC6454">
            <front>
               <title>The Web Origin Concept</title>
               <author fullname="A. Barth" initials="A." surname="Barth"/>
               <date month="December" year="2011"/>
            </front>
            <seriesInfo name="RFC" value="6454"/>
            <seriesInfo name="DOI" value="10.17487/RFC6454"/>
         </reference>
      </references>
      <references title="Informative References">
         <reference anchor="RFC4648">
            <front>
               <title>The Base16, Base32, and Base64 Data Encodings</title>
               <author fullname="S. Josefsson" initials="S." surname="Josefsson"/>
               <date month="October" year="2006"/>
            </front>
            <seriesInfo name="RFC" value="4648"/>
            <seriesInfo name="DOI" value="10.17487/RFC4648"/>
         </reference>
         <reference anchor="RFC5234">
            <front>
               <title>Augmented BNF for Syntax Specifications: ABNF</title>
               <author fullname="D. Crocker"
                       initials="D."
                       role="editor"
                       surname="Crocker"/>
               <author fullname="P. Overell" initials="P." surname="Overell"/>
               <date month="January" year="2008"/>
            </front>
            <seriesInfo name="STD" value="68"/>
            <seriesInfo name="RFC" value="5234"/>
            <seriesInfo name="DOI" value="10.17487/RFC5234"/>
         </reference>
         <reference anchor="RFC6265">
            <front>
               <title>HTTP State Management Mechanism</title>
               <author fullname="A. Barth" initials="A." surname="Barth"/>
               <date month="April" year="2011"/>
            </front>
            <seriesInfo name="RFC" value="6265"/>
            <seriesInfo name="DOI" value="10.17487/RFC6265"/>
         </reference>
         <reference anchor="I-D.ietf-tls-tls13">
            <front>
               <title>The Transport Layer Security (TLS) Protocol Version 1.3</title>
               <author fullname="Eric Rescorla" initials="E" surname="Rescorla"/>
               <date day="15" month="February" year="2018"/>
            </front>
            <seriesInfo name="Internet-Draft" value="draft-ietf-tls-tls13-24"/>
         </reference>
         <reference anchor="Service-Workers"
                    target="https://www.w3.org/TR/2016/WD-service-workers-1-20161011/">
            <front>
               <title>Service Workers 1</title>
               <author fullname="Alex Russell" initials="A." surname="Russell"/>
               <author fullname="Jungkee Song" initials="J." surname="Song"/>
               <author fullname="Jake Archibald" initials="J." surname="Archibald"/>
               <author fullname="Marijn Kruisselbrink"
                       initials="M."
                       surname="Kruisselbrink"/>
               <date month="October" year="2016"/>
            </front>
            <seriesInfo name="W3C Working Draft" value="WD-service-workers-1-20161011"/>
         </reference>
         <reference anchor="Fetch" target="https://fetch.spec.whatwg.org/">
            <front>
               <title>Fetch Standard</title>
               <author/>
               <date year="n.d."/>
            </front>
         </reference>
         <reference anchor="Cuckoo"
                    target="https://www.cs.cmu.edu/~dga/papers/cuckoo-conext2014.pdf">
            <front>
               <title>Cuckoo Filter: Practically Better Than Bloom</title>
               <author/>
               <date year="n.d."/>
            </front>
         </reference>
         <reference anchor="RFC3864">
            <front>
               <title>Registration Procedures for Message Header Fields</title>
               <author fullname="G. Klyne" initials="G." surname="Klyne"/>
               <author fullname="M. Nottingham" initials="M." surname="Nottingham"/>
               <author fullname="J. Mogul" initials="J." surname="Mogul"/>
               <date month="September" year="2004"/>
            </front>
            <seriesInfo name="BCP" value="90"/>
            <seriesInfo name="RFC" value="3864"/>
            <seriesInfo name="DOI" value="10.17487/RFC3864"/>
         </reference>
      </references>
      <section anchor="encoding-the-cachedigest-frame-as-an-http-header"
               title="Encoding the CACHE_DIGEST frame as an HTTP Header">
         <t>On some web browsers that support Service Workers <xref target="Service-Workers"/> but not Cache Digests (yet), it is possible to achieve the benefit of using Cache Digests by emulating the frame using HTTP Headers.</t>
         <t>For the sake of interoperability with such clients, this appendix defines how a CACHE_DIGEST frame can be encoded as an HTTP header named <spanx style="verb">Cache-Digest</spanx>.</t>
         <t>The definition uses the Augmented Backus-Naur Form (ABNF) notation of <xref target="RFC5234"/> with the list rule extension defined in <xref target="RFC7230" x:fmt="," x:sec="7"/>.</t>
         <figure>
            <artwork type="abnf7230">
  Cache-Digest  = 1#digest-entity
  digest-entity = digest-value *(OWS ";" OWS digest-flag)
  digest-value  = &lt;Digest-Value encoded using base64url&gt;
  digest-flag   = token
</artwork>
         </figure>
         <t>A Cache-Digest request header is defined as a list construct of cache-digest-entities. Each cache-digest-entity corresponds to a CACHE_DIGEST frame.</t>
         <t>Digest-Value is encoded using base64url <xref target="RFC4648" x:fmt="," x:sec="5"/>. Flags that are set are encoded as digest-flags by their names that are compared case-insensitively.</t>
         <t>Origin is omitted in the header form. The value is implied from the value of the <spanx style="verb">:authority</spanx> pseudo header. Client MUST only send Cache-Digest headers containing digests that belong to the origin specified by the HTTP request.</t>
         <t>The example below contains one digest of fresh resource and has only the <spanx style="verb">COMPLETE</spanx> flag set.</t>
         <figure>
            <artwork type="example">
  Cache-Digest: AfdA; complete
</artwork>
         </figure>
         <t>Clients MUST associate Cache-Digest headers to every HTTP request, since Fetch <xref target="Fetch"/> - the HTTP API supported by Service Workers - does not define the order in which the issued requests will be sent to the server nor guarantees that all the requests will be transmitted using a single HTTP/2 connection.</t>
         <t>Also, due to the fact that any header that is supplied to Fetch is required to be end-to-end, there is an ambiguity in what a Cache-Digest header respresents when a request is transmitted through a proxy. The header may represent the cache state of a client or that of a proxy, depending on how the proxy handles the header.</t>
      </section>
      <section anchor="acknowledgements" title="Acknowledgements">
         <t>Thanks to Yoav Weiss for his idea and text to use Cuckoo Filter.</t>
         <t>Thanks to Stefan Eissing for his suggestions.</t>
      </section>
      <section anchor="changes" title="Changes">
         <section anchor="since-draft-ietf-httpbis-cache-digest-02"
                  title="Since draft-ietf-httpbis-cache-digest-02">
            <t>
               <list style="symbols">
                  <t>Switch to Cuckoo Filter.</t>
               </list>
            </t>
         </section>
         <section anchor="since-draft-ietf-httpbis-cache-digest-01"
                  title="Since draft-ietf-httpbis-cache-digest-01">
            <t>
               <list style="symbols">
                  <t>Added definition of the Cache-Digest header.</t>
                  <t>Introduce ACCEPT_CACHE_DIGEST SETTINGS parameter.</t>
                  <t>Change intended status from Standard to Experimental.</t>
               </list>
            </t>
         </section>
         <section anchor="since-draft-ietf-httpbis-cache-digest-00"
                  title="Since draft-ietf-httpbis-cache-digest-00">
            <t>
               <list style="symbols">
                  <t>Make the scope of a digest frame explicit and shift to stream 0.</t>
               </list>
            </t>
         </section>
      </section>
   </back>
</rfc>
