Subject: [hybi] The future of WebSockets, and the WiSH proposal

From: Takeshi Yoshino <[email-masked]>
Date: Tue, 25 Apr 2017 16:26:16 +0900

Hi,

I’d like to start discussing here on HyBi ML how we should evolve
WebSockets.

We’ve been thinking about this topic, and proposed WiSH [1] briefly at the
HTTP WG (IETF 97 f2f) in Nov 2016. The HTTP-WG chairs suggested that this
topic should be discussed within the WebSocket community. While HyBi WG is
currently closed, this ML is still the best place to have this discussion.

[Background]

WebSocket (WS) is widely adopted. Popular sites such as GitHub, Slack,
WhatsApp and Twitch are using WS. A majority of HTTP implementations now
support WS, including client/server libraries, web frameworks and
intermediaries.

HyBi WG had been trying to evolve WS after finalizing the base WS protocol.
Personally I have been the editor for the compression spec [2].

[WiSH]

WiSH [1] is a general purpose message framing format for providing
bi-directional message-based communication for the Web, considering
compatibility with the WebSocket API and intermediaries. WiSH is applicable
for any byte-stream oriented reliable wire protocols.

Given the wide adoption of WS and the rapid evolution of HTTP, e.g. QUIC
[3], we believe that the WiSH proposal creates an ideal evolution path for
WS users, by leveraging the HTTP infrastructure and the widely deployed WS
ecosystems at the same time.

In designing the WiSH spec, we decided to layer WS framing as a MIME type
over the standard HTTP semantics (v.s. any specific wire-transport version
such as HTTP/1.1 or HTTP/2). WiSH will be made transparent to existing
applications, i.e. WiSH doesn’t require extending or modifying existing
APIs on the client or server side. WiSH can also automatically benefit from
infrastructure support for HTTP/*, especially with guaranteed connectivity
(no/less fallback needed). This makes the overall solution much more Web
friendly and future proof

We’d like to hear your feedback on the WiSH proposal and/or any general
thoughts on how to evolve WS.

Thanks

[1] WiSH I-D https://tools.ietf.org/html/draft-yoshino-wish (GitHub
https://github.com/bidiweb/wish/blob/master/draft-yoshino-wish.txt)
[2] RFC 7692 Compression Extensions for WebSocket
https://tools.ietf.org/html/rfc7692
[3] QUIC Protocol https://www.chromium.org/quic

---

From: Anne van Kesteren <[email-masked]>
Date: Tue, 25 Apr 2017 10:09:12 +0200

> thoughts on how to evolve WS.

I still don't really understand why we'd put new code in browsers
before gaining some experience with full-duplex fetch(). What
advantages remain? That you get a dedicated connection? That the
frames are slightly smaller? Can we find ways to get those advantages
into fetch() and a future version of HTTP?

-- 
https://annevankesteren.nl/

---

From: Takeshi Yoshino <[email-masked]>
Date: Tue, 25 Apr 2017 17:51:46 +0900

> into fetch() and a future version of HTTP?

Yes, theoretically there are lots of overlap between what the
fetch()/Streams effort realizes and current/WiSH-ed WebSocket realizes.

However, there is existing big WebSocket ecosystem based on the WebSocket
web API, server APIs designed to match it, intermediaries, etc. I'd like to
hear opinions from them. That's actually one of the main purposes of this
discussion.

The bottom of the background section of the I-D (
https://tools.ietf.org/html/draft-yoshino-wish-02#section-2) is
unintentionally (I forgot to update it) left to be talking about using WiSH
framing over fetch()/Streams to improve the WebSocket ecosystem without
introducing any dedicated browser code. This is also a possible option
though it requires developers to include Polyfill in their code.

---

From: Andy Green <[email-masked]>
Date: Tue, 25 Apr 2017 17:01:18 +0800

On 04/25/2017 04:51 PM, Takeshi Yoshino wrote:
> On Tue, Apr 25, 2017 at 5:09 PM, Anne van Kesteren <[email-masked] 
> <mailto:[email-masked]>> wrote:
>
>     On Tue, Apr 25, 2017 at 9:26 AM, Takeshi Yoshino
>     <[email-masked] <mailto:[email-masked]>> wrote:

Can someone point the rump of hybi-subscribers who have no idea what you 
are talking about with this "fetch() / Streams" stuff to some definitive 
documentation?
>
> However, there is existing big WebSocket ecosystem based on the 
> WebSocket web API, server APIs designed to match it, intermediaries, 
> etc. I'd like to hear opinions from them. That's actually one of the 
> main purposes of this discussion.
>
> The bottom of the background section of the I-D 
> (https://tools.ietf.org/html/draft-yoshino-wish-02#section-2) is 
> unintentionally (I forgot to update it) left to be talking about using 
> WiSH framing over fetch()/Streams to improve the WebSocket ecosystem 
> without introducing any dedicated browser code. This is also a 
> possible option though it requires developers to include Polyfill in 
> their code.

The basic problem underneath all this is the guys who defined http/2 
considered ws so declasse they did not need to honor the existing JS 
apis in http/2.

They took care of every other functionality in use in http/1 in http/2 
as far as I know.  But ws is a red-haired stepchild to them... the 
official stance is use http/1.  What about it offends their delicate 
sensibilities I dunno.

Anyway I appreciate Yoshino-san at least threw his hat in the ring with 
some data.

-Andy

>
>
>
> _______________________________________________
> hybi mailing list
> [email-masked]
> https://www.ietf.org/mailman/listinfo/hybi

---

From: Anne van Kesteren <[email-masked]>
Date: Tue, 25 Apr 2017 11:10:32 +0200

On Tue, Apr 25, 2017 at 11:01 AM, Andy Green <[email-masked]> wrote:
> Can someone point the rump of hybi-subscribers who have no idea what you are
> talking about with this "fetch() / Streams" stuff to some definitive
> documentation?

Apologies, fetch() is basically what replaces XMLHttpRequest and it
has slowly evolved to expose streams which in theory allows for
full-duplex communication even over H/1:

  https://fetch.spec.whatwg.org/
  https://streams.spec.whatwg.org/

It's still early days implementation-wise though with regards to the
streams integration.

---

From: Loïc Hoguin <[email-masked]>
Date: Tue, 25 Apr 2017 11:58:42 +0200

Hello,

> It's still early days implementation-wise though with regards to the

While this looks interesting, it doesn't help any of us with 
non-browser/non-JS clients, like server-side clients or mobile applications.

Here are a few things my users would like to be able to do:

* Make their custom Websocket code work over HTTP/2 or any future 
protocol (QUIC or other)

* Continue using the Websocket sub-protocol feature without having to 
dedicate an entire connection for it (layering an existing protocol over 
HTTP has advantages for authentication and routing)

* Have a good media type for the streaming of binary events

A common pattern my users have when contacting a server is to first 
request a resource that will stream events, then perform other requests 
separately.

Here are the issues commonly encountered right now. I'm assuming here 
that clients can use HTTP/2:

* Having to open 2 connections (not the best idea for mobile clients, 
and uses twice the memory on the server side)

* Having to reimplement a custom HTTP/2-like protocol on top of 
Websocket to avoid having those 2 connections (works, but non-standard, 
and prone to errors)

* Having to use text/event-stream with base64-encoded binary data 
(inefficient, especially for larger events)

* For users who would otherwise be fine with text-based events: having 
to use text encodings. JSON in particular is very inefficient and puts a 
heavy strain on the server, switching from JSON to msgpack for example 
makes my servers load go back to 0 even with tens of thousands of 
connections. Even if using something other than JSON, there's still the 
matter of decoding text/event-stream.

* Having to implement a custom multipart media type for events, for 
those who go that route. Few do because it's non-standard.

My users tend to have servers with 10K+ or sometimes 100K+ connections, 
so we have slightly different needs than most people, but they're still 
worth considering when defining standards I think.

On top of that WiSH is easier to integrate on the server because it fits 
better with the HTTP semantics (using content negotiation, in 
particular). It would be possible to have common code for 
text/event-stream and WiSH should one desire to, while Websocket itself 
makes that less practical.

I don't really know how the standards process works but I would be 
really interesting to see WiSH make it in one form or another even if 
browsers are not willing to implement it, because it would definitely 
benefit the rest of us.

Cheers,

-- 
Loïc Hoguin
https://ninenines.eu

---

From: Andy Green <[email-masked]>
Date: Tue, 25 Apr 2017 18:47:58 +0800

> * Make their custom Websocket code work over HTTP/2 or any future 

Yeah.  I proposed this on the http/2 list before http/2 came out and 
more recently.  It was ignored the first time and the second time, the 
responsible guy was surprised that there was even any non-browser ws 
usage.  So I dunno what planet he's on, but clearly it's not a good 
planet from which to direct the future of ws.

Wow you have a lot of points but I think they are not all generic.

> dedicate an entire connection for it (layering an existing protocol 
> over HTTP has advantages for authentication and routing)

Generally speaking, atm I think by default http/2 looks like the future.

The problem is not that we need to "add mux" to http/1 as Google tried 
and failed to "add mux" to ws, but that the guys defining http/2 
unaccountably dropped the ball when they did not include ws support in 
it already.

> request a resource that will stream events, then perform other 
> requests separately.
>

You mean two TCP connections?

Why?  You mean fetching the html that has the scripts and then the 
scripts opening the ws connection?

> Websocket to avoid having those 2 connections (works, but 
> non-standard, and prone to errors)

Eh... what did you mean then "two connections"?

> (inefficient, especially for larger events)

What's up with ws BINARY?
> to use text encodings. JSON in particular is very inefficient and puts 
> a heavy strain on the server, switching from JSON to msgpack for 
> example makes my servers load go back to 0 even with tens of thousands 
> of connections. Even if using something other than JSON, there's still 
> the matter of decoding text/event-stream.

... JSON can make a lot of sense when things are less intense. What's up 
with BINARY ws connections though?
> those who go that route. Few do because it's non-standard.

Can you explain what this means?  It sounds kind of specific to whatever 
it is you are doing.

>
> My users tend to have servers with 10K+ or sometimes 100K+ 
> connections, so we have slightly different needs than most people, but 
> they're still worth considering when defining standards I think.
>
> On top of that WiSH is easier to integrate on the server because it 
> fits better with the HTTP semantics (using content negotiation, in 
> text/event-stream and WiSH should one desire to, while Websocket 
> itself makes that less practical.
>

I did not read the wish stuff yet.  But although http/2 guys are too 
important to deal with ws and pushed it back on hybi to discuss, 
actually decision about the generic scope of wish and integration to 
http/2 is more a decision for http/2 than for ws.  ws is just one 
proposed usecase for it.

-Andy

---

From: Loïc Hoguin <[email-masked]>
Date: Tue, 25 Apr 2017 13:26:11 +0200

Might be clearer to say that my users generally want:

* a standard solution (not reinvent the wheel)

* 1 always-on TCP connection

* binary events (not always required, sometimes just for efficiency 
and/or convenience)

HTTP/2 + WiSH makes that possible.

Applications are (soft) realtime systems (messaging, games, IoT 
networks, databases and more).

All these are different solutions that my users have used, none of which 
are satisfactory. They are mostly independent. I'll make clear the 
issues for each case.

> scripts opening the ws connection?

Two TCP connections yes, because the clients need to receive events as 
soon as they occur on the server, and as far as standards are concerned 
there's only Websocket and text/event-stream allowing this, and only 
Websocket is efficient with binary data.

> Eh... what did you mean then "two connections"?

That's a separate solution that allows only one connection, but is 
completely non-standard and requires implementing in all languages involved.

> What's up with ws BINARY?

It's perfect! But requires a separate connection.

> with BINARY ws connections though?

I usually recommend to start with JSON because it's the simplest to go 
with, and only replace it with something else when necessary. It often 
becomes necessary. That's probably not the case in general though.

> Can you explain what this means?  It sounds kind of specific to whatever

It's yet another solution allowing a single solution, but again 
non-standard.

-- 
Loïc Hoguin
https://ninenines.eu

---

From: Andy Green <[email-masked]>
Date: Tue, 25 Apr 2017 20:06:01 +0800

> * a standard solution (not reinvent the wheel)

Mmm I think everyone would say they prefer this.  But although the JS 
apis should stay the same, to some extent if we implement the wire 
protocol we can't have that because http/2 is nothing like http/1.

> * 1 always-on TCP connection

Yeah it is preferable.  Http/1 has gone away from that, in current 
browsers they don't even really do pipelining any more, eg Mozilla just 
shrugs and says use http/2 if you care about it.  (But they will say use 
http/1 if you want ws...)

> * binary events (not always required, sometimes just for efficiency 
Yes, even original ws has this though.
> HTTP/2 + WiSH makes that possible.

OK... but http/2 brings most of what is needed including the mux.  I 
don't know what wish brings yet, but it will be a relatively small part 
of the puzzle from ws point of view.  Eg native http/2 framing for ws 
that they should have done in the first place would also completely 
deliver what you want by the sound of it.  There are definitely other 
ways of letting ws streams share http/2 links... wish or something else 
will ultimately be a political http/2 decision.

> networks, databases and more).

Yes you don't have to sell that to me at least, libwebsockets also has a 
lot of users using it as both ws client and server all over the shop.  
Recently since lws also handles client and server http[s] part of the 
job, there has been interest in http/2 support but it currently is 
meaningless for ws since no standardized way to carry it.

>
> All these are different solutions that my users have used, none of 
> which are satisfactory. They are mostly independent. I'll make clear 
> the issues for each case.
>
> soon as they occur on the server, and as far as standards are 
> concerned there's only Websocket and text/event-stream allowing this, 
> and only Websocket is efficient with binary data.

So to be clear IIUI one of these TCP connections is the http one, and 
the TCP second connection is spawned by the stuff brought back by the 
first connection.

If http/2 guys had implemented ws transport on http/2 like they 
implemented everything else, this would be one TCP connection with two 
streams, and less roundtrip-times setting that up.  That's definitely 
what any future ws work should be aiming for.

> completely non-standard and requires implementing in all languages 

I think it's out of scope, you yourself just said "my users generally 
want ... a standard solution".  For http and ws that means one or 
another standardized http and some way to upgrade a stream or connection 
to ws.

> It's perfect! But requires a separate connection.

Yes ws/1 if we can call it that means one ws "connection" = one TCP 
connection.  But what we want to do is find an acceptable way to let ws 
flow as an http/2 stream.  So then the equivalent of ws BINARY stream 
will satisfy this IIUI.
> becomes necessary. That's probably not the case in general though.

Right... a lot of ws is just "long poll" and not actually intense... 
JSON is fine for both sides then.  If not, BINARY.

> It's yet another solution allowing a single solution, but again 

I think this falls into DIY "subprotocol definition" envisaged by the 
original ws and is out of scope (or in some different scope).

Basically I think what you're saying boils down to you want 
ws-over-http/2 (I completely agree that is what is needed), and you 
think http/2 + wish will deliver that.  I already know http/2 will 
deliver 90%+ of it by itself, so no argument here up to the "http/2 +" 
part at least.

-Andy

---

From: Loïc Hoguin <[email-masked]>
Date: Tue, 25 Apr 2017 14:17:02 +0200

> deliver 90%+ of it by itself, so no argument here up to the "http/2 +"

Yes.

-- 
Loïc Hoguin
https://ninenines.eu

---

From: Takeshi Yoshino <[email-masked]>
Date: Thu, 27 Apr 2017 19:37:34 +0900

Hi Andy-san, Loïc-san,

Thank you for providing feedback and data quickly.

I've been aware of that there are lots of non-browser/non-JS WS users in
the world. That's great and it's also great if WiSH could make them happier.

As noted in the Background section of the I-D, I think use of HTTP
semantics as-is would make things simpler. That's one of the keys of the
WiSH proposal. We now have good client/server/framework/intermediary
support for WS, but we've spent years to get that.

----

Regarding the fetch()/Streams, in addition to the specs Anne introduced, we
have an introduction doc.
https://docs.google.com/document/d/12ADRjKTu8LmzPgBZs0ksNz7SVsq0Vh6sFFeUq9Fb6Mk/pub

---

From: Takeshi Yoshino <[email-masked]>
Date: Thu, 27 Apr 2017 20:20:56 +0900

Anne,

Regarding my thoughts about choosing web APIs to focus,

I understand that we have many APIs around for doing the similar thing. I'm
following your thoughts regarding e.g. that we've frozen XHR while evolving
only fetch(). But I'm thinking that it's worth improving the WS ecosystem
even while we're evolving fetch()/Streams considering risk, gain and
velocity as follows.

Risk
- WiSH doesn't require any change to the API surface.
- WS API can always fallback to use WS/1.0 protocol when WiSH capability is
not announced.

Gain
- As I quoted in the first mail, there are lots of WS users in the Web.
According to Chrome's stats, 3.7% of page views contain WebSocket
initiation [1]. I think it's been serving significant portion of web apps'
cloud communication.
- The top starred issue for AppEngine has been WS [2].

Velocity
- As it stays inside the standard HTTP semantics, it wouldn't require so
much logic in the browser as when we introduced WS. The same about
frameworks/intermediaries, etc.
- We definitely continue making HTTP web APIs better by evolving fetch(),
but it takes some time. WiSH + HTTP/2 might be able to give enough benefit
quickly with small investment

Though all of these depend on data/feedback from the community as Addy,
Loïc, Greg have already expressed, I think it's worth exploring.

[1] Please note that our adoption metrics (
https://www.chromestatus.com/metrics/feature/timeline/popularity/1149) is
showing a smaller value currently, but will be replaced to more accurate
one according to which it's 3.7%.
[2] https://issuetracker.google.com/savedsearches/559750

---

From: Philipp Serafin <[email-masked]>
Date: Thu, 27 Apr 2017 22:52:28 +0000

+1 for WS-over-HTTP/2

I may be wrong, but intuitively, I'd say that the assumptions "The response
body is finite", "The request body is finite" and "The response comes after
the request" are pretty fundamental parts of HTTP's semantics - at least
they are inferred by the original purpose of HTTP and by "standard"
use-cases of HTTP on the web. As such I think it's likely that a lot of
software - client, server or intermediate - takes that assumption for
granted.

(The first assumption is a pretty weak one, due to long polling, SSE, etc -
but so far no widely deployed technology seems to break the other two
assumptions from what I know)

So at best the "strict HTTP semantics" name is slightly questionable
because, even if WiSH confirms to the letter of HTTP, it doesn't seem to
confirm to the spirit (expected usage pattern).
At worst I think this could cause failure with software that uses those
assumptions or could make future evolution of HTTP harder.

fetch+streams seems similar in that regard, as it allows the same
communication pattern but also leaves the framing and content-type up to
the application, making it harder for intermediaries or libraries to
distinguish such special streams from ordinary HTTP.

HTTP/2 is of course less problematic but still seems strange: We're taking
a bidi message-based protocol (HTTP/2 frames), layer a
request/response-based protocol on top (HTTP), then *undo* the
request/response semantics and layer *another* message-based protocol on
top (WS). Why not simply provide access to HTTP/2 frames? (Or, if URL
addressing and header support is needed, define a direct WS-to-HTTP/2
mapping)

As there used to be a draft for WS-over-HTTP2 [1] and there seems to be
some interest in that feature in this discussion, I'd like to ask: what
were the reasons the draft was discontinued. Are there some strong reasons
that speak against that feature?

[1] https://tools.ietf.org/html/draft-hirano-httpbis-websocket-over-http2-01

Takeshi Yoshino <[email-masked]> schrieb am Do., 27. Apr. 2017, 12:38:

> Regarding the fetch()/Streams, in addition to the specs Anne introduced,
> we have an introduction doc.
>