Subject: Re: [hybi] Framing and design philosophy

From: "Martin J. Dürst" <[email-masked]>
Date: Sun, 01 Aug 2010 16:03:40 +0900

On 2010/07/31 4:54, James Graham wrote:
> On Fri, 30 Jul 2010, Ian Fette (イアンフェッティ) wrote:
>
>> FWIW we discussed this exact point at the f2f. The counter argument
>> raised was that in most languages, you have some sort of
>> write() function call that takes a number of bytes to be written, as
>> opposed to passing in a string, and so most implementers of
>> the protocol would have to know the length of the data anyways.
>
> Is that true (it might be, I don't know)? At least in modern scripting
> languages having to specify the number of bytes to write out seems very
> unusual. Since the type of authors we are concerned with making unicode
> vs bytes mistakes are presumably more likely to be using Python than C,
> it seems that the behaviour of these languages should be weighted more
> highly.

Agreed. But then, in most of these scripting languages, it's a piece of 
cake to create a layer that takes care of creating frames. What I would 
expect is that in no time, these languages have functions/methods like

sendAsWSTextFrame(text)
or
text.send_ws_frame

or some such. The method would check whether the text is in UTF-8, if 
not convert it to such, measure the length in bytes, add the framing 
headers bytes, and ship it off. This (and something similar on the 
receiving side) is indeed about the first thing I'd work on when 
creating some kind of WebSockets library.

So I agree with Ian that using the length in terms of characters rather 
than bytes is easy to get wrong, but I think this is something that 
libraries will cover in no time, so it's not a big issue as it may seem 
for the first pioneers (such as Ian) who write everything by hand.

>> The other point that came up is that if you aren't capable of
>> counting the length of data you are sending, you are likely to have
>> more serious errors anyways and perhaps should not be writing
>> code for any sort of real use/reach.
>
> I don't think "if you get this wrong you are too dumb to be writing
> websockets servers" is a reasonable argument, especially since the state
> of the web suggests that many people will write and deploy bad code
> whether we lik it or not. It is certianly not just the small sites that
> are full of WTF level javascript, for example.
>
> For the particular case of failure-to-convert-unicode-to-bytes-correctly
> type errors, I suggest Googling for UnicodeDecodeError or
> UnicodeEncodeError. These are Python exceptions thrown when converting
> to/from byte strings goes wrong. Note that Python 2.x has the flaw that
> it will work for ascii without the author explicitly converting, but
> break once non-ascii data is involved; therefore these errors occur in
> the same kinds of situations as the websockets error we are concerned
> with. In my experience - which I think Google backs up - these errors
> are *very* common; I have got them from well known packages and, sadly,
> have made the same mistake myself more than once.

I don't disagree that these kinds of errors are frequent. But for 
WebSockets, they are mainly relevant if a server-side application 
library isn't character-encoding-aware and handles everything as bytes, 
and then the data gets handled to a WebSockets library call (such as the 
above) which is supposed to figure out what the actual character 
encoding is. Such errors are quite independent of the length/sentinel 
question.

Regards,  Martin.

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

---

From: Wenbo Zhu <[email-masked]>
Date: Mon, 2 Aug 2010 04:50:57 -0700

On Fri, Jul 30, 2010 at 4:23 PM, Patrick McManus <[email-masked]>wrote:

>
> Related to the syntax of framing and chunking, I also urge the group to
> tackle multiplexing in the first round of the draft. Connection
> management has long been a thorn in the side of HTTP - leading to
> arbitrary numbers of parallel connections and their assorted problems
> interacting poorly with buffering and TCP congestion control.
>
Or, without multiplexing, I'd argue that the plain-old HTTP would be
sufficient in itself - to be used as a transport protocol for the WebSocket
API.
We had use cases that involve 1) streaming-only transport; and 2) API
clients. Based on initial discussions over httpbis, full-duplex HTTP seems
to be a viable option:
http://lists.w3.org/Archives/Public/ietf-http-wg/2010AprJun/0111.html ,
http://tools.ietf.org/html/draft-zhu-http-fullduplex-01  ...

Not saying that we don't need a new protocol ... but its incompatibility
with HTTP, as cost, needs be justified.

- Wenbo

>
> Multiplexing multiple websocket messages simultaneously over a single
> TCP channel (using chunks as necessary) allows them to share a single
> TCP congestion control block as well as a single TCP handshake. Both of
> those things will be significant wins in terms of reliable efficient
> performance.
>
> There is a downside in terms of fate sharing across messages during loss
> recovery events, but frankly a single busy TCP session makes loss
> recovery much more efficient than if the same data is spread of
> unrelated TCP flows. More importantly the number of client induced
> losses due to inaccurate aggregate cwnd's across the large number of
> parallel connections is reduced. That's probably the most important
> thing.
>
> Not tackling it now basically makes repeating the mistakes of http
> forseeable, and I would not support the IETF endorsing such a
> specification.
>
>
>
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi
>

---

From: Jamie Lokier <[email-masked]>
Date: Tue, 3 Aug 2010 21:18:53 +0100

Ian Hickson wrote:
> Once we have compression, why would you use anything uncompressed?

Because compression is slow and uses significant memory per connection.

If the link bandwidth is the bottleneck, you'll use compression.

If you're talking to a web application over a decent LAN, you'll
probably *disable* compression to reduce the load on the server.

If you're transmitting pre-compressed messages, then you'll disable
WebSocket compression because it's a waste of time trying to compress twice.

If you have large numbers of connections, you might have to disable
compression on a server just to reduce the memory used, if purchasing
more hardware and parallelising the application isn't an option.

-- Jamie

---

From: Roberto Peon <[email-masked]>
Date: Tue, 3 Aug 2010 13:21:10 -0700

Also, there are payloads for which compression is at best a net-zero win on
the space side (e.g. video) while being a significant cost on the CPU+memory
size.

-=R

---

From: Jamie Lokier <[email-masked]>
Date: Tue, 3 Aug 2010 21:31:37 +0100

Ian Hickson wrote:
> On Fri, 30 Jul 2010, Roberto Peon wrote:
> > > >
> > > > I've already shown that with length prefixing you can have the 
> > > > receiver chose to parse using either sentinel scanning or 
> > > > byte-counting with semantics that provide for non-channel-close 
> > > > error semantics where appropriate.
> > >
> > > Unfortunately this kind of redundancy in practice leads to 
> > > implementation differences that become very relevant. For example, 
> > > suppose IE implements just the length measuring, and ignores the 
> > > sentinels. A server that doesn't correctly send the sentinels then 
> > > will work with IE and fail with browsers that do stricter checking. If 
> > > IE has high market share when this happens, the net result will be 
> > > that we can no longer do the stricter checking, and now we have a 
> > > vestigial feature in the protocol.
> > 
> > Isn't this an argument for not having two framing types as well?
> 
> I don't see how. An implementation can't ignore part of the framing 
> mechanisms as the spec is written today, so interoperability isn't at 
> risk as far as I can tell. If you can come up with a scenario where this 
> could occur, though, maybe the spec needs changing.

An implementation obviously *can* ignore the part of the spec which
tells it to parse the variable-length length field of binary frames and
ignore the data part.  With no adverse effects at present.

The problem is such an implementation can get widely deployed with
nobody noticing a problem, as nobody is using binary frames.

Interoperability then arises as soon as someone tries sending a binary
frame in the hope that deployed implementations will ignore it and
finds that some market leader either doesn't ignore it, or parses it
wrongly.

Worse: WS aware proxies/routers may exist by then which parse the
framing, and we may find that they break with binary frames, making
binary frames unusable.  That would be an unpleasant "vestigial"
outcome.

-- Jamie

---

From: Jamie Lokier <[email-masked]>
Date: Tue, 3 Aug 2010 21:41:32 +0100

Roberto Peon wrote:
> 
>    Also, there are payloads for which compression is at best a net-zero
>    win on the space side (e.g. video) while being a significant cost on
>    the CPU+memory size.

I'm all in favour of transporting video over WebSocket and think
there's no good reason to artificially prohibit such uses, but I think
you might have to make a case for it ;-) Even the most binary-friendly
framing suggestions seem to balk at the transmission of 5GB-size
messages (which may be annoying when 5GB strings take less than a
second to transmit from a script).

However there are much smaller, realistic examples:

 -> *Tiny* messages are also incompressible.

There's no point keeping around a 100kB compression state on both
sides, if the application is exchanging sporadic 10-byte messages,
just to compress them to 5 bytes plus header.

It will save nothing of network bandwidth, not even a few percent, as
the number of minimal-size packets will stay the same.  All it will do
is add CPU load for nothing.

Also many types of compression aren't effective when done
incrementally a few bytes at a time, which is another reason not to
bother with sporadic tiny messages.  It's only worth it when you have
a batch of them to compress together, which you don't if they are sporadic.

-- Jamie

---

From: Mike Belshe <[email-masked]>
Date: Tue, 3 Aug 2010 14:10:17 -0700

> more hardware and parallelising the application isn't an option.

Your thoughts are logical - I agree 100% with the logic yet disagree with
the conclusion :-)  This line of perfectly rational thought is what lead to
our state today, with only 66% of compressible resources compressed over
HTTP and a mere 44% for SSL...  (
http://code.google.com/speed/articles/web-metrics.html)  Those numbers are
so staggeringly low that it's time we fix it.

That said, I'm not convinced there is a one-size fits all compression at the
framing layer for a websocket which makes sense.   Websocket content is not
the same as http content.  My gut tells me to require it at the JS API
layer.  Not sure.

Mike

---

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

On 4 August 2010 07:10, Mike Belshe <[email-masked]> wrote:

>
> That said, I'm not convinced there is a one-size fits all compression at
> the framing layer for a websocket which makes sense.   Websocket content is
> not the same as http content.  My gut tells me to require it at the JS API
> layer.  Not sure.
>
>
I agree that it is highly likely that there is no one-size fits all
compression.

My feeling is that we should not including it explicitly in the framing for
now, mostly because there is no consensus.

Moving forward we have 4 options:

 1) never have compression
 2) an extension could use binary frames to send compressed frames
 3) we could go for stream compression
 4) a future version of the spec could add a compression bit

All have pros and cons and there is no clear best approach to me.
None of those really need anything in framing now (ok 4 needs a suitable
bit  that could eventually be repurposed), so we can probably defer this for
a while

cheers

---

From: Dave Cridland <[email-masked]>
Date: Wed, 04 Aug 2010 10:06:27 +0100

> second to transmit from a script).
I don't think they do, do they? I mean, no more so than any other  
transmission medium. There's a chunking overhead, but I don't feel  
this is a particularly onerous thing.

> just to compress them to 5 bytes plus header.
It's 300kB of codec on each side, with maximal compression. Which is  
why you want a maximum of one per WebSocket, not one per multiplexed  
stream.

> a batch of them to compress together, which you don't if they are  

This is largely wrong with DEFLATE. I thought that it would make a  
difference, but no compression state is lost with a synchronizing  
flush (which is what you'd use between packets), so certainly with  
XMPP, the difference between buffering up a load of stanzas and  
compressing all at once, compared with compressing one by one, is  
virtually nil.

When I realised why, I also realised that the same is likely to be  
true of the vast majority of compression codecs. I appreciate only  
too well that this is counter-intuitive to some people, myself  
included.

The only overhead is the padding to bring it up to an integer number  
of octets, and the block headers, which are themselves a small number  
of bits - I think you'd be getting a single octet overhead at worst  
case.

Dave.
-- 
Dave Cridland - mailto:[email-masked] - xmpp:[email-masked]
  - acap://acap.dave.cridland.net/byowner/user/dwd/bookmarks/
  - http://dave.cridland.net/
Infotrope Polymer - ACAP, IMAP, ESMTP, and Lemonade