Subject: Re: [hybi] Framing take III

From: Sylvain Hellegouarch <[email-masked]>
Date: Sun, 1 Aug 2010 12:13:34 +0200

On Sun, Aug 1, 2010 at 8:15 AM, Willy Tarreau <[email-masked]> wrote:

> Hi Greg,
>
> On Sun, Aug 01, 2010 at 09:13:41AM +1000, Greg Wilkins wrote:
> > I agree a ping request and ping response op-code is the best way to
> prevent
> > loops (names leave a little to be desired).
>
> Agreed the names are a bit odd. You could use an "AYT" (Are You There)
> message for the request and IAT (I Am There) for the response of the
> unsollicited message. I believe it's telnet which uses this terminology
> but I may be wrong as I've not worked on it for some time. At least it
> clearly states the intent of each messages.
>

What about ping for the request and pong for the response ? Unless folks
feel uncomfortable on naming unsolicited messages "pong".

-- 
- Sylvain
http://www.defuze.org
http://twitter.com/lawouach

---

From: Patrick McManus <[email-masked]>
Date: Sun, 01 Aug 2010 10:11:38 -0400

On 8/1/10 2:15 AM, Willy Tarreau wrote:
> Indeed, my feeling is that it will be harder to implement on senders because
> they'll have to count data sent + padding and could easily get it wrong
The technical reasoning is fairly complex, but the actual protocol 
adjustment is dead simple.

padding = round length up to multiple of four.

I'm pretty sure anyone that can grok a handshake algorithm full of 
nonces and transforms can handle rounding up to four.
> as cheap as the ntohs() which would be required on many platforms anyway.
>    
imo, the answer to that is the length should be little endian and the 
byte conversion will be a nop for most people, tradition be damned. As 
you say - most implementations want it in little endian, so let's save 
all the useless conversions to and from network order on both ends. A 
good optimization.

Its true that this stuff is about optimizations for high volume 
implementations, and certainly not as big of a deal as using a fixed 
length framing format to begin with, but web applications have a 
historical need for great scalability. Websockets isn't going to be 
different. I feel that alignment is a good technical reason and 
technical points are the raison d'etre of the working group.

This is exactly the kind of stuff you cannot fix through extensions and 
versioning later on because clients don't have an incentive to rewrite 
their code the way centralized servers do. If the complexity of writing 
it the more efficient way the first time is roughly the same (which in 
this case it is) I don't see the argument for deploying and supporting 
the less capable version.

---

From: Willy Tarreau <[email-masked]>
Date: Sun, 1 Aug 2010 17:08:21 +0200

> padding = round length up to multiple of four.

oh I clearly see how to pad, it's just that I think it adds complexity
for some users. Well in fact this should lie in the low-level API that
users will rely on and it would probably be transparent to them.

> nonces and transforms can handle rounding up to four.

that's a good point ;-)

> all the useless conversions to and from network order on both ends.

It would be a wrong choice to switch to little endian, because there are
primitives to handle big-endian in every network stack, while there aren't
the equivalent to manipulate little endian in big endian machines. Anyone
is able to manipulate 16- or 32-bit big endian words at very low cost, and
networking hardware is designed that way too.

Regards,
Willy

---

From: Scott Ferguson <[email-masked]>
Date: Sun, 01 Aug 2010 11:22:29 -0700

Greg Wilkins wrote:
>
> I hear/share Scotts concerns about how are multiple extensions going 
> to work and share a limited op code space. Having an extra opcode 
> octet may decrease the chance of collisions, but it would not remove 
> it, so we would still need to have some kind of central register of 
> extensions (which would be a pain and difficult to administer and a 
> drag on innovation).

Exactly.

>
> This is kind of complex and it may be far far simpler just to 
> allocated core op-codes for known things like meta-data and 
> multiplexing.  Maybe we need to do a thought experiment and list every 
> conceivable extension that might need an op-code within header rather 
> than body and see how many there actually are. If the number is small 
> then let's avoid a complex ext op-code allocation mechanism.

Here's one idea: define a standard extension-data payload for opcode %x03 as

  mycom.CrazyExperimentalExtension LF
  <binary-data>

The extension-data grammar is

  extension-data := NAME_CHAR+ LF OCTET*

The name addresses the conflict/registry issue, and the OCTET* lets the 
extension define any payload it needs.

The very few standard performance-critical extensions like multiplexing 
would still get their own opcode(s) out of the core 32 for efficiency.

-- Scott

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 2 Aug 2010 08:58:10 +1000

Scott,

If we define a standard op-code for a meta data packet, then we can put
arbitrary header values into that, which should support many  different
extensions using field names to avoid collisions.

Even something like multiplexing could be done this way, but I do thing that
it has enough standing to be allocated it's own op-codes.

So maybe we can just call the unused bits undefined (for use by future
versions of the protocol), rather than as being available for extension.
Extensions can use a standard meta-data message.

cheers

On 2 August 2010 04:22, Scott Ferguson <[email-masked]> wrote:

> Greg Wilkins wrote:
>
>>
>> I hear/share Scotts concerns about how are multiple extensions going to
>> work and share a limited op code space. Having an extra opcode octet may
>> decrease the chance of collisions, but it would not remove it, so we would
>> still need to have some kind of central register of extensions (which would
>> be a pain and difficult to administer and a drag on innovation).
>>
>
> Exactly.
>
>
>
>> This is kind of complex and it may be far far simpler just to allocated
>> core op-codes for known things like meta-data and multiplexing.  Maybe we
>> need to do a thought experiment and list every conceivable extension that
>> might need an op-code within header rather than body and see how many there
>> actually are. If the number is small then let's avoid a complex ext op-code
>> allocation mechanism.
>>
>

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Sun, 1 Aug 2010 16:35:47 -0700

Here's another thought, and it's relatively fresh in my mind and I haven't
given it much consideration, so apologies in advance if it's a horrible
idea.

Right now, we essentially have something like <type> <length> <data>, where
we assume that <length> and <type> are of fixed-length. I don't want to get
into any length-of-length things here, but what if we did something like the
following?

