Subject: Some general SPDY feedback / questions

From: James M Snell <[email-masked]>
Date: Wed, 18 Jul 2012 13:35:48 -0700

Just need a few clarifications as I've been going through the spec... some
of these are probably obvious but I wanted to get the "official" answer...

1. Section 3.2 HTTP Request/Response is fairly under-defined.
   For example...
   - are all request headers REQUIRED to be contained within the SYN_STREAM
or can some be pushed off to additional HEADERS frames? Likewise with
SYN_REPLY frames.
   - is it possible to interleave HEADERS and DATA frames within a request
or response Stream? (I noticed discussion of this with regards to
server-push, but did not see any discussion of it with regards to regular
http methods)
   - Since SPDY effectively eliminates Transfer-Encodings, are Trailers
still allowed? That is, for example, what if I wanted to send a HEADERS
frame containing a Content-Integrity header following a set of DATA frames?

  (Personal Opinion: it should be possible to interleave HEADERS anywhere
into the stream. With a few specific exceptions, It should also be possible
to override a given headers value by sending another instance of the header
along later in the same stream. Doing so raises the possibility of more
efficient multipart encodings, incremental data-integrity checks, etc)

2. Just for the sake of clarity, what is the expected behavior if a
user-agent interleaves multiple modification requests to the same resource?
For instance:

   => SYN_STREAM(id=1,:method=PUT,:path=/my/resource)
   => SYN_STREAM(id=2,:method=DELETE,:path=/my/resource)
   => SYN_STREAM(id=3,:method=POST, :path=/my/resource)

   While this may appear on the surface to be a silly question, it speaks
to a fundamental issue of allowing unsafe/non-idempotent methods to be
multiplexed, particularly if the processing order for requests interleaved
on a single connection is indeterminate. From
draft-ietf-httpbis-p1-messaging-20 6.3.2.2:

     Clients SHOULD NOT pipeline requests using non-idempotent request
     methods or non-idempotent sequences of request methods (see Section
     2.1.2 of [Part2]).  Otherwise, a premature termination of the
     transport connection could lead to indeterminate results.  A client
     wishing to send a non-idempotent request SHOULD wait to send that
     request until it has received the response status line for the
     previous request.

3. How are Informational 1xx Status Codes handled? The current SPDY draft
does not appear to support "provisional responses".

4. Note that the Upgrade header as currently defined within HTTP/1.1 will
need to be revisited. In fact, as currently defined, Upgrade is
incompatible with SPDY.

5. There's a fairly obvious security DoS concern about allowing a user
agent to multiplex multiple ranged GETs over a single connection. See
draft-ietf-httpbis-p5-range-20 Section 7.1 on "Overlapping Ranges".

6. It's good that Section 5.4 deals with cache control validation with
server push but the requirement needs to be made stronger. If the
originating stream utilizes any content negotiation mechanisms at all, and
those mechanisms impact the selection of resources that are pushed to the
client, the *server* MUST include an appropriate Vary header with the
pushed content. Right now, the spec states only that "browsers MUST be
careful to inherit request headers" ... but that leaves out any possible
intermediary caches along the way, which can obviously cause major problems.

7. What methods can trigger a server push? For instance, if I send a POST
request, is it possible for the server to respond with a push? For example,
I send a POST to a server to modify an image. In response to the POST, the
server returns a 200 OK with a page describing the changes and pushes the
modified image resource in a separate stream. Or are pushes only triggered
by GET requests? What are the conditions in which a push would be
considered inappropriate?

- James

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Wed, 18 Jul 2012 21:03:51 +0000

In message <CABP7RbfFj__CeriiJA-caEda_h0K5b__oj6-zYRuA=[email-masked]>

>   => SYN_STREAM(id=3,:method=POST, :path=/my/resource)

This is entirely parallel to the same issue with respect to
tagged-queueing of requests to a disk drive and remote filesystem
operations.

You basically have three choices:

1. Make it automatic.

   Any non-idempotent operation is a synchronizing/stalling event
   that prevents reordering of other operations across it.

   The following request stream will always execute seqentially
   in this case:

   => SYN_STREAM(id=1,:method=GET,:path=/my/resource)
   => SYN_STREAM(id=2,:method=PUT,:path=/my/resource)
   => SYN_STREAM(id=3,:method=GET,:path=/my/resource)
   => SYN_STREAM(id=4,:method=DELETE,:path=/my/resource)
   => SYN_STREAM(id=5,:method=GET,:path=/my/resource)
   => SYN_STREAM(id=6,:method=POST, :path=/my/resource)
   => SYN_STREAM(id=7,:method=GET,:path=/my/resource)

