Subject: Proposal for cache control of pushed streams

From: Alek Storm <[email-masked]>
Date: Thu, 7 Jun 2012 14:15:07 -0500

Several others have raised legitimate concerns that the current server push
feature in SPDY may waste bandwidth by pushing resources to clients which
are either unable to accept them or have already stored them in cache.
Although other solutions, such as extending Link headers and framing-level
flags have been hinted at, I believe HTTP cache control is the only system
flexible enough to solve this problem.

This proposal is an outline written in the style of RFC 2616, as I was
unaware of HTTPbis when drafting it - my apologies for any incongruity.
Header descriptions have been condensed down to the interesting parts, and
the material here would likely be spread over multiple parts of the HTTP
spec.

Since the future of SPDY server push itself is uncertain, I would greatly
appreciate any guidance on the next steps to take (if any), if this
proposal meets with the approval of the group. Under what conditions would
opening a ticket on the issue tracker be appropriate?

Alek Storm

*Request Headers*

*Subresources-If-None-Match*

Subresources-If-None-Match = "Subresources-If-None-Match" ":" ( "*" |
1#entity-tag )

For each entity that would have been pushed in response to a similar GET
request (without the Subresources-If-None-Match) on that resource, if:

(1) its entity tag is included in the list of entity tags; or

(a) "*" is given; and
(b) any current entity exists for that resource

then the server MUST NOT push that entity, unless required to do so because
the entity's modification date fails to match that supplied in an
Subresources-If-Modified-Since header field in the request. Instead, if the
request method was GET or HEAD, the server SHOULD push a 304 (Not Modified)
response, including the cache-related header fields (particularly ETag) of
one of the entities that matched.

Comments: Clients should include entity tags for resources which included
the requested URI in their Subresource-Of header when they were last
fetched, or all entity tags from the requested domain for Content-Types
likely to be pushed (application/javascript, text/css). Other heuristics
are possible as well.

*Subresources-If-Modified-Since*

Subresources-If-Modified-Since = "Subresources-If-Modified-Since" ":"
HTTP-date

For each entity that would have been pushed in response to a similar GET
request (without the Subresources-If-Modified-Since) on that resource, if:

(1) the given date is valid; and

(a) the entity has not been modified since the given date; or
(b) the entity was not related to the requested resource at the given date;
or

(i) it is not known whether the entity was related to the requested
resource at the given date; and
(ii) the requested resource has not been modified since the given date

then the server MUST NOT push that entity. Instead, if the request method
was GET or HEAD, the server SHOULD push a 304 (Not Modified) response. If
Subresources-If-Modified-Since is not present, or if the given date is
invalid, the If-Modified-Since date may be used instead, if present.

Comments: Although If-Modified-Since is also a good heuristic (and can be
used if Subresources-If-Modified-Since is missing), clients will not send
it if they were instructed not to cache the original URI the last time it
was fetched, even if the pushed resources were cacheable. Thus, this header
is necessary.

*Analogous Subresources-If-Match and Subresources-If-Unmodified-Since
headers are omitted here for brevity.*

*Additional-Push*
*
*

Additional-Push = "Additional-Push" ":" 1#( absoluteURI | relativeURI )

A list of absolute or relative URIs that the server or any intermediate
caches MAY push in addition to any resources that would otherwise have been
pushed.

Comments: This provides client with a way to hint which subresources they
believe will be called for to braindead servers unaware of inter-resource
relationships. Servers that know what they're doing are free to ignore it.
Although servers are unlikely to be interested in pushing resources from
other domains, intermediate proxies may use this information to save the
client a round-trip.

*Response Headers*

*Subresource-Of*

Subresource-Of = "Subresource-Of" ":" 1#relativeURI

A list of prefixes of request URIs the resource would likely be pushed in
response to. For example, "Subresource-Of: /static/, /foo.html" specifies
that this resource is a subresource of /foo.html and all URIs prefixed with
/static/.

Comments: This is also powerful in the hands of intermediate caches, which
have more information about how different resources are interrelated.

*Cache-control Directives*

Default behavior: The server and any intermediate caches MAY push streams
in response to a request.

no-push (client)

Indicates the both the server and any intermediate caches MUST NOT push any
streams in response to this request.

no-proxy-push (server)

Indicates that any intermediate caches MUST NOT push any streams in
response to this request.

push-if-original-invalidated (client)

Indicates that both the server and any intermediate caches MUST NOT push
any streams in response to this request if the request is successfully
revalidated (i.e. a 304 Not Modified response is sent).

push-if-invalidated (client)

Indicates that both the server and any intermediate caches MUST NOT push
any stream in response to this request if the pushed resource is
successfully revalidated (i.e. a 304 Not Modified would be sent).

push-max-age, push-min-fresh, push-max-stale (client)

Identical to their variants without "push-", but only apply to pushed
streams.

*Server Push Restrictions*

Pushed streams MUST have one of the following response codes: 200, 204,
206, 301, 302, 303, 304, 307.

Servers and intermediate caches MUST NOT push two streams associated with
the same URL, or a stream associated with the URL of the original request,
unless both streams have response code 206 and contain non-overlapping byte
ranges.

Comments: It shouldn't be possible to create a pushed stream associated
with another pushed stream, but this should probably be addressed at the
framing layer.

---

From: Alek Storm <[email-masked]>
Date: Thu, 7 Jun 2012 18:31:46 -0500

A requirement should also be added that entity tags MUST be unique across
resources on the same domain. Thanks to Jonathan Silvera and others at
Microsoft for pointing this out.

Alek

On Thu, Jun 7, 2012 at 2:15 PM, Alek Storm <[email-masked]> wrote:

> Several others have raised legitimate concerns that the current server
> push feature in SPDY may waste bandwidth by pushing resources to clients
> which are either unable to accept them or have already stored them in
> cache. Although other solutions, such as extending Link headers and
> framing-level flags have been hinted at, I believe HTTP cache control is
> the only system flexible enough to solve this problem.
>
> then the server MUST NOT push that entity, unless required to do so
> because the entity's modification date fails to match that supplied in an
> (b) the entity was not related to the requested resource at the given
> date; or
>
> Indicates the both the server and any intermediate caches MUST NOT push
> any streams in response to this request.
>
> no-proxy-push (server)
>