encapsulate details in happy-eyeballs

This commit is contained in:
Simon Knott 2024-09-17 09:07:06 +02:00
parent c29a5562e0
commit 5d4f149c64
No known key found for this signature in database
GPG key ID: 8CEDC00028084AEC
2 changed files with 15 additions and 5 deletions

View file

@ -30,7 +30,7 @@ import { HttpsProxyAgent, SocksProxyAgent } from '../utilsBundle';
import { BrowserContext, verifyClientCertificates } from './browserContext';
import { CookieStore, domainMatches } from './cookieStore';
import { MultipartFormData } from './formData';
import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent } from '../utils/happy-eyeballs';
import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent, timingForSocket } from '../utils/happy-eyeballs';
import type { CallMetadata } from './instrumentation';
import { SdkObject } from './instrumentation';
import type { Playwright } from './playwright';
@ -488,8 +488,9 @@ export abstract class APIRequestContext extends SdkObject {
request.on('socket', socket => {
// happy eyeballs don't emit lookup and connect events, so we use our custom ones
dnsLookupAt = (socket as any).dnsLookupAt;
tcpConnectionAt = (socket as any).tcpConnectionAt;
const happyEyeBallsTimings = timingForSocket(socket);
dnsLookupAt = happyEyeBallsTimings.dnsLookupAt;
tcpConnectionAt = happyEyeBallsTimings.tcpConnectionAt;
// non-happy-eyeballs sockets
socket.on('lookup', () => { dnsLookupAt = monotonicTime(); });

View file

@ -29,6 +29,9 @@ import { monotonicTime } from './time';
// Same as in Chromium (https://source.chromium.org/chromium/chromium/src/+/5666ff4f5077a7e2f72902f3a95f5d553ea0d88d:net/socket/transport_connect_job.cc;l=102)
const connectionAttemptDelayMs = 300;
const kDNSLookupAt = Symbol('kDNSLookupAt')
const kTCPConnectionAt = Symbol('kTCPConnectionAt')
class HttpHappyEyeballsAgent extends http.Agent {
createConnection(options: http.ClientRequestArgs, oncreate?: (err: Error | null, socket?: net.Socket) => void): net.Socket | undefined {
// There is no ambiguity in case of IP address.
@ -134,12 +137,12 @@ export async function createConnectionAsync(
port: options.port as number,
host: address });
(socket as any).dnsLookupAt = dnsLookupAt;
(socket as any)[kDNSLookupAt] = dnsLookupAt;
// Each socket may fire only one of 'connect', 'timeout' or 'error' events.
// None of these events are fired after socket.destroy() is called.
socket.on('connect', () => {
(socket as any).tcpConnectionAt = monotonicTime();
(socket as any)[kTCPConnectionAt] = monotonicTime();
connected.resolve();
oncreate?.(null, socket);
@ -195,3 +198,9 @@ function clientRequestArgsToHostName(options: http.ClientRequestArgs): string {
throw new Error('Either options.hostname or options.host must be provided');
}
export function timingForSocket(socket: net.Socket | tls.TLSSocket) {
return {
dnsLookupAt: (socket as any)[kDNSLookupAt] as number | undefined,
tcpConnectionAt: (socket as any)[kTCPConnectionAt] as number | undefined,
}
}