diff --git a/explainer.md b/explainer.md index 3f74ae5f7..a3eb5aeac 100644 --- a/explainer.md +++ b/explainer.md @@ -49,7 +49,9 @@ intermediate) and forwards it to a client (or another intermediate). When an HTTP exchange is encoded into a resource, the resource can be fetched from a **physical URL** that is different from the **logical URL** of the -encoded exchange. +encoded exchange. We talk about the **inner** exchange, the **outer** resource +it's encoded into, and sometimes the outer exchange that fetches the outer +resource. ## Component documents @@ -95,8 +97,8 @@ Signed exchanges can also be sent to a client in three ways: non-origin signatures and to provide an origin-trusted signature to intermediates. 1. Enveloped into the `application/signed-exchange` content type. In this case, - the signed exchange has both the logical URL of its embedded request, and the - physical URL of the envelope itself. + the signed exchange has both the logical URL of its inner request, and the + physical URL of the outer envelope itself. 1. In an HTTP/2-Pushed exchange. ### Bundled exchanges @@ -246,10 +248,10 @@ reviewed for. ## Signed Exchange Loading Sketch -When an **embedder** prefetches or embeds an enveloped signed exchange, or a -client navigates from the embedder to an enveloped signed exchange, the -client goes through several steps to open the envelope and load the signed -resource. +When an **embedder** prefetches or embeds an application/signed-exchange +resource, or a client navigates from the embedder to an +application/signed-exchange, the client goes through several steps to open the +outer envelope and load the inner exchange. ### Fetch the physical URL @@ -260,11 +262,10 @@ embedder's and any parent frame's Content Security Policy, and goes through the physical URL's Service Worker for navigations or the embedder's otherwise. Once the response comes back, its `Content-Type: application/signed-exchange` -header tells the client that it represents a signed exchange, but it's initially -treated like any other response: the Response object shown to the Service Worker -(if any) is the bytes of the `application/signed-exchange` resource, not the -response inside it, and the `application/signed-exchange` participates in caches -the same way as any other resource. +header tells the client that it's the outer resource of a signed exchange, but +it's initially treated like any other response: the Response object shown to the +Service Worker (if any) is the bytes of the outer, not the inner response, and +the outer resource participates in caches the same way as any other resource. ### Fetch the certificate chain @@ -290,14 +291,13 @@ Each signature with a valid certificate chain is passed on to the next step. ### Signature verification -Once the certificates are validated and enough of the -`application/signed-exchange` resource is received to parse the claimed -signed-exchange headers, the client extracts the logical URL from those headers -and then tries to find a valid signature over the headers that is trusted for -the claimed origin. If none of the signatures are valid, it either +Once the certificates are validated and enough of the outer resource is received +to parse the claimed inner headers, the client extracts the logical URL from +those headers and then tries to find a valid signature over the headers that is +trusted for the logical URL's origin. If none of the signatures are valid, it +either -1. redirects to the logical URL as if the whole signed exchange were a 302 - response, or +1. redirects to the logical URL as if the outer response were a 302 redirect, or 2. fails with a network error. We're not yet certain which behavior is best. The first is slightly more @@ -311,7 +311,7 @@ records into a response stream as they arrive. ### Prefetching stops here -At this point, the client's behavior depends on whether the signed exchange was +At this point, the client's behavior depends on whether the outer exchange was requested as a [prefetch](https://w3c.github.io/resource-hints/#prefetch). To satisfy the [privacy-preserving prefetch](#privacy-preserving-prefetch) use case, prefetches can't fully load the logical URL, which would create an HTTP @@ -330,34 +330,37 @@ simpler than expected. ### Caching the signed response If the signed exchange was requested as a navigation or subresource (i.e. *not* -prefetches), the client tries to cache the request→response pair it contains. +prefetches), the client tries to cache the inner exchange. This *doesn't* happen if: -* The signed exchange's request headers aren't sufficiently similar (TBD) to the +* The inner request headers aren't sufficiently similar (TBD) to the request headers the client would use for a normal request in the same context. This prevents a malicious intermediate from sticking the wrong content-negotiated resource in the HTTP cache. -* There's a response in the HTTP (or any?) cache with a newer Date header - than the signed exchange's response. This prevents some downgrade attacks. +* There's a response in the HTTP (or any?) cache with a newer Date header than + the inner response's Date header. This prevents some downgrade attacks. In either of these cases, the client just skips to the redirect in the next step. -If we're still here, the signed exchange is put into a "use-once" cache similar -to the [preload cache](https://github.com/whatwg/fetch/issues/590) and, if the -response headers allow it (and review of this explainer indicates it's a good -idea), the [HTTP cache](https://tools.ietf.org/html/rfc7234). +If we're still here, the inner exchange is treated as if it had been prefetched +from the original origin. Note that the [prefetch +specification](https://w3c.github.io/resource-hints/) doesn't say exactly what +this means. It is similar to the [preload +cache](https://github.com/whatwg/fetch/issues/590) but situated between the HTTP +cache and the Service Worker, and not exactly the same in other respects. -If we put the signed exchange in the HTTP cache, its freshness has to be bounded -by the shorter of the normal HTTP cache lifetime or the signature's expiration. +If this behavior puts the inner exchange in the [HTTP +cache](https://tools.ietf.org/html/rfc7234), its freshness has to be bounded by +the shorter of the normal HTTP cache lifetime or the signature's expiration. This is more strict than the bound on cache freshness when it crosses a certificate or OCSP response expiration in order to partially mitigate [downgrade attacks](https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#seccons-downgrades). For *later* loads of the logical URL (in particular, not the load that's happening through the signed exchange, since it's fulfilled using the -above-mentioned "use-once" cache), a stale entry can be revalidated in the +above-mentioned prefetch cache), a stale entry can be revalidated in the following ways: * If the `Signature` is expired but the HTTP caching information is fresh, the