Subject: Re: [Ietf-message-headers] Requesting provisional registration for AMP-Cache-Transform header

From: Mark Nottingham <[email-masked]>
Date: Thu, 14 Mar 2019 15:38:26 +1100

Hi Devin,

Sorry for the delay. Responses below.

> On 12 Feb 2019, at 11:00 am, Devin Mullins <[email-masked]> wrote:
> 
> -ietf-message-headers, +ietf-http-wg
> 
> Hi Mark, you're absolutely right; q-values could be used to accomplish that bit. I'd given it a bit of thought in the past, but I'm not sure I really gave it enough thought until now. Here's a couple things that make me hesitant to use q-values:
> 
> 1. AFAIK, googlebot currently requests with Accept headers that match what browsers commonly send (https://www.searchdatalogy.com/blog/googlebots-http-headers/). With the addition of application/signed-exchange to Chromium, this remains true (https://cs.chromium.org/chromium/src/content/browser/loader/navigation_url_loader_impl.cc?l=237&rcl=7d726373f502fd5e20cede7e22da049b16f77377). However, using q-values means googlebot would need to send a significantly different Accept header. I fear that this would cause unintentional breakage with servers that implement an improper content negotiation algorithm.

You're suggesting a new, duplicative content negotiation mechanism be created to avoid this fear, but haven't presented any data to support it. 

It should be possible to quantify how often origin servers mis-implement content negotiation, both by probing the Internet (and Google is in a uniquely good place to gather that data), and examining common implementations. 

Even if some were found, I wonder why you can't work with them -- since they're already adopting the format you're defining -- to fix the problem, rather than introduce a new mechanism. After all, such a change should only affect sites that actually offer the format you're defining, correct?

> 2. Chromium's accept header does not place application/signed-exchange;v=b3 on a lower q-value than other formats. Thus, if publishers wish to serve SXGs crawlers by looking only at the Accept header, they may also inadvertently serve them to browsers, too. Of course, publishers are free to use an algorithm that only selects signed-exchange if its weight is strictly greater than the alternatives. But such a rule isn't implemented today, and wouldn't make sense for most media types; at the point we are suggesting writing new code for a specific case, then the simplest change necessary seems preferable.

Again, data please. Why do you think that origin servers don't implement response selection by qvalue?

> For example, "just test for the presence of an AMP-Cache-Transform header" is doable in most reverse-proxy config languages, and possibly sufficient.

It's also a one-off solution. I'm concerned that if every new format defines such a mechanism, we're going to be overcome by lots of slightly different ways of doing things. From a reverse proxy / CDN standpoint, it's better if we can reuse existing mechanisms that don't require special handling (some do not allow factoring additional request headers into the cache key easily).

>  Alternatively, Chromium could lower the q-value in its own Accept header; I haven't explored this, and may bring it up with the Chrome team to gauge their opinion. But I could see reasons they might prefer not to do that, for use cases other than the "privacy-preserving prefetch" that is a priority to AMP.

I'd be interested to hear the reaction. 

> 3. There's some other data not captured by existing request headers:
> 
> 3a. For privacy-preserving prefetch, googlebot will request a particular variant of the resource with rewritten subresource URLs (https://github.com/ampproject/amphtml/blob/master/spec/amp-cache-transform.md#target-specific-constraints), to match what the AMP Cache does today. So the target of those rewrites (e.g. cdn.ampproject.org) needs to be specified on the HTTP request. (This is, hopefully, only an interim requirement, to be replaced with signed subresource substitution [https://github.com/WICG/webpackage/issues/347] or with bundled exchanges.) I had considered using Referer or Origin to indicate this desired variant, but it seems to me like that's not what these header fields are intended for, and thus there may be unexpected consequences of using it here. Perhaps I'm wrong?

I think it depends on whether Origin (for example) is available and the right value to use in all cases. If it is, that would probably be sufficient -- although I'd bounce the idea against people like Anne van Kesteren and Mike West.

> 3b. Similar to 3a, googlebot will request a particular "version" of the AMP transforms. (These are transformations to be run by the publisher, meant to replicate those currently run by AMP Caches, and address a couple of needs, including speed, privacy, and security.) The version is required to be able to make breaking changes to these transforms. (I suspect, as long as there are changes to AMP component library, there may be corresponding changes to the transforms. But maybe time will show that breaking changes aren't needed, and the requirement can be removed.)

That sounds an awful lot like a media type parameter (or a number of them).

> In both 3a and 3b, we could indicate this on the URL, but my understanding is that doing so would create difficulties for search indexing implementations. It's possible this data could be in the `AMP-Cache-Transform` header while the "prefer SXG" bit is still in Accept, but I'm not sure of the benefits of doing so. (As opposed to the benefits of not introducing a new header at all, which seem a little more clear to me... if the costs can be mitigated.)
> 
> Please let me know if you see a different solution to all these twisty little constraints. Especially as this moves from an AMP-specific criterion to a more general one (https://amphtml.wordpress.com/2018/03/08/standardizing-lessons-learned-from-amp/), it would be nice to minimize the requirements on top of HTTP/HTML that are necessary.

I do agree with the motivation to  minimise additional requirements. I'm not certain that using Accept is going to be the best solution for you; it might be a partial solution, though. 

If you do end up needing to specify a new content negotiation mechanism here, you really should have a look at Client Hints -- which is turning into a framework for doing so. See: <https://httpwg.org/http-extensions/draft-ietf-httpbis-client-hints.html>. Note that that should be updated to include Variants eventually <https://httpwg.org/http-extensions/draft-ietf-httpbis-variants.html>; you'll need to specify a variant algorithm as well if you define a new conneg mechanism.

Cheers,

> 
> Thanks,
> Devin
> 
> On Mon, Feb 4, 2019 at 7:45 PM Mark Nottingham <[email-masked]> wrote:
> Hi Devin,
> 
> Sorry for the delay; I saw this a while ago but didn't look into it deeply. For future reference, you're much more likely to get reviews if you send this to the HTTP WG mailing list (we're in the process of separating HTTP headers out into their own registry, in part to make that more clear).
> 
> Without commenting on the entire document you link to, it says:
> 
> > Therefore, the need arises for the origin to distinguish requests from users and requests from SXG intermediaries. That is, there is a difference between "I can understand the SXG format" and "I prefer an SXG if available". Accept: application/signed-exchange indicates the former. No currently-defined header indicates the latter.
> 
> However, Accept *can* express that; e.g.,
> 
> Accept: application/signed-exchange;q=1.0, */*;q=0.05
> 
> Did you consider using qvalues in the accept header to achieve this?
> 
> Cheers,
> 
> P.S. It may be good to follow up on [email-masked], and then report the result back here. I haven't CC:ed them to avoid cross-posting.
> 
> 
> 
> > On 7 Sep 2018, at 10:33 am, Devin Mullins <twifkak=[email-masked]> wrote:
> > 
> > Header field name: AMP-Cache-Transform
> > Applicable protocol: http
> > Status: provisional
> > Author: Devin Mullins <[email-masked]>; Google; https://www.ampproject.org/
> > Specification: https://github.com/ampproject/amphtml/blob/master/spec/amp-cache-transform..md
> > 
> > Let me know what other information I can provide.
> > 
> > Thanks!
> > Devin
> > _______________________________________________
> > Ietf-message-headers mailing list
> > [email-masked]
> > https://www.ietf.org/mailman/listinfo/ietf-message-headers
> 
> --
> Mark Nottingham   https://www.mnot.net/
> 

--
Mark Nottingham   https://www.mnot.net/

---

From: Devin Mullins <[email-masked]>
Date: Thu, 28 Mar 2019 11:45:00 -0700

Thanks for the responses, Mark.

On Wed, Mar 13, 2019 at 9:38 PM Mark Nottingham <[email-masked]> wrote:

> > 1. AFAIK, googlebot currently requests with Accept headers that match
> what browsers commonly send (
> https://www.searchdatalogy.com/blog/googlebots-http-headers/). With the
> addition of application/signed-exchange to Chromium, this remains true (
> https://cs.chromium.org/chromium/src/content/browser/loader/navigation_url_loader_impl.cc?l=237&rcl=7d726373f502fd5e20cede7e22da049b16f77377).
> However, using q-values means googlebot would need to send a significantly
> different Accept header. I fear that this would cause unintentional
> breakage with servers that implement an improper content negotiation
> algorithm.
>
> You're suggesting a new, duplicative content negotiation mechanism be
> created to avoid this fear, but haven't presented any data to support it.
>
> It should be possible to quantify how often origin servers mis-implement
> content negotiation, both by probing the Internet (and Google is in a
> uniquely good place to gather that data), and examining common
> implementations.
>

Sure, happy to explore some common implementations. According to the latest
Netcraft survey
<https://news.netcraft.com/archives/2019/02/28/february-2019-web-server-survey.html>,
the top servers on a couple different axes are Apache, nginx, and IIS.
(There are other ways of ranking servers, but this one was readily
available from a quick search. If you think this is a source of significant
bias, I'd be interested to hear.)

Apache:

   - Has a documented conneg algorithm
   <https://httpd.apache.org/docs/2.4/content-negotiation.html#methods>
   - Supports q-values
   - It also supports server-side preference among multiple variants when
   the client expresses indifference. (see "quality-of-source" or "qs" on that
   page or this one
   <https://httpd.apache.org/docs/2.4/mod/mod_negotiation.html#typemaps>).
   Potential downsides:
      - It appears this makes use of a "type map" format that is specific
      to Apache.
      - This seems incompatible with a mod_proxy setup, and that seems like
      an important use-case. (As one data point, AMP's canonical
      implementation <https://github.com/ampproject/amppackager> of an
      exchange signer is meant to be used behind a revproxy. We could just
      suggest that frontends forward all requests to amppkg regardless
of Accept,
      but that vastly limits its utility, as amppkg has not been optimized to
      serve user-facing traffic. Other implementations may experience similar
      problems; for instance, they may wish for an edge node to deliver cached
      content if possible, and may not wish to host AMP transformation on the
      edge.)
         - For instance, it is unclear if backends can return type maps, or
         they need to be retrieved as files by Apache.
         - Also, it would need to pass the negotiated media type on to the
         backend. For instance, say the client requests `Accept:
         application/signed-exchange;v=b3;amp="google;v=\"3\"";q=0.8,
application/signed-exchange;v=b3;amp="google;v=\"1..2\""`.
         Then the backend needs to know that version 1..2 is being
requested, not 3.
         It could recompute the negotiated media type, but that risks
mismatch with
         what the frontend computed.

nginx:

   - Doesn't support conneg natively.
   - Example configurations
   <https://www.google.com/search?q=nginx+content+negotiation> supporting
   it make use of regexes and scripts that parse Accept only approximately.
   - I couldn't find any that support negotiation on qvalues.

IIS:

   - Supports conneg through a CLR API
   <https://docs.microsoft.com/en-us/aspnet/web-api/overview/formats-and-model-binding/content-negotiation>
   - The default content negotiator:
      - Supports q-values
      - Appears to support server-side preference through the
      MediaTypeMapping
      <https://docs.microsoft.com/en-us/previous-versions/aspnet/hh834723(v%3Dvs.118)>
class's
      TryMatchMediaType
      <https://docs.microsoft.com/en-us/previous-versions/visualstudio/hh835829(v%3Dvs.118)>
abstract
      method.

As far as probing the internet, that's not something I'm inclined to do
unless the benefit well outweighs the (internal and external) costs. Can
you walk me through what you had in mind? Lacking widespread support for
Variants, I'm not sure how I would create an unbiased sample of URLs that
have multiple known variants. (I could look at a biased sample by, e.g.
looking at responses with `Vary: Accept` and then trying a few
known-related media types to discover the variants, before then probing
with trickier Accept headers. But even ignoring the bias, I suspect the
success rate on finding variants would be pretty low.)

Even if some were found, I wonder why you can't work with them -- since
> they're already adopting the format you're defining -- to fix the problem,
> rather than introduce a new mechanism. After all, such a change should only
> affect sites that actually offer the format you're defining, correct?
>

The modified Accept header will be sent on most Googlebot requests, so in
the extreme, it could negatively affect servers that e.g. don't parse
Accept properly. (For a contrived example: `Accept:
application/signed-exchange;v=b3;amp="amp*webp*lace;v=\"1\""` may trip the
webp detector in this example
<https://github.com/cdowdy/Nginx-Content-Negotiation/blob/master/nginx.conf>,
even if the server doesn't support AMP or signed exchanges.)

But excepting that, it's true that the effect is limited to sites wishing
to adopt the new format. Still, our goal is to minimize the barrier to
entry for web developers wishing to adopt it, within the technical
constraints imposed by this space.

It's also a one-off solution. I'm concerned that if every new format
> defines such a mechanism, we're going to be overcome by lots of slightly
> different ways of doing things. From a reverse proxy / CDN standpoint, it's
> better if we can reuse existing mechanisms that don't require special
> handling (some do not allow factoring additional request headers into the
> cache key easily).

I'd be interested for some detail on this. Off-hand, I see that Varnish
supports customizing cache key
<https://varnish-cache.org/docs/trunk/users-guide/vcl-hashing.html>, though
that's where my knowledge on this ends. (I'm unable to find recent
documentation on Squid's Vary support, after a few minutes' searching.)

<snip things I have no update on>

If you do end up needing to specify a new content negotiation mechanism
> here, you really should have a look at Client Hints -- which is turning
> into a framework for doing so. See: <
> https://httpwg.org/http-extensions/draft-ietf-httpbis-client-hints.html>.
> Note that that should be updated to include Variants eventually <
> https://httpwg.org/http-extensions/draft-ietf-httpbis-variants.html>;
> you'll need to specify a variant algorithm as well if you define a new
> conneg mechanism.
>

Thanks! For now, I included a "future work" note about Variants on the
AMP-Cache-Transform doc, and will take a closer look at how Client Hints
could be applicable.

Devin