Subject: SPDY Review

From: "Martin Nilsson" <[email-masked]>
Date: Thu, 07 Jun 2012 16:18:18 +0200

I've taken an internal assessment of SPDY and cleaned it up a bit  
(removing internal or 3rd party NDA information). Apologies in advance to  
any misunderstandings, mistakes or inaccuracies I've managed to produce.

			     SPDY review

1. Introduction

   Opera Software has a long experience of HTTP optimization protocols,
   both through our own products Opera Mini and Opera Turbo, but also
   from integrating with 3rd party optimization, predominantly in the
   mobile space. In this document we compare the features of SPDY with
   our implementation and deployment experiences from equivalent
   features of other protocols.

   We struggled a bit with the format of this document, as there are a
   lot of interdependencies between the protocol format and its
   different features. We've decided to present the review in three
   parts. First we look at the individual conceptual features of SPDY,
   directly followed by a quick evaluation for each. After that comes a
   short discussion of the binary serialization of the protocol.
   Finally we offer our ideas for how to improve the SPDY protocol.

   This document is a compilation of analysis and comments from
   multiple teams within Opera, and I would like to specially thank Per
   Hedbor, Markus Johansson and Jonny Rein Eriksen for their
   contributions.

   A review of the SPDY protocol, based on the ID
   draft-mbelshe-httpbis-spdy-00. Last update 2012-04-19.

2. Feature overview

   SPDY is a transport layer protocol that acts on top of TCP and
   replaces HTTP while allowing all HTTP semantics to be mapped onto
   SPDY. In addition SPDY provides

   - Enforced pipelining
   - Out of order response
   - Multiplexed requests and responses
   - Flow control
   - Header compression
   - Asynchronous headers
   - Push

2.1. Pipelining & response order

   Pipelining is very important to avoid the overhead of setting up new
   TCP connections. Limiting the number of connections is also
   beneficial for congestion control. HTTP pipelining is defined in
   HTTP 1.1 and Opera has spent considerable effort to make it work as
   widely as possible. Unfortunately quite a lot of equipment doesn't
   implement HTTP 1.1 correctly, so lots of heuristics has to be
   applied in real world scenarios.

   Given the non-uniform response times of different requests from the
   same server, due to different amount of backend work required to
   generate a response, pipelining is prone to stalling when a slow
   request blocks a faster request. Out-of-order response is a good
   solution to the problem. It can easily be added to HTTP by adding a
   request ID header in each request and expecting corresponding
   response IDs in the responses.

   By adding priority information to the requests the server can take
   active decision in which resource to send first.

2.1.1. Evaluation

   Pipelining and out-of-order response are two important concepts that
   significantly improves HTTP performance. Client indicated priority
   preference further enhances the protocol. It is worth noting that
   for implementation purposes, e.g. issues in underlaying software
   layers, multiple connections may be preferable to a single one.

2.2. Multiplexing

   The SPDY multiplexing feature allows for multiple resources to load
   in parallel over a single TCP connection. The benefit is that it
   offers a protection against stalling of prioritized
   resources. Stalling in this case doesn't mean that the connection is
   idle, but it could be downloading a large, low prioritized resource,
   when the client issues a request for a higher prioritized resource.

   An alternative to multiplexing would be to open a new connection and
   let the current one, with only low priority requests on it, starve
   until the high priority items have been handled. This is however bad
   from congestion control point of view, and resets any states, like
   compression contexts, associated with the first connection (although
   those could theoretically be copied to new connections). Also, since
   SPDY supports push, it may not be technically possible to initiate a
   new connection from the server to push a high priority resource to
   the client.

   Finally we can note that multiplexing in SPDY always incur a data
   overhead. The lower latency we want for higher priority requests to
   reach the other side, the higher the overhead will be.

2.2.1. Evaluation

   Multiplexing allows for higher priority requests/responses to
   interrupt lower priority uploads/downloads without OOB signaling
   that interferes with TCP.

   The SPDY specification offers no insight in how frame sizes should
   be chosen.

2.3. Flow control

   SPDY provides a per stream flow control mechanism by defining a
   recipient buffer size that the sender needs to keep track of. The
   recipient has to acknowledge received data by responding with the
   currently available buffer space. This feature can be used for
   several things.

   - Throttling of then entire connection due to one endpoint having
     capacity issues.

   - Dynamic reprioritization of streams.

   - Throttling of unwanted pushed content.

   - Throttling of a specific stream due to backend issues for that
     specific stream.

   - Throttling of a specific stream due to rate of consumption.

