Server Push and Content Negotiation

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
2 messages Options
Reply | Threaded
Open this post in threaded view
|

Server Push and Content Negotiation

Mark Nottingham-2
The interaction of Content Negotiation and Server Push isn't really specified. Depending on how it's implemented, it could be quite tricky, because it seemingly requires the server to guess what the client would have sent, in order to negotiate upon it.

However, it becomes much simpler if we assume that the client SHOULD NOT check a `PUSH_PROMISE` request's headers to see whether or not it would have sent that request.

This means, for example, that if you `PUSH_PROMISE` the "wrong" `User-Agent`, `Accept-Encoding`, `User-Agent` or even `Cookie` header field, the client SHOULD still use the pushed response; all they're looking for is a matching request method and URL.

However, this does imply a few things:

* The pushed request and response MUST still "agree"; i.e., if you're using gzip encoding, `Accept-Encoding` and `Content-Encoding` should be pushed with appropriate values.
* The pushed response MUST have an appropriate `Vary` header field, if it is cacheable. This is so that the cache operates properly.

Additionally, the server needs to know what the base capabilities and preferences of the client are, to allow it to select the appropriate responses to push. To aid this, servers SHOULD create a PUSH_PROMISE's request by copying the values of the request header fields mentioned in the `Vary` response header field from the request that is identified by the `PUSH_PROMISE` frame's Stream ID.

So, for example, if the first request for a page had the following headers:

~~~
:method: GET
:scheme: https
:authority: www.example.com
:path: /
User-Agent: FooAgent/1.0
Accept-Encoding: gzip, br
Accept-Language: en, fr
Accept: text/html,s application/example, image/*
Cookie: abc=123
~~~

and the server wishes to push these response headers for `/style.css`:

~~~
:status: 200
Content-Type: text/css
Cache-Control: max-age=3600
Content-Encoding: gzip
Vary: Accept-Encoding
~~~

then it should use these headers for the `PUSH_PROMISE`:

~~~
:method: GET
:scheme: https
:authority: www.example.com
:path: /style.css
Accept-Encoding: gzip, br
~~~

This approach has its limits. For example, use of Client Hints might not be practical with server push (since in some circumstances, hints might change between the base page request and the request for what's been pushed).

I'd be tempted to go even further and say that PUSH_PROMISE headers SHOULD NOT contain `DNT`, `User-Agent`, `Cookie` or similar headers UNLESS they were specified in Vary.

What do people think -- is this worth specifying? How are implementations currently doing this?


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


Reply | Threaded
Open this post in threaded view
|

Re: Server Push and Content Negotiation

Patrick McManus
[implementer hat]

On Wed, Aug 24, 2016 at 12:26 AM, Mark Nottingham <[hidden email]> wrote:
What do people think -- is this worth specifying? How are implementations currently doing this?

push is one way - negotiation doesn't make any sense and yet the alternative to negotiation is some kind of sniffing. sniffing is awful and is even harder here where you don't have a request to sniff - you'd have to do some whole connection guess.

how would you push some feature that relies on conneg today - like webp or brotli?

I think as a client realistically you have to wait for the response headers and check them out to see if its an acceptable push. Whatever is in the request headers isn't really enough for that - which is a bit of a change from what I currently do.

fwiw, this was one of the reasons gzip was a mandatory-to-implement CE in spdy and probably should have stayed. It meant you could reliably push it. Doing so now is really just an assumption that gzip is a defacto standard.

Or this all might be another argument about the excessive complexity of push - maybe that should be a document :)