Subject: Re: Restarting the discussion on HTTP/2 stream priorities

From: [email-masked]
Date: Sun, 3 Nov 2013 07:37:46 -0800

Going through your example, would the prioritization at any instant be any different if you simply assigned two priorities -- high for resources that are blocking (the .js and the .css in your example) and low for resources that are non-blocking (the .jpgs)? 

Sorry if I'm missing something but it doesn't seem like it to me.

Peter

On Oct 28, 2013, at 3:45 PM, William Chan (陈智昌) <[email-masked]> wrote:

> On Mon, Oct 28, 2013 at 3:34 PM, Martin Thomson <[email-masked]> wrote:
> On 28 October 2013 14:32, William Chan (陈智昌) <[email-masked]> wrote:
> > I think that the second point is far more controversial and requires more
> > discussion.
> 
> It may be the case that you find the first issue compelling enough
> that a change of some form is justified regardless of what you think
> on the second :)
> 
> Of course, I think that there are some significant problems with the
> proposal, most of which I think that you will find are easy to fix.
> 
> The first is largely procedural.  I've have people complain about the
> use of references to documents like the above for archival and IPR
> reasons.  Maybe copying and pasting the entirety of that document to
> an email will address those concerns.  Maybe it will also help you
> understand that it is a little wordy and that perhaps the essence of
> your proposal could be made more succinctly :)
> 
> I have to confess that I heard complaints but never understood the reasoning behind them. If it's archival/IPR, I'm perfectly happy to copy/paste the document into email. These concerns aren't obvious to me as I'm a relative newb to IETF stuff.
> 
> As far as the proposal's wordiness, I mostly view it as a straw man to ignite discussion. I'm completely expecting that it will be ripped apart :) I'm hoping to rely heavily on editors to make it much more succinct once we reach some rough consensus. Or perhaps this was a subtle play on your part to get me to do better editorial work before sending it to the group :)
> 
> I'll give others a chance to discuss other points first. I don't want to yell more loudly than others anymore than I already do.
>  
> 
> The second is that the idea of prioritization between separate trees
> isn't really described as being prioritization.  I think that what you
> want to do is a proportional allocation of resources between those
> trees, so a term like "weight" is probably more accurate.  You even
> use that word later.  (Oh crap, I just realized that this is a classic
> case of "the names aren't important, the standards committee always
> changes them anyway" scenario, sorry.)
> 
> Probably more substantially, you need to be a little more concrete
> when it comes to requirements for managing placeholders and garbage
> collection.
> 
> The settings seem like over-engineering to me.  I'm sure that a server
> implementation can arrive at a reasonable set of behaviours that
> doesn't degrade too badly for their common workloads without settings
> being exchanged.  When it comes to resource exhaustion, I think that
> it's probably more appropriate to deal with those in the DoS
> considerations than with settings.
> 
> On the over-engineering theme, the idea that you can reprioritize
> multiple streams with a single PRIORITY frame concerns me.  That's
> going to mess with intermediaries of all sorts.  The cost of a
> PRIORITY frame for each stream is 4 bytes per stream, but then you
> weren't going to bother with that anyway.
> 
> Please consider placing default values on priority.  Since you are
> only going to be able to provide either a dependency or a weight, the
> complementary item is going to inherit a default.
> 
> I'm copy/pasting the doc here:
> Proposal for Stream Dependencies in SPDY
> Draft 1
> Last Updated: 26 October 2012
> 
> This document proposes changes to the SPDY protocol to support stream dependencies. During a pageload, the server uses dependencies to improve performance by allocating bandwidth capacity to the most important resource transfers first.
> 
> The remainder of this document describes the motivation for dependencies, protocol changes to support them, and examples of how those mechanisms can be used by the browser. We conclude with a discussion of the client and server policies afforded by expressing dependency information in SPDY.
> 
> (Note that flow control is the subject of a separate document and is out of scope here.)
> Motivation
> In SPDY today, each stream has a priority (0–7) chosen by the client upon stream creation. Push streams are 
> an exception. The server policy today is to assume push streams are all low priority. Push or pull, the priority of a stream cannot be changed once created. 
> 
> Priorities provide hints to the server about which streams are most important to the client, but they are poorly suited to several common use-cases.
> 
> Specifying an ordering of resource transfers
> 
> Sharing bandwidth between resource transfers may degrade performance as measured by page-load time, e.g., when transferring two Javascript resources that cannot be executed until transfer is complete, or two video chunks that will be played back-to-back. In these circumstances, the browser may wish to specify an ordering --- HTML before script1.js before script2.js before image.png, for example, or video_chunk1 before video_chunk2 and so on. (Moreover, changing the priority of the HTML transfer itself may benefit performance; e.g., a large blocking script will be interpreted and executed more quickly if it does not compete for bandwidth capacity with a large HTML transfer.)
> 
> 
> With a small number of fixed priorities, the browser is simply unable to express an ordering over many resource transfers, and with a large number of priorities, reordering is costly.
> Reacting to document parsing
> 
> Because the browser's document parser blocks while waiting for script and style resource transfers to complete, many resource requests will be speculative. (For more background, see Tony Gentilcore's excellent summary of Chrome's implementation of speculative parsing, the preload scanner.) These requests may need to be preempted as the document parser learns of higher priority resources. For example, if a script a.js uses document.write to embed another script, b.js, the transfer of b.js should preempt other in-flight resource transfers, as the receipt of b.js blocks page layout. As another example, consider images styled with display: none; once such styling is discovered during parsing, associated image transfers should be deferred to prioritize visible content.
> 
> Reacting to user behavior
> Suppose a SPDY proxy is servicing multiple users. In this case, many tabs (and their associated streams) are multiplexed over the same SPDY connection. Fixed priorities (i.e., unchanging over the lifetime of a stream) preclude reacting to user behavior; e.g., a user may switch among concurrently loading tabs.
> 
> Server push
> No single fixed priority is appropriate for server push. A stream pushing a large image, for example, should have lower priority than JS/CSS. But, when pushing JS/CSS that the browser needs, those stream should have high priority.
> 
> In sum, for many common scenarios, fixed priorities are not sufficient to optimize the allocation of bandwidth among competing requests.
> 
> Protocol changes
> To address the limitations of priorities, we propose expressing dependencies among streams. Dependencies improve matters in two main ways:
> 
> Dependencies more accurately reflect the constraints of the browser.
> 
> Rendering a page is a streaming process that naturally leads to a series of dependencies among resource transfers. For example, a script may block HTML parsing, and a final layout may depend on an external stylesheet.
> 
> Dependencies can be updated efficiently.
> The relative importance of streams may change as Javascript executes or a user changes tabs, for example. Dependencies allow the browser to express these changes compactly. If a user changes tabs, for example, the browser may simply signal a change in priority of the tab's dependency root, thereby reducing (or increasing) the bandwidth allocated to all dependent transfers.
> 
> Dependencies are expressed in two ways: 1) a new dependency field in the SYN_STREAM message, and 2) a new REPRI message that updates the dependency pointers of existing streams. To allow servers to advertise their support for scheduling transfers based on dependencies, we propose a new SETTINGS id/value pair. We describe the layout and semantics of each in turn. 
> 
> Note that these protocol changes are defined in terms of the latest version of the SPDY draft specification.
> 
> SYN_STREAM:
>     0        1        2        3         4        5        6        7
> +--------+--------+--------+-|-------+--------+--------+--------+--------+
> | Length(16)      |Flags(8)|1| Stream Id(31)                    |    0x1 | ->
> +--------+--------+--------+-|-------+--------+--------+--------+--------+
> 
>     8        9        10        11     12,13,14..N     
> +-+-------+--------+--------+--------+=========================+
> |P| PriOrDep(31)                     | Name/Value Header Block |
> +-+-------+--------+--------+--------+=========================+
> 
> Here, the first 8 bytes are the standard control frame header (§2.2.2). A new 32 bit field replaces the existing SYN_STREAM priority bits (§2.6.1) with:
> 
> P: A bit indicating whether the following PriOrDep bits specify a priority (P = 1) or a stream ID (P = 0) on which this new stream depends.
> PriOrDep: Depending on the value of P, either the priority of the new stream or a stream ID on which this new stream depends.
> The structure and semantics of the Name/Value header block (§2.6.11) are unchanged.
> 
> P is exclusive; a stream may be assigned a priority or a parent dependency upon creation, but not both. There are no constraints of the value of PriOrDep; any 31 bit value is valid. Thus, a stream may refer to a dependency identifier that does not correspond to any current or previous stream ID. This is a deliberate design choice that increases flexibility for clients when structuring dependencies, a topic we expand upon in the policies section.
> 
> Server push streams are assigned an initial parent at the discretion of the server. A conformant implementation SHOULD create a dependency on the push stream's associated-to-stream-id (§3.3.1).
> 
> REPRI:
>     0        1        2        3         4        5        6        7
> +--------+--------+--------+-|-------+--------+--------+--------+--------+
> | Length(16)      |Flags(8)|1| Dependency Id(31)                |    0xc | ->
> +--------+--------+--------+-|-------+--------+--------+--------+--------+
> 
>     8        9        10        11   
> +-+-------+--------+--------+--------+
> |P| PriOrDep(31)                     | optionally followed by:
> +-+-------+--------+--------+--------+
> 
> DependencyPriOrDep pairs, where a DependencyPriOrDep pair is:
> 
> +-|-------+--------+--------+--------+-|-------+--------+--------+--------+
> |X| Dependency Id (31)               |P| PriOrDep(31)                     |
> +-|-------+--------+--------+--------+-|-------+--------+--------+--------+
> 
> As in SYN_STREAM, the control frame header is standard, followed by a P/PriOrDep label indicating an update to the 31 bit Dependency Id specified in the header. We relabel the typical Stream Id here as Dependency Id since a dependency need not correspond to an actual stream. (Recall that any 31 bit value is a valid dependency identifier.)
> 
> To support batched updates of dependencies, an optional list of DependencyPriOrDep pairs with identical semantics may follow. The number of such pairs is determined by examining the frame length.
> number-of-pairs = ((length - 12) / 8). (12 required bytes, 8 bytes from len(stream_id) + len(PriOrDep))
> 
> We expect most streams to have at most a single dependency, but this is not a protocol requirement. (Later, we describe scenarios where multiple parents may improve efficiency.) If a stream is referenced more than once in a single frame, this indicates multiple parents. A server implementation which does not support multiple parents MUST use the last referenced parent. Clients which send multiple parents thus SHOULD put the most important parent last.
> 
> SETTINGS:
> Recall that dependencies and priorities are advisory. While servers must accept the messages, they are not required to incorporate them into scheduling decisions. A client may benefit from knowing a server's level of support; e.g., a client may specify priorities only if it knows a server will ignore dependencies. To communicate this, we propose a new SETTINGS ID/value pair (§2.6.4),
> 
> ID 9 - SETTINGS_MAX_CONCURRENT_DEPENDENCY_SCHEDULING_NODES allows the server to indicate resource limits for dependency scheduling, e.g., to limit memory consumption. A value of 0 indicates that the server does not support dependency scheduling. (We expect most implementations will select a value greater than or equal to MAX_CONCURRENT_STREAMS.)
> 
> ID 10 - SETTINGS_DEPENDENCY_SCHEDULING_NODE_TIMEOUT indicates how long the server will maintain dependency nodes after creation. The value is an interval in milliseconds. This allows the client to estimate if previously created dependency relationships are still available for reference at the server. (We expect conformant implementations to maintain dependencies for at least as long as associated streams are active, although this is not a correctness requirement.)
> 
> Both of these values are advisory. Servers need not abide by their stated values and clients may disregard them. Conformant clients should respect the concurrency limit, but servers must be robust to a client that exceeds it. Similarly, servers may drop dependency information at any time regardless of previous statements made in SETTINGS. This is intended to provide flexibility for service policies; e.g., a server may reduce the timeout in response to memory pressure or abandon dependency scheduling entirely.
> 
> Examples / use-cases revisited
> The combination of dependencies and priorities suffices to express serialized as well as concurrent transfer schedules. (Both are necessary, as we describe below.) But, how should the browser choose dependencies and priorities when making requests? This question is best answered quantitatively, but as a starting point, we consider the following policy in our examples:
> 
> Resource dependencies are (re)configured to reflect parser-blocking order. The transfer of non-streaming resources is always serialized; i.e., non-async scripts and styling.
> Resources that can be progressively rendered (e.g., images) are transferred concurrently and (re)configured to depend on parser-blocking resource transfers.
> To ensure that the speculative parser can maintain enough in-flight requests to fill pipe between the client and server, page HTML is always a top-level dependency, although it may have lower priority than a resource transfer currently blocking document parsing.
> 
> When scheduling transfers, we consider a server that allocates bandwidth hierarchically within dependency trees and splits equally among streams with the same parent.
> 
> Concretely, suppose a SPDY connection is multiplexing multiple tabs from a user connected to a SPDY proxy, with parent pointers and priorities as shown below. (P6, for example, indicates a priority of 6.)
> 
> To color in this example, suppose that Tab 1 is the foreground tab, loading in parallel with Tab 2 in the background. Thus, its relatively higher weight. a.js and b.js are scripts required for the first tab and should be transferred serially (as scripts are executed in the order they are declared in the document, and are not parsed until transfer completes.) Thus, a.js depends on b.js depends on tab1.htm. In the background tab, two image transfers share capacity as both can be rendered progressively. Both image transfers have the same parent and hence transfer concurrently.
> 
> Because the streams associated with the transfers of tab1 and tab2 have no parent, they are always scheduled before any lower level in their trees. But, bandwidth allocation among trees remains proportional as defined by the relative priority of roots. For example, if the transfer of tab2.htm is in progress and tab1.htm (now complete) is selected, a.js will be scheduled before tab2.htm completes. This process proceeds until all transfers in a tree have completed.
> 
> As a practical matter, the timeout for pruning nodes in a tree should be selected to allow transfers to complete and to allow clients to name currently completed parents when defining transfer dependencies. Concretely, on a high delay path, a small HTML transfer may be flushed entirely by the server before the client receives any data and begins making dependent requests for resources embedded in the page.
> 
> With these client and server policies in mind, we revisit the motivating use-cases described above in greater detail.
> 
> - Specifying an ordering of resource transfers 
> 
> - Reacting to document parsing
> 
> 
> We illustrate the need for both serial dependencies, concurrency, and reprioritization in these cases with a simple example. 
> 
> Suppose site.com has index.htm:
> <html>
> 
> <body>
> 
> <script src="a.js"></script>
> 
> <img src="a.jpg" width="100" height="100"/>
> 
> <img src="b.jpg" width="100" height="100"/>
> 
> <link rel="stylesheet" type="text/css" href="style.css">
> 
> </body>
> 
> 
> with a.js:
> document.write('<script src="b.js"></script>');
> 
> b.js:
> document.write('<div>blocker</div>');
> 
> and style.css:
> div {
>   border: 1px solid #000;
> 
> }
> 
> How would this example page be transferred today? As the main HTML is received and parsed, a request for a.js will be issued and block the document parser. As the remaining HTML streams in, the speculative parser will issue requests for a.jpg, b.jpg, and style.css in quick succession. Once a.js is received and executed, a request for b.js will be issued, which again blocks parsing until received. Visually:
> 
> 
> This transfer schedule is suboptimal. Page rendering will complete only when style.css and b.js have completed, but receiving each of those critical resources is slowed by competition for bandwidth capacity with bulk data that's not on the critical path (a.jpg and b.jpg).
> 
> What we would like is serialized transfer that reflects the document parse order with concurrency for nonblocking, streaming resources. More specifically, we want to receive: 1) index.html, 2) a.js, 3) b.js, and 4) style.css serialized (i.e., with no deliberate sharing of capacity among the ordered transfers). After those critical transfers have completed, a.jpg and b.jpg should be transferred concurrently (as they may be displayed progressively.)
> 
> Folding in the protocol mechanisms described above:
> 
> 
> In the figure, each resource request corresponds to a new SPDY stream with the form ID: reqest (PriOrDep). In more detail:
> 
> The SYN_STREAM for the index.htm request has a parent indicating a default priority (3) and a stream id of 1.
> 
> The document parser is blocked once the external script a.js is parsed. At this point, the speculative  parser looks ahead and creates new streams for a.jpg, b.jpg in parse order. a.jpg and b.jpg can be progressively rendered, so their transfer is concurrent (same parent, 2, corresponding to a.js). 
> 
> When the parser encounters style.css, back-to-back control messages are sent to create the stream and update the dependencies of the image transfers. Since stylesheets block rendering and cannot be streamed, the image transfers are updated to depend on style.css (P5).
> 
> Once a.js completes, the document parser continues, executing a.js and inserting b.js via document.write(), again blocking document parsing on the receipt of b.js. At this point, b.js should preempt all other transfers since it's a non-streaming resource that is blocking page rendering. To this end, the client creates the b.js stream with a.js as its parent (or, equivalently, index.htm). Batched with this SYN_STREAM is another REPRI message rewiring style.css to depend on b.js. This serializes the transfers (modulo the delay associated with message propagation and any transfer buffering delay at the server).
> 
> This transfer schedule may significantly improve performance. By serializing the transfer of resources on the critical path, the browser can ensure that resources needed immediately do not compete for bandwidth capacity with less important transfers. Yet, the pipe remains full, as a queue of requests is maintained in the scheduling tree ready to fill any idle capacity with useful data. Where we cannot make an informed scheduling decision, we hedge our bets with concurrent transfers by hinting that they are peers and letting the server decide what makes the most sense --- as in the case of two above the fold images that can be rendered progressively.
> 
> Note that this sort of explicit scheduler hinting is not possible in HTTP today. Requests, once issued, cannot be reprioritized or reordered on a single connection. This results in suboptimal transfer schedules given the limitations of HTML lookahead scanning. Yet, lookahead is essential for ensuring the concurrency necessary to keep the client <-> server pipe full. While the browser might serialize transfers itself, the many small transfers typical of pageloads would significantly limit utilization. With ordering and reprioritization in SPDY, browsers can jointly optimize both the transfer pipeline and resource priority as desired, rather than being forced to accept poor utilization or poor transfer schedules.
> 
> - Servicing multiple tabs/users over a single SPDY session
> 
> As an illustration of this case, recall the example from our straw-man design:
> 
> 
> Suppose concurrent tabs are loading with a scheduling forest as shown. When a user changes tabs, the browser simple sends a REPRI for the stream associated with tab2.htm to, say, priority 8. (A batched message might also reduce the priority of tab1.htm to weight 3.) Because bandwidth allocation decisions are made tree-by-tree and level-by-level, increasing the priority of tab2.htm effectively shifts capacity for all resource transfers depending on tab1.htm to tab2.htm.
> 
> - Server push
> As in client SYN_STREAM messages, server push messages indicate the priority and dependencies of a resource as chosen by the server. Much like the client, the server is free to adopt prioritization policies to improve performance, e.g., by prioritizing pushes of styles over images. But, as in our example above, the browser may update the server's choices as information about resources needed for parsing is learned. (Again, expressed via REPRI messages.)
> 
> Policy considerations
> Both priorities and stream dependencies are advisory hints. Browsers may adopt sophisticated policies or leave dependencies entirely unspecified. Similarly, servers may incorporate dependency hints into very sophisticated schedulers or ignore them entirely. The protocol mechanisms for encoding dependencies are designed to be simple. But, these mechanisms afford a very flexible set of policies depending on how browsers and servers use them. This section expands on several policy considerations.
> 
> Assigning and updating dependencies.
> 
> Updates and overhead
> 
> In our examples, we consider a browser that configures dependencies to reflect parser-blocking order for resources, updated as parsing continues. We expect this to improve performance, but browsers are free to deviate from this policy, and there may be good reasons to do so. For example, if the parser-blocking order is highly dynamic (e.g., in response to many JS events), the overhead of updating dependencies may not be worth the cost, particularly for small transfers. A sophisticated client may base dependency update decisions on content-length and/or RTT, restricting updates to only those streams likely to benefit from it. Quantitative implementation experience will be helpful here.
> 
> 
> The overhead of updating dependencies depends in part on the existing structure of dependencies. In some scenarios, it may be more efficient to introduce placeholder nodes to improve the efficiency of common update operations. For example, consider a variant of our earlier example page:
> 
> 
> <html>
> 
> <body>
> 
> <script src="a.js"></script> <!-- containing: document.write('<script src="b.js"></script>'); -->
> 
> <img src="1.jpg" width="100" height="100"/>
> 
> <img src="2.jpg" width="100" height="100"/>
> 
> <img src="3.jpg" width="100" height="100"/>
> 
> ...
> 
> <img src="10.jpg" width="100" height="100"/>
> 
> </body>
> 
> 
> In this example, the speculative parser might create 10 streams depending on the JS transfer; i.e.,
> 
> But, once a.js is executed, the transfer of b.js should preempt all image transfers; i.e.,
> 
> Transitioning between these dependency structures requires sending REPRI messages for each image. Because updating the dependencies of images is common, a client might create all image streams with a placeholder dependency, yielding an initial configuration of:
> With such an initial configuration, updating the dependencies of the images to the stream associated with b.js can be accomplished with a single REPRI message updating the placeholder.
> 
> Multiple parents
> 
> All of our examples have considered nodes with a single parent. But, single parent trees cannot express some transfer schedules. For example, an asynchronous script at the end of HTML is non-blocking and does not block interaction or pageload. It should be loaded after all visible resources (e.g., images) have completed. A possible dependency graph is:
> 
> 
> 
> Here, any of img1, img2, or img3 should be prioritized before the asynchronous script, a schedule that cannot be expressed with single parent pointers.
> 
> 
> Reacting to server capabilities
> Clients should not specify dependencies to servers that do not support it (as indicated by SETTINGS_MAX_CONCURRENT_DEPENDENCY_SCHEDULING_NODES in the SETTINGS frame). Rather, an intelligent client may fall back to specifying priorities only, thereby improving performance relative to specifying dependencies that will be ignored.
> 
> 
> Server scheduling.
> 
> A conformant server should respect the semantics of priorities and dependencies in its scheduling policy. Priorities indicate a preference for weighted scheduling (e.g., using a lottery scheduler) among root nodes (i.e., those created with a priority and not a parent). Interior nodes with identical parents are weighted equally.
> 
> 
> Server scheduling should reflect guidance from dependencies, but it need need not be strict. If all streams in a dependency tree have data available to write at the server, writes should be serviced first for root nodes, then children, then grandchildren, and so on. But, children that are ready to write should not starve to enforce a scheduling dependency. In other words, scheduling dependencies should not lead servers to waste capacity. If data is not available to continue writing the root, for example, a child ready to write should do so.
> 
> 
> Finally, we point out that servers may improve performance even if clients do not provide dependency information or priorities. For example, an intelligent server may inspect the content type of resources to make informed prioritization decisions on its own without client guidance. (However, respecting client-provided hints when available is likely to improve performance, as clients have detailed knowledge of parser dependencies.)
> 
> Garbage collecting dependency information.
> 
> SPDY implementations must take care to protect themselves from the use of dependencies as a DoS vector. The protocol provides wide flexibility in this regard; servers are free to drop dependency or priority data at any time without sacrificing correctness.
> 
> 
> Otherwise, we envision servers choosing a timeout value for dependency nodes that is large enough to cover the likely time period during which a client may reference a node; e.g., page load time + rtt. Alternatively, a large fixed number of dependencies may be maintained per-session with LRU eviction. Either of these policies is likely to sharply limit the number of missed dependency references. On the client side, browsers should take care to manage dependencies according to server policies, e.g., by creating new dependency structures rather than referring to those that have likely timed out and been garbage collected.
> 
> While missed references may be rare, they are unavoidable in an asynchronous system with timeouts. (This is why we require that servers accept as correct any dependency id.) In cases where a reference is made to an unknown node at the server, the server may create the referenced id as a new root for future reference or ignore the dependency entirely (i.e., treat the new stream as a root). 
> 
> 
>