2.3.1. Evaluation

   While not stated in the SPDY specification what problem the SPDY
   level flow control aims to solve, Mike Belshe writes an example in
   his blog that stalling recipient of data as a situation where SPDY
   flow control is helpful, to avoid buffering potentially unbound
   amount of data. While the concerns is valid, flow control looks like
   overkill to something where a per-channel pause control frame could
   do the same job with less implementation and protocol overhead.

   To throttle the entire connection there is already data rate
   management implemented in TCP. It is possible to throttle specific
   streams, but that should already be taken care of by the priority
   settings. Dynamic reprioritization is possible, but would be better
   made into an explicit stream property. Throttling or avoiding pushed
   content is another reason, but again an explicit mechanism would be
   preferrable. For real time communication each sender already have
   the ability to let one stream starve other streams, though UDP would
   be preferrable over TCP. Also note that TCP provides the URG channel
   for exception messaging.

2.4. Header compression

   For many applications the HTTP headers are a significant
   overhead. This is most visible in the mobile space where the content
   itself often is heavily minimized for the lowest common denominator,
   while at the same time mobile devices can send huge amounts of
   UAProf headers in every request. Even on Desktop the amount of
   cookies sent for every request is significant. Header compression is
   a good solution to this issue.

   SPDY uses a binary representation of headers, encoded as a set of
   Hollerith encoded key-value pairs. The first line of the HTTP
   request is also broken into its components and sent as key-value
   pairs in the stream headers. To mitigate this somewhat less compact
   representation of the headers, SPDY compresses the headers with
   zlib, uses a persistent LZ-window for the connection and uses a
   static dictionary.

2.4.1. Evaluation

   Header compression is a good feature with real world applications,
   and deflate with persistent context is a good approach to achieve
   it. A fixed dictionary is probably not very effective as it
   complicates the implementation while only providing initial value to
   the compression. As an example, this is how the average requests
   sizes compares between HTTP and SPDY in different modes, using the
   set of captured headers used to train the current SPDY 3 dictionary.

     HTTP                             821.1
     HTTP zlib compressed             543.5
     HTTP compressed with dictionary  497.0
     SPDY                             913.7
     SPDY zlib compressed             606.5
     SPDY compressed with dictionary  517.0

   I.e. Just putting the HTTP request in a SPDY stream (after removing
   disallowed headers) only differs by 20 bytes to SPDY binary header
   format with dictionary based zlib compression. The benefit of using
   a dictionary basically goes away entirely on the subsequent request.

   For very constrained devices the major issue with using deflate is
   the 32K LZ window. The actual decompression is very light weight and
   doesn't require much code. When sending data, using the no
   compression mode of deflate effectively disables compression with
   almost no code. Using fixed huffman codes is almost as easy.

2.5. Asynchronous headers

   The HEADERS frame allows either side set additional headers for the
   request or response at any point while the stream is open. This
   differs from normal HTTP semantics where headers are sent strictly
   before any data, and at half duplex, and allows for parallel
   generation of headers and contents. While this is already possible
   to do with chunked encoding trailer, it is not a feature in popular
   use.

2.5.1. Evaluation

   The problem with this frame is that it creates a situation where a
   potentially critical header for the interpretation of the content is
   sent last, thus forcing the receiver to put data processing on hold.
   As additional headers can be sent up until the stream is closed
   (though it doesn't specify what is allowed on half-closed
   connections) this potentially makes all streams subject to last
   minute reinterpretations. The specification doesn't define the
   behavior when updating already sent headers. This feature also makes
   SPDY more vulnerable to protocol injection attacks.

2.6. Push

   SPDY allows the server to open a stream towards the client and
   effectively push content to the client. The idea is cache seeding,
   where resources likely or known to be requested soon will be pushed
   to the client. Server push has to happen as a result of an earlier
   client request, which must be explicitly linked.

2.6.1. Evaluation

   As defined the feature is not powerful enough to push non-request
   related content (such as new RSS items), while also lacking
   mechanisms to limit the size of pushed content or fully disable
   pushing. The client has the option to read and discard this
   information, but that may be a costly waste of bandwidth.

3. Binary representation

3.1. Control frame version

   The version field of the control frame is odd for several different
   reasons.

   - The field is huge, 15 bits, which given the rate of incompatible
   changes in released protocols (IPv6, HTTP 1.1 etc) appears
   unwarranted. Also, adding more room for the version field is easy if
   different versions are considered incompatible. The version field is
   meaningless if different versions are compatible.

   - The version is sent in every control frame, which appears overly
   redundant.

   - There is no clear semantics of how the version should be
   handled. While status code 4, UNSUPPORTED_VERSION, gives a clue that
   messages with unknown versions should be rejected, there is only a
   mechanism to do it for streams.