During the handshake, we negotiate whatever extensions are known and
accepted by both ends. Let's imagine that we decide on E-1, E-2, and E-3
(and I will for now leave the mechanism by which we agree on the extensions
out-of-scope). All three are well defined and both the client and the server
have the same expectation of how they operate. E-1 requires the use of 3
bits in the frame, E-2 requires the use of 4 bits, and E-3 does not require
the use of any bits in the framing. We assume that there is an ordering of
extensions (this might be necessary for e.g. encryption and compression, or
it might not but we enforce one anyways using e.g. whichever extension name
is alphabetically first.) As there is a total of 7 required bits, we assume
that the first one byte after <length> is a byte used by the extensions,
with E-1 having the high 3 bits and E-2 having the next 4 bits to use in
this, with the low bit undefined. We have no length indication in the
framing itself for the "extension bytes", instead we calculate it based on
our knowledge of the agreed-upon extensions.

Any intermediaries unaware of the the extensions that had been negotiated
would presumably not have trouble as it still carries the normal type +
length indicators and these remain valid (assuming <length> includes the N
bytes for however many bytes are required by extensions). At the same time,
we now have some amount of extensibility if the extensions need to indicate
something in the framing.

Thoughts?

On Sun, Aug 1, 2010 at 3:58 PM, Greg Wilkins <[email-masked]> wrote:

> Even something like multiplexing could be done this way, but I do thing
> that it has enough standing to be allocated it's own op-codes.
>
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi
>
>

---

From: Greg Wilkins <[email-masked]>
Date: Mon, 2 Aug 2010 16:29:35 +1000

2010/8/2 Ian Fette (イアンフェッティ) <[email-masked]>
> out-of-scope).

I think it is going to be really  hard to evaluate all the possibilities for
extensible op-codes unless we have some use-cases for E-1, E-2, and E-3.
 I don't think compression is one, as it should be part of the core
protocol.  Multi-plexing maybe, but it also has a case to at least be
defined within the scope of the core protocol.    Do we have any other
examples of extensions that could only be done well by having access to bits
and/or op-codes in the header of a frame, and that could not be done with a
meta-data frame?

My feeling is that even moderately complex op-code extension mechanisms
might make it harder to get consensus on the core framing.

I think that we have reasonable consensus on something like:

  +---------------------------------------+
  | frag(1) | opcode(7) |  Length(16)     |
  +---------------------------------------+
   |                Data                   |
  +---------------------------------------+

    ws-frame            = frame-fragment
                          frame-opcode
                          frame-length
                          octet-data

    frame-frament       = %x0 ; not a fragment
                        | %x1 ; fragment

    frame-opcode        = %x00 ; text data frame
                        | %x01 ; binary data frame
                        | %x02 ; ping
                        | %x03 ; pong
                        | %x7f ; final frame

    frame-length        = %x0000-FFFF

    octet-data          = *( %x00-FF )

This gives us an underutilized op-code space with no clear way of how to
allocate that to extensions, which is not unlike the current situation with
the frame-type byte in current protocol.  I think this represents a minimal
conversion of the current framing to length based framing.

Personally I think we could do OK with something as simple as this and put
all extensions into generic meta-data frame definted as an opcode.

But if we want to go a little more complex, then there have been some
acceptance of compression and padding proposals, that together with
meta-data  would give something like:

  +-----------------------------------------------+
  |frag(1)|comp(1)|opcode(6)| Length(24)          |
  +-----------------------------------------------+
   |                     Data                      |
  +-----------------------------------------------+
  |  Data(0|8|16|24)  | 0xff Padding(8|16|24|32)  |
  +-----------------------------------------------+

    ws-frame            = frame-fragment
                          frame-compressed
                          frame-opcode
                          frame-length
                          octet-data
                          data-padding

    frame-frament       = 0 ; not a fragment
                        | 1 ; fragment

    frame-compressed    = 0 ; not compressed
                        | 1 ; compressed

    frame-opcode        = 0x00 ; text data frame
                        | 0x01 ; binary data frame
                        | 0x02 ; ping
                        | 0x03 ; pong
                        | 0x04 ; message meta-data
                        | 0x05 ; connection meta-data
                        | 0x7f ; final frame

    frame-length        = %x0000-FFFF

    octet-data          = *( %x00-FF )

    data-padding        = %xFF | %xFFFF | %xFFFFFF | %xFFFFFFFF

I've interpretted the extra padding to always have at least one %xFF, so
that it can be used as a sentinel and as protection against injection.

I've used the space in the header for extra frame length, but it could
equally be used for:

   - more op-codes
   - an opcode extension mechanism
   - a channel ID
   - a checksum
   - a %x00 sentinel

The compression alg could just be gzip or negotiated in the handshake.

However, before we get carried away defining more framing features, I would
point out that we would not have to add very much more before we had
reinvented SPDY framing, which current has a control frame like:
   +----------------------------------+
  |1| Version(15)   | Opcode(16)     |
  +----------------------------------+
  | Flags (8)  |  Length (24)        |
  +----------------------------------+
  |               Data               |
  +----------------------------------+

and a data frame like:
   +----------------------------------+
  |0|       Stream-ID (31bits)       |
  +----------------------------------+
  | Flags (8)  |  Length (24 bits)   |
  +----------------------------------+
   |               Data               |
  +----------------------------------+

If we really are thinking about adding mutliplexing etc. in the core
protocol, then we really should consider some kind of convergence with SPDY
(or  them with websocket).

cheers

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Sun, 1 Aug 2010 23:45:24 -0700

On Sun, Aug 1, 2010 at 11:29 PM, Greg Wilkins <[email-masked]> wrote:

> I think it is going to be really  hard to evaluate all the possibilities
> for extensible op-codes unless we have some use-cases for E-1, E-2, and E-3.
I guess I was trying to plan for the case where multiplexing got kicked out
of the base protocol and into an extension, at which point you have a choice
of indicating the stream in in each frame or via a control frame that
switches the context of the overall connection - the advantage of having the
stream ID in each frame is that you carry (slightly) less state on the
server, and may be slightly better if you're imagining that the context
switches frequently, e.g. you have a number of connections all sending
smaller amounts of data. For that case, you may want more than just a few
bits in the frame, such as SPDY which you mention.

