uWebSockets.js
uWebSockets.js copied to clipboard
Experimental HTTP3
There is now a HIGHLY experimental HTTP3 server built-in on x64 Linux binaries in unreleased binaries branch (npm install uNetworking/uWebSockets.js#binaries)
- uWS.startQuicServer() launches a hello world server on port 9004 ipv6 ::1
- It will not work if your localhost interface has no ipv6 address.
- You can reach it by ./quiche-client --no-verify https://[::1]:9004/
- I just remembered certs must lie in /home/alexhultman/uWebSockets.js/misc folder, so until I fix this nobody but me can run it 😉 But this will be fixed soon.
- This function is obviously just a smoke test and will be replaced with proper uWS.QuicApp interfaces!
You may be interested to have autotests and relative results of other servers, here is a ready-made solution https://interop.seemann.io/
P.S.
By last spec recommend not to use the word QUIC in high level interfaces, recommend instead H3 and WebTransport )
uWS::H3App is good
https://github.com/uNetworking/uWebSockets.js/blob/master/examples/H3lloWorld.js
This example works and is programmable. I just need to fix the hardcoded cert paths, port and localhost address then it should be testable by others.
Doing so, means you’ll be able to swap from uWS.App to uWS.H3App without changing any of your business logic — uWebSockets.js exposes HTTP/3 under the same very interface as it does HTTP/1.1.
Sounds cool for businessmen, but I'm an engineer and I doubt that compatibility will be 100%, but the goals are correct )
Server pushes are only allowed to happen if the client side has agreed to them. In HTTP/3 the client even sets a limit for how many pushes it accepts by informing the server what the max push stream ID is. Going over that limit will cause a connection error.
Since you still need to handle a failed push, and the fact pushes are merely optimization attempts, you can have the same interface for http 1, only that those pushes always fails
This is the same idea about making quic and TCP the same interface in uSockets; you just need to introduce the concept of streams inside connections, only that a TCP connection has a maximum of 1 stream.
Over generalization like this will allow everything to be more or less identical across all transports
uWS is primarily interested in a high-performance implementation of websocket, H3 is interesting in a possible implementation of WebTransport, my doubts were about the possibility of making a backward compatible websocket interface with WebTransport.
I don't agree. I think the killer demo/feature would be to make a standalone proxy that does WebSocket to WebTransport termination. A single binary you install with curl and run boom now you can test WebTransport. And when people feel like they want to invest more they use the server library directly
People want simplicity and familiarity, and they want to hit the ground running.
@alexhultman does the experimental http3 work include support for WebTransport that we can test, or is that yet to be implemented?
No but it will be very interesting to benchmark it when it becomes a standard.
Do you know where to track progress of WebTransport becoming a standard? I saw that HTTP/3 just became a standard but not sure about WebTransport
No I'm also wondering. WebTransport is a tiny layer above Http3 so maybe it will land soon?
WebTransport client has been available in Chrome Stable since v97 Jan 4 2022, you can open a console and use it right now. It needs a easy to use server preferably JavaScript, that would have large demand for those who need it. Not everyone needs it and WebSocket is a good easy option, if you have lots of streams and need low latency WebTransport is good
const wt = new WebTransport(url);
Yep but it's still a draft. And I'm still wondering how popular services like Cloudflare will support it. Until all that is figured out there's no reason to rush
I expect Cloudflare to expose WebTransport as a proxy to WebSocket origin servers.
Below is quick reference to the WebTransport browser client API:
const wt = new WebTransport(url);
// Datagram read
for await (const data of wt.datagrams.readable) { /* datagram message */ }
// Datagram write
const writer = wt.datagrams.writable.getWriter();
writer.write(data);
// Incoming Uni-Directional Streams
for await (const stream of wt.incomingUnidirectionalStreams) {
for await (const chunk of stream) { /* stream chunk */ }
}
// Create Uni-Directional Streams
const stream = await wt.createUnidirectionalStream();
const writer = stream.getWriter();
writer.write(data);
// Incoming Bi-Directional Streams
for await (const duplexStream of wt.incomingBidirectionalStreams) {
// read
for await (const chunk of duplexStream.readable) { /* stream chunk */ }
// write
const writer = duplexStream.writable.getWriter(); writer.write(data);
}
// Create Bi-Directional Streams
const duplexStream = await wt.createBidirectionalStream();
// read
for await (const chunk of duplexStream.readable) { /* stream chunk */ }
// write
const writer = duplexStream.writable.getWriter(); writer.write(data);
The server API could look like anything, here is potential mockup:
// App options, Incoming Streams and Datagram messages
app.wt('/', {
open: (wt) => {}, // new WebTransport connection
datagram: (wt, arrayBuffer) => {}, // incoming datagram message
stream: (wt, stream) => {}, // new incoming Bi or Uni directional stream
close: (wt, code) => {}, // wt closed
});
// Stream methods
stream.write(data);
stream.subscribe(topic);
stream.onData(arrayBuffer => {});
stream.onClose(code => {});
stream.close(code);
// WT methods
wt.datagram(data);
wt.subscribeDatagram(topic);
stream = wt.stream(options);
wt.close(code);
// App methods
app.publishDatagram(topic, data);
app.publishStream(topic, data);
I've taken a look at WebTransport in lsquic and looked at the draft. This will need support in lsquic, it's not possible to implement WT without inherent support in lsquic.
Link to track the status of the development of WebTransport in Safari https://github.com/WebKit/standards-positions/issues/18