Network Working Group | A. Silvas |
Internet-Draft | GoDaddy |
Intended status: Experimental | June 26, 2016 |
Expires: December 28, 2016 |
Push-Assets Header Field
draft-asilvas-http-push-assets-00
Push-Assets is a header field that provides the necessary client state in order for servers to utilize HTTP/2 Server Push with confidence in knowing what resources SHOULD or SHOULD NOT be sent, reducing waste, and ultimately providing an improved user experience. This document will provide an overview of Push-Assets requirements, and describes any implementation concerns.
This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.
Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at http://datatracker.ietf.org/drafts/current/.
Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."
This Internet-Draft will expire on December 28, 2016.
Copyright (c) 2016 IETF Trust and the persons identified as the document authors. All rights reserved.
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Simplified BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Simplified BSD License.
As described in [HighPerformance], transfer sizes and resource counts continue to increase. While network conditions continue to improve, resulting in lower latencies and increased bandwidth, HTTP/1.1 ([RFC7230] and [RFC7231]) fails to address the underlying problem of resource dependencies and the resulting "waterfall" of blocked requests.
HTTP/2 [RFC7540] aims to address some of these problems, by way of Streams and Multiplexing, combined with HTTP/2 Server Push [RFC7540]. A ruthless combination, addressing "head-of-line blocking" through Multiplexing, and optimistic pre-loading by way of Server Push.
Where Server Push begins to fall short is around client state, leaving it up to servers to leverage existing HTTP State Management Mechanism [RFC6265] with Cookies, which are not purpose built to solve the problem of resource dependency state. This lack of client state can result in HTTP/2 [RFC7540] RST_STREAM, where-in in-flight Server Push Streams will be cancelled, incurring client and server waste.
This document aims to address resource dependency state by looking to Caching [RFC7234] familiar with existing HTTP/1.1 requests (see [RFC7230] and [RFC7231]). By pulling this state data into the request, servers are able to intelligently and responsibly Server Push only missing or outdated resource.
In this document, the key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” are to be interpreted as described in BCP 14, RFC 2119 [RFC2119] and indicate requirement levels for compliant implementations.
This document uses the Augmented BNF defined in [RFC5234].
Here we can begin to see the problem with vanilla HTTP/2 [RFC7540] Server Push without client state management.
+----------------------------+-------------------------+ | Client | Server | +----------------------------+-------------------------+ | [ TCP+TLS+HTTP/2 Negotiation ] | | | | | GET /A.html =======> | | | <======= | PUSH_PROMISE GET /A1.js | | <======= | PUSH_PROMISE GET /AB.js | | <======= | GET /A.html | | <======= | GET /A1.js | | <======= | GET /AB.js | | [Page Complete] | | | | | | [Navigate to "/B"] | | | | | | GET /B.html =======> | | | <======= | PUSH_PROMISE GET /B1.js | | <======= | PUSH_PROMISE GET /AB.js | (Server doesn't know Client has this) | <======= | GET /B.html | | <======= | GET /B1.js | | RST_STREAM /AB.js =======> | (Hault transfer) | | <======= | GET /AB.js | (Cancelled pre-flight, may be fully | | | transferred before RST_STREAM | [Page Complete] | | received) +----------------------------+-------------------------+
While in some situations cookie-based management will address the above, ultimately it'll vary depending on the complexity of the origin, including but not limited to the number of assets and the frequency of change.
Figure 1
With Push-Assets enabled both client and server adhere to a strict dependency state contract.
+----------------------------+-------------------------+ | Client | Server | +----------------------------+-------------------------+ | [ TCP+TLS+HTTP/2 Negotiation ] | | | | | GET /A.html =======> | | | <======= | PUSH_PROMISE GET /A1.js | | <======= | PUSH_PROMISE GET /AB.js | | <======= | GET /A.html | | <======= | GET /A1.js | | <======= | GET /AB.js | | [Page Complete] | | | | | | [Navigate to "/B"] | | | | | | GET /B.html =======> | | | <======= | PUSH_PROMISE GET /B1.js | | <======= | GET /B.html | | <======= | GET /B1.js | | [Page Complete] | | +----------------------------+-------------------------+
Avoiding needless waste, the benefits of Push-Assets far outweighs the additional header data needed to track client state.
Figure 2
Often the most import visit to a site is the first. Push-Assets provides the necessary client state for the server to confidently know which resources are missing or outdated.
As users navigate to previously visited resources, or new resources where some shared resources have been cached, Push-Assets provides the necessary client state to make efficient use of Server Push, only sending what resources the client does not already have.
On one end of the spectrum of proxies lies your server proxies, with CDN's on the other end.
[Client] <==[CDN]<=======================[Proxy]<==[Origin]
Figure 3
With Push-Assets providing efficient communication between two points, this may lend to potential benefits between Proxies and their Origin server as well. While the Proxy nearest your Client SHOULD support Push-Assets for best results, it MAY elect not to also leverage Push-Assets between the Proxy and Origin.
For proxies with caching nearest to Client (namely CDN's), they may further benefit from Push-Assets by way of efficient use of Server Push.
By enabling Push-Assets between any two points, Server Push can be used to reduce waste and provide improved performance. The greater the shared resources, the greater the potential benefits.
With Push-Assets being nothing more than an HTTP Header, extending the benefits to other Content Type's [RFC2045] is entirely up to the Client and Server. Consider circumstances where you retrieve a JSON resource, which signals relationships with other resources. Push-Assets reduces waste and enables better user experiences irrespective of Content-Type.
Push-Assets = [*][Asset-Key=Caching-Headers][;Asset-Key=Caching-Headers]
A request header field SHALL be sent by the client when requesting the server to support Push-Assets.
Comprised of zero or more resources addressed by their Asset-Key.
An Asset-Key is the name of the resource uniquely identifiable by the resource or matching resources.
Push-Assets = Asset-Key=[etag(etag-value),][last-modified(date)][no-push]
Caching MAY include an etag, and/or last-modified, or no-push. This provides necessary client state of dependencies to server.
Push-Assets = *
Where * informs server to Server Push all push-enabled dependencies, if Push-Assets is enabled. Servers MUST push all missing or outdated push-enabled resources.
Push-Asset-Key = Asset-Key
A PUSH_PROMISE response Header field MAY be sent to inform the client that the resource should be tracked as a Push-Asset.
The Asset-Key MUST be stored in the header field as an MD5 representation of the desired Key.
Unlike the Asset-Key in a request, the Push-Asset-Key header field corresponds to the Key of the PUSH_PROMISE response.
Push-Asset-Key = core-bundle.js
By naming a resource, you MAY share that resource across multiple resources, and MAY change the URI [RFC3986] as necessary without resulting in wasted requests.
Push-Asset-Key = $
Where $ is reserved as a short-hand for the client to recognize the key as the URI Path [RFC3986], and MUST NOT include the query string.
Example URI Path [RFC3986] of /my/resource?some=thing would by keyed as /my/resource.
If there are more than one cached resources on the client for a given Push-Asset-Key, the client MUST treat the most recent Key as the current version.
Push-Asset-Match = Asset-Path[;Asset-Path]
An OPTIONAL PUSH_PROMISE response header field.
An Asset-Match supports the lexical matching of the URI Path [RFC3986], and MAY end with reserved wildcard * to indicate matching all requests "equal or greater than" the URI Path. While one or more Asset-Path's may be provided, they SHOULD be consistent between requests to avoid any caching proxies from serving varying responses. Usage of Vary header field (Section 7.1.4 of [RFC3986]) MAY be applied with Push-Asset-Match to permit varying responses, but SHOULD NOT be used in most scenarios to avoid unnecessary complexity.
Push-Asset-Match = /some-path/*
Where all requests with URI Path [RFC3986] greater than or equal to /some-path/ will be matched.
Push-Asset-Match = *
* is reserved to indicate "match all requests". This is the equivalent of /*, matching all from root.
State management can be simple for simple origins, but complex for complex origins. Following is a set of usage scenarios and suggested tactics to combat unnecessary waste.
Not uncommon amongst websites are changes to the URI Path [RFC3986] of a resource when contents change. For these assets, utilizing the default Push-Asset-Key of $ MAY result in excessive waste by way of the client sending state of matching resources that are no longer applicable.
An effective measure is to leverage a uniquely named Push-Asset-Key, enabling the client and server to understand that the resource has effectively been renamed.
Leveraging the power of the Push-Asset-Match header field MAY greatly improve the efficiency of resources shared amongst many resources. If used excessively where-in many requests do not depend on the matched resource MAY lead to waste, as the state of matching resources are sent via Push-Assets header field.
The server MAY improve effectiveness by way of highly specific Push-Asset-Match definitions, breaking an origin into multiple sub-paths to permit parts an Origin to operate without negative affect from other parts of Origin. For example, /some-path/ does NOT need to use the same shared resources as /some-other-path/, as they MAY NOT know about one another.
In cases where even with highly specific Push-Asset-Match do not address excessive matching, the client MAY track historical false positives where-in matching resources are not served from requested resources, and MAY determine a threshold from which the client MAY elect NOT to send alongside Push-Assets requests.
With Push-Assets not being specific to html resources, clients MUST NOT match resources across requests with varying Content Type's [RFC2045].
If a server has enabled Push-Assets for more than one Content Type, the client MUST only notify the server of matching resources that were from the same Content Type of the parent resource.
As an example, "/home.html" with a dependent resource that matches all URI Paths, MUST NOT be sent via Push-Assets when making a request for "/file.js" as the parent resources differ in Content Type.
[HighPerformance] | Grigorik, I., "High Performance Browser Networking", September 2013. |
[RFC2045] | Freed, N. and N. Borenstein, "Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies", RFC 2045, DOI 10.17487/RFC2045, November 1996. |
[RFC6265] | Barth, A., "HTTP State Management Mechanism", RFC 6265, DOI 10.17487/RFC6265, April 2011. |