> I think that we have reasonable consensus on something like:

There have been many talks here at Google about websockets-over-spdy. I
certainly find it interesting, that said I don't want to necessarily tie
WebSockets to SPDY as WS seems to have a bit more traction at the moment in
terms of deployment.

---

From: Scott Ferguson <[email-masked]>
Date: Mon, 02 Aug 2010 09:29:52 -0700

Greg Wilkins wrote:
> Scott,
>
> If we define a standard op-code for a meta data packet, then we can 
> put arbitrary header values into that, which should support many  
> different extensions using field names to avoid collisions.

Overloading the %x02 meta-data frame itself as an extension frame would 
be a mistake, I think, because the meta-data frame has a nice clear, 
simple purpose.

But we could certainly use a key: value syntax for a %x03 extension frame.

There are a few reasons I'm leaning against that key: value syntax, though

  a) It forces the implementation to build a map of the <key, value>.  
There may be a future need where that performance penalty might be a 
problem.

  b) It makes the implementation of the dispatching a little more 
complicated, presumably using a filter system of the extensions to 
process that map, rather than dispatching directly to the extension.

  c) It restricts the value to a line-based value, instead of leaving it 
entirely open to the extension.

Those are just cautions, though. A key: value extension syntax would be 
reasonable.

>
> Even something like multiplexing could be done this way, but I do 
> thing that it has enough standing to be allocated it's own op-codes.

Yep.

> versions of the protocol), rather than as being available for 
> extension.  Extensions can use a standard meta-data message.

I think that's a good idea. I'd rather call it something like an 
extension frame, though, because extensions aren't necessarily 
meta-data. An authentication extension isn't meta-data.

-- Scott

---

From: Scott Ferguson <[email-masked]>
Date: Mon, 02 Aug 2010 09:59:12 -0700

Ian Fette (イアンフェッティ) wrote:
> On Sun, Aug 1, 2010 at 11:29 PM, Greg Wilkins <[email-masked] 
> <mailto:[email-masked]>> wrote:
>
>
>     2010/8/2 Ian Fette (イアンフェッティ) <[email-masked]
>     <mailto:[email-masked]>>
>
>         During the handshake, we negotiate whatever extensions are
>         known and accepted by both ends. Let's imagine that we decide
>         on E-1, E-2, and E-3 (and I will for now leave the mechanism
>         by which we agree on the extensions out-of-scope).
>
>
>     I think it is going to be really  hard to evaluate all the
>     possibilities for extensible op-codes unless we have some
>     use-cases for E-1, E-2, and E-3.    I don't think compression is
>     one, as it should be part of the core protocol.  Multi-plexing
>     maybe, but it also has a case to at least be defined within the
>     scope of the core protocol.    Do we have any other examples of
>     extensions that could only be done well by having access to bits
>     and/or op-codes in the header of a frame, and that could not be
>     done with a meta-data frame?
>
>     My feeling is that even moderately complex op-code extension
>     mechanisms might make it harder to get consensus on the core framing.
>
>
> I guess I was trying to plan for the case where multiplexing got 
> kicked out of the base protocol and into an extension, at which point 
> you have a choice of indicating the stream in in each frame or via a 
> control frame that switches the context of the overall connection - 
> the advantage of having the stream ID in each frame is that you carry 
> (slightly) less state on the server, and may be slightly better if 
> you're imagining that the context switches frequently, e.g. you have a 
> number of connections all sending smaller amounts of data. For that 
> case, you may want more than just a few bits in the frame, such as 
> SPDY which you mention.

It sounds like we really do need that multiplexing discussion to happen 
soon, because we could either pre-allocate channel/stream bits in the 
frame flags following Ian's idea (a 4 byte header), or use separate 
opcodes, like a switch model (a 3 byte header).

With Ian's model the core frame header might be something like:

  +---------+-----------+--------------+-------------+
  | frag(1) | opcode(5) | reserved(10) | length (16) |
  +---------+-----------+--------------+-------------+

where the multiplexing extension activates stream(7) bits and 
compression activates compress(1) and 2 remain reserved.
>
>
>
>     But if we want to go a little more complex, then there have been
>     some acceptance of compression and padding proposals, that
>     together with meta-data  would give something like:
>

I'd like to caution against padding, because the few cycles saved with 
alignment are insignificant for an application server because of the 
application's own code, and on the browser the JavaScript/rendering time 
swamps any alignment saving time.

Before going forward on padding, it would be good to have some 
measurements on intermediaries to see how much performance we'd gain, 
remembering that it's really only a single 16-bit short that might be 
misaligned.

-- Scott

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 3 Aug 2010 08:50:26 +1000

On 3 August 2010 02:59, Scott Ferguson <[email-masked]> wrote:

> soon, because we could either pre-allocate channel/stream bits in the frame
> flags following Ian's idea (a 4 byte header), or use separate opcodes, like
> a switch model (a 3 byte header).
>

I'll try to sketch up a minimal multiplexing semantic later this week... or
somebody else can preempt me...

> where the multiplexing extension activates stream(7) bits and compression
> activates compress(1) and 2 remain reserved.
>
>>

Hmmm, Ian(f)s proposal does not look so complex when expressed like that,
but the reserved space looks a little tight. Although I'd put the reserved
between the frag and the opcode so  that a) the opcode is word aligned (for
easy reading of hex) and the reserved bits could be used for either more
flags or a larger opcode in the future.   Also, with extension I think we
could initially limit ourselves to just 3 opcode bits:

+---------+-----------+--------------+-------------+
|frag(1)|ext(12)|op(3)|           length (16)      |
+---------+-----------+--------------+-------------+

%x0 text data frame
%x1 binary data frame
%x2 ping
%x3 pong
%x4 message meta-data (eg content-type)
%x5 connection meta-data (eg timeouts )
%x6 extension frame
%x7 final frame