---

From: [email-masked]
Date: Sun, 3 Nov 2013 07:58:09 -0800

From section 8.2.1...

   The server SHOULD send PUSH_PROMISE (Section 6.6) frames prior to
   sending any frames that reference the promised resources.  This
   avoids a race where clients issue requests for resources prior to
   receiving any PUSH_PROMISE frames.

   For example, if the server receives a request for a document
   containing embedded links to multiple image files, and the server
   chooses to push those additional images to the client, sending push
   promises before the DATA frames that contain the image links ensure
   that the client is able to see the promises before discovering the
   resources.  Similarly, if the server pushes resources referenced by
   the header block (for instance, in Link header fields), sending the
   push promises before sending the header block ensures that clients do
   not request those resources.

I know from experience implementing a prefetching proxy, requiring push_promise frames prior to sending frames that reference the promised resources is simpler (you don't have to deal with the race) but it introduces delays. The ideal prefetching proxy does whatever work it needs to identify resources to promise asynchronously so that browser requested data never waits but this means that push_promise frames will often be sent AFTER the frames that reference the promised resources.

It's a performance versus simplicity tradeoff that this list may have discussed in the past but I can't find the thread if so.

Thanks,

Peter

---

From: Martin Thomson <[email-masked]>
Date: Sun, 3 Nov 2013 08:54:39 -0800

The intent would be to use ordering (i.e. dependencies) for this scenario,
not "priorities" (aka weights).

On 3 November 2013 07:37, <[email-masked]> wrote:

> Going through your example, would the prioritization at any instant be any
> different if you simply assigned two priorities -- high for resources that
> are blocking (the .js and the .css in your example) and low for resources
> that are non-blocking (the .jpgs)?
>
> On Mon, Oct 28, 2013 at 3:34 PM, Martin Thomson <[email-masked]>wrote:
>
> I have to confess that I heard complaints but never understood the
> reasoning behind them. If it's archival/IPR, I'm perfectly happy to
> copy/paste the document into email. These concerns aren't obvious to me as
> I'm a relative newb to IETF stuff.
>
> As far as the proposal's wordiness, I mostly view it as a straw man to
> ignite discussion. I'm completely expecting that it will be ripped apart :)
> I'm hoping to rely heavily on editors to make it much more succinct once we
> reach some rough consensus. Or perhaps this was a subtle play on your part
> to get me to do better editorial work before sending it to the group :)
>
> I'll give others a chance to discuss other points first. I don't want to
> yell more loudly than others anymore than I already do.
>
>
>>
> This document proposes changes to the SPDY protocol to support stream
> dependencies. During a pageload, the server uses dependencies to improve
> performance by allocating bandwidth capacity to the most important resource
> transfers first.
>
> The remainder of this document describes the motivation<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.dwzsju9gmwit>for dependencies, protocol
> changes<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=kix.hiogy1u6j43a>to support them, and
> examples<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.9awxmm9y20yn>of how those mechanisms can be used by the browser. We conclude with a
> discussion of the client and server policies<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.6ii1fem7qsws>afforded by expressing dependency information in SPDY.
>
> an exception. The server policy today is to assume push streams are all
> low priority. Push or pull, the priority of a stream cannot be changed once
> created.
>
> Priorities provide hints to the server about which streams are most
> important to the client, but they are poorly suited to several common
> use-cases.
>
>
>    Sharing bandwidth between resource transfers may degrade performance
>    as measured by page-load time, e.g., when transferring two Javascript
>    resources that cannot be executed until transfer is complete, or two video
>    chunks that will be played back-to-back. In these circumstances, the
>    browser may wish to specify an ordering --- HTML before script1.js before
>    script2.js before image.png, for example, or video_chunk1 before
>    video_chunk2 and so on. (Moreover, changing the priority of the HTML
>    transfer itself may benefit performance; e.g., a large blocking script will
>    be interpreted and executed more quickly if it does not compete for
>    bandwidth capacity with a large HTML transfer.)
>
>    With a small number of fixed priorities, the browser is simply unable
>    to express an ordering over many resource transfers, and with a large
>    number of priorities, reordering is costly.
>    Because the browser's document parser blocks while waiting for script
>    and style resource transfers to complete, many resource requests will be
>    speculative. (For more background, see Tony Gentilcore's excellent
>    summary <http://gent.ilcore.com/2011/01/webkit-preloadscanner.html> of
>    Chrome's implementation of speculative parsing, the preload scanner.) These
>    requests may need to be preempted as the document parser learns of higher
>    priority resources. For example, if a script a.js uses document.writeto embed another script,
>    b.js, the transfer of b.js should preempt other in-flight resource
>    transfers, as the receipt of b.js blocks page layout. As another
>    example, consider images styled with display: none; once such styling
>    is discovered during parsing, associated image transfers should be deferred
>    to prioritize visible content.
>    - Reacting to user behavior
>    Suppose a SPDY proxy is servicing multiple users. In this case, many
>    tabs (and their associated streams) are multiplexed over the same SPDY
>    connection. Fixed priorities (i.e., unchanging over the lifetime of a
>    stream) preclude reacting to user behavior; e.g., a user may switch among
>    concurrently loading tabs.
>    - Server push
>    No single fixed priority is appropriate for server push. A stream
>    pushing a large image, for example, should have lower priority than JS/CSS.
>    But, when pushing JS/CSS that the browser needs, those stream should have
>    high priority.
>
>
> In sum, for many common scenarios, fixed priorities are not sufficient to
> optimize the allocation of bandwidth among competing requests.
>
> Protocol changes
> To address the limitations of priorities, we propose expressingdependencies among streams.
> Dependencies improve matters in two main ways:
>
>    1. Dependencies more accurately reflect the constraints of the browser.
>    Rendering a page is a streaming process that naturally leads to a
>    series of dependencies among resource transfers. For example, a script may
>    block HTML parsing, and a final layout may depend on an external stylesheet.
>    2. Dependencies can be updated efficiently.
>    The relative importance of streams may change as Javascript executes
>    or a user changes tabs, for example. Dependencies allow the browser to
>    express these changes compactly. If a user changes tabs, for example, the
>    browser may simply signal a change in priority of the tab's dependency
>    root, thereby reducing (or increasing) the bandwidth allocated to all
>    dependent transfers.
>
>
> Dependencies are expressed in two ways: 1) a new dependency field in the
> SYN_STREAM message, and 2) a new REPRI message that updates the
> dependency pointers of existing streams. To allow servers to advertise
> their support for scheduling transfers based on dependencies, we propose a
> new SETTINGS id/value pair. We describe the layout and semantics of each
> in turn.
>
> Note that these protocol changes are defined in terms of the latest
> version of the SPDY draft specification<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html>
> .
>
> SYN_STREAM:
>    0        1        2        3         4        5        6        7
> Here, the first 8 bytes are the standard control frame header (§2.2.2<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#ControlFrames>).
> A new 32 bit field replaces the existing SYN_STREAM priority bits (§2.6.1<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#SYN_STREAM>)
> with:
>
>
>    - P: A bit indicating whether the following PriOrDep bits specify a
>    priority (P = 1) or a stream ID (P = 0) on which this new stream
>    depends.
>    - PriOrDep: Depending on the value of P, either the priority of the
>    new stream or a stream ID on which this new stream depends.
>    - The structure and semantics of the Name/Value header block (§2.6.11<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#HeaderBlock>)
>    are unchanged.
>
>
> P is exclusive; a stream may be assigned a priority or a parent
> dependency upon creation, but not both. There are no constraints of the
> value of PriOrDep; any 31 bit value is valid. Thus, a stream may refer to
> a dependency identifier that does not correspond to any current or previous
> stream ID. This is a deliberate design choice that increases flexibility
> for clients when structuring dependencies, a topic we expand upon in the policies
> section<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.6ii1fem7qsws>
> .
>
> Server push streams are assigned an initial parent at the discretion of
> the server. A conformant implementation SHOULD create a dependency on the
> push stream's associated-to-stream-id (§3.3.1<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#anchor20>
> ).
>
> REPRI:
>    0        1        2        3         4        5        6        7
> As in SYN_STREAM, the control frame header is standard, followed by a
> P/PriOrDep label indicating an update to the 31 bit Dependency Id specified
> in the header. We relabel the typical Stream Id here as Dependency Idsince a dependency need not correspond to an actual stream. (Recall that
> any 31 bit value is a valid dependency identifier.)
>
> To support batched updates of dependencies, an optional list of
> DependencyPriOrDep pairs with identical semantics may follow. The number
> of such pairs is determined by examining the frame length.
> We expect most streams to have at most a single dependency, but this is
> not a protocol requirement. (Later, we describe scenarios where multiple
> parents may improve efficiency.) If a stream is referenced more than once
> in a single frame, this indicates multiple parents. A server implementation
> which does not support multiple parents MUST use the last referenced
> parent. Clients which send multiple parents thus SHOULD put the most
> important parent last.
>
> SETTINGS:
> Recall that dependencies and priorities are advisory. While servers must
> accept the messages, they are not required to incorporate them into
> scheduling decisions. A client may benefit from knowing a server's level of
> support; e.g., a client may specify priorities only if it knows a server
> will ignore dependencies. To communicate this, we propose a new SETTINGSID/value pair (
> §2.6.4<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#SETTINGS>
> ),
>
>
>    - ID 9 - SETTINGS_MAX_CONCURRENT_DEPENDENCY_SCHEDULING_NODES allows
>    the server to indicate resource limits for dependency scheduling, e.g., to
>    limit memory consumption. A value of 0 indicates that the server does not
>    support dependency scheduling. (We expect most implementations will select
>    a value greater than or equal to MAX_CONCURRENT_STREAMS.)
>    - ID 10 - SETTINGS_DEPENDENCY_SCHEDULING_NODE_TIMEOUT indicates how
>    long the server will maintain dependency nodes after creation. The value is
>    an interval in milliseconds. This allows the client to estimate if
>    previously created dependency relationships are still available for
>    reference at the server. (We expect conformant implementations to maintain
>    dependencies for at least as long as associated streams are active,
>    although this is not a correctness requirement.)
>
>
> Both of these values are advisory. Servers need not abide by their stated
> values and clients may disregard them. Conformant clients should respect
> the concurrency limit, but servers must be robust to a client that exceeds
> it. Similarly, servers may drop dependency information at any time
> regardless of previous statements made in SETTINGS. This is intended to
> provide flexibility for service policies; e.g., a server may reduce the
> timeout in response to memory pressure or abandon dependency scheduling
> entirely.
>
> The combination of dependencies and priorities suffices to express
> serialized as well as concurrent transfer schedules. (Both are necessary,
> as we describe below.) But, how should the browser choose dependencies and
> priorities when making requests? This question is best answered
> quantitatively, but as a starting point, we consider the following policy
> in our examples:
>
>
>    1. Resource dependencies are (re)configured to reflect parser-blocking
>    order. The transfer of non-streaming resources is always serialized; i.e.,
>    non-async scripts and styling.
>    2. Resources that can be progressively rendered (e.g., images) are
>    transferred concurrently and (re)configured to depend on parser-blocking
>    resource transfers.
>    3. To ensure that the speculative parser can maintain enough in-flight
>    requests to fill pipe between the client and server, page HTML is always a
>    top-level dependency, although it may have lower priority than a resource
>    transfer currently blocking document parsing.
>
>
> When scheduling transfers, we consider a server that allocates bandwidth hierarchically
> within dependency trees and splits equally among streams with the same
> parent.
>
> Concretely, suppose a SPDY connection is multiplexing multiple tabs from a
> user connected to a SPDY proxy, with parent pointers and priorities as
> shown below. (P6, for example, indicates a priority of 6.)
>
> To color in this example, suppose that Tab 1 is the foreground tab,
> loading in parallel with Tab 2 in the background. Thus, its relatively
> higher weight. a.js and b.js are scripts required for the first tab and
> should be transferred serially (as scripts are executed in the order they
> are declared in the document, and are not parsed until transfer completes.)
> Thus, a.js depends on b.js depends on tab1.htm. In the background tab,
> two image transfers share capacity as both can be rendered progressively.
> Both image transfers have the same parent and hence transfer concurrently.
>
> Because the streams associated with the transfers of tab1 and tab2 have no
> parent, they are always scheduled before any lower level in their trees.
> But, bandwidth allocation among trees remains proportional as defined by
> the relative priority of roots. For example, if the transfer of tab2.htmis in progress and
> tab1.htm (now complete) is selected, a.js will be scheduled before
> tab2.htm completes. This process proceeds until all transfers in a tree
> have completed.
>
> As a practical matter, the timeout for pruning nodes in a tree should be
> selected to allow transfers to complete and to allow clients to name
> currently completed parents when defining transfer dependencies.
> Concretely, on a high delay path, a small HTML transfer may be flushed
> entirely by the server before the client receives any data and begins
> making dependent requests for resources embedded in the page.
>
> With these client and server policies in mind, we revisit the motivating
> use-cases described above in greater detail.
>
> We illustrate the need for both serial dependencies, concurrency, and
> reprioritization in these cases with a simple example.
>
> How would this example page be transferred today? As the main HTML is
> received and parsed, a request for a.js will be issued and block the
> document parser. As the remaining HTML streams in, the speculative parser
> will issue requests for a.jpg, b.jpg, and style.css in quick succession.
> Once a.js is received and executed, a request for b.js will be issued,
> which again blocks parsing until received. Visually:
>
>
> This transfer schedule is suboptimal. Page rendering will complete only
> when style.css and b.js have completed, but receiving each of those
> critical resources is slowed by competition for bandwidth capacity with
> bulk data that's not on the critical path (a.jpg and b.jpg).
>
> What we would like is serialized transfer that reflects the document
> parse order with concurrency for nonblocking, streaming resources. More
> specifically, we want to receive: 1) index.html, 2) a.js, 3) b.js, and 4)
> style.css serialized (i.e., with no deliberate sharing of capacity among
> the ordered transfers). After those critical transfers have completed,
> a.jpg and b.jpg should be transferred concurrently (as they may be
> displayed progressively.)
>
> In the figure, each resource request corresponds to a new SPDY stream with
> the form ID: reqest (PriOrDep). In more detail:
>
>
>    - The SYN_STREAM for the index.htm request has a parent indicating a
>    default priority (3) and a stream id of 1.
>    - The document parser is blocked once the external script a.js is
>    parsed. At this point, the speculative  parser looks ahead and creates new
>    streams for a.jpg, b.jpg in parse order. a.jpg and b.jpg can be
>    progressively rendered, so their transfer is concurrent (same parent, 2,
>    corresponding to a.js).
>    - When the parser encounters style.css, back-to-back control messages
>    are sent to create the stream and update the dependencies of the image
>    transfers. Since stylesheets block rendering and cannot be streamed, the
>    image transfers are updated to depend on style.css (P5).
>    - Once a.js completes, the document parser continues, executing a.js
>    and inserting b.js via document.write(), again blocking document
>    parsing on the receipt of b.js. At this point, b.js should preempt all
>    other transfers since it's a non-streaming resource that is blocking page
>    rendering. To this end, the client creates the b.js stream with a.js as its
>    parent (or, equivalently, index.htm). Batched with this SYN_STREAM is
>    another REPRI message rewiring style.css to depend on b.js. This
>    serializes the transfers (modulo the delay associated with message
>    propagation and any transfer buffering delay at the server).
>
>
> This transfer schedule may significantly improve performance. By
> serializing the transfer of resources on the critical path, the browser can
> ensure that resources needed immediately do not compete for bandwidth
> capacity with less important transfers. Yet, the pipe remains full, as a
> queue of requests is maintained in the scheduling tree ready to fill any
> idle capacity with useful data. Where we cannot make an informed scheduling
> decision, we hedge our bets with concurrent transfers by hinting that they
> are peers and letting the server decide what makes the most sense --- as in
> the case of two above the fold images that can be rendered progressively.
>
> Note that this sort of explicit scheduler hinting is not possible in HTTP
> today. Requests, once issued, cannot be reprioritized or reordered on a
> single connection. This results in suboptimal transfer schedules given the
> limitations of HTML lookahead scanning. Yet, lookahead is essential for
> ensuring the concurrency necessary to keep the client <-> server pipe full.
> While the browser might serialize transfers itself, the many small
> transfers typical of pageloads would significantly limit utilization. With
> ordering and reprioritization in SPDY, browsers can jointly optimize both
> the transfer pipeline and resource priority as desired, rather than being
> forced to accept poor utilization or poor transfer schedules.
>
> Suppose concurrent tabs are loading with a scheduling forest as shown.
> When a user changes tabs, the browser simple sends a REPRI for the stream
> associated with tab2.htm to, say, priority 8. (A batched message might also
> reduce the priority of tab1.htm to weight 3.) Because bandwidth allocation
> decisions are made tree-by-tree and level-by-level, increasing the priority
> of tab2.htm effectively shifts capacity for all resource transfers
> depending on tab1.htm to tab2.htm.
>
> - Server push
> As in client SYN_STREAM messages, server push messages indicate the
> priority and dependencies of a resource as chosen by the server. Much
> like the client, the server is free to adopt prioritization policies to
> improve performance, e.g., by prioritizing pushes of styles over images.
> But, as in our example above, the browser may update the server's choices
> as information about resources needed for parsing is learned. (Again,
> expressed via REPRI messages.)
>
> Policy considerations
> Both priorities and stream dependencies are advisory hints. Browsers may
> adopt sophisticated policies or leave dependencies entirely unspecified.
> Similarly, servers may incorporate dependency hints into very sophisticated
> schedulers or ignore them entirely. The protocol mechanisms for encoding
> dependencies are designed to be simple. But, these mechanisms afford a very
> flexible set of policies depending on how browsers and servers use them.
> This section expands on several policy considerations.
>
> In our examples, we consider a browser that configures dependencies to
> reflect parser-blocking order for resources, updated as parsing continues.
> We expect this to improve performance, but browsers are free to deviate
> from this policy, and there may be good reasons to do so. For example, if
> the parser-blocking order is highly dynamic (e.g., in response to many JS
> events), the overhead of updating dependencies may not be worth the cost,
> particularly for small transfers. A sophisticated client may base
> dependency update decisions on content-length and/or RTT, restricting
> updates to only those streams likely to benefit from it. Quantitative
> implementation experience will be helpful here.
>
> The overhead of updating dependencies depends in part on the existing
> structure of dependencies. In some scenarios, it may be more efficient to
> introduce placeholder nodes to improve the efficiency of common update
> operations. For example, consider a variant of our earlier example page:
>
> <html>
> <body>
> Transitioning between these dependency structures requires sending REPRImessages for each image. Because updating the dependencies of images is
> common, a client might create all image streams with a placeholder
> dependency, yielding an initial configuration of:
> With such an initial configuration, updating the dependencies of the
> images to the stream associated with b.js can be accomplished with a single
> REPRI message updating the placeholder.
>
> Multiple parents
> All of our examples have considered nodes with a single parent. But,
> single parent trees cannot express some transfer schedules. For example, an
> asynchronous script at the end of HTML is non-blocking and does not block
> interaction or pageload. It should be loaded after all visible resources
> (e.g., images) have completed. A possible dependency graph is:
>
> Here, any of img1, img2, or img3 should be prioritized before the
> asynchronous script, a schedule that cannot be expressed with single parent
> pointers.
>
> Clients should not specify dependencies to servers that do not support it
> (as indicated by SETTINGS_MAX_CONCURRENT_DEPENDENCY_SCHEDULING_NODES in
> the SETTINGS frame). Rather, an intelligent client may fall back to
> specifying priorities only, thereby improving performance relative to
> specifying dependencies that will be ignored.
>
> Server scheduling.
> A conformant server should respect the semantics of priorities and
> dependencies in its scheduling policy. Priorities indicate a preference for weighted
> scheduling (e.g., using a lottery scheduler<http://dl.acm.org/citation.cfm?id=1267639>)
> among root nodes (i.e., those created with a priority and not a parent).
> Interior nodes with identical parents are weighted equally.
>
> Server scheduling should reflect guidance from dependencies, but it need
> need not be strict. If all streams in a dependency tree have data available
> to write at the server, writes should be serviced first for root nodes,
> then children, then grandchildren, and so on. But, children that are ready
> to write should not starve to enforce a scheduling dependency. In other
> words, scheduling dependencies should not lead servers to waste capacity.
> If data is not available to continue writing the root, for example, a child
> ready to write should do so.
>
> Finally, we point out that servers may improve performance even if clients
> do not provide dependency information or priorities. For example, an
> intelligent server may inspect the content type of resources to make
> informed prioritization decisions on its own without client guidance.
> (However, respecting client-provided hints when available is likely to
> improve performance, as clients have detailed knowledge of parser
> dependencies.)
> SPDY implementations must take care to protect themselves from the use of
> dependencies as a DoS vector. The protocol provides wide flexibility in
> this regard; servers are free to drop dependency or priority data at any
> time without sacrificing correctness.
>
> Otherwise, we envision servers choosing a timeout value for dependency
> nodes that is large enough to cover the likely time period during which a
> client may reference a node; e.g., page load time + rtt. Alternatively, a
> large fixed number of dependencies may be maintained per-session with LRU
> eviction. Either of these policies is likely to sharply limit the number of
> missed dependency references. On the client side, browsers should take care
> to manage dependencies according to server policies, e.g., by creating new
> dependency structures rather than referring to those that have likely timed
> out and been garbage collected.
> While missed references may be rare, they are unavoidable in an
> asynchronous system with timeouts. (This is why we require that servers
> accept as correct any dependency id.) In cases where a reference is made to
> an unknown node at the server, the server may create the referenced id as a
> new root for future reference or ignore the dependency entirely (i.e.,
> treat the new stream as a root).
>
>
>

---

From: Martin Thomson <[email-masked]>
Date: Sun, 3 Nov 2013 08:57:48 -0800

On 3 November 2013 07:58,  <[email-masked]> wrote:
> It's a performance versus simplicity tradeoff that this list may have
> discussed in the past but I can't find the thread if so.

The text uses SHOULD intentionally. We recognize that you might want
to avoid this problem.  However, if you don't follow this guidance, be
prepared for the consequences.

---

From: [email-masked]
Date: Sun, 3 Nov 2013 08:59:46 -0800

The introduction, pasted below, is a nice summary of the benefits of HTTP 2.0. But it made me realize there is nothing in it for either uploads or large file downloads. Reading through the rest of the spec I still couldn't find any benefits for simple file transfers. So a couple questions:

Is there any reason why HTTP file transfer clients like curl and wget should ever implement 2.0?

More radically, since there is no benefit for uploads, should HTTP 2.0 even support the upload verbs?

Or, is the argument that 2.0 flow control is less effective if there are non-2.0 TCP connections between the browser and the content server that the 2.0 connection is competing against (and unable to account for in its flow control dance) and therefore uploads and large file downloads should use HTTP 2.0? That seems like a small benefit, and it only kicks in when the user is doing both web browsing (transferring lots of small files efficiently with 2.0) and transferring large files.

Thanks,
 
Peter

1.  Introduction

   The Hypertext Transfer Protocol (HTTP) is a wildly successful
   protocol.  However, the HTTP/1.1 message format ([HTTP-p1], Section
   3) is optimized for implementation simplicity and accessibility, not
   application performance.  As such it has several characteristics that
   have a negative overall effect on application performance.

   In particular, HTTP/1.0 only allows one request to be outstanding at
   a time on a given connection.  HTTP/1.1 pipelining only partially
   addressed request concurrency and suffers from head-of-line blocking.
   Therefore, clients that need to make many requests typically use
   multiple connections to a server in order to reduce latency.

   Furthermore, HTTP/1.1 header fields are often repetitive and verbose,
   which, in addition to generating more or larger network packets, can
   cause the small initial TCP congestion window to quickly fill.  This
   can result in excessive latency when multiple requests are made on a
   single new TCP connection.

   This document addresses these issues by defining an optimized mapping
   of HTTP's semantics to an underlying connection.  Specifically, it
   allows interleaving of request and response messages on the same
   connection and uses an efficient coding for HTTP header fields.  It
   also allows prioritization of requests, letting more important
   requests complete more quickly, further improving performance.

   The resulting protocol is designed to be more friendly to the
   network, because fewer TCP connections can be used, in comparison to
   HTTP/1.x.  This means less competition with other flows, and longer-
   lived connections, which in turn leads to better utilization of
   available network capacity.

   Finally, this encapsulation also enables more scalable processing of
   messages through use of binary message framing.

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 09:04:40 -0800

Right. But my point is that an extremely simple scheme, where the browser
just indicates that an object is blocking or not, gets you to the same
place as the dependency scheme.

Peter

On Sun, Nov 3, 2013 at 8:54 AM, Martin Thomson <[email-masked]>wrote:

>> Going through your example, would the prioritization at any instant be
>> any different if you simply assigned two priorities -- high for resources
>> that are blocking (the .js and the .css in your example) and low for
>> resources that are non-blocking (the .jpgs)?
>>
>> On Mon, Oct 28, 2013 at 3:34 PM, Martin Thomson <[email-masked]
>> > wrote:
>>
>>    summary <http://gent.ilcore.com/2011/01/webkit-preloadscanner.html>of Chrome's implementation of speculative parsing, the preload scanner.)
>>    These requests may need to be preempted as the document parser learns of
>>    higher priority resources. For example, if a script a.js uses
>>    document.write to embed another script, b.js, the transfer of b.jsshould preempt other in-flight resource transfers, as the receipt of
>>    b.js blocks page layout. As another example, consider images styled
>>    with display: none; once such styling is discovered during parsing,
>>    associated image transfers should be deferred to prioritize visible content.
>> value of PriOrDep; any 31 bit value is valid. Thus, a stream may refer
>> to a dependency identifier that does not correspond to any current or
>> previous stream ID. This is a deliberate design choice that increases
>> flexibility for clients when structuring dependencies, a topic we expand
>> upon in the policies section<https://docs.google.com/a/google.com/document/d/1pNj2op5Y4r1AdnsG8bapS79b11iWDCStjCNHo3AWD0g/edit#bookmark=id.6ii1fem7qsws>
>> .
>>
>>    1. Resource dependencies are (re)configured to reflect
>>    parser-blocking order. The transfer of non-streaming resources is always
>>    serialized; i.e., non-async scripts and styling.
>>    3. To ensure that the speculative parser can maintain enough
>>    in-flight requests to fill pipe between the client and server, page HTML is
>>    always a top-level dependency, although it may have lower priority than a
>>    resource transfer currently blocking document parsing.
>>
>>
>> Concretely, suppose a SPDY connection is multiplexing multiple tabs from
>> a user connected to a SPDY proxy, with parent pointers and priorities as
>> Because the streams associated with the transfers of tab1 and tab2 have
>> no parent, they are always scheduled before any lower level in their trees.
>> In the figure, each resource request corresponds to a new SPDY stream
>> with the form ID: reqest (PriOrDep). In more detail:
>>
>>
>> the transfer pipeline and resource priority as desired, rather than
>> being forced to accept poor utilization or poor transfer schedules.
>>
>> When a user changes tabs, the browser simple sends a REPRI for the
>> stream associated with tab2.htm to, say, priority 8. (A batched message
>> might also reduce the priority of tab1.htm to weight 3.) Because bandwidth
>> allocation decisions are made tree-by-tree and level-by-level, increasing
>> the priority of tab2.htm effectively shifts capacity for all resource
>> transfers depending on tab1.htm to tab2.htm.
>>
>> - Server push
>> Finally, we point out that servers may improve performance even if
>> clients do not provide dependency information or priorities. For example,
>> an intelligent server may inspect the content type of resources to make

---

From: Martin Thomson <[email-masked]>
Date: Sun, 3 Nov 2013 09:04:57 -0800

> Is there any reason why HTTP file transfer clients like curl and wget should

That's not our choice.  Though I would suggest that some of the wget
modes of operation would benefit; and there are potentially some
advantages to be gained from having opportunistic encryption for http:
resources.

> support the upload verbs?

Absolutely yes.  There's more to HTTP PUT than file upload.  And the
benefits to proxies and gateways in terms of multiplexing are
incredible.

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 09:17:54 -0800

On Sun, Nov 3, 2013 at 9:04 AM, Martin Thomson <[email-masked]>wrote:

> > Is there any reason why HTTP file transfer clients like curl and wget
> should
> > ever implement 2.0?
>

Opportunistic encryption would be great if it gets in and I agree that then
there is a benefit for simple file transfers.

>
> > More radically, since there is no benefit for uploads, should HTTP 2.0
> even
> > support the upload verbs?
>

Do you mean the benefit to the proxies of sharing the same TCP connection
for uploads and downloads? File upload traffic is not responsible for large
numbers of connections today, is it?

A related point...uploading and downloading large numbers of data frames
over the same connection is problematic b/c the WINDOW_UPDATE frames will
get blocked behind data frames in each direction, making flow control
slower to adapt and so more bursty. Better is just to send the uploads over
their own TCP connection, I realize this goes against:

   Clients SHOULD NOT open more than one HTTP/2.0 connection to a given
   origin ([RFC6454 <http://tools.ietf.org/html/rfc6454>])
concurrently.  A client can create additional
   connections as replacements, either to replace connections that are
   near to exhausting the available stream identifiers (Section 5.1.1
<http://tools.ietf.org/html/draft-ietf-httpbis-http2-07#section-5.1.1>),
   or to replace connections that have encountered errors
   (Section 5.4.1
<http://tools.ietf.org/html/draft-ietf-httpbis-http2-07#section-5.4.1>).

But this is only a SHOULD and so user agents are free to choose the
better performing approach, which will often be to use multiple TCP
connections.

Peter

Peter

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 09:29:17 -0800

Okay gotcha. I'm still getting a feel for what is meant by these key terms.

Question: if the browser issues a normal HEADERS frame GET for an object
that subsequently arrives via a PUSH_PROMISE stream, will it use the pushed
copy if that pushed copy arrives before any data frames arrive on the
stream the browser initiated?

Thanks,

Peter

---

From: Martin Thomson <[email-masked]>
Date: Sun, 3 Nov 2013 09:34:58 -0800

On 3 November 2013 09:29, Peter Lepeska <[email-masked]> wrote:
> copy if that pushed copy arrives before any data frames arrive on the stream
> the browser initiated?

That's the browser's business.  If it were me, I'd try to reduce the
possibility the number of bytes wasted, so I'd probably send
RST_STREAM on one or other stream, probably the one I initiated since
that is likely to be the later one.

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 09:41:15 -0800

Me too. When a pushed resource arrives ahead of a browser initiated
resource for the same object, send RST_STREAM and use the pushed resource.

Any reason this clarification shouldn't be incorporated into the spec?
Seems an important detail to the server push implementation that we'd want
to make consistent across all browsers. SPDY proxy vendors doing server
push would appreciate it anyway.

Thanks,

Peter

---

From: Martin Thomson <[email-masked]>
Date: Sun, 3 Nov 2013 10:00:28 -0800

On 3 November 2013 09:41, Peter Lepeska <[email-masked]> wrote:
> Any reason this clarification shouldn't be incorporated into the spec? Seems
> an important detail to the server push implementation that we'd want to make
> consistent across all browsers.

I don't see any real need for consistency there.  I'm sure that all
the browsers will do what makes the most sense within the constraints
of their architectures.

---

From: Roberto Peon <[email-masked]>
Date: Sun, 3 Nov 2013 10:06:09 -0800

If there is only one stream, then multiplexing isn't terribly interesting,
though flow control (to cap the bandwidth or memory usage) is potentially
useful.

Users of wget, curl, etc. are unlikely to benefit when not doing mirroring
operations (though do when they do). The server may see benefit, however,
even if the user doesn't, especially in the upload case.

-=R
On Nov 3, 2013 9:20 AM, "Peter Lepeska" <[email-masked]> wrote:

> Opportunistic encryption would be great if it gets in and I agree that
> then there is a benefit for simple file transfers.
>
>
>>
>    origin ([RFC6454 <http://tools.ietf.org/html/rfc6454>]) concurrently.  A client can create additional
>    near to exhausting the available stream identifiers (Section 5.1.1 <http://tools.ietf.org/html/draft-ietf-httpbis-http2-07#section-5.1.1>),
>    (Section 5.4.1 <http://tools.ietf.org/html/draft-ietf-httpbis-http2-07#section-5.4.1>).
>
>
> But this is only a SHOULD and so user agents are free to choose the better performing approach, which will often be to use multiple TCP connections.
>
>
> Peter
>
>
> Peter
>

---

From: David Morris <[email-masked]>
Date: Sun, 3 Nov 2013 10:37:42 -0800 (PST)

AND, wget and curl are valuable diagnostic tools when websites are
not working for whatever reason. So I'd recommend that their
respective development communities implement 2.0 support

---

From: Daniel Stenberg <[email-masked]>
Date: Sun, 3 Nov 2013 19:57:01 +0100 (CET)

> Is there any reason why HTTP file transfer clients like curl and wget should 

I can't speak for wget, but I'm the primary curl developer. We will certainly 
support HTTP2 and we're already in progress[1].

As has been mentioned already, these tools are used a lot like diagnostics 
tools and as command line versions of getting things done like a browser. When 
browsers do HTTP2, we need tools that can do HTTP2 as well.

when the "browser-web" moves to HTTP2, there's a big risk that the plain HTTP 
side of sites and services will be left behind and thus I find it very likely 
that in N years into the future, getting things with HTTP2 like the browsers 
do, will be more likely to succeed than asking for the same thing over old 
HTTP.

Finally, curl is actually built on libcurl which is a transfer library that 
works as a foundation to hundreds or thousands of applications and many of 
them will in fact benefit from the HTTP2 features much more than the curl 
command line tool will. Offering HTTP2 support for them is obvious to us.

[1] = http://curl.haxx.se/mail/lib-2013-09/0020.html

-- 

  / daniel.haxx.se

---

From: [email-masked]
Date: Sun, 3 Nov 2013 11:56:42 -0800

Okay that makes sense.

But I do have trouble seeing HTTP2 obsoleting HTTP1.1 since for so many purposes it is a step sideways. But let's see how it goes.

Thanks for the explanation,

Peter

On Nov 3, 2013, at 10:57 AM, Daniel Stenberg <[email-masked]> wrote:

> I can't speak for wget, but I'm the primary curl developer. We will certainly support HTTP2 and we're already in progress[1].
> 
> As has been mentioned already, these tools are used a lot like diagnostics tools and as command line versions of getting things done like a browser. When browsers do HTTP2, we need tools that can do HTTP2 as well.
> 
> when the "browser-web" moves to HTTP2, there's a big risk that the plain HTTP side of sites and services will be left behind and thus I find it very likely that in N years into the future, getting things with HTTP2 like the browsers do, will be more likely to succeed than asking for the same thing over old HTTP.
> 
> Finally, curl is actually built on libcurl which is a transfer library that works as a foundation to hundreds or thousands of applications and many of them will in fact benefit from the HTTP2 features much more than the curl command line tool will. Offering HTTP2 support for them is obvious to us.
>

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 11:58:38 -0800

Proxies need consistency so they don't have to behave one way for one web
browser and another way for another web browser, much like the days when
IE6 incompatibilities required multiple implementations of web pages to
work across browsers.

Peter

On Sun, Nov 3, 2013 at 10:00 AM, Martin Thomson <[email-masked]>wrote:

> Seems

---

From: Patrick McManus <[email-masked]>
Date: Sun, 3 Nov 2013 15:15:07 -0500

either end can cancel any stream at any time. What is the specificinterop
problem trying to be solved by proscribing exactly 1 stream to be rst and
the other to be received? I'm not clear on that.

consider the case where the flow control window for the latter pulled
stream is already bigger than the window associated with the earlier pushed
stream. The benefits of being earlier might well be wiped out by the rtt
needed to open that window.

Perhaps both streams are needed and none will be reset. (2 queries and a
"cache" that is really just a ram fifo)

-P

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 12:41:09 -0800

The main thing I'm trying to avoid is sending an object redundantly when it
doesn't need to be. And at the same time not require push_promises to be
sent before the frame that contains the reference to it.

Ideally we'd cancel the pulled request at the proxy because we know we've
already sent a prefetched (server pushed) copy of the same object. The HTTP
2.0 proxy could then inform the browser that the pulled request was
canceled via an error code that specifically indicates that the request was
redundant with a pushed resource. This would remove the need for the
RST_STREAM and eliminate the race.

If this is unclear I can describe what I'm suggesting in more detail.

Peter

On Sun, Nov 3, 2013 at 12:15 PM, Patrick McManus <[email-masked]>wrote:

> On Sun, Nov 3, 2013 at 2:58 PM, Peter Lepeska <[email-masked]>wrote:
>
>> On Sun, Nov 3, 2013 at 10:00 AM, Martin Thomson <[email-masked]
>> > wrote:
>>

---

From: Patrick McManus <[email-masked]>
Date: Sun, 3 Nov 2013 16:09:38 -0500

Every push is speculative and risks wasting a window of bw. To me this just
seems like a special case of that. Too much info asymetry to specify
behavior.

Just my thoughts.. See ya in yvr
 On Nov 3, 2013 2:41 PM, "Peter Lepeska" <[email-masked]> wrote:

> The main thing I'm trying to avoid is sending an object redundantly when
> it doesn't need to be. And at the same time not require push_promises to be
>>> Proxies need consistency so they don't have to behave one way for one
>>> web browser and another way for another web browser, much like the days
>>> when IE6 incompatibilities required multiple implementations of web pages
>>> to work across browsers.
>>>
>>> Peter
>>>
>>>
>>> On Sun, Nov 3, 2013 at 10:00 AM, Martin Thomson <
>>> [email-masked]> wrote:
>>>

---

From: Yoav Nir <[email-masked]>
Date: Sun, 3 Nov 2013 21:15:07 +0000

> But I do have trouble seeing HTTP2 obsoleting HTTP1.1 since for so many purposes it is a step sideways. But let's see how it goes.

Hi, Peter

I understand what you mean by "sideways", but why is that an obstacle for HTTP/2 replacing HTTP/1.1 ?

I could argue that the extra stuff in HTTP/1.0 and HTTP/1.1 are also not quite needed for WGET, and yet that tools did implement HTTP/1.1.

Is there some use case where HTTP/2 is inferior?  I realize that a minimal implementation is more complicated than a minimal implementation of HTTP/1. But assuming you have both an HTTP/2 and an HTTP/1 implementation, is there a reason to use the HTTP/1 in any case?

Yoav

---

From: William Chan (陈智昌) <[email-masked]>
Date: Sun, 3 Nov 2013 13:30:27 -0800

I think you're assuming that all streams in a connection belong to a single
webpage load. Let me know if not, and I can explain further.
On Nov 3, 2013 9:04 AM, "Peter Lepeska" <[email-masked]> wrote:

>> The intent would be to use ordering (i.e. dependencies) for this
>> scenario, not "priorities" (aka weights).
>>
>>
>>> dependencies. During a pageload, the server uses dependencies to
>>> improve performance by allocating bandwidth capacity to the most important
>>> resource transfers first.
>>>
>>>    With a small number of fixed priorities, the browser is simply
>>>    unable to express an ordering over many resource transfers, and with a
>>>    large number of priorities, reordering is costly.
>>>    Because the browser's document parser blocks while waiting for
>>>    script and style resource transfers to complete, many resource requests
>>>    will be speculative. (For more background, see Tony Gentilcore's
>>>    excellent summary<http://gent.ilcore.com/2011/01/webkit-preloadscanner.html>of Chrome's implementation of speculative parsing, the preload scanner.)
>>> In sum, for many common scenarios, fixed priorities are not sufficient
>>> to optimize the allocation of bandwidth among competing requests.
>>>
>>> Protocol changes
>>> new SETTINGS id/value pair. We describe the layout and semantics of
>>> each in turn.
>>>
>>> A new 32 bit field replaces the existing SYN_STREAM priority bits (
>>> §2.6.1<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#SYN_STREAM>)
>>> with:
>>>
>>>
>>> DependencyPriOrDep pairs with identical semantics may follow. The
>>> number of such pairs is determined by examining the frame length.
>>> Both of these values are advisory. Servers need not abide by their
>>> stated values and clients may disregard them. Conformant clients should
>>> respect the concurrency limit, but servers must be robust to a client that
>>> exceeds it. Similarly, servers may drop dependency information at any time
>>>    - When the parser encounters style.css, back-to-back control
>>>    messages are sent to create the stream and update the dependencies of the
>>>    image transfers. Since stylesheets block rendering and cannot be streamed,
>>>    the image transfers are updated to depend on style.css (P5).
>>>    parent (or, equivalently, index.htm). Batched with this SYN_STREAMis another
>>>    REPRI message rewiring style.css to depend on b.js. This serializes
>>>    the transfers (modulo the delay associated with message propagation and any
>>>    transfer buffering delay at the server).
>>>
>>>
>>> Note that this sort of explicit scheduler hinting is not possible in
>>> HTTP today. Requests, once issued, cannot be reprioritized or reordered on
>>> a single connection. This results in suboptimal transfer schedules given
>>> the limitations of HTML lookahead scanning. Yet, lookahead is essential for
>>> schedulers or ignore them entirely. The protocol mechanisms for
>>> encoding dependencies are designed to be simple. But, these mechanisms
>>> afford a very flexible set of policies depending on how browsers and
>>> servers use them. This section expands on several policy considerations.
>>>

---

From: Patrick McManus <[email-masked]>
Date: Sun, 3 Nov 2013 16:33:25 -0500

over the same connection is problematic b/c the WINDOW_UPDATE frames will
get blocked behind data frames in each direction,

Hopefully not. Just use small frame sizes so you can inject update at
will.. Using small frames and not over buffering is pretty much always
needed to make priority mux work.

Bufferbloat at a lower layer is a problem.. But its the same problem for a
2 TCP flow alternative

---

From: Michael Sweet <[email-masked]>
Date: Sun, 03 Nov 2013 17:47:27 -0500

On Nov 3, 2013, at 12:17 PM, Peter Lepeska <[email-masked]> wrote:
> On Sun, Nov 3, 2013 at 9:04 AM, Martin Thomson <[email-masked]> wrote:
> Opportunistic encryption would be great if it gets in and I agree that then there is a benefit for simple file transfers.

FWIW, HTTP/1.1 already has opportunistic encryption - see RFC 2817.

_________________________________________________________
Michael Sweet, Senior Printing System Engineer, PWG Chair

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 14:57:33 -0800

Sorry I thought by opportunistic encryption we were referring to Mark's
Internet Draft --
http://tools.ietf.org/html/draft-nottingham-http2-encryption-00.

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 15:07:49 -0800

Hi Yoav,

Two things:

1) I think one of the reasons that HTTP has been "wildly popular" is its
simplicity. I think we should only give that up if we have to. At the Hyatt
bar last night I was talking to an IETFer who is focused on DNS but he has
read the HTTP 2 draft and he mentioned that he loves the fact that he can
open a telnet prompt and GET files using simple ASCII HTTP. I wouldn't be
surprised to hear that 100,000 different HTTP client implementations exist.
How many HTTP 2.0 implementations do we expect in 20 years by comparison?

2) HTTP 1.x will outperform HTTP 2.x under some conditions and in some
implementations due to flow control. I'm worried that flow control HTTP 2.0
implementations will vary and I'll start spending a lot of time debugging
HTTP-level flow control in addition to the TCP flow control I already spend
a lot of time puzzling over. In addition, in the single stream case, TCP
can do flow control much better b/c it gets receive window updates with
every ack. Why is HTTP trying to tell the sender how much to send when TCP
often knows much better? Flow control is a very complicated business. I
think HTTP 2.0 should only do it when it must, and when there is a clear
benefit.

Thanks for asking,

Peter

On Sun, Nov 3, 2013 at 1:15 PM, Yoav Nir <[email-masked]> wrote:

> > But I do have trouble seeing HTTP2 obsoleting HTTP1.1 since for so many
> purposes it is a step sideways. But let's see how it goes.
>
> Hi, Peter
>
> I could argue that the extra stuff in HTTP/1.0 and HTTP/1.1 are also not
> quite needed for WGET, and yet that tools did implement HTTP/1.1.
>
> Is there some use case where HTTP/2 is inferior?  I realize that a minimal
> implementation is more complicated than a minimal implementation of HTTP/1.
> But assuming you have both an HTTP/2 and an HTTP/1 implementation, is there
> a reason to use the HTTP/1 in any case?
>
> Yoav
>
>

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 15:18:32 -0800

Interesting. I hadn't realized that window updates would be sent as often
as once per frame but that makes sense. Does Firefox do this? Are you using
smaller than max frames during large transfers in order to send window
updates more frequently?

Thanks,

Peter

---

From: Peter Lepeska <[email-masked]>
Date: Sun, 3 Nov 2013 15:21:48 -0800

Yes I was assuming that. Let me think on the two tab example you give a
little more.

Thanks,

Peter

On Sun, Nov 3, 2013 at 1:30 PM, William Chan (陈智昌) <[email-masked]>wrote:

> I think you're assuming that all streams in a connection belong to a
> single webpage load. Let me know if not, and I can explain further.
>>>> I'll give others a chance to discuss other points first. I don't want
>>>> to yell more loudly than others anymore than I already do.
>>>>
>>>>
>>>>>
>>>>    Sharing bandwidth between resource transfers may degrade
>>>>    performance as measured by page-load time, e.g., when transferring two
>>>>    Javascript resources that cannot be executed until transfer is complete, or
>>>>    two video chunks that will be played back-to-back. In these circumstances,
>>>>    the browser may wish to specify an ordering --- HTML before script1.js
>>>>    before script2.js before image.png, for example, or video_chunk1 before
>>>>    Suppose a SPDY proxy is servicing multiple users. In this case,
>>>>    many tabs (and their associated streams) are multiplexed over the same SPDY
>>>>    The relative importance of streams may change as Javascript
>>>>    executes or a user changes tabs, for example. Dependencies allow the
>>>>    browser to express these changes compactly. If a user changes tabs, for
>>>>    example, the browser may simply signal a change in priority of the tab's
>>>>    dependency root, thereby reducing (or increasing) the bandwidth allocated
>>>>    to all dependent transfers.
>>>>
>>>>
>>>> Dependencies are expressed in two ways: 1) a new dependency field in
>>>> the SYN_STREAM message, and 2) a new REPRI message that updates the
>>>>    - The structure and semantics of the Name/Value header block (
>>>>    §2.6.11<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#HeaderBlock>)
>>>>    are unchanged.
>>>>
>>>>
>>>> Recall that dependencies and priorities are advisory. While servers
>>>> must accept the messages, they are not required to incorporate them into
>>>> will ignore dependencies. To communicate this, we propose a new
>>>> SETTINGS ID/value pair (§2.6.4<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#SETTINGS>
>>>> ),
>>>>
>>>>
>>>> regardless of previous statements made in SETTINGS. This is intended
>>>> to provide flexibility for service policies; e.g., a server may reduce the
>>>> When scheduling transfers, we consider a server that allocates
>>>> bandwidth hierarchically within dependency trees and splits equallyamong streams with the same parent.
>>>>
>>>> Concretely, suppose a SPDY connection is multiplexing multiple tabs
>>>> from a user connected to a SPDY proxy, with parent pointers and priorities
>>>> as shown below. (P6, for example, indicates a priority of 6.)
>>>>
>>>> higher weight. a.js and b.js are scripts required for the first tab
>>>> and should be transferred serially (as scripts are executed in the order
>>>> they are declared in the document, and are not parsed until transfer
>>>> completes.) Thus, a.js depends on b.js depends on tab1.htm. In the
>>>> background tab, two image transfers share capacity as both can be rendered
>>>> progressively. Both image transfers have the same parent and hence transfer
>>>> concurrently.
>>>>
>>>> the relative priority of roots. For example, if the transfer of
>>>> tab2.htm is in progress and tab1.htm (now complete) is selected, a.jswill be scheduled before
>>>> tab2.htm completes. This process proceeds until all transfers in a
>>>> tree have completed.
>>>>
>>>> As a practical matter, the timeout for pruning nodes in a tree should
>>>> be selected to allow transfers to complete and to allow clients to name
>>>> With these client and server policies in mind, we revisit the
>>>> motivating use-cases described above in greater detail.
>>>>
>>>>    - The SYN_STREAM for the index.htm request has a parent indicating
>>>>    a default priority (3) and a stream id of 1.
>>>>    - Once a.js completes, the document parser continues, executing
>>>>    a.js and inserting b.js via document.write(), again blocking
>>>>    document parsing on the receipt of b.js. At this point, b.js should preempt
>>>>    all other transfers since it's a non-streaming resource that is blocking
>>>>    page rendering. To this end, the client creates the b.js stream with a.js
>>>>    as its parent (or, equivalently, index.htm). Batched with this
>>>>    SYN_STREAM is another REPRI message rewiring style.css to depend on
>>>>    b.js. This serializes the transfers (modulo the delay associated with
>>>>    message propagation and any transfer buffering delay at the server).
>>>>
>>>>
>>>> Both priorities and stream dependencies are advisory hints. Browsers
>>>> may adopt sophisticated policies or leave dependencies entirely
>>>> unspecified. Similarly, servers may incorporate dependency hints into very
>>>> sophisticated schedulers or ignore them entirely. The protocol
>>>> mechanisms for encoding dependencies are designed to be simple. But,
>>>> these mechanisms afford a very flexible set of policies depending on how
>>>> browsers and servers use them. This section expands on several policy
>>>> considerations.
>>>>
>>>> Transitioning between these dependency structures requires sending
>>>> REPRI messages for each image. Because updating the dependencies of
>>>> images is common, a client might create all image streams with a
>>>> placeholder dependency, yielding an initial configuration of:

---

From: William Chan (陈智昌) <[email-masked]>
Date: Sun, 3 Nov 2013 15:23:40 -0800

Also please consider a proxy. For example, a forward proxy that has
multiple browsers connecting through it to a single HTTP/2 capable origin.

On Sun, Nov 3, 2013 at 3:21 PM, Peter Lepeska <[email-masked]> wrote:

>>> Right. But my point is that an extremely simple scheme, where the
>>> browser just indicates that an object is blocking or not, gets you to the
>>> same place as the dependency scheme.
>>>
>>> Peter
>>>
>>>
>>> On Sun, Nov 3, 2013 at 8:54 AM, Martin Thomson <[email-masked]
>>> > wrote:
>>>
>>>>> an exception. The server policy today is to assume push streams are
>>>>> all low priority. Push or pull, the priority of a stream cannot be changed
>>>>> once created.
>>>>>
>>>>>    b.js blocks page layout. As another example, consider images
>>>>>    styled with display: none; once such styling is discovered during
>>>>>    parsing, associated image transfers should be deferred to prioritize
>>>>>    visible content.
>>>>>    - P: A bit indicating whether the following PriOrDep bits specify
>>>>>    a priority (P = 1) or a stream ID (P = 0) on which this new stream
>>>>>    depends.
>>>>>    - PriOrDep: Depending on the value of P, either the priority of
>>>>>    the new stream or a stream ID on which this new stream depends.
>>>>> value of PriOrDep; any 31 bit value is valid. Thus, a stream may
>>>>> refer to a dependency identifier that does not correspond to any current or
>>>>> Server push streams are assigned an initial parent at the discretion
>>>>> of the server. A conformant implementation SHOULD create a dependency on
>>>>> the push stream's associated-to-stream-id (§3.3.1<http://grmocg.github.com/SPDY-Specification/draft-mbelshe-httpbis-spdy-00.html#anchor20>
>>>>> ).
>>>>>
>>>>> REPRI:
>>>>>     0        1        2        3         4        5        6        7
>>>>>
>>>>> We expect most streams to have at most a single dependency, but this
>>>>> is not a protocol requirement. (Later, we describe scenarios where multiple
>>>>>    - ID 9 - SETTINGS_MAX_CONCURRENT_DEPENDENCY_SCHEDULING_NODESallows the server to indicate resource limits for dependency scheduling,
>>>>>    e.g., to limit memory consumption. A value of 0 indicates that the server
>>>>>    does not support dependency scheduling. (We expect most implementations
>>>>>    will select a value greater than or equal to MAX_CONCURRENT_STREAMS
>>>>>    .)
>>>>>    - ID 10 - SETTINGS_DEPENDENCY_SCHEDULING_NODE_TIMEOUT indicates
>>>>>    how long the server will maintain dependency nodes after creation. The
>>>>>    value is an interval in milliseconds. This allows the client to estimate if
>>>>> Because the streams associated with the transfers of tab1 and tab2
>>>>> have no parent, they are always scheduled before any lower level in their
>>>>> trees. But, bandwidth allocation among trees remains proportional as
>>>>> defined by the relative priority of roots. For example, if the transfer of
>>>>> This transfer schedule is suboptimal. Page rendering will complete
>>>>> only when style.css and b.js have completed, but receiving each of those
>>>>>    SYN_STREAM is another REPRI message rewiring style.css to depend
>>>>>    on b.js. This serializes the transfers (modulo the delay associated with

---

From: Yoav Nir <[email-masked]>
Date: Sun, 3 Nov 2013 23:31:51 +0000

Hi Peter. See inline.

On Nov 3, 2013, at 3:07 PM, Peter Lepeska <[email-masked]<mailto:[email-masked]>> wrote:

Hi Yoav,

Two things:

1) I think one of the reasons that HTTP has been "wildly popular" is its simplicity. I think we should only give that up if we have to. At the Hyatt bar last night I was talking to an IETFer who is focused on DNS but he has read the HTTP 2 draft and he mentioned that he loves the fact that he can open a telnet prompt and GET files using simple ASCII HTTP. I wouldn't be surprised to hear that 100,000 different HTTP client implementations exist. How many HTTP 2.0 implementations do we expect in 20 years by comparison?

[Yoav] I love that telnet ability as well, but that is part of HTTP/0.9. While I can type in "HTTP/1.1", this usually doesn't buy me anything. It's a nice feature of HTTP/1.0 and HTTP/1.1 that they kept this working, and I'm sorry to see it go. I think a simplified HTTP/2 (one resource at a time, no flow control, reject all server push) can be done as an undergraduate project.

2) HTTP 1.x will outperform HTTP 2.x under some conditions and in some implementations due to flow control. I'm worried that flow control HTTP 2.0 implementations will vary and I'll start spending a lot of time debugging HTTP-level flow control in addition to the TCP flow control I already spend a lot of time puzzling over. In addition, in the single stream case, TCP can do flow control much better b/c it gets receive window updates with every ack. Why is HTTP trying to tell the sender how much to send when TCP often knows much better? Flow control is a very complicated business. I think HTTP 2.0 should only do it when it must, and when there is a clear benefit.

I agree, and HTTP/2 allows the client to disable flow control. You can do this in the SETTINGS frame, and not worry about flow control at all. I would expect WGET to do this.

Thanks for asking,

Peter

On Sun, Nov 3, 2013 at 1:15 PM, Yoav Nir <[email-masked]<mailto:[email-masked]>> wrote:

Hi, Peter

Yoav

Email secured by Check Point

---

From: William Chan (陈智昌) <[email-masked]>
Date: Sun, 3 Nov 2013 15:40:41 -0800

I don't think Firefox sends a window update per data frame (I'd be
surprised). But as discussed previously, the data frame overhead is pretty
low, and having smaller frames lets you be more responsive (send control
frames as needed, interleave other perhaps higher priority data frames from
other streams, etc). See this email from Patrick from before:
http://lists.w3.org/Archives/Public/ietf-http-wg/2013JanMar/0650.html.

On Sun, Nov 3, 2013 at 3:18 PM, Peter Lepeska <[email-masked]> wrote:

>> > A related point...uploading and downloading large numbers of data
>> frames over the same connection is problematic b/c the WINDOW_UPDATE frames
>> will get blocked behind data frames in each direction,
>>
>> Bufferbloat at a lower layer is a problem.. But its the same problem for
>> a 2 TCP flow alternative
>>
>
>

---

From: Roberto Peon <[email-masked]>
Date: Sun, 3 Nov 2013 16:18:58 -0800

> How many HTTP 2.0 implementations do we expect in 20 years by comparison?
Having implemented both, I can tell you that it is much more difficult to
make an interoperable HTTP/1.1 implementation than it is to implement the
draft HTTP/2 stuff. Ease and reliability of implementation was the primary
reason for doing binary in the first place!

And yes, text is easier to debug than binary, however, it requires far, far
more debugging.

I have no way of predicting how many HTTP/1.1 implementations will exist in
 X years, but *shrug* I prefer to care about the impact it has where it is
implemented.

> think HTTP 2.0 should only do it when it must, and when there is a clear
TCP knows about TCP stuff, and not application-layer stuff. This creates
optimality problems all over the place. It might be possible to remove one
level of flow control if TCP implementations allowed for much more fine
grained window observation/control, but even then one must be careful since
you don't want to deadlock (and having flow-control apply to control
messages can cause that to occur)!

In any case, I think we all agree that implementations should only do flow
control when they are going to do a good job of it/it is required.

-=R

Thanks for asking,
>> Is there some use case where HTTP/2 is inferior?  I realize that a
>> minimal implementation is more complicated than a minimal implementation of
>> HTTP/1. But assuming you have both an HTTP/2 and an HTTP/1 implementation,
>> is there a reason to use the HTTP/1 in any case?
>>
>> Yoav
>>
>>
>

---

From: Patrick McManus <[email-masked]>
Date: Mon, 4 Nov 2013 02:39:36 -0500

Hi Peter,

On Sun, Nov 3, 2013 at 6:18 PM, Peter Lepeska <[email-masked]> wrote:

> as once per frame but that makes sense. Does Firefox do this?
>
Are you using smaller than max frames during large transfers in order to
> send window updates more frequently?
>

Firefox doesn't ack^h^h^hsend window updates all that frequently unless the
available window has gotten quite small and is therefore in danger of
running dry. However it does always use smallish frame sizes (4000 bytes
iirc) with minimal buffering so that if a higher priority message presents
itself (such as a window update) it can be sent post haste,

---

From: Peter Lepeska <[email-masked]>
Date: Mon, 4 Nov 2013 13:28:22 -0800

Reading more closely I see that I was wrong -- this scheme does allow for
more complex decision making. It supports changing between active tabs and
also supports distinguishing between html and blocking scripts. I'm all
about performance so I hate to be negative against any scheme that improves
performance, and I think this one would do so.

My only issue is with the level of complexity of the concept. But maybe the
additional complexity added is worth the performance benefit.

Thanks,

Peter

On Sun, Nov 3, 2013 at 3:23 PM, William Chan (陈智昌) <[email-masked]>wrote:

> On Sun, Nov 3, 2013 at 3:21 PM, Peter Lepeska <[email-masked]>wrote:
>
>> On Sun, Nov 3, 2013 at 1:30 PM, William Chan (陈智昌) <[email-masked]
>> > wrote:
>>
>>>> On Sun, Nov 3, 2013 at 8:54 AM, Martin Thomson <
>>>>>> Going through your example, would the prioritization at any instant
>>>>>> be any different if you simply assigned two priorities -- high for
>>>>>> resources that are blocking (the .js and the .css in your example) and low
>>>>>> for resources that are non-blocking (the .jpgs)?
>>>>>>
>>>>>> As far as the proposal's wordiness, I mostly view it as a straw man
>>>>>> to ignite discussion. I'm completely expecting that it will be ripped apart
>>>>>> :) I'm hoping to rely heavily on editors to make it much more succinct once
>>>>>> we reach some rough consensus. Or perhaps this was a subtle play on your
>>>>>> part to get me to do better editorial work before sending it to the group :)
>>>>>>
>>>>>> In sum, for many common scenarios, fixed priorities are not
>>>>>> sufficient to optimize the allocation of bandwidth among competing requests.
>>>>>>
>>>>>> Protocol changes
>>>>>>    a priority (P = 1) or a stream ID (P = 0) on which this new
>>>>>>    stream depends.
>>>>>> As in SYN_STREAM, the control frame header is standard, followed by
>>>>>> a P/PriOrDep label indicating an update to the 31 bit Dependency Id specified
>>>>>>    will select a value greater than or equal to
>>>>>>    MAX_CONCURRENT_STREAMS.)
>>>>>>    2. Resources that can be progressively rendered (e.g., images)
>>>>>>    are transferred concurrently and (re)configured to depend on
>>>>>>    parser-blocking resource transfers.
>>>>>>    - The SYN_STREAM for the index.htm request has a parent
>>>>>>    indicating a default priority (3) and a stream id of 1.
>>>>>> Suppose concurrent tabs are loading with a scheduling forest as
>>>>>> shown. When a user changes tabs, the browser simple sends a REPRIfor the stream associated with tab2.htm to, say, priority 8. (A batched
>>>>>> message might also reduce the priority of tab1.htm to weight 3.) Because
>>>>>> bandwidth allocation decisions are made tree-by-tree and level-by-level,
>>>>>> increasing the priority of tab2.htm effectively shifts capacity for
>>>>>> all resource transfers depending on tab1.htm to tab2.htm.
>>>>>>
>>>>>> - Server push
>>>>>> priority and dependencies of a resource as chosen by the server.
>>>>>> Much like the client, the server is free to adopt prioritization policies
>>>>>> to improve performance, e.g., by prioritizing pushes of styles over images.
>>>>>> In our examples, we consider a browser that configures dependencies
>>>>>> to reflect parser-blocking order for resources, updated as parsing
>>>>>> continues. We expect this to improve performance, but browsers are free to
>>>>>> deviate from this policy, and there may be good reasons to do so. For
>>>>>> example, if the parser-blocking order is highly dynamic (e.g., in response
>>>>>> to many JS events), the overhead of updating dependencies may not be worth
>>>>>> the cost, particularly for small transfers. A sophisticated client may base

---

From: Mike Bishop <[email-masked]>
Date: Mon, 4 Nov 2013 23:52:00 +0000

Continuing our conversation on push here....  I'm the one who pushed for SHOULD rather than MUST.  Because I own a component which sits between the application telling us to push and the wire, I can't comply with a MUST without inspecting and interpreting the HTML and headers being sent by the app calling me.  It's a SHOULD because non-compliance is dumb and wasteful, but not an interoperability issue.

As for the advantage or lack thereof to a proxy, the proxy should be doing its own pushes or receipt of pushes.  Given that in your scenario there's almost zero latency between the client and the proxy, it might make sense to never pass a push to the client and just let the server's pushes fill your cache.  You can then fulfill client requests from cache immediately.

You can't "kill" the request, because you might mess up the browser's state.  If you already pushed a copy, you clearly have it at the proxy, so just satisfy the request from cache again without passing it to the server.

Sent from Windows Mail

From: Patrick McManus<mailto:[email-masked]>
Sent: ?Sunday?, ?November? ?3?, ?2013 ?1?:?12? ?PM
To: Peter Lepeska<mailto:[email-masked]>
Cc: HTTP Working Group<mailto:[email-masked]>, Martin Thomson<mailto:[email-masked]>

Every push is speculative and risks wasting a window of bw. To me this just seems like a special case of that. Too much info asymetry to specify behavior.

On Nov 3, 2013 2:41 PM, "Peter Lepeska" <[email-masked]<mailto:[email-masked]>> wrote:
The main thing I'm trying to avoid is sending an object redundantly when it doesn't need to be. And at the same time not require push_promises to be sent before the frame that contains the reference to it.

Ideally we'd cancel the pulled request at the proxy because we know we've already sent a prefetched (server pushed) copy of the same object. The HTTP 2.0 proxy could then inform the browser that the pulled request was canceled via an error code that specifically indicates that the request was redundant with a pushed resource. This would remove the need for the RST_STREAM and eliminate the race.

Peter

On Sun, Nov 3, 2013 at 12:15 PM, Patrick McManus <[email-masked]<mailto:[email-masked]>> wrote:
either end can cancel any stream at any time. What is the specificinterop problem trying to be solved by proscribing exactly 1 stream to be rst and the other to be received? I'm not clear on that.

consider the case where the flow control window for the latter pulled stream is already bigger than the window associated with the earlier pushed stream. The benefits of being earlier might well be wiped out by the rtt needed to open that window.

Perhaps both streams are needed and none will be reset. (2 queries and a "cache" that is really just a ram fifo)

-P

On Sun, Nov 3, 2013 at 2:58 PM, Peter Lepeska <[email-masked]<mailto:[email-masked]>> wrote:
Proxies need consistency so they don't have to behave one way for one web browser and another way for another web browser, much like the days when IE6 incompatibilities required multiple implementations of web pages to work across browsers.

Peter

On Sun, Nov 3, 2013 at 10:00 AM, Martin Thomson <[email-masked]<mailto:[email-masked]>> wrote:

---

From: Peter Lepeska <[email-masked]>
Date: Mon, 4 Nov 2013 16:19:55 -0800

Hi Mike,

Thanks for the good discussion - so much more efficient in person.

"Given that in your scenario there’s almost zero latency between the client
and the proxy, it might make sense to *never* pass a push to the client and
just let the server’s pushes fill your cache.  You can then fulfill client
requests from cache immediately."

For the sake of not causing confusion on the list, I'd rather not go into
the specifics of the satellite two part proxy that I work on. After all,
one of the reasons I'm so excited about HTTP 2.0 is so I can push directly
to the browser.

Peter

On Mon, Nov 4, 2013 at 3:52 PM, Mike Bishop <[email-masked]>wrote:

>  Continuing our conversation on push here….  I’m the one who pushed for
> SHOULD rather than MUST.  Because I own a component which sits between the
> application telling us to push and the wire, I can’t comply with a MUST
> without inspecting and interpreting the HTML and headers being sent by the
> app calling me.  It’s a SHOULD because non-compliance is dumb and wasteful,
> but not an interoperability issue.
>
>  As for the advantage or lack thereof to a proxy, the proxy should be
> doing its own pushes or receipt of pushes.  Given that in your scenario
> there’s almost zero latency between the client and the proxy, it might make
> sense to *never* pass a push to the client and just let the server’s
> pushes fill your cache.  You can then fulfill client requests from cache
> immediately.
>
>  You can’t “kill” the request, because you might mess up the browser’s
> state.  If you already pushed a copy, you clearly have it at the proxy, so
> just satisfy the request from cache again without passing it to the server.
>
>  Sent from Windows Mail
>
>   *From:* Patrick McManus <[email-masked]>
> *Sent:* Sunday, November 3, 2013 1:12 PM
> *To:* Peter Lepeska <[email-masked]>
> *Cc:* HTTP Working Group <[email-masked]>, Martin Thomson<[email-masked]>
>
>  Every push is speculative and risks wasting a window of bw. To me this
> just seems like a special case of that. Too much info asymetry to specify
> behavior.
>
>>  Ideally we'd cancel the pulled request at the proxy because we know
>> we've already sent a prefetched (server pushed) copy of the same object.
>> The HTTP 2.0 proxy could then inform the browser that the pulled request
>> was canceled via an error code that specifically indicates that the request
>> was redundant with a pushed resource. This would remove the need for the
>>>  either end can cancel any stream at any time. What is the
>>> specificinterop problem trying to be solved by proscribing exactly 1 stream
>>> to be rst and the other to be received? I'm not clear on that.
>>>
>>>  Perhaps both streams are needed and none will be reset. (2 queries and
>>> a "cache" that is really just a ram fifo)
>>>
>>>  -P
>>>
>>>
>>>