diff --git a/packages/bruno-requests/src/network/agent-defaults.ts b/packages/bruno-requests/src/network/agent-defaults.ts deleted file mode 100644 index 5725349c2d8..00000000000 --- a/packages/bruno-requests/src/network/agent-defaults.ts +++ /dev/null @@ -1,24 +0,0 @@ -import http from 'node:http'; -import { fastLookup } from './fast-lookup'; - -/** - * Shared agent configuration for HTTP/HTTPS agents across the application. - * - * - keepAlive: Reuse TCP connections to avoid repeated handshakes. - * - maxSockets: 100 concurrent sockets per host — high enough for parallel - * collection runs, low enough to avoid file-descriptor exhaustion. - * - maxFreeSockets: 10 idle sockets kept alive for reuse between bursts. - * - scheduling: 'fifo' distributes requests across connections evenly, - * which avoids head-of-line blocking that 'lifo' (Node's default) can - * cause when one connection stalls. - * - lookup: fastLookup uses async c-ares (dns.resolve4/6) to bypass the - * libuv thread pool bottleneck, falling back to dns.lookup for /etc/hosts - * and mDNS hostnames. - */ -export const defaultAgentOptions: http.AgentOptions = { - keepAlive: true, - maxSockets: 100, - maxFreeSockets: 10, - scheduling: 'fifo', - lookup: fastLookup as http.AgentOptions['lookup'] -}; diff --git a/packages/bruno-requests/src/network/axios-instance.ts b/packages/bruno-requests/src/network/axios-instance.ts index abb4339e3c7..ba778d9e881 100644 --- a/packages/bruno-requests/src/network/axios-instance.ts +++ b/packages/bruno-requests/src/network/axios-instance.ts @@ -1,7 +1,6 @@ import { default as axios, AxiosRequestConfig, AxiosRequestHeaders, AxiosResponse, InternalAxiosRequestConfig } from 'axios'; import http from 'node:http'; import https from 'node:https'; -import { defaultAgentOptions } from './agent-defaults'; /** * @@ -30,8 +29,8 @@ type ModifiedAxiosResponse = AxiosResponse & { const baseRequestConfig: Partial = { proxy: false, - httpAgent: new http.Agent(defaultAgentOptions), - httpsAgent: new https.Agent(defaultAgentOptions), + httpAgent: new http.Agent({ keepAlive: true }), + httpsAgent: new https.Agent({ keepAlive: true }), transformRequest: function transformRequest(data: any, headers: AxiosRequestHeaders) { const contentType = headers.getContentType() || ''; const hasJSONContentType = contentType.includes('json'); diff --git a/packages/bruno-requests/src/network/fast-lookup.spec.ts b/packages/bruno-requests/src/network/fast-lookup.spec.ts deleted file mode 100644 index 89205f3e265..00000000000 --- a/packages/bruno-requests/src/network/fast-lookup.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import dns from 'node:dns'; -import { fastLookup } from './fast-lookup'; - -type DnsMethod = 'resolve4' | 'resolve6'; - -function mockResolve(method: DnsMethod, result: string[], err: Error | null = null): void { - (jest.spyOn(dns, method) as any).mockImplementation((_hostname: string, cb: Function) => { - cb(err, result); - }); -} - -function mockLookup(address: string, family: number): void { - (jest.spyOn(dns, 'lookup') as any).mockImplementation((_hostname: string, _options: dns.LookupOptions, cb: Function) => { - cb(null, address, family); - }); -} - -describe('fastLookup', () => { - afterEach(() => { - jest.restoreAllMocks(); - }); - - it('should resolve a public hostname via dns.resolve4', (done) => { - mockResolve('resolve4', ['93.184.216.34']); - - fastLookup('example.com', {}, (err, address, family) => { - expect(err).toBeNull(); - expect(address).toBe('93.184.216.34'); - expect(family).toBe(4); - done(); - }); - }); - - it('should fall back to dns.lookup when both resolvers fail', (done) => { - mockResolve('resolve4', [], new Error('ENOTFOUND')); - mockResolve('resolve6', [], new Error('ENOTFOUND')); - mockLookup('127.0.0.1', 4); - - fastLookup('my-local-host', {}, (err, address, family) => { - expect(err).toBeNull(); - expect(address).toBe('127.0.0.1'); - expect(family).toBe(4); - done(); - }); - }); - - it('should return all addresses when options.all is true', (done) => { - mockResolve('resolve4', ['1.2.3.4', '5.6.7.8']); - - fastLookup('example.com', { all: true }, (err, addresses) => { - expect(err).toBeNull(); - expect(Array.isArray(addresses)).toBe(true); - expect(addresses).toEqual([ - { address: '1.2.3.4', family: 4 }, - { address: '5.6.7.8', family: 4 } - ]); - done(); - }); - }); -}); diff --git a/packages/bruno-requests/src/network/fast-lookup.ts b/packages/bruno-requests/src/network/fast-lookup.ts deleted file mode 100644 index 6f103bff866..00000000000 --- a/packages/bruno-requests/src/network/fast-lookup.ts +++ /dev/null @@ -1,32 +0,0 @@ -import dns from 'node:dns'; - -/** - * Fast DNS lookup that bypasses the libuv thread pool. - * - * Tries dns.resolve4 then dns.resolve6 (async, c-ares based), - * falls back to dns.lookup for /etc/hosts and mDNS hostnames. - * - * NOTE: `options.family` is not currently respected — the function always - * tries IPv4 first regardless of the caller's preference. This is safe today - * because Bruno's HTTP agents use the default family (0), but should be - * addressed if any code path starts specifying a family. - */ -export function fastLookup( - hostname: string, - options: dns.LookupOptions | undefined, - callback: (err: Error | null, address: string | dns.LookupAddress[], family?: number) => void -): void { - dns.resolve4(hostname, (err4, addresses4) => { - if (!err4 && addresses4?.length) { - return options?.all - ? callback(null, addresses4.map((a) => ({ address: a, family: 4 }))) - : callback(null, addresses4[0], 4); - } - - // Forward to standard dns.lookup for /etc/hosts, mDNS, and other - // non-public hostnames that c-ares cannot resolve. - dns.lookup(hostname, options ?? {}, (err, address, family) => { - callback(err, address, family); - }); - }); -} diff --git a/packages/bruno-requests/src/utils/agent-cache.ts b/packages/bruno-requests/src/utils/agent-cache.ts index b054453058d..c7dc40105f5 100644 --- a/packages/bruno-requests/src/utils/agent-cache.ts +++ b/packages/bruno-requests/src/utils/agent-cache.ts @@ -3,7 +3,6 @@ import tls from 'node:tls'; import type { Agent as HttpAgent } from 'node:http'; import type { Agent as HttpsAgent } from 'node:https'; import { createTimelineAgentClass, createTimelineHttpAgentClass, type TimelineEntry, type AgentOptions, type HttpAgentOptions, type AgentClass, type HttpAgentClass } from './timeline-agent'; -import { defaultAgentOptions } from '../network/agent-defaults'; /** * Agent cache for SSL session reuse. @@ -268,16 +267,8 @@ function getOrCreateAgentInternal( } const AgentClass = timeline ? getTimelineClass(BaseAgentClass) : BaseAgentClass; - - // Inject shared agent defaults (DNS lookup, socket pool settings), then - // layer on the caller's options so per-agent overrides still take effect. - const optimizedOptions = { - ...defaultAgentOptions, - ...options - }; - // Convert raw `ca` to a secureContext that adds CAs on top of OpenSSL defaults - const resolvedOptions = applySecureContext(optimizedOptions); + const resolvedOptions = applySecureContext(options); let agent: HttpAgent | HttpsAgent; if (timeline) {