The meta-data frames could be name value pairs - but potentially length
encoded rather than CRLF sentinel encoded.
I've included a connection meta-data not because I think connections really
need to change meta-data mid-stream, but so that we can support handshake
mechanisms (eg TLS) that do not support arbitrary meta-data exchange.

Some example frames (with padding see below):

text:   0x000B 'Hello World'  0xff
frags:  0x8006 'Hello '     0xffff
        0x0005 'World' 0xff 0xffff
binary: 0x0110 0x0123 0x4567 0x89AB 0xCDEF 0xffff
ping:   0x0200 0xffff
pong:   0x0300 0xffff
meta:   0x0420 'Content-Type: application/json' CR LF 0xffff 0xffff
final:  0x0700 0xffff

The extension frame could simply be a extension name, ID (or dynamic ID)
followed by arbitrary data meaningful only to the extensions. We could
reserve some extension ID space for protocol extensions so that future
versions of the protocol.

> swamps any alignment saving time.

I tend to agree that on it's own padding is not all that compelling.
However, having 1-4 0xff padding bytes does also provide:

   - validation that the framing is in sync
   - some protection against injection.
   - an 8 byte minimum frame size, which for performance minded people fits
   in a 64 bit word

Taken together, these are a little more convincing, but they still do not
shout "must have" at me, but if the header is already word aligned, then
it's not very onerous either.

cheers

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Mon, 2 Aug 2010 17:29:02 -0700

> could initially limit ourselves to just 3 opcode bits:

This assumes you want to force the extension metadata into a separate frame.
That may not be desirable, especially if the data switches back and forth,
as now I have two frames for every message. What I was actually proposing
was something more like:

+-----------------------------------------------+
|frag(1)|comp(1)|opcode(6)| Length(24)          |
+-----------------------------------------------+
|      Extensions (0|8|16|24|32|...)            |
+-----------------------------------------------+
|                     Data                      |
+-----------------------------------------------+
|  Data(0|8|16|24)  | 0xff Padding(8|16|24|32)  |
+-----------------------------------------------+

 where the length of Extensions is calculated and is fixed across all frames
exchanged between a client and server, and is calculated based upon the
extensions the client and server have agreed to. This has the advantage that
to anyone who is unaware of the extensions, it looks just like data that
will not be interfered with.

(We can go back and forth about whether the padding is a good idea, that's a
bit orthogonal to what I was trying to propose.)

>    - an 8 byte minimum frame size, which for performance minded people
>    fits in a 64 bit word
>

---

From: "Thomson, Martin" <[email-masked]>
Date: Tue, 3 Aug 2010 08:48:00 +0800

> %x5 connection meta-data (eg timeouts )

I really, really don't like the idea that there is state accumulated in this fashion.  It makes implementations much more fragile.

It's also unnecessary.  This sort of thing can be punted.

--Martin

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 3 Aug 2010 11:06:06 +1000

On 3 August 2010 10:48, Thomson, Martin <[email-masked]> wrote:

> I really, really don't like the idea that there is state accumulated in
> this fashion.  It makes implementations much more fragile.
>

Martin,

I think whether we like it or not, connections will be somewhat stateful and
message meta-data is an oft requested feature that will need to be supported
either in the core protocol or a standard extension.

So I don't think we can simply punt either of them with out a counter
proposal for how they can be supported (not necessarily as part of the core,
possibly as an extension).

For connection meta data, I'm not saying that we should support arbitrary
changes to the negotiated connection state, simply that we need a way to
exchange connection state if the HTTP headers of the handshake are not
available (eg if we establish with TLS next protocol).  This is not to say
that we should allow connection meta-data to be changed at any time or that
we should go out of our way to create more connection state.    I think
simplicity comes from having simple state, not by pretending we have no
state.

For message meta data, this is something that we must have if we are going
to support polymorphic binary types (eg jpg, png or gif on the same
connection).   So I've proposed a frame of meta data that applies to the
next message.  This implies that the connection is a little stateful as it
needs to remember the meta data until the next message comes.

To make this slightly less stateful, we could make the meta data frame part
of the message by setting the fragment bit.  Thus a message could be
represented as:

    ws-message  = *(message-meta-data-frame) data-frame *(data-frame)

An example using the format of my last post (but without padding) would be

0x8419 'Content-Type: text/html' CR LF
0x8009 '<b>Hello '
0x0009 'World</b>'

Of course this is still stateful, but only within the reception of one
message.  Implementations that don't support meta-data can just discard all
meta-data frames and they would have the same state machine required  for
any multi-frame message.

Do you have any other suggestions?

cheers

---

From: "Thomson, Martin" <[email-masked]>
Date: Tue, 3 Aug 2010 10:33:56 +0800

It’s possible to mark a single message as being a MIME message.  A new frame type, for example.

MIME headers are added to the top of the frame body, separated from the body by “\r\n\r\n”.  The body could be binary or text, depending on the content-type.

Then you could have three frame types: binary, text and MIME.

From: Greg Wilkins [mailto:[email-masked]]
Sent: Tuesday, 3 August 2010 11:06 AM
To: Thomson, Martin
Cc: [email-masked]; [email-masked]
Subject: Re: [hybi] Framing take III

Martin,

I think whether we like it or not, connections will be somewhat stateful and message meta-data is an oft requested feature that will need to be supported either in the core protocol or a standard extension.

So I don't think we can simply punt either of them with out a counter proposal for how they can be supported (not necessarily as part of the core, possibly as an extension).

For connection meta data, I'm not saying that we should support arbitrary changes to the negotiated connection state, simply that we need a way to exchange connection state if the HTTP headers of the handshake are not available (eg if we establish with TLS next protocol).  This is not to say that we should allow connection meta-data to be changed at any time or that we should go out of our way to create more connection state.    I think simplicity comes from having simple state, not by pretending we have no state.

For message meta data, this is something that we must have if we are going to support polymorphic binary types (eg jpg, png or gif on the same connection).   So I've proposed a frame of meta data that applies to the next message.  This implies that the connection is a little stateful as it needs to remember the meta data until the next message comes.

To make this slightly less stateful, we could make the meta data frame part of the message by setting the fragment bit.  Thus a message could be represented as:

Of course this is still stateful, but only within the reception of one message.  Implementations that don't support meta-data can just discard all meta-data frames and they would have the same state machine required  for any multi-frame message.

cheers

---

From: Roberto Peon <[email-masked]>
Date: Mon, 2 Aug 2010 22:23:50 -0700

*Proposal : Websocket framing*

The websocket framing be changed to only support binary framing as defined
by

         ws-frame            = frame-flags
                           metadata-fields
                           frame-length
                           octet-data   ; binary data

    metadata-fields     = metadata-fields-count metadata-entry{
metadata-fields-count }

    metadata-fields-count = %x00-FF

    metadata-entry      = metadata-entry-length metadata-data
          ; the number of metadata-entrys is exactly determined by the
metadata-fields-count

    metadata-entry-length = %x00-FF

    metadata-data       = * ( %x00-FF )
            ; the number of octets is exactly the length determined
            ; by the metadata-entry-length

     frame-flags         = %x00-FF

    frame-length        = %x00-FF %x00-FF

    octet-data          = *( %x00-FF )
            ; the number of octets is exactly the length determined
            ; by the frame-length

This would make any extensions we'd like (including MIME data, if desired)
work, as would multiplexing for multiplex-aware endpoints, assuming we had a
metadata-field which was well-known to both endpoints.

Obviously, my preference is that we address multiplexing. I still have
strong concerns about the scalability of the WS protocol through NAT boxes
(which are prevalent) as well as load on the servers (something which is
"easier" to deal with by throwing more machines at the problem). If we don't
address multiplexing, the proposal above at least allows for it to happen in
the future in a backwards compatible way.

-=R

On Mon, Aug 2, 2010 at 6:06 PM, Greg Wilkins <[email-masked]> wrote:

> I think whether we like it or not, connections will be somewhat stateful
> and message meta-data is an oft requested feature that will need to be
> supported either in the core protocol or a standard extension.
>

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Mon, 2 Aug 2010 22:36:48 -0700

> the future in a backwards compatible way.

I like the proposal overall, but a few questions:

1. Is there any reason not to switch the length and metadata, such that
length is always at a known position?
2. Is there any implied ordering of the metadata fields, or are they all
key-value pairs that one has to decipher?

>> On 3 August 2010 10:48, Thomson, Martin <[email-masked]>wrote:
>>
>> To make this slightly less stateful, we could make the meta data frame
>> part of the message by setting the fragment bit.  Thus a message could be
>> represented as:
>>

---

From: Roberto Peon <[email-masked]>
Date: Mon, 2 Aug 2010 22:40:01 -0700

> length is always at a known position?

Seems fine to me.

> key-value pairs that one has to decipher?

Nope, they're all key-value fields to be deciphered.

Note that this proposal with metadata would be unnecessary imho if we do
multiplexing ;)

-=R

>>> For message meta data, this is something that we must have if we are
>>> going to support polymorphic binary types (eg jpg, png or gif on the same

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Mon, 2 Aug 2010 22:51:00 -0700

2010/8/2 Roberto Peon <[email-masked]>

>>> The websocket framing be changed to only support binary framing as
>>> defined by
>>>
>>>          ws-frame            = frame-flags
>>>                             metadata-fields
>>>                            frame-length
>>>                            octet-data   ; binary data
>>>
>>> This would make any extensions we'd like (including MIME data, if
>>> desired) work, as would multiplexing for multiplex-aware endpoints, assuming
>>> we had a metadata-field which was well-known to both endpoints.
>>>

If this is for a world where we don't have multiplexing in the base
protocol, it seems like it would be desirable to access the stream ID at a
fixed position rather than having to hunt around for it. That's one of the
things I tried to do in my strawman...

>>>> For connection meta data, I'm not saying that we should support
>>>> arbitrary changes to the negotiated connection state, simply that we need a
>>>> way to exchange connection state if the HTTP headers of the handshake are
>>>> not available (eg if we establish with TLS next protocol).  This is not to
>>>> say that we should allow connection meta-data to be changed at any time or
>>>> that we should go out of our way to create more connection state.    I think

---

From: Roberto Peon <[email-masked]>
Date: Mon, 2 Aug 2010 22:59:18 -0700

I don't think you ever get a fixed position if you allow arbitrary
extensions unless it is the first extension, or am I missing something?
-=R

On Mon, Aug 2, 2010 at 10:51 PM, Ian Fette (イアンフェッティ) <[email-masked]>wrote:

>>>>>> I really, really don't like the idea that there is state accumulated
>>>>>> in this fashion.  It makes implementations much more fragile.
>>>>>>
>>>>> I think whether we like it or not, connections will be somewhat
>>>>> stateful and message meta-data is an oft requested feature that will need to
>>>>> be supported either in the core protocol or a standard extension.
>>>>>

---

From: Ian Fette (イアンフェッティ) <[email-masked]>
Date: Mon, 2 Aug 2010 23:05:29 -0700

If you assume that all extensions have fixed-length space in a
fixed-ordering that they reserve in each frame, you get that. However,
perhaps that's not a safe assumption to make, I don't know. (At least, it
would be fixed for all frames within a given connection).

>>> On Mon, Aug 2, 2010 at 10:36 PM, Ian Fette (イアンフェッティ) <[email-masked]
>>> > wrote:
>>>
>>>>>            ; the number of metadata-entrys is exactly determined by
>>>>> the metadata-fields-count
>>>>>
>>>>> On Mon, Aug 2, 2010 at 6:06 PM, Greg Wilkins <[email-masked]>wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 3 Aug 2010 16:07:21 +1000

Roberto,

nice one - it solves several things:

   - it avoids our attempts to ration ext space in the header
   - it avoids sentinel framing within a frame
   - it associates meta-data with a frame and thus makes the connection less
   stateful.

The main down side is that it is a little bit harder for a simple client to
ignore meta data as it can't just discard a meta data frame. So either all
implementations need to know how to skip such headers, or the handshake has
to make it very clear if a client does never wants to receive such
headers.   That's why I kind of like meta-data in a frame of it's own.

So it is a trade off between the complexity of a slightly stateful
connection, vs the complexity of ignore unwanted meta-data.

cheers

---

From: Roberto Peon <[email-masked]>
Date: Mon, 2 Aug 2010 23:12:00 -0700

The simplest thing we could do is to have a metadata offset. This would be
part of the octet data, but would not be payload data to the API.
One could fit the formatted meta-data that I suggested earlier into this.

I didn't go that route however, because I wanted to ensure that stream-id
can be present in every frame. If we're ever to do multiplexing, this is a
very reasonable thing.
One could do a combination of meta frames and data frames, however you'd end
up with a 1-1 correspondence between meta frame and data frame if you ever
do multiplexing.... well that isn't completely true. One could have a single
meta frame followed my many data frames so long as they're all part of the
same stream, but then you get into maintaining a hair more state on both
client and server and you increase the risk of desync.

-=R

On Mon, Aug 2, 2010 at 11:07 PM, Greg Wilkins <[email-masked]> wrote:

>    - it associates meta-data with a frame and thus makes the connection
>    less stateful.
>

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 3 Aug 2010 16:39:14 +1000

Roberto,

Very good point about multiplexing and aggregation.  Any solution that
relies on the semantic of "this frame applies to the next frame" would be
vulnerable to other frames being injected and/or aggregated.

So I think we can say that we have a requirement that meta-data can be
non-divisible from the associated frame.
But I also think it is vital to have easily ignorable meta-data, because I
don't think we want to negotiations to effect what is sent so much.

So your offset idea probably works well.  We had a header like

+------------------------------------------------------+
|frag(1)|comp(1)|op(2)| meta(12)  |   length (16)      |
+------------------------------------------------------+
+                     meta data                        +
+------------------------------------------------------+
+                        data                          +
+------------------------------------------------------+

Length should always be the total length of meta data + data, so a simple
intermediary can just forward length octets.
The meta(12) length would be the length of the meta data (or offset to where
data is).
op codes could be simplified to

%x0 text data frame
%x1 binary data frame
%x2 ping
%x3 final frame

(we'd have to use meta data to distinguish a pong, or borrow another bit
from the meta length).

Simple senders would just send frames like:

+------------------------------------------------------+
|frag(1)|comp(1)|op(2)| %x000   |     length (16)      |
+------------------------------------------------------+
+                        data                          +
+------------------------------------------------------+

Simple receivers would just have to be implemented to skip meta bytes, which
not a very high a complexity price.

I think the meta data should be length encoded UTF-8 as you suggest, which
may be compressed if the compression bit is set.

cheers

On 3 August 2010 16:12, Roberto Peon <[email-masked]> wrote:

> One could do a combination of meta frames and data frames, however you'd
> end up with a 1-1 correspondence between meta frame and data frame if you
> ever do multiplexing.... well that isn't completely true. One could have a
> single meta frame followed my many data frames so long as they're all part
> of the same stream, but then you get into maintaining a hair more state on
> both client and server and you increase the risk of desync.
>
> -=R
>
>> The main down side is that it is a little bit harder for a simple client
>> to ignore meta data as it can't just discard a meta data frame. So either
>> all implementations need to know how to skip such headers, or the handshake
>> has to make it very clear if a client does never wants to receive such

---

From: "Martin J. Dürst" <[email-masked]>
Date: Tue, 03 Aug 2010 17:27:41 +0900

> The websocket framing be changed to only support binary framing as defined

By "binary framing", do you mean length-based framing as opposed to 
sentinel-based framing? In that case, length-based framing is the better 
term. We till need the basic distinction between text and binary. Is the 
assumption in your proposal that that's done in the frame flags, or that 
that's gone?

Regards,   Martin.

-- 
#-# Martin J. Dürst, Professor, Aoyama Gakuin University
#-# http://www.sw.it.aoyama.ac.jp   mailto:[email-masked]

---

From: "Anne van Kesteren" <[email-masked]>
Date: Tue, 03 Aug 2010 13:38:13 +0200

On Tue, 03 Aug 2010 04:33:56 +0200, Thomson, Martin  
<[email-masked]> wrote:
> MIME headers are added to the top of the frame body, separated from the  
> body by “\r\n\r\n”.  The body could be binary or text, depending on the  
> content-type.
>

What exactly is the benefit of this? Why can MIME not be something  
implemented by subprotocols? It does not at all seem like something that  
should be had before wider deployment.

-- 
Anne van Kesteren
http://annevankesteren.nl/

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 3 Aug 2010 21:52:29 +1000

On 3 August 2010 21:38, Anne van Kesteren <[email-masked]> wrote:

> On Tue, 03 Aug 2010 04:33:56 +0200, Thomson, Martin <
> [email-masked]> wrote:
>

Anne,

There are several use-cases for meta-data.

If we are to have binary messages, then polymorphic messages will be sent
(eg image/png, image/gif, image,jpeg etc) and each message will need to be
labelled with content type so that the receiver can interpret it.   I
believe that we do not want to delegate such a common feature to a sub
protocol in the application layer, as that will only encourage re-invention
of the wheel, limit interoperability and the creation of common
infrastructure and tools.

Another use case is for extensions and subprotocols to be implemented by
exchanging meta-data. For example multiplexing can be implemented by
associating channel ID meta data with each frame.  Without standard meta
data,  every extension and subprotocol would need to implement it's own meta
data mechanism and we would have re-invention, limited interoperability and
less common infrastructure and tools.

Note that at this stage the proposal is just about how meta data can be
carried by the framing mechanism.  There is no proposal to require any
specific meta data.

regards

---

From: "Anne van Kesteren" <[email-masked]>
Date: Tue, 03 Aug 2010 14:13:44 +0200

On Tue, 03 Aug 2010 13:52:29 +0200, Greg Wilkins <[email-masked]> wrote:
> (eg image/png, image/gif, image,jpeg etc) and each message will need to  
> be labelled with content type so that the receiver can interpret it.   I
> protocol in the application layer, as that will only encourage  
> re-invention of the wheel, limit interoperability and the creation of  
> common

I do not think that is really problematic. And you can still have common  
infrastructure and tools, you just share them at the application layer  
rather than the protocol layer. Encouraging people to experiment with how  
they do these things is actually a rather nice property of the current  
approach in my opinion.

> data, every extension and subprotocol would need to implement it's own  
> meta data mechanism and we would have re-invention, limited  
> interoperability and less common infrastructure and tools.

Apart from certain important pieces of infrastructure, i.e. multiplexing,  
I do not think that is a problem. We want to expose a fairly low-level  
protocol here and leave a bunch of things to the application layer. We can  
over time put some commonly used features in the protocol layer, but that  
should not require metadata for each frame type.

> carried by the framing mechanism.  There is no proposal to require any

That would go way too far.

---

From: Roderick Baier <[email-masked]>
Date: Tue, 03 Aug 2010 14:41:39 +0200

Greg Wilkins schrieb:
> labelled with content type so that the receiver can interpret it.

Which use cases do you have in mind (except webcam streaming)? I can 
imagine that there will be a lot of developers who just send a json 
message with a (relative) url to the image and some meta data and get 
the image by XHR. My simple client implementation will not be able to 
receive other messages until it recv()ed the full image.

Best regards
Roderick

---

From: Greg Wilkins <[email-masked]>
Date: Tue, 3 Aug 2010 23:25:23 +1000

On 3 August 2010 22:41, Roderick Baier <[email-masked]>wrote:

> imagine that there will be a lot of developers who just send a json message
> with a (relative) url to the image and some meta data and get the image by
> XHR. My simple client implementation will not be able to receive other
> messages until it recv()ed the full image.
>
>
Roderick,

one use-case I know is mobile devices and networks, which have a high price
on both connections and data rate. I have already had experience with
implementing a comet/chat service for a large mobile carrier, where the URL
sending techniques used for normal web clients had to be modified for mobile
clients so that a single connection was used to send both chat and images in
a single stream.

I can also image games and auctions sites where the extra RTT of sending a
URL that then needs to be fetched will greatly effect the QoS.  I've
certainly experienced that problem with comet based card games where you
visibly notice the first time a particular card is dealt (yes pre-fetching
can help if the images are known, but that is not always possible).

cheers

---

From: Arman Djusupov <[email-masked]>
Date: Tue, 03 Aug 2010 17:23:37 +0300

Anne van Kesteren wrote:
> rather than the protocol layer. Encouraging people to experiment with 
> how they do these things is actually a rather nice property of the 
> current approach in my opinion.
> 

Since the metadata frame is optional, I don't see any problem implementing support for custom metadata exchange for the applications that need them.

Some basic things such as the content-type can go into the metadata frame. Having a metadata mechanism in place would simplify the development of a sub-protocol since the basics (i.e. metadata support) would already be in the spec.

However, I would like to note than encoding the metadata in a textual format might not be the most efficient way to encode a channelID in case of multiplexing or for performing flow control. Parsing textual metadata can consume more processing time than actually reading the frame. It is quite faster to multiplex frames that belong to different channels by using the first byte of a frame content rather than parsing the text header on per message or per frame basis.

IMHO Greg's initial idea of *Control frames* that contain a text header and apply to the entire channel state at once (rather than attached to every single message) is more flexible. Another very interesting item in Greg's initial proposal was that the *Control frames* could be disabled during the WebSocket handshake. This would allow sub-protocols to optionally use metadata for headers like content-type, file-name, file-attributes or whatever else makes sense, or not to advertise the *Control frames* feature and instead use their own solution.

With best regards,
Arman

---

From: Scott Ferguson <[email-masked]>
Date: Tue, 03 Aug 2010 09:26:31 -0700

Anne van Kesteren wrote:
>> MIME headers are added to the top of the frame body, separated from 
>> the body by “\r\n\r\n”.  The body could be binary or text, depending 
>> on the content-type.
>>
> implemented by subprotocols? It does not at all seem like something 
> that should be had before wider deployment.
+1

Although MIME is certainly useful for higher protocols, I don't see why 
it's a good idea in this layer. A big minus would be significant added 
complexity to a server API. (I'd assume the same minus would be true for 
the browser.)

Without MIME, we have a simple stream protocol (InputStream and Reader 
in Java because of the binary/text frames), and a server API can be 
correspondingly simple with about 4-ish data methods.

With MIME, the API needs to add encoding/decoding of objects, plus 
registration and configuration of mime/decoders, plus calls and 
structures to access the metadata directly, which is a much more 
complicated API. The Java API to handle MIME decoding is not a 
small/simple API.

With a simple stream protocol, MIME can be easily supported by a 
protocol layer/library on top of the simple stream layer, which the 
application needs to write anyway because it needs to know which 
messages are supposed to be objects and which are protocol/control messages.

(I've read Greg's response to Anne's message. But that's an argument for 
MIME in _some_ layer, like a library, not an argument for putting it in 
the framing layer.)

-- Scott

---

From: Greg Wilkins <[email-masked]>
Date: Wed, 4 Aug 2010 09:09:55 +1000

Scott,

But MIME is just one example of meta data.   The same mechanism can be used
to build a multiplexing extension.

Surely there is benefit in having a common (optional) basis for extension?

On 4 August 2010 02:26, Scott Ferguson <[email-masked]> wrote:

> complexity to a server API. (I'd assume the same minus would be true for the
> browser.)
>
> Without MIME, we have a simple stream protocol (InputStream and Reader in
> Java because of the binary/text frames), and a server API can be
> registration and configuration of mime/decoders, plus calls and structures
> to access the metadata directly, which is a much more complicated API. The
> Java API to handle MIME decoding is not a small/simple API.
>
> With a simple stream protocol, MIME can be easily supported by a protocol
> layer/library on top of the simple stream layer, which the application needs
> to write anyway because it needs to know which messages are supposed to be
> objects and which are protocol/control messages.
>
> MIME in _some_ layer, like a library, not an argument for putting it in the
> framing layer.)
>
> -- Scott
>
>>
>>
>>
>

---

From: "Thomson, Martin" <[email-masked]>
Date: Wed, 4 Aug 2010 07:30:48 +0800

> that should be had before wider deployment.

I can't agree more.

My point, which was perhaps a little oblique, was that this is a continuum.  When we decide to distinguish text and binary frames, we have decided to take the path that leads to metadata.  Adding a richer description of the content of the frame - MIME - is the next logical step.

Consider this an argument for only supporting binary framing.

--Martin

---

From: Scott Ferguson <[email-masked]>
Date: Tue, 03 Aug 2010 17:47:43 -0700

Greg Wilkins wrote:
> Scott,
>
> But MIME is just one example of meta data.   The same mechanism can be 
> used to build a multiplexing extension.
>

It's specifically content meta-data that I'm against, because having a 
simple content model is a real benefit for the protocol, as Martin has 
been pointing out.

Non-content meta-data, like connection parameters, multiplexing, 
non-content extensions, etc. are a whole different issue. I'm not 
opposed to that. Those are less of a problem because they don't really 
complicate the API. It's the content model and the corresponding 
application-visible API I'd want to keep simple. In other words, I think 
it's best to keep those two concepts separate.

Going from binary-only to binary/text is a small increase in complexity. 
It's straightforward to write a complete, small client with those two 
types. But adding mime encoding/decoding is a major increase in 
complexity (essentially allowing infinite, extensible types), and it's 
then hard to write a complete, small client, and hard to create a simple 
API.

-- Scott

>
>
>
> On 4 August 2010 02:26, Scott Ferguson <[email-masked] 
> <mailto:[email-masked]>> wrote:
>
>     Anne van Kesteren wrote:
>
>         <[email-masked] <mailto:[email-masked]>>
>         wrote:
>
>             MIME headers are added to the top of the frame body,
>             separated from the body by “\r\n\r\n”.  The body could be
>             binary or text, depending on the content-type.
>
>         What exactly is the benefit of this? Why can MIME not be
>         something implemented by subprotocols? It does not at all seem
>         like something that should be had before wider deployment.
>
>     +1
>
>     Although MIME is certainly useful for higher protocols, I don't
>     see why it's a good idea in this layer. A big minus would be
>     significant added complexity to a server API. (I'd assume the same
>     minus would be true for the browser.)
>
>     Without MIME, we have a simple stream protocol (InputStream and
>     Reader in Java because of the binary/text frames), and a server
>     API can be correspondingly simple with about 4-ish data methods.
>
>     protocol layer/library on top of the simple stream layer, which
>     the application needs to write anyway because it needs to know
>     which messages are supposed to be objects and which are
>     protocol/control messages.
>
>     (I've read Greg's response to Anne's message. But that's an
>     argument for MIME in _some_ layer, like a library, not an argument
>     for putting it in the framing layer.)
>
>     -- Scott
>
>
>
>
>

---

From: Simone Bordet <[email-masked]>
Date: Wed, 4 Aug 2010 17:31:09 +0200

Hi,

On Wed, Aug 4, 2010 at 02:47, Scott Ferguson <[email-masked]> wrote:
> It's straightforward to write a complete, small client with those two types.
> But adding mime encoding/decoding is a major increase in complexity
> (essentially allowing infinite, extensible types), and it's then hard to
> write a complete, small client, and hard to create a simple API.

Maybe I am missing something, but let's assume JS has binary (or a non
JS client), then how do you distinguish between image/png and
image/jpg (actually the same applies to application/json and text/xml)
?
You can write that information in the payload before the image bytes,
but seems not ideal to me.
You can open 2 different websocket "channels" to handle them, so
you're sure of what type the bytes are (e.g. new
WebSocket("/png-images"), new WebSocket("jpg-images")).
You can leave that to subprotocols, but then all subprotocols must
reinvent metadata exchange.

IIUC, the websocket API would not try to interpret the data for you,
but just give you access to the metadata, like in
ws.getMeta("content-type").
Mostly like the servlet API (modulo some encoding bit ;): you get a
reader/inputstream, you can read bytes, but you can also get the
content type and have the application make its logic with bytes and
mime.

Regards,

Simon
-- 
http://bordet.blogspot.com
---
Finally, no matter how good the architecture and design are,
to deliver bug-free software with optimal performance and reliability,
the implementation technique must be flawless.   Victoria Livschitz

---

From: James Graham <[email-masked]>
Date: Wed, 04 Aug 2010 18:00:48 +0200

On 08/04/2010 05:31 PM, Simone Bordet wrote:
> Hi,
>
> On Wed, Aug 4, 2010 at 02:47, Scott Ferguson<[email-masked]>  wrote:

Why isn't that ideal? You don't really explain this.

It seems that there is some tension between people who want the protocol 
to be simple at the cost of making applications slightly more complex, 
and people who want to bake a lot of cleverness into the protocol layer.

To me, the advantages of keeping the protocol as simple as possible (but 
no simpler) seem compelling:

a) It means that implementation will be simpler, so there will be fewer 
bad / non-interoperable implementations

b) We don't have to spend time guessing what subprotocol/application 
authors want, we can just let them do what ever they need. This means 
that we can iterate faster and get more rapid deployment.

c) We don't run the risk of ending up with a bunch of useless features 
that bloat the protocol and the APIs that are not actually needed in 
many cases.

d) Where features are implemented in a wide variety of subprotocols we 
can bake those features in to the main protocol later if it makes sense 
to do so.

I think MIME is far too far on the wrong side of the "features that 
everyone needs" vs "features that a few subprotocols will need" divide 
to bake it in to the base protocol, especially at this stage.

---

From: Simone Bordet <[email-masked]>
Date: Wed, 4 Aug 2010 18:20:21 +0200

Hi,

> Why isn't that ideal? You don't really explain this.

Right.
What I meant is that if there is no support for content metadata, then
applications have to do their own and start writing text data, but
only these many bytes and with this encoding, then binary data, which
complicates applications quite a bit.

I see that "Framing take IV" has several proposed ways of specifying
metadata, even content metadata, with a clear way to say "here's where
the metadata ends and data starts", so the implementation - and not
the application - will take care of parsing the metadata and offer it
to the application in a simpler way (though I guess it would require
an API change).

Simon