quic: support multiple ALPN negotiation · nodejs/node@abb881e
@@ -33,7 +33,6 @@ let debug = require('internal/util/debuglog').debuglog('quic', (fn) => {
33333434const {
3535Endpoint: Endpoint_,
36-Http3Application: Http3,
3736 setCallbacks,
38373938// The constants to be exposed to end users for various options.
@@ -115,7 +114,6 @@ const {
115114const kEmptyObject = { __proto__: null };
116115117116const {
118- kApplicationProvider,
119117 kBlocked,
120118 kConnect,
121119 kDatagram,
@@ -1787,7 +1785,6 @@ class QuicEndpoint {
17871785 * @param {{replace?: boolean}} [options]
17881786 */
17891787setSNIContexts(entries, options = kEmptyObject) {
1790-QuicEndpoint.#assertIsQuicEndpoint(this);
17911788if (this.#handle === undefined) {
17921789throw new ERR_INVALID_STATE('Endpoint is destroyed');
17931790}
@@ -2053,7 +2050,7 @@ function processIdentityOptions(identity, label) {
20532050function processTlsOptions(tls, forServer) {
20542051const {
20552052 servername,
2056-protocol,
2053+alpn,
20572054 ciphers = DEFAULT_CIPHERS,
20582055 groups = DEFAULT_GROUPS,
20592056 keylog = false,
@@ -2071,9 +2068,6 @@ function processTlsOptions(tls, forServer) {
20712068if (servername !== undefined) {
20722069validateString(servername, 'options.servername');
20732070}
2074-if (protocol !== undefined) {
2075-validateString(protocol, 'options.protocol');
2076-}
20772071if (ciphers !== undefined) {
20782072validateString(ciphers, 'options.ciphers');
20792073}
@@ -2084,11 +2078,42 @@ function processTlsOptions(tls, forServer) {
20842078validateBoolean(verifyClient, 'options.verifyClient');
20852079validateBoolean(tlsTrace, 'options.tlsTrace');
208620802081+// Encode the ALPN option to wire format (length-prefixed protocol names).
2082+// Server: array of protocol names. Client: single protocol name.
2083+// If not specified, the C++ default (h3) is used.
2084+let encodedAlpn;
2085+if (alpn !== undefined) {
2086+const protocols = forServer ?
2087+(ArrayIsArray(alpn) ? alpn : [alpn]) :
2088+[alpn];
2089+if (!forServer) {
2090+validateString(alpn, 'options.alpn');
2091+}
2092+let totalLen = 0;
2093+for (let i = 0; i < protocols.length; i++) {
2094+validateString(protocols[i], `options.alpn[${i}]`);
2095+if (protocols[i].length === 0 || protocols[i].length > 255) {
2096+throw new ERR_INVALID_ARG_VALUE(`options.alpn[${i}]`, protocols[i],
2097+'must be between 1 and 255 characters');
2098+}
2099+totalLen += 1 + protocols[i].length;
2100+}
2101+// Build wire format: [len1][name1][len2][name2]...
2102+const buf = Buffer.allocUnsafe(totalLen);
2103+let offset = 0;
2104+for (let i = 0; i < protocols.length; i++) {
2105+buf[offset++] = protocols[i].length;
2106+buf.write(protocols[i], offset, 'ascii');
2107+offset += protocols[i].length;
2108+}
2109+encodedAlpn = buf.toString('latin1');
2110+}
2111+20872112// Shared TLS options (same for all identities on the endpoint).
20882113const shared = {
20892114__proto__: null,
20902115 servername,
2091-protocol,
2116+alpn: encodedAlpn,
20922117 ciphers,
20932118 groups,
20942119 keylog,
@@ -2191,13 +2216,8 @@ function processSessionOptions(options, forServer = false) {
21912216 maxStreamWindow,
21922217 maxWindow,
21932218 cc,
2194-[kApplicationProvider]: provider,
21952219} = options;
219622202197-if (provider !== undefined) {
2198-validateObject(provider, 'options[kApplicationProvider]');
2199-}
2200-22012221if (cc !== undefined) {
22022222validateString(cc, 'options.cc');
22032223if (cc !== 'reno' || cc !== 'bbr' || cc !== 'cubic') {
@@ -2226,7 +2246,6 @@ function processSessionOptions(options, forServer = false) {
22262246 maxStreamWindow,
22272247 maxWindow,
22282248 sessionTicket,
2229- provider,
22302249 cc,
22312250};
22322251}
@@ -2328,7 +2347,8 @@ module.exports = {
23282347 QuicEndpoint,
23292348 QuicSession,
23302349 QuicStream,
2331- Http3,
2350+DEFAULT_CIPHERS,
2351+DEFAULT_GROUPS,
23322352};
2333235323342354ObjectDefineProperties(module.exports, {