wintercg / proposal-sockets-api

Proposal for an API for establishing TCP connections in Non-Browser JavaScript runtime environments
https://sockets-api.proposal.wintercg.org/
Other
46 stars 2 forks source link

Early data, handshake promise, and ALPN negotiation #14

Open mmastrac opened 1 year ago

mmastrac commented 1 year ago

The spec likely needs to deal with these three items which are necessary for creating HTTP/2 connections.

The socket options must allow outgoing connections to specify ALPN negotation strings and/or byte strings, and should return the negotiated values as part of a handshake.

In addition, a socket should be configured so that it may optionally send/receive data before the handshake promise completes.

jasnell commented 1 year ago

I touch on this a bit in #17 and #15 ...

Specifically, I think we absolutely want to have a mechanism for declaring the ALPN in the connect options (along with SNI), and we ought to be able to use socket.info.alpn / socket.info.sni metadata to identify the values that are negotiated when the handshake completes.

As for early data, the API is specifically designed to allow implementations to support early data. This was a key goal especially since I want to be able to use this API also to eventually support the implementation of QUIC in Node.js. Specifically, if we look at the pattern:

const enc = new TextEncoder();
const socket = connect('address:1234', { secureTransport: 'on' });
const writer = socket.writable.getWriter();
writer.write(enc.encode('foo'));
// ...

There is nothing in the API that says that the secure connection has to be fully established for the outbound writes to begin. What would be needed is some indicator that the implementation should wait to actually begin establishing the connection lazily when the writes start in order to support early data transmitted during the handshake... so something like...

const enc = new TextEncoder();
const socket = connect('address:1234', { secureTransport: 'early' });
const writer = socket.writable.getWriter();
writer.write(enc.encode('foo'));
// ...

This 'early' mode for secureTransport would be a clear indicator that the connection should support 0RTT/0.5RTT early data. We'd have to figure out some details, of course, but this is roughly the direction I had in mind. Absolutely open to other alternatives tho!

mmastrac commented 1 year ago

That's a good point -- early might be enough of a special case to justify its own initial mode like that. It could be specified that the first and only the first enqueued packet would be part of the early data.

An alternative API that may not be as ergonomic (though may be more composable) might be the ability to pass a Uint8Array | ReadableStream<Uint8Array> as an early data parameter when creating a TLS stream:

const socket = connect('address:1234', { secureTransport: 'on', earlyData: new ReadableStream({...}) });
jasnell commented 1 year ago

Yeah, I've played around with that approach for the QUIC api implementation and it is certainly workable. It's absolutely worth exploring both approaches.

jasnell commented 11 months ago

alpn has been added.