Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scoping of Accept-CH #307

Closed
mnot opened this issue Mar 2, 2017 · 10 comments
Closed

Scoping of Accept-CH #307

mnot opened this issue Mar 2, 2017 · 10 comments

Comments

@mnot
Copy link
Member

mnot commented Mar 2, 2017

The Accept-CH response header is defined as:

When a client receives Accept-CH, or if it is capable of processing the HTML response and finds an equivalent HTML meta element, it can treat it as a signal that the server is interested in receiving the Client-Hint header fields that match the advertised field-values; subsequent requests initiated to the same server and, optionally any subresource requests initiated as a result of processing the response from the server that includes the Accept-CH opt-in, can include the Client-Hint header fields that match the advertised field-values.

For example, based on Accept-CH example above, a user agent could append DPR, Width, Viewport-Width, and Downlink header fields to all subresource requests initiated by the page constructed from the response. Alternatively, a client can treat advertised support as a persistent origin preference and append same header fields on all future requests initiated to and by the resources associated with that origin.

"All future requests" is a long time indeed. While of course the client isn't going to literally do that (eventually it'll be garbage collected, or the user will reset state, or the machine will be recycled), from a server-side perspective, it'd be nice to have some level of control over how bloated your requests get.

Additionally, having Accept-CH possibly indicate that future references to and from this origin seems like a pretty broad brush to be painting with. While Chrome might make some reasonable decisions about tradeoffs here (and probably needs some wiggle room), if this ever does get implemented elsewhere, this broadness and freedom is a recipe for bad interop and worse server-side headaches.

So, can we nail this down at all?

The most conservative approach is:

"Send CH headers on subrequests generated by this content, please."

However, the above also says "subsequent requests initiated to the same server" in the primary spot; the case above is relegated to "optionally."

Personally, my preference would be to drop "subsequent requests initiated to the same server and, optionally" and the corresponding text in the example below it. The primary use case for CH as I understand it is serving appropriate subresources, NOT dynamically modifying HTML, so that should do the trick.

Am I missing something, @igrigorik?

Regardless of that, "server" is used very loosely above; I think you mean "origin", right? And "can" should probably be "MAY".

CC @yoavweiss

@igrigorik
Copy link
Member

The primary use case for CH as I understand it is serving appropriate subresources, NOT dynamically modifying HTML, so that should do the trick.

With the benefit of few years of experience, absence of hints on the initial request has proven to be a major limitation that prevented wider adoption. In practice, many of the most critical decisions about page format are made when the HTML is generated -- e.g. whether you should serve "light" version of the page, picking resource density, ..., and feature-detecting support for CH to begin with. In short, we do need to allow hints on navigation responses.

"Send CH headers on subrequests generated by this content, please."

I think that's a reasonable definition for Accept-CH, iff we also combine it with Accept-CH-Lifetime proposed in #306 to cover the case for initial navigation. Concretely, the proposal here would be:

  • Scope down Accept-CH to "subsequent requests generated by this content"
  • Define Accept-CH-Lifetime to allow opt-in to be remembered for specified period of time.
    • When this is present, opt-in applies for all content that belongs to the origin.

@michael-oneill
Copy link

DNT has a mechanism for determining if the DNT:0 header sent to subresources, a JS API for specifying "site-specific" consent. This also can specify lifetime by having an "expires" or "maxAge" property in the parameter dictionary for the call.

The TPWG has discussed using cookies as a more generic method, but the SOP gets in the way (you cannot limit the state to a top level context).

The Accept-CH header is similarly determining stateful site-specific behaviour for subresources, perhaps this points to a generalised solution? Especially as there are privacy/user control issues in common?

I am thinking about a well-known cookie prefix (as proposed for RFC6265bis) that would cause the cookie to be sent to subresources in the cookie header, but only within the context of the parent that placed it. The existence of particular forms of this well-known cookie could then determine UA behaviour (such as sending Client Hints to subresources).

Implementation would be simpler because the expiry procedures are already in place.

A further advantage would then be that the state is automatically contained in the UAs cookie store, accessible to existing privacy oriented UA UIs and extensions, increasing transparency.

For example:

Set-Cookie: __SRAccept-CH=DPR;expires=Sat, 05 Mar 2017 00:00:00 GMT

@mnot
Copy link
Member Author

mnot commented Mar 6, 2017

@igrigorik - Just thinking through doing this, a couple of questions --

It seems like there are a lot of potential dimensions that the server's preferences for sending CH could vary -- e.g., same-origin vs. third-party, navigation vs. subresource, etc. Are we offering the right capability (all requests from a given origin) here?

