tls: add ALPNCallback server option for dynamic ALPN negotiation
This is an alternate fix for #45056 (closed) (which replaces #45075).
I'd definitely appreciate careful reviewing of the native parts of this, I'm not familiar with a lot of the standard approaches and concerns there and this is definitely more complex than the other approach.
A few open questions:
-
I've usedResolved in favour ofserverName
as the field for the server name that's passed to the callback. Some of the existing API usesservername
instead, but that casing seems very odd. Which do we prefer?servername
- The implementation here throws an error if the server callback returns a string that isn't in the client's offered protocols. Reading the RFC that's implicitly what you should do, but I don't think it's strictly required - it's weird but not 100% invalid as far as I can tell to send an ALPN response telling the client you're speaking a protocol they didn't ask for. I assume we're fine with being strict here, but worth considering.
- The implementation here doesn't support returning no ALPN extension if you set a callback. If you've provided an ALPN callback, then when an ALPN-using client arrives you must either return an ALPN response or reject the connection entirely. That's equivalent to the current
ALPNProtocols
behaviour, but is that correct? We could relax this with some other special return value, either now or in future, e.g. "returnundefined
if no ALPN values match to reject the handshake, orfalse
to skip ALPN and send no handshake at all" (or some other pair of non-string values). I'm not sure if anybody will need this, but it's perfectly legitimate behaviour (servers aren't required to send ALPN responses AFAICT) so it's probably good to at least leave space for this in the API design in case we want it later.