3.2. Field sizes

   The specification is consistently using 24 bit frame sizes but 32
   bit sizes for almost all counters and size fields for frame internal
   data. In design notes 4.4. "Fixed vs Variable Length Fields" the
   authors note that this is done for speed and simplicity. There is no
   reason why an 8, 16 or 24 bit field wouldn't be simple or fast
   enough, especially given the existence of 31-bit and 3-bit fields
   that also exists in the specification.

3.3. Directionality

   While the SPDY draft attempt to implement two independent layers, a
   general purpose framing layer with an HTTP-like layer on top of it,
   this separation creates some unneeded complexities. The two main use
   cases for SPDY is HTTP request-response and HTTP push. Both of these
   are unidirectional once established and both of them have some
   mandatory header fields that are more efficiently encoded in a fixed
   structure.

3.4. Stream header coding

   Multiple headers with the same name are encoded as a list of null
   separated values. This removes the possibility to store binary
   values in headers, which both prevents unencoded values and more
   natural representations of e.g. size, date, age, hash etc.

4. Proposed changes

   This section details some ideas for improvements of the SPDY draft.

4.1. Handshake

   We believe the versioning semantics needs to be better formalized,
   and that the version information can be moved into a connection
   handshake. In its simplest form a SETTINGS frame is always sent
   first in the connection, establishing the version and connection
   parameters. A connection should be rejected if the version is out of
   range for the server. The server should respond with the highest
   supported protocol version before closing.

4.2. Field sizes

   Define a reasonable range for each field, based on statistics where
   possible, and resize them where appropriate.

4.3. Specialized HTTP frames

   For the common case of using SPDY as an HTTP substitute, create
   special frames to open HTTP request-response and HTTP push
   streams. This removes the need for explicit unidirectional flag and
   mandatory header values.

4.4. Typed key-value pairs

   Create a better structure for the key-value pair lists where it is
   possible to have binary values and typed values. The types can
   include binary string, integer and list. Standardize how all
   standard HTTP headers should be normalized and typed, including
   which ones are disallowed to be in lists of multiple values.

   Introduce a mechanism that allows headers to be properties of the
   stream, to be used internally in SPDY, and move optional parameters
   and parameters that seldom deviate from default value to use
   internal headers (e.g. priority, slot, associate-to-stream-id). This
   also provides a mechanism for easy extension.

4.5. Push

   The client needs to be in control of what pushed data to accept. A
   simple accept flag may be too simplisitc, as it prevents tricks like
   redirect collapsing, but would be an improvement nevertheless.

4.6. Flow control

   Remove the SPDY flow control and instead introduce a control
   mechanism to actively put a stream on hold. If priority is moved to
   stream properties, as suggested in 3.4., dynamic reprioritization is
   possible.

4.7. Header compression

   Remove the header compression dictionary. It creates little benefit
   for the added complexity it introduces.

4.8. Asynchronous headers

   Specify the asynchronous header feature stricter so that overwriting
   HTTP headers isn't allowed and the receiver knows in advance what
   headers will be generated later.

/Martin Nilsson

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/

---

From: Martin Thomson <[email-masked]>
Date: Thu, 7 Jun 2012 09:12:24 -0700

Interesting, thorough and well-considered review.  A few opinions
included inline:

>  active decision in which resource to send first.

I don't think priority is as big a deal as people are making out.  On
the contrary, it's a distraction.

1. The server is probably more likely to know what resources need to
be acquired first.
2. The client has the ultimate control over what resources are
requested, so they already have control over priority (if resource A
is more important than resource B, just don't request resource B).

Beyond this, the main reason you might use priority is for large
concurrent representation (i.e., file) transfers.  Bittorrent has this
feature for torrents with multiple files.  The utility for HTTP is
somewhat limited.  That's not to say that it isn't a useful feature,
but I don't see it as a core necessity.

>  [...]  While the concerns is valid, flow control looks like

The problem with a pause frame is the time that it takes to propagate.
 During that time, you can end up getting a lot of data that you can't
do anything with.  Flow control is a well understood mechanism that
solves the problem.

I'm going to argue that flow control is the necessity and priority is
the unnecessary feature gold plating.

>  The problem with [asynchronous headers] is that it creates a situation where a

If you read the guidance on trailing headers (footers?), the key
message is that they should not be critical.  The same guidance should
apply to any asynchronous headers.

The utility of a trailer can be significant.  For instance, if you
have to calculate a hash of the representation, they represent a
significant performance gain.  In this case, I can imagine wanting to
send supplementary information after the representation; Link headers,
for instance.

> 2.6. Push

Is not sufficiently justified to warrant the significant change in
protocol semantics.

---

From: Julian Reschke <[email-masked]>
Date: Thu, 07 Jun 2012 18:33:42 +0200

On 2012-06-07 16:18, Martin Nilsson wrote:
> ...
> ...

Note: that doesn't work with caching.

But see the Assoc-Req header field described in 
<http://tools.ietf.org/html/draft-nottingham-http-pipeline-00#section-5> 
-- I think it's experimentally implemented in Firefox (which means it 
needs a spec :-)