2. Give the requestor a synchronizing primitive.

   Basically allowing the client to say "don't reorder anything
   across this marker, but continue to optimize on both sides"

   The following request stream will always execute seqentially
   in this case:

   => SYN_STREAM(id=1,:method=GET,:path=/my/resource1)
   => SYN_STREAM(id=2,:method=GET,:path=/my/resource2; sync=yes)
   => SYN_STREAM(id=3,:method=GET,:path=/my/resource1)

   (Notice that you can sync on an indempotent operation, this
   is deliberate, as it allows "cheap" NOP-sync operations.)

3. Leave the behaviour undefined.

   It's anyones guess what will happen.

In a web where client-side is non-participating in application logic
(ie: the good old fill-the-form-press-submit model), any of these
will do.

But we are increasingly seeing web-apps that actively participate
in, and have deep knowledge of the application logic on the
server side.

For those, number one is the safe choice, but it pessimizes needlessly
and number three will cost RTT's because the client has to wait for
operations to complete before issuing dependent operations.

That leaves the second option, and given the cheapness of implemenation
(You tag all requests with a generation number which increases after
every sync-tag, never sort higher generation before lower.) I think
that is the most future-proof choice for HTTP/2.0.

-- 
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.

---

From: Roberto Peon <[email-masked]>
Date: Wed, 18 Jul 2012 14:35:22 -0700

On Wed, Jul 18, 2012 at 1:35 PM, James M Snell <[email-masked]> wrote:

>    - are all request headers REQUIRED to be contained within the
> SYN_STREAM or can some be pushed off to additional HEADERS frames? Likewise
> with SYN_REPLY frames.
>

It depends.
For server push, split headers (i.e. some in SYN_REPLY, some in a HEADERS
frame) are expected.
For normal requests, this isn't the case.

One of the solutions that was discussed was to have a flag in any of the
header blocks on these frames which indicated that we'd entered a different
phase of metadata processing, e.g. once for the request or reply, then
another for trailers/chunk extension equivalent.

Here is the most recent discussion on the matter:
  https://groups.google.com/d/topic/spdy-dev/KO8rMMFGzd8/discussion
The changes mentioned here didn't get folded into the spec, but probably
should have.
The spec could and should be much clearer on this, and the protocol should
be changed to make it very obvious. :/

> server-push, but did not see any discussion of it with regards to regular

It is.

> frame containing a Content-Integrity header following a set of DATA frames?

We keep going round and round on that. It isn't well spec'd because no-one
who implements spdy client-side has yet had an implementation that would
use them.
Theoretically, you'd just use a header frame at the end.

> draft-ietf-httpbis-p1-messaging-20 6.3.2.2:

The spec doesn't define the behavior, as you've noted. The expectation is
that HTTP semantics w.r.t. non-idempotent methods will be preserved for
HTTP streams.
This is not optimal in a number of ways. Personally, I'd love to leave it
up to the application and provide more rich signaling as to when requests
were sent, response headers received, etc.

> does not appear to support "provisional responses".

Here is the most recent discussion on the matter (same one as before):
   https://groups.google.com/d/topic/spdy-dev/_DJSgQ-3PP0/discussion

> intermediary caches along the way, which can obviously cause major problems.

Sure, are you up for changing it to how you'd like it to read?
The most current version of the spec is hosted on Github here (and we make
changes to it there):

   https://github.com/mbelshe/SPDY-Specification/tree/gh-pages

> considered inappropriate?

Any request could trigger a push. The server cannot do a push until there
is a request, and all pushed resources are associated with one request,
though the responses could be used by multiple pages/page views.
-=R

---

From: Roberto Peon <[email-masked]>
Date: Wed, 18 Jul 2012 14:37:34 -0700

> that is the most future-proof choice for HTTP/2.0.

Even that one has its problems. What happens when the connection is for
multiple domains?
Is there a separate sequencing for each domain (that'd make sense as that
is what happens for HTTP).

In the end, I think that idempotent/non-idempotent determination by method
has become so polluted as to be unworkable, and applications should
probably just figure it out themselves by controlling when the requests are
issued (which is what they do today).
-=R

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Wed, 18 Jul 2012 21:45:59 +0000

In message <[email-masked]>

>is what happens for HTTP).

We actually dont need to specify that do we ?

If the two domains are independent, their transactions will not
interefere with each other as they end up in different places.  If
the are dependent, presumably they will end up the same place, and
the sync=yes will DTRT.

>issued (which is what they do today).

(= option 3 "make it undefined")

Yes, that is the simpler solution, but if we are serious about
shaving RTTs it is not a good choice.

---

From: James M Snell <[email-masked]>
Date: Wed, 18 Jul 2012 14:57:50 -0700

On Wed, Jul 18, 2012 at 2:35 PM, Roberto Peon <[email-masked]> wrote:

>> Just need a few clarifications as I've been going through the spec...
>> some of these are probably obvious but I wanted to get the "official"
>> answer...
>>