Will having one Accept-CH policy for an entire origin work? What if different resources need different headers? How should clients behave when they get conflicting lists of headers and/or lifetimes for a given origin?

Using a cache to determine whether to sent hint headers means that the initial navigation request to a given origin won't have them, so any behaviour that depends on them will need a fallback. Is that just going to be "serve the heavier page", or something more complex?

@igrigorik
Copy link
Member

It seems like there are a lot of potential dimensions that the server's preferences for sending CH could vary -- e.g., same-origin vs. third-party, navigation vs. subresource, etc. Are we offering the right capability (all requests from a given origin) here?

Based on the experience and feedback so far.. yes. It's the simplest strategy that covers all the use cases, and everything else just adds more configuration and implementation complexity.

Will having one Accept-CH policy for an entire origin work? What if different resources need different headers? How should clients behave when they get conflicting lists of headers and/or lifetimes for a given origin?

Last registration wins, similar to HSTS.

Using a cache to determine whether to sent hint headers means that the initial navigation request to a given origin won't have them, so any behaviour that depends on them will need a fallback. Is that just going to be "serve the heavier page", or something more complex?

The former. Practically speaking, sites can't rely on CH hints being available from every browser in any case, so they need a fallback strategy regardless.

@igrigorik
Copy link
Member

@mnot @mikewest would love to hear your thoughts on the cookie opt-in idea floated above.

Set-Cookie: __Secure-Accept-CH=DPR; Secure; Path=/images; Expires=<date>

  • It does provides more flexibility than the origin wide opt-in -- e.g. customizable by path, etc.
  • It's visible to the user and subject to all other cookie policies and workflows.

Do we have any other precedents that use cookies for feature opt-ins? Any gotchas with going down this path, spec/layering and implementation wise? It's also unclear to me whether we'd really need to invent new prefixes.. hoping the answer is "no".

@mikewest
Copy link
Member

From a practical perspective, this sounds expensive if we need to consult the cookie monster for every request. I suspect that we'd internally need to turn this into something like HSTS where we store the pins distinctly from cookies, at which point we lose much of the elegance of the proposal, I think.

From a theoretical perspective, this is breaking new ground. We don't have any other special-purpose cookies that I know of. We'd need to reserve the name in some way (which is absolutely doable, if odd). Also, cookies have terrible scoping rules. The less eTLD+1 we have, the better, from my perspective.

From a pinning perspective, spelling the pin as Set-Cookie vs Set-CH-Disposition or something is not terribly concerning. The server is expressing a preference, and we're caching it locally. The general idea of pinning that kind of preference seems fine to me. I'd prefer to see it done via origin policy, but I still haven't found anyone to implement that (nor have I addressed @mnot's feedback on the spec... :( ).

@igrigorik
Copy link
Member

From a practical perspective, this sounds expensive if we need to consult the cookie monster for every request. I suspect that we'd internally need to turn this into something like HSTS where we store the pins distinctly from cookies, at which point we lose much of the elegance of the proposal, I think.

Right, you confirmed my main worry. Solving this problem via cookies is doable, but brings a lot of unrelated complexity that I'd much rather avoid. I'm inclined to keep things simple and...

  • Define a standalone Accept-CH-Lifetime, as proposed in Allow servers to specify max-age in the client hints header #306 (comment)
    • Give it origin-wide scope -- no subpaths, etc.
    • Pin expires based on specified lifetime, or whenever cookies are cleared.
  • When we ship Origin Policy developers can just move the pin into their policy and everything will continue working as before.

I'll take a run at a PR for the above.

igrigorik added a commit that referenced this issue Mar 17, 2017
@igrigorik
Copy link
Member

First run at Accept-CH-Lifetime: #313 - ptal.

@michael-oneill
Copy link

Doesn't "the cookie monster" have to be consulted anyway for every request? If only to work out what to put in the Cookie header?

My idea was mainly to give users (and privacy protection extensions) the ability to detect the existence of the CH state by keeping it in the same place as cookies, where there already exist UIs etc. for seeing/dealing with them.

If a parallel system is implemented to manage CH state (with expiry etc.) then there would also be a need for similar UIs, API to support extensions etc. For cookies that already exists.

It is true the scoping rules are horrible, but they do not need to be used for these special prefixes. The "secure" attribute already restricts scoping for some cookies.

igrigorik added a commit that referenced this issue Mar 26, 2017
* define Accept-CH-Lifetime

Closes #307 and #306.
@yoavweiss
Copy link
Contributor

Doesn't "the cookie monster" have to be consulted anyway for every request? If only to work out what to put in the Cookie header?

Not from inside the rendering engine, which is where CH headers are added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

5 participants