chore: use happy eyeballs for client-certificates (#31859)
This commit is contained in:
Родитель
d3e2c6cbb2
Коммит
0c6ecf8df4
|
@ -20,7 +20,7 @@ import type https from 'https';
|
|||
import fs from 'fs';
|
||||
import tls from 'tls';
|
||||
import stream from 'stream';
|
||||
import { createSocket } from '../utils/happy-eyeballs';
|
||||
import { createSocket, createTLSSocket } from '../utils/happy-eyeballs';
|
||||
import { isUnderTest, ManualPromise } from '../utils';
|
||||
import type { SocksSocketClosedPayload, SocksSocketDataPayload, SocksSocketRequestedPayload } from '../common/socksProxy';
|
||||
import { SocksProxy } from '../common/socksProxy';
|
||||
|
@ -42,22 +42,21 @@ class ALPNCache {
|
|||
const result = new ManualPromise<string>();
|
||||
this._cache.set(cacheKey, result);
|
||||
result.then(success);
|
||||
const socket = tls.connect({
|
||||
createTLSSocket({
|
||||
host,
|
||||
port,
|
||||
servername: net.isIP(host) ? undefined : host,
|
||||
ALPNProtocols: ['h2', 'http/1.1'],
|
||||
rejectUnauthorized: false,
|
||||
});
|
||||
socket.on('secureConnect', () => {
|
||||
// The server may not respond with ALPN, in which case we default to http/1.1.
|
||||
result.resolve(socket.alpnProtocol || 'http/1.1');
|
||||
socket.end();
|
||||
});
|
||||
socket.on('error', error => {
|
||||
}).then(socket => {
|
||||
socket.on('secureConnect', () => {
|
||||
// The server may not respond with ALPN, in which case we default to http/1.1.
|
||||
result.resolve(socket.alpnProtocol || 'http/1.1');
|
||||
socket.end();
|
||||
});
|
||||
}).catch(error => {
|
||||
debugLogger.log('client-certificates', `ALPN error: ${error.message}`);
|
||||
result.resolve('http/1.1');
|
||||
socket.end();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import * as https from 'https';
|
|||
import * as net from 'net';
|
||||
import * as tls from 'tls';
|
||||
import { ManualPromise } from './manualPromise';
|
||||
import { assert } from './debug';
|
||||
|
||||
// Implementation(partial) of Happy Eyeballs 2 algorithm described in
|
||||
// https://www.rfc-editor.org/rfc/rfc8305
|
||||
|
@ -66,7 +67,41 @@ export async function createSocket(host: string, port: number): Promise<net.Sock
|
|||
});
|
||||
}
|
||||
|
||||
async function createConnectionAsync(options: http.ClientRequestArgs, oncreate: ((err: Error | null, socket?: net.Socket) => void) | undefined, useTLS: boolean) {
|
||||
export async function createTLSSocket(options: tls.ConnectionOptions): Promise<tls.TLSSocket> {
|
||||
return new Promise((resolve, reject) => {
|
||||
assert(options.host, 'host is required');
|
||||
if (net.isIP(options.host)) {
|
||||
const socket = tls.connect(options)
|
||||
socket.on('connect', () => resolve(socket));
|
||||
socket.on('error', error => reject(error));
|
||||
} else {
|
||||
createConnectionAsync(options, (err, socket) => {
|
||||
if (err)
|
||||
reject(err);
|
||||
if (socket)
|
||||
resolve(socket);
|
||||
}, true).catch(err => reject(err));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export async function createConnectionAsync(
|
||||
options: http.ClientRequestArgs,
|
||||
oncreate: ((err: Error | null, socket?: tls.TLSSocket) => void) | undefined,
|
||||
useTLS: true
|
||||
): Promise<void>;
|
||||
|
||||
export async function createConnectionAsync(
|
||||
options: http.ClientRequestArgs,
|
||||
oncreate: ((err: Error | null, socket?: net.Socket) => void) | undefined,
|
||||
useTLS: false
|
||||
): Promise<void>;
|
||||
|
||||
export async function createConnectionAsync(
|
||||
options: http.ClientRequestArgs,
|
||||
oncreate: ((err: Error | null, socket?: any) => void) | undefined,
|
||||
useTLS: boolean
|
||||
): Promise<void> {
|
||||
const lookup = (options as any).__testHookLookup || lookupAddresses;
|
||||
const hostname = clientRequestArgsToHostName(options);
|
||||
const addresses = await lookup(hostname);
|
||||
|
|
Загрузка…
Ссылка в новой задаче