W3C home > Mailing lists > Public > ietf-http-wg@w3.org > July to September 2013

RE: [#153] PUSH_PROMISE headers

From: Mike Bishop <Michael.Bishop@microsoft.com>
Date: Mon, 1 Jul 2013 18:44:30 +0000
To: Roberto Peon <grmocg@gmail.com>, James M Snell <jasnell@gmail.com>
CC: Martin Thomson <martin.thomson@gmail.com>, HTTP Working Group <ietf-http-wg@w3.org>
Message-ID: <b7f7bb824fe34aa9ab92d22716d25b3f@BY2PR03MB025.namprd03.prod.outlook.com>
I had previously read the spec as sending a preview of the response headers, and this still feels more reasonable to me than the server sending request headers to the client, particularly a request the client wouldn't have actually made (If-Match for your GET below).  I'll concede it may be equally unnatural for the server to be sending back the resource URI in response headers, and a double header-block is also unappealing.

There are some wasted bytes if the server sends back the entire request headers, since the headers are supposed to be copied from the initial request and the client already knows what it sent.  Are we presuming that the server is sending back only the headers whose values it wants to override?  (If so, how does the server express that it wants to drop a header, override it to empty?)

Sending request headers does offer a solution to the case where the server includes a Set-Cookie in the response for the initial request and would expect that cookie to be in any subsequent requests as well - it could just inform the client that it used the new cookie in the pushed requests, potentially before the client has even seen that Set-Cookie.

From: Roberto Peon [mailto:grmocg@gmail.com]
Sent: Friday, June 28, 2013 10:54 PM
To: James M Snell
Cc: Martin Thomson; HTTP Working Group
Subject: Re: [#153] PUSH_PROMISE headers

Actually, I think you're right, since the resource is identified by the URL name (unfortunate in some ways). I was thinking that you'd want to indicate both the canonical name for the served resource and the name used to identify the request, but that'd be a bigger change.
-=R

On Fri, Jun 28, 2013 at 10:44 PM, James M Snell <jasnell@gmail.com<mailto:jasnell@gmail.com>> wrote:
I just gave an example that uses content-negotiation so that argument
doesn't really work. The server is crafting the request headers for an
implied GET, so it gets to construct those request headers to be as
specific as it wants them to be, without much need for actual
content-negotiation.

For example, suppose the server receives a request for an HTML page like this...

GET /index.html HTTP/1.1
Accept: text/html, image/jpeg, image/gif

The server decides that it wants to push jpeg files to the client... it sends

PUSH_PROMISE
  :path = /images/f.jpg
  :method = GET
  :host: example.org<http://example.org>
  :if-match: "my-etag1"
  accept: image/jpeg

That's pretty darn unambiguous. I can easily check to see if I have a
representation of "/images/f.jpg" with etag "my-etag1" and
content-type "image/jpeg" in my local cache, without the need to have
*any* response headers in the PUSH_PROMISE.

Perhaps you have another, more specific example in mind?


On Fri, Jun 28, 2013 at 10:36 PM, Roberto Peon <grmocg@gmail.com<mailto:grmocg@gmail.com>> wrote:
> ... because by then you've opened up a stream., and you're back into
> problematic territorry.
> PUSH_PROMISE exists because we need to indicate to the browser all of the
> information it needs to make a determination about whether or not it wants
> the stream (and to short circuit the inlining/push mechanism when it already
> has what it needs!)
> -=R
>
>
> On Fri, Jun 28, 2013 at 10:34 PM, Roberto Peon <grmocg@gmail.com<mailto:grmocg@gmail.com>> wrote:
>>
>> Any content negotiation would be an appropriate example. :)
>>
>> You don't want to have to wait for the HEADERS frame to indicate to the
>> client which resource it might already have (it should have the opportunity
>> to RST_STREAM if it has it in cache, for instance).
>> -=R
>>
>>
>> On Fri, Jun 28, 2013 at 10:25 PM, James M Snell <jasnell@gmail.com<mailto:jasnell@gmail.com>> wrote:
>>>
>>> Have an example handy?
>>>
>>> Here's an example that shows that response headers in the PUSH_PROMISE
>>> would not be necessary... Let's say I send a PUSH_PROMISE with the
>>> following bits of info...
>>>
>>> PUSH_PROMISE
>>>   :path = /images/f.jpg
>>>   :method = GET
>>>   :host = example.org<http://example.org>
>>>   :scheme = http
>>>   accept = image/jpeg
>>>   if-match: "my-etag1"
>>>   cache-control: max-age=1000
>>>
>>> These headers are giving me everything I would need to determine if
>>> there is a matching resource in my local cache. I have the method, I
>>> have the etag, I have the cache-control parameters, accept... There's
>>> no need for response headers at this point.
>>>
>>> Later, once I start accepting the frames for the pushed content, I
>>> would get something like...
>>>
>>> HEADERS
>>>   :status = 200
>>>   content-type: image/jpeg
>>>   content-length: 123
>>>   etag: "my-etag1"
>>>   vary: accept
>>>   cache-control: public
>>>
>>> On the off chance that the PUSH_PROMISE doesn't give me what I need,
>>> the follow on HEADERS frame will give me the rest.
>>>
>>>
>>>
>>> On Fri, Jun 28, 2013 at 9:55 PM, Roberto Peon <grmocg@gmail.com<mailto:grmocg@gmail.com>> wrote:
>>> > Depending on how the request might have been been constructed, response
>>> > headers may be necessary to identify the resource in the cache, as
>>> > compared
>>> > to the resource specified in the HTML (I'm thinking about vary: stuff).
>>> >
>>> > -=R
>>> >
>>> >
>>> > On Fri, Jun 28, 2013 at 9:44 PM, James M Snell <jasnell@gmail.com<mailto:jasnell@gmail.com>>
>>> > wrote:
>>> >>
>>> >> Let's take a step back and consider what a pushed stream is...
>>> >>
>>> >> A pushed stream is essentially an "Implied GET". This means that a
>>> >> server is going to assume that the client was going to send a GET for
>>> >> the pushed resource. This also means that the server has to make some
>>> >> assumptions about the make up of that implied GET.
>>> >>
>>> >> Now, consider how HTTP caching works. When a cache receives a request
>>> >> for a resource, how does it determine whether or not it has a
>>> >> representation of the resource already available? Does it look at the
>>> >> request headers or the response headers? Obviously, it looks at the
>>> >> request headers. It uses the response headers when populating the
>>> >> cache.
>>> >>
>>> >> So, if we look at the pushed resource sent by the server, what we need
>>> >> is for A) the server to first let us know about the implied GET
>>> >> request.. which means pushing down a set of request headers then B)
>>> >> the server to send the actual resource, which means pushing down the
>>> >> response headers.
>>> >>
>>> >> Already in our design for pushed resources, we have the server sending
>>> >> a PUSH_PROMISE frame that contains a header block, followed by a
>>> >> HEADERS frame that also contains a headers block. It stands to reason
>>> >> that the PUSH_PROMISE frame would contain the set of request headers
>>> >> that the server is assuming for the implied GET. These are delivered
>>> >> to the client, which uses those to determine whether or not a cached
>>> >> representation of the resource is already available (just as any cache
>>> >> would do using the request headers). The server would then send it's
>>> >> response headers in a HEADERS frame, just as it would any response to
>>> >> any other kind of GET.
>>> >>
>>> >> Two examples to show how this naturally fits... First, let's look at a
>>> >> normal GET request sent by the client to the server...
>>> >>
>>> >> Client                 Server
>>> >> ------                 ------
>>> >>   |                        |
>>> >>   | ---------------------> |
>>> >>   |   HEADERS              |
>>> >>   |     GET                |
>>> >>   |     /images/f.jpg      |
>>> >>   |     If-Match: etag1    |
>>> >>   |     Accept: image/jpeg |
>>> >>   |                        |
>>> >>   | <--------------------- |
>>> >>   |   HEADERS              |
>>> >>   |     200                |
>>> >>   |     Content-Type:      |
>>> >>   |       image/jpeg       |
>>> >>   |     Content-Length:    |
>>> >>   |       123              |
>>> >>   |                        |
>>> >>   | <--------------------- |
>>> >>   |   DATA....DATA....     |
>>> >>   |                        |
>>> >>
>>> >> Now consider the same resource being pushed by the server using
>>> >> PUSH_PROMISE...
>>> >>
>>> >> Client                 Server
>>> >> ------                 ------
>>> >>   |                        |
>>> >>   | <--------------------- |
>>> >>   |   PUSH_PROMISE         |
>>> >>   |     GET                |
>>> >>   |     /images/f.jpg      |
>>> >>   |     If-Match: etag1    |
>>> >>   |     Accept: image/jpeg |
>>> >>   |                        |
>>> >>   | <--------------------- |
>>> >>   |   HEADERS              |
>>> >>   |     200                |
>>> >>   |     Content-Type:      |
>>> >>   |       image/jpeg       |
>>> >>   |     Content-Length:    |
>>> >>   |       123              |
>>> >>   |                        |
>>> >>   | <--------------------- |
>>> >>   |   DATA....DATA....     |
>>> >>   |                        |
>>> >>
>>> >>
>>> >> Note that the only difference here is the direction and type of the
>>> >> first frame. Everything else is identical. The PUSH_PROMISE contains
>>> >> everything the client needs to determine whether or not it already has
>>> >> the resource in it's local cache (request URI, etag, content-type...).
>>> >>
>>> >> There's no need to get any more complicated than this. We already
>>> >> require two distinct header blocks for every request. We already send
>>> >> two distinct header blocks for each pushed stream. We already indicate
>>> >> that a pushed stream is an implied GET. To make it work, we simply
>>> >> state that the PUSH_PROMISE contains the Request headers that the
>>> >> server has assumed for the implied GET request, while the HEADERS
>>> >> frame sent later contains the Response headers. If the request headers
>>> >> in the PUSH_PROMISE end up not being adequate enough to properly
>>> >> determine if the resource is already cached, then we treat it as just
>>> >> another cache miss.
>>> >>
>>> >> On Fri, Jun 28, 2013 at 5:21 PM, Martin Thomson
>>> >> <martin.thomson@gmail.com<mailto:martin.thomson@gmail.com>> wrote:
>>> >> > https://github.com/http2/http2-spec/issues/153
>>> >> >
>>> >> > The current text describes PUSH_PROMISE as having a few request
>>> >> > headers, plus some response headers, but it's quite vague.
>>> >> >
>>> >> > I think that if this is going to be properly workable across a wide
>>> >> > range of uses with lots of different headers, PUSH_PROMISE needs to
>>> >> > include two sets of headers: the ones that it overrides from the
>>> >> > associated request (:path being foremost of those) and the ones that
>>> >> > it provides as a "preview" of the response (e.g., ETag might allow
>>> >> > caches to determine if they were interested in the rest of the
>>> >> > response).
>>> >> >
>>> >>
>>> >
>>
>>
>
Received on Monday, 1 July 2013 18:47:20 UTC

This archive was generated by hypermail 2.4.0 : Friday, 17 January 2020 17:14:14 UTC