Yes, it definitely needs to be clearer. This is one of the areas where some
of the general concepts in the network-friendly-upgrade draft could come in
handy. It would be helpful to identify a primary set of headers that MUST
always appear within the SYN_STREAM or SYN_REPLY, but allow additional
headers to be specified in follow on HEADER frames, and only allow
duplicates in very specific cases.

SYN_REPLY(id=1, :status=100, :version=2.0)
...
HEADERS(id=1, :status=201, :version=2.0)
...

Another example... I've been exploring the theoretical possibility of using
spdy framing to provide an alternative to multipart/* packaging... imagine
the following response...

SYN_REPLY(
  id=1,
  :status=200,
  :version=2.0)
HEADERS (
  id=1,
  Content-Type: text/plain,
  Content-Length: 5)
DATA (id=1, "abcde")
HEADERS (
  id=1,
  Content-Integrity: 9b9af6945c95f1aa302a61acf75c9bd6,
  Content-Type: text/plain,
  Content-Length: 5)
DATA (id=1, "fghij")
HEADERS (
   flags: fin,
   Content-Integrity: d2d048a734af96bf0b7b1b24a431814a)

Yes, this is a change to existing HTTP semantics, but this kind of
optimization is definitely interesting... and not entirely insane.

>
>
>>    - is it possible to interleave HEADERS and DATA frames within a
>> request or response Stream? (I noticed discussion of this with regards to

Yes, that's it exactly. They should be allowed, period.

> were sent, response headers received, etc.

I'm fine with this for now but it needs to be stated explicitly in the
spec. Basically, a client SHOULD NOT multiplex non-idempotent requests.

>    https://github.com/mbelshe/SPDY-Specification/tree/gh-pages

I'll see if I can draft up some language.

> though the responses could be used by multiple pages/page views.

Ok.

Thanks for the responses... i'm sure I'll have lots more questions soon :-)

- James

---

From: "Manger, James H" <[email-masked]>
Date: Thu, 19 Jul 2012 14:01:36 +1000

> Another example... I've been exploring the theoretical possibility of using spdy framing to provide an alternative to multipart/* packaging... imagine the following response...
>
> SYN_REPLY(
>   id=1, 
>  :status=200, 
>  :version=2.0)
> HEADERS (
>  id=1, 
> Yes, this is a change to existing HTTP semantics, but this kind of optimization is definitely interesting... and not entirely insane.

Doesn't this badly clash with your desire to send trailer in later HEADERS? When does HEADERS introduce a new part and when does it just provide more metadata for the current part?

The PUSH mechanism might be a good alternative to multipart/* packaging. Make the reply a list of URIs of the parts, and push each part.

--
James Manger

---

From: James M Snell <[email-masked]>
Date: Wed, 18 Jul 2012 22:37:14 -0700

Yes yes... details details ;) the intent of the question and the example is
primarily to draw out information about the spdy designers original intent.
The spdy framing model opens many possibilities about what could be done
but is silent in many ways on what should. So far, to me, it seems like a
great place to start but I want to get a better sense of what issues the
authors have or may not have considered.
On Jul 18, 2012 9:01 PM, "Manger, James H" <[email-masked]>
wrote:

> > Another example... I've been exploring the theoretical possibility of
> using spdy framing to provide an alternative to multipart/* packaging...
> imagine the following response...
> >
> > SYN_REPLY(
> >   id=1,
> >  :status=200,
> >  :version=2.0)
> > HEADERS (
> >  id=1,
> Doesn't this badly clash with your desire to send trailer in later
> HEADERS? When does HEADERS introduce a new part and when does it just
> provide more metadata for the current part?
>
> The PUSH mechanism might be a good alternative to multipart/* packaging.
> Make the reply a list of URIs of the parts, and push each part.
>
> --
> James Manger
>

---

From: James M Snell <[email-masked]>
Date: Wed, 18 Jul 2012 23:37:15 -0700

On Jul 18, 2012 2:35 PM, "Roberto Peon" <[email-masked]> wrote:
>[snip]
>> 3. How are Informational 1xx Status Codes handled? The current SPDY
draft does not appear to support "provisional responses".

Thank you for the reference to the thread. After reading through it one
thing became obvious: while it would likely not be difficult to provide
support for a 100-continue like mechanism within spdy, the protocols
current design would essentially require a suboptimal hack in order to
retain existing http/1.1 semantics and preserve spdy-to-http1.1 pass
through or would require that we design a new similar mechanism, optimized
for spdy that changes an aspect of http/1.1 semantics.

As Mark  has pointed out recently, however, our job here currently is to
only define a new transport for http and not to change existing http
semantics. So i am at a bit of a loss as to what the charter will let us do
in this case.

Mark... any guidance?