Best regards, Julian

---

From: Alek Storm <[email-masked]>
Date: Thu, 7 Jun 2012 12:43:09 -0500

On Thu, Jun 7, 2012 at 9:18 AM, Martin Nilsson <[email-masked]> wrote:

> <snip>

SETTINGS frames are always optional, so we can't rely on them for
discovering unsupported versions. However, I agree that the "version" field
should only appear in SYN_STREAM frames, as the spec specifically states it
should be ignored in all others.

4.2. Field sizes
>  possible, and resize them where appropriate.

Agreed.

>  streams. This removes the need for explicit unidirectional flag and

The UNIDIRECTIONAL flag is set to be removed in spdy/4. Elsewhere, you
advocate moving information specific to request-response and pushed streams
to the headers section, which appears to conflict with this proposal.

>  which ones are disallowed to be in lists of multiple values.

This sounds like a can of worms. Depending on the serialization format you
look at, there's already a zoo of possible "types" to encode data as - and
what if you want something outside the norm, like JSON? The only problem
you raised with the current encoding is that binary data would have to be
escaped; this looks like overkill.

>  also provides a mechanism for easy extension.

I'll admit, the criteria for choosing which parameters become headers and
which become binary fields has always been a bit murky. It appears to
depend on whether the parameter is framing-specific, and whether it's
variable-length. I agree that this needs more discussion.

4.5. Push
>  redirect collapsing, but would be an improvement nevertheless.

The client can already RST_STREAM+CANCEL unwanted pushed streams (and may
do so selectively after reading their :scheme/:host/:uri headers). More
fine-grained control is the domain of cache directives.

4.6. Flow control
>  stream properties, as suggested in 3.4., dynamic reprioritization is

We've been discussing possible changes to the flow control mechanism on
spdy-dev, and this idea for a txon/txoff signal did come up. Although some
still support it, others (including myself) have pointed out that it
requires receivers to buffer at least a BDP's worth of data for each
stream. For endpoints sitting on high-bandwidth pipes that handle large
numbers of concurrent requests (like gateways or non-blocking servers),
this is logistically impossible.

4.7. Header compression
>  for the added complexity it introduces.

This paper (http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf)
claims 8% size reduction of the request header and an additional 15%
reduction of the reply header. Giving more detail on the benchmarks you
cited earlier would help us evaluate the differing results.

>  headers will be generated later.

Sending duplicate headers, whether within the same SYN_REPLY/HEADERS frame
or across HEADERS frames, is already explicitly disallowed, though perhaps
the language could be moved to a more prominent place in the specification.

Alek

---

From: William Chan (陈智昌) <[email-masked]>
Date: Thu, 7 Jun 2012 12:10:27 -0700

I'm glad to see that Opera has thought deeply about SPDY. I think this is
by and large a very reasonable analysis of SPDY, thanks for sharing this. I
think that issues like flow control and push are very interesting to
discuss and merit separate discussion threads, as is already happening with
push. For the rest, I've commented inline.

>  reach the other side, the higher the overhead will be.

I think I agree with you, but this paragraph is a bit short and I wanted to
ask for a clarification. When you say data overhead, you're referring to
the framing overhead, right? And when you say lower latency for high
priority requests requires higher overhead, you in particular mean that by
choosing smaller frame sizes, you have more opportunity to interleave, at
the cost of more framing overhead, right? If so, I agree.

>  The SPDY specification offers no insight in how frame sizes should

Yes, this is up to the implementation, which should be guided by the
concerns you raised in the previous section. Would you prefer that this
discussion were included in the spec?

>  - Throttling of a specific stream due to rate of consumption.

Just for everyone's reference, there's a lot of interesting SPDY flow
control discussion happening at
https://groups.google.com/forum/#!topic/spdy-dev/JB_aQPNI7rw/discussion.
There's a lot more to say here than just in these bullets :) Since this is
already being heavily discussed on spdy-dev@ and we're trying to figure out
our thoughts there, I don't feel particularly inclined reopen the can of
worms here until that discussion concludes.

>  almost no code. Using fixed huffman codes is almost as easy.

I'm happy that you agree with the use of header compression. As for the
details of header compression, I'm pretty open to tweaks and what not,
provided they're guided by data and implementation experience.

>  SPDY more vulnerable to protocol injection attacks.

Some discussion can be found here:
https://groups.google.com/d/topic/spdy-dev/bRkEsta9ovk/discussion<https://groups.google.com/forum/?fromgroups#!searchin/spdy-dev/HEADERS$20frame/spdy-dev/bRkEsta9ovk/0gFYlb8P_xUJ>

>  supported protocol version before closing.

I will freely admit the versioning issue may need some work, and this is
worth discussion. For Chromium, this has not been an issue since we only
deploy over TLS using the NPN extension which handles this negotiation for
us in a fairly clean manner. We haven't invested much effort on the
non-TLS-NPN deployment case.

>  possible, and resize them where appropriate.

"Define a reasonable range" :) I'm open to resizing fields. There's been
some amount of debate on certain fields on the spdy-dev@ mailing list.

>  streams. This removes the need for explicit unidirectional flag and

What do you mean by mandatory header values? Those are specific to HTTP
over SPDY, right? I'm not convinced about the necessity of baking in HTTP
assumptions into the core SPDY layer, rather than defining the mandatory
headers at the HTTP layering over SPDY level.

>  stream, to be used internally in SPDY, and move optional parameters

Did you mean properties of the session? Headers are already metadata for
the stream.

>  redirect collapsing, but would be an improvement nevertheless.

I'm open to trying to better define when a client accepts pushed data. A
primary concern here is the possible deployment of intermediaries that
out-right disable server push, so server push becomes no longer
realistically deployable on the internet. Of course, clients can already
RST_STREAM(CANCEL) server pushes, and it'd be unfortunate if intermediaries
always did this. There's definitely room for discussion here, as has
already started happening on Gabriel's thread.

>  stream properties, as suggested in 3.4., dynamic reprioritization is

Do you have implementation experience that justifies this suggestion? I'm
skeptical about this solution, which has been discussed on
https://groups.google.com/forum/#!topic/spdy-dev/JB_aQPNI7rw/discussion.
That said, it's a very worthwhile discussion to have.

---

From: Roberto Peon <[email-masked]>
Date: Thu, 7 Jun 2012 12:57:38 -0700

Martin-
Thanks for this, it is great!

>  features of other protocols.

Can you tell us more about your or Opera's operational experience with
equivalent features?
I'd be rapt at any such presentation!

>  Finally we offer our ideas for how to improve the SPDY protocol.

I'm interested in how you'd prefer it organized. Anything that makes it
clearer and easier to understand is always good.

>  Hedbor, Markus Johansson and Jonny Rein Eriksen for their

Thanks all!

>  layers, multiple connections may be preferable to a single one.

Also, browsers can eliminate heuristics about delaying the transmission of
requests, at least when tied with using one connection.

>  The SPDY specification offers no insight in how frame sizes should

We wanted to allow for implementations to do whatever seems right at the
time.
Any addition to the spec here would hopefully be a guideline and not an
implementation requirement.
2k-4k is fine for today, but if goodput is 10X higher in the future,
scaling this up reduces overhead by 10X.
Overhead isn't terribly large at either size-- with a 4k frame, you'll have
0.19% overhead due to the protocol overhead.

>  - Dynamic reprioritization of streams.

I'm convinced that allowing the client to announce a new priority for an
existing stream would be good. It shouldn't have to rely upon flow control
for that.

>  - Throttling of unwanted pushed content.

I'll talk about push soon. :)

>  - Throttling of a specific stream due to backend issues for that

This is the main real-world usecase, imho.

>  do the same job with less implementation and protocol overhead.

xon/xoff flow control seems difficult to get right.
It either gives you no guarantees about the amount of receiver-side
buffering, or it requires a prescient determination of the channel BDP,
which as far as I know isn't a solvable problem with current network
architectures :)

>  made into an explicit stream property.

Awesome, totally agree as you can see!

> Throttling or avoiding pushed
Does URG work? last time I looked, PSH, etc. was ignored by hardware that
I've had experience with. I'd be particularly suspicious of it working on
mobile devices given the lower-layer's attempts (mostly successful) to
cover up random loss at the radio level.

>  almost no code. Using fixed huffman codes is almost as easy.

I agree totally that better approaches on the compression side likely exist.
I'm surprised at the numbers, though. Our experience in the past was that
headers were significantly more compressed than you're seeing here.

>  information, but that may be a costly waste of bandwidth.
I'll talk about server push a bit later.

>  mechanism to do it for streams.
100% agreed.
There is a lot of room for improvement in various field sizes, and
elimination of repeated data.

>  mandatory header fields that are more efficiently encoded in a fixed

We'll hopefully put websockets over it as well. We've been suffering from a
lack of interested parties in websocket as it exists right now, and so a
lack of interest in making it go.

>  natural representations of e.g. size, date, age, hash etc.

Agreed. If I remember properly, interpretation of these fields is only
defined for HTTP streams, where we shouldn't be seeing binary in the keys
or values.
For a non-HTTP stream, the interpretation is whatever the implementation
decides to do.
Since the key/values are length-prefixed instead of token-based, any number
of nulls can be encoded.

>  supported protocol version before closing.

So long as it doesn't require the client or server to wait for an RTT
before sending data, sounds good!

>  streams. This removes the need for explicit unidirectional flag and

It moves mandatory values into mandatory frames, right?
I can see that we might achieve a small byte savings at the cost of making
it more difficult for proxies to deal with non-HTTP stuff in the future?
I guess I mean I don't see the advantage.

>  which ones are disallowed to be in lists of multiple values.
I'm not sure if this is necessary? Where would it be used?
Right now HEADERS has a definition of interpretation for HTTP, but if not
used for HTTP, since it uses length-prefix fields instead of token-based
fields, you can put anything in without worrying about escaping.

>  also provides a mechanism for easy extension.

Do you mean properties of the session as opposed to stream?
If so I heartily agree. At the last IETF, when I was talking to Willy, it
seemed that we both agreed that defining per-session, per-connection, and
per-stream headers would obviate much of the requirement for compression.
All of the compression stuff can use work.

>  redirect collapsing, but would be an improvement nevertheless.
There is a lot of confusion about server-push, which I hope to clear up :)
The server *always* gets to decide what to send. The client only gets the
choice to interpret it or ignore it.
The client is *never* in control of what it accepts. This is true of any
protocol, including HTTP/1.1 today.

SPDY's server-push allows for naming of the resources, and thus it allows
for them to be stored in the cache as separate objects.
In *all* other ways, server-push is 100% equivalent to inlining stuff in
your response.

To reiterate, server push is functionally equivalent to inlining while
identifying the resource name.
Are we suggesting that clients should have the ability to ignore inlined
data?
If not, then why would we be arguing against server-push as inlining and
server-push are mostly equivalent...

>  stream properties, as suggested in 3.4., dynamic reprioritization is

There is a lot of conversation happening around flow control right now on
the spdy-dev list, and I'd prefer to not have two separate conversations
about it :)

>  headers will be generated later.
I'm not actually familiar with the expected semantics for the
interpretation of chunk-extensions and trailers in HTTP/1.1.
Last time I looked it wasn't defined?

I'd be fine defining initial-headers, stream-metadata, and final-headers I
guess?
We all know about the usecases for initial-headers.
Stream-metadata will get interesting as we wish to provide integrity
security, checksums, etc. for streams.
final-headers could possibly useful for debugging and profiling responses
since it is the obvious place for a server to insert data about what it did
for you.

-=R

---

From: Mike Belshe <[email-masked]>
Date: Thu, 7 Jun 2012 19:11:09 -0700

> the contrary, it's a distraction.

I didn't put in priorities because I wanted them - I put them in because
the first version of SPDY, which didn't have them was slower than HTTP :-)
 The problem is that once the client can flood the server with requests,
the server gets inundated with a set of low priority (usually images) and
high priority requests. Without priorities, these all compete for the same
bandwidth leading to materially slower page load times.  I encourage you to
remove priorities and see this for yourself - it is evident with every
benchmark we ran.

> 1. The server is probably more likely to know what resources need to

Again, this is not true.  You should look into the resource loaders for
firefox or webkit before making such claims.  Only the browser knows which
resources are blocking rendering.  The client can prioritize best and MUST
be given a mechanism to tell the server which resources are needed first.
 This is actually an area where browsers can continue to improve.  The JS
file that the renderer is blocked on right now is more important than the
others.  Chrome, at least, doesn't yet make this distinction (but in the
future it could!)  Also, browsers are multi-tabbed beasts these days.  The
tab which the user is active on should have higher priority than all other
tabs.  The server, of course, has no idea which request is coming from
which tab or which tab is most important.

Of course, server implementors can ignore the browser hint (this is allowed
in the protocol today), but I strongly advise against it.

> is more important than resource B, just don't request resource B).

It's about the round trips, not the ordering.  100ms delays are simply not
acceptable anymore.

Mike

---

From: "Martin Nilsson" <[email-masked]>
Date: Fri, 08 Jun 2012 18:25:56 +0200

> the contrary, it's a distraction.

As Mike points out priority is of great importance from a browser point of  
view. Javascripts are executed in sequence on a page, and it is not  
uncommon for once script to load another one, or one style sheet to  
include another one. At the same time you have images from the main  
document being loaded. The relative importance of the resources can shift  
during the loading of the page as well, e.g. if the user started to scroll  
down the page and view new items.

> Is not sufficiently justified to warrant the significant change in

We can see several use cases for Push, but there needs to be better user  
agent control.

/Martin Nilsson

---

From: "Martin Nilsson" <[email-masked]>
Date: Fri, 08 Jun 2012 18:27:03 +0200

> to the headers section, which appears to conflict with this proposal.

Some of the proposals are mutually exclusive, yes.

> escaped; this looks like overkill.

One complaint that perhaps doesn't come across as clear as it should is  
that the current SPDY serialization takes more space than HTTP (c.f. table  
in 2.4.1). If you are moving away from HTTP, and thus not reusing existing  
protocol code, it's reasonable to consider alternative encodings as well.  
Types here doesn't refer to anything more exotic than the examples given  
(string, integer, list). To encode a time stamp like "Thu, 29 Apr 2010  
13:36:52 GMT" as a 64 bit integer doesn't appear as a radical suggestion  
to me.

> cited earlier would help us evaluate the differing results.

It claims an 8/15% improvement over the previous dictionary, but doesn't  
compare it with the no dictionary case. Doing some simple tests over 5000  
requests I see about 15% additional compression on requests and 25% on  
response headers for the first request. For subsequent requests dictionary  
only gives a few bytes extra savings. Somewhat better compression on the  
response side with about 10-20 bytes savings, but then dwarfed by the  
actual payload.

/Martin Nilsson

---

From: "Martin Nilsson" <[email-masked]>
Date: Fri, 08 Jun 2012 18:29:53 +0200

> I'd be rapt at any such presentation!

We have Opera Mini that uses several different protocols, both similar to  
HTTP as well as of the persistent TCP connection type. These are all  
binary protocols using different versions of request-response, RPC, push  
features, as well as compression of different sorts. We have Opera Turbo,  
which is essentially a modified HTTP with prioritized, out-of-order  
pipelining and some simple compression. Finally we have integrations with  
different 3rd party technologies, some of which are mentioned on the press  
release pages
http://www.opera.com/press/releases/2004/11/04/
http://www.opera.com/press/releases/2007/02/06/

Not really an answer to your question though, I'm afraid. I would need  
more time (and meetings) to collect that...

> headers were significantly more compressed than you're seeing here.

I'm using the same data as the  
http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf and when using  
the evaluation set they use I actually get somewhat better compression  
values (probably due to better header normalization).

/Martin Nilsson

---

From: "Martin Nilsson" <[email-masked]>
Date: Fri, 08 Jun 2012 18:27:51 +0200

> the cost of more framing overhead, right? If so, I agree.

Correct.

> headers at the HTTP layering over SPDY level.

The background for this suggestion is the assumption that HTTP will be a  
significant use case of SPDY that may be worth optimizing for, and that  
the current SPDY binary format isn't very size efficient. There were also  
some concerns about the generic approach to directionality, which no  
longer applies if that feature is being removed.

> Did you mean properties of the session? Headers are already metadata for

This is a request for separation between SPDY specific stream headers  
(priority, slot and associate-to-stream-id given as examples) and HTTP  
(stream) headers.

/Martin Nilsson

---

From: Mike Belshe <[email-masked]>
Date: Fri, 8 Jun 2012 12:10:59 -0700

On Fri, Jun 8, 2012 at 9:29 AM, Martin Nilsson <[email-masked]> wrote:

> HTTP as well as of the persistent TCP connection type. These are all binary
> protocols using different versions of request-response, RPC, push features,
> as well as compression of different sorts. We have Opera Turbo, which is
> essentially a modified HTTP with prioritized, out-of-order pipelining and
> some simple compression. Finally we have integrations with different 3rd
> party technologies, some of which are mentioned on the press release pages
> http://www.opera.com/press/**releases/2004/11/04/<http://www.opera.com/press/releases/2004/11/04/>
> http://www.opera.com/press/**releases/2007/02/06/<http://www.opera.com/press/releases/2007/02/06/>
>
> I'm using the same data as the http://www.eecis.udel.edu/~**
> amer/PEL/poc/pdf/SPDY-Fan.pdf<http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf>and when using the evaluation set they use I actually get somewhat better
> compression values (probably due to better header normalization).

The point of SPDY header compression is to use stateful compression.  If
you only compress one chunk of headers, you'll get modest savings - 30-50%.
 but on the second set, you get like 95% :-)  For SPDY sessions in steady
state, the typical size of a request is 50-60 bytes.  Almost everything,
including the cookies, compresses out.

Mike

---

From: "Martin Nilsson" <[email-masked]>
Date: Sat, 09 Jun 2012 00:30:09 +0200

On Fri, 08 Jun 2012 21:10:59 +0200, Mike Belshe <[email-masked]> wrote:

>> amer/PEL/poc/pdf/SPDY-Fan.pdf<http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf>and  
>> when using the evaluation set they use I actually get somewhat better

Yes, that is quite clear from the specification, and I noted "deflate with  
persistent context is a good approach" in the original text. The context  
here is about using a deflate dictionary, and then the subsequent requests  
compress almost equally well without dictionary. This is natural given how  
LZ77 works and the repetitive nature of HTTP headers. So if you are only  
making single requests on every SPDY connection, the dictionary gives you  
a 15-25% boost on the header compression. If you are making multiple  
requests you will however very quickly see the benefit over normal deflate  
disappear.

/Martin Nilsson

---

From: Mike Belshe <[email-masked]>
Date: Fri, 8 Jun 2012 15:55:42 -0700

On Fri, Jun 8, 2012 at 3:30 PM, Martin Nilsson <[email-masked]> wrote:

>>> amer/PEL/poc/pdf/SPDY-Fan.pdf<**http://www.eecis.udel.edu/~**
>>> amer/PEL/poc/pdf/SPDY-Fan.pdf<http://www.eecis.udel.edu/~amer/PEL/poc/pdf/SPDY-Fan.pdf>
>>> >**and when using the evaluation set they use I actually get somewhat
>>> better
>>>
> making single requests on every SPDY connection, the dictionary gives you a
> 15-25% boost on the header compression. If you are making multiple requests
> you will however very quickly see the benefit over normal deflate disappear.

OK.   Yes, we know that the dictionary only helps a small amount.  But it
does help.  The good news is that its basically free to use the dictionary,
so I don't really see any downsides.

Mike

---

From: Mike Belshe <[email-masked]>
Date: Sat, 9 Jun 2012 10:03:32 -0700

> more time (and meetings) to collect that...

I'd be interested to hear if Opera would ever open-source these protocols
and any reasons for why or why not that Opera would be willing to disclose.

> compression values (probably due to better header normalization).

I feel like we're getting caught up in noise here; looking at single block
compression is uninteresting.  In real world cases, with repeated cookie
blocks, the algorithm does great, at over 85% compression.  We can do
incrementally better and I'm not opposed to that.  But the use of the
dictionary or not is trivial and doesn't matter in the overall picture.

Is there something else you wanted to propose?

Mike

---

From: "Martin Nilsson" <[email-masked]>
Date: Mon, 11 Jun 2012 18:27:01 +0200

> so I don't really see any downsides.

I would guess that there are device manufacturers that would object
that 1k data for 100 bytes saving when establishing a connection is
not free nor worthwhile. That is not our main objection though.

The dictionary is a fixed magic number that has to go into every SPDY
implementation. Since the dictionary is not well researched there will
likely be future proposals for replacements. If approved this creates
either the necessity for some handshaking or a library of
dictionaries. Also, no matter how perfect we make it now, thinking of
all different existing user agents and use cases, it will lose its
relevance over time as these change.

I'm basing the assertion that it is not well researched on the fact
that it is easy to propose improvements on it. The most major ones
would be adding tokens like ":method", ":version" and ":scheme" to the
dictionary (they were not updated in the dictionary when the protocol
was changed between version 2 and 3, and gives an instant 2%
improvement) and to split the dictionary for the request context and
the recipient context, as the headers are mostly mutually exclusive.

If you look at the compressed data you will see that 50% of the
characters in the dictionary are used in less than 5% of the cases.
7% are never used, not even accidentally like creating " Apple" from
" Apr" and "Implemented".

Bottom line is that the cost is insignificant, the savings are
insignificant, but the maintenance is an issue.

/Martin Nilsson

---

From: "Martin Nilsson" <[email-masked]>
Date: Mon, 11 Jun 2012 18:28:45 +0200

> and any reasons for why or why not that Opera would be willing to  

We do not have any such plans at the moment.

> Is there something else you wanted to propose?

I'm more than happy to answer any questions I can. We'll try to think of  
how we can best help improving SPDY from this point forward.

/Martin Nilsson

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Mon, 11 Jun 2012 18:12:59 +0000

>insignificant, but the maintenance is an issue.

...and more importantly: LZ is a horrible compression to deal with
in hardware based designs, compared to pretty much anything else
in the entire realm of compression...

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
[email-masked]         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.