Skip to content

Commit

Permalink
Allow H2 and CA from options (microsoft#228697)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrmarti authored and NikolaRHristov committed Nov 19, 2024
1 parent 8887c61 commit 016b89d
Showing 1 changed file with 64 additions and 11 deletions.
75 changes: 64 additions & 11 deletions Source/vs/workbench/api/node/proxyResolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,13 @@ function patchFetch(originalFetch: typeof globalThis.fetch, configProvider: ExtH
return originalFetch(input, init);
}
const ca = addCerts ? [...tls.rootCertificates, ...await loadAdditionalCertificates()] : undefined;
const { allowH2, requestCA, proxyCA } = getAgentOptions(ca, init);
if (!proxyURL) {
const modifiedInit = {
...init,
dispatcher: new undici.Agent({
allowH2: true,
connect: { ca },
allowH2,
connect: { ca: requestCA },
})
};
return originalFetch(input, modifiedInit);
Expand All @@ -208,12 +209,10 @@ function patchFetch(originalFetch: typeof globalThis.fetch, configProvider: ExtH
...init,
dispatcher: new undici.ProxyAgent({
uri: proxyURL,
allowH2: true,
allowH2,
headers: proxyAuthorization ? { 'Proxy-Authorization': proxyAuthorization } : undefined,
...(addCerts ? {
proxyTls: { ca },
requestTls: { ca },
} : {}),
...(requestCA ? { requestTls: { ca: requestCA } } : {}),
...(proxyCA ? { proxyTls: { ca: proxyCA } } : {}),
clientFactory: (origin: URL, opts: object): undiciType.Dispatcher => (new undici.Pool(origin, opts) as any).compose((dispatch: undiciType.Dispatcher['dispatch']) => {
class ProxyAuthHandler extends undici.DecoratorHandler {
private abort: ((err?: Error) => void) | undefined;
Expand Down Expand Up @@ -369,7 +368,7 @@ function certSettingV2(configProvider: ExtHostConfigProvider) {
return !!http.get<boolean>('experimental.systemCertificatesV2', systemCertificatesV2Default) && !!http.get<boolean>('systemCertificates');
}

const modulesCache = new Map<IExtensionDescription | undefined, { http?: typeof http; https?: typeof https }>();
const modulesCache = new Map<IExtensionDescription | undefined, { http?: typeof http; https?: typeof https; undici?: typeof undiciType }>();
function configureModuleLoading(extensionService: ExtHostExtensionService, lookup: ReturnType<typeof createPatchedModules>): Promise<void> {
return extensionService.getExtensionPathIndex()
.then(extensionPaths => {
Expand All @@ -384,7 +383,7 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku
return lookup.tls;
}

if (request !== 'http' && request !== 'https') {
if (request !== 'http' && request !== 'https' && request !== 'undici') {
return original.apply(this, arguments);
}

Expand All @@ -394,14 +393,68 @@ function configureModuleLoading(extensionService: ExtHostExtensionService, looku
modulesCache.set(ext, cache = {});
}
if (!cache[request]) {
const mod = lookup[request];
cache[request] = <any>{ ...mod }; // Copy to work around #93167.
if (request === 'undici') {
const undici = original.apply(this, arguments);
patchUndici(undici);
cache[request] = undici;
} else {
const mod = lookup[request];
cache[request] = <any>{ ...mod }; // Copy to work around #93167.
}
}
return cache[request];
};
});
}

const agentOptions = Symbol('agentOptions');
const proxyAgentOptions = Symbol('proxyAgentOptions');

function patchUndici(undici: typeof undiciType) {
const originalAgent = undici.Agent;
const patchedAgent = function PatchedAgent(opts?: undiciType.Agent.Options): undiciType.Agent {
const agent = new originalAgent(opts);
(agent as any)[agentOptions] = {
...opts,
...(opts?.connect && typeof opts?.connect === 'object' ? { connect: { ...opts.connect } } : undefined),
};
return agent;
};
patchedAgent.prototype = originalAgent.prototype;
(undici as any).Agent = patchedAgent;

const originalProxyAgent = undici.ProxyAgent;
const patchedProxyAgent = function PatchedProxyAgent(opts: undiciType.ProxyAgent.Options | string): undiciType.ProxyAgent {
const proxyAgent = new originalProxyAgent(opts);
(proxyAgent as any)[proxyAgentOptions] = typeof opts === 'string' ? opts : {
...opts,
...(opts?.connect && typeof opts?.connect === 'object' ? { connect: { ...opts.connect } } : undefined),
};
return proxyAgent;
};
patchedProxyAgent.prototype = originalProxyAgent.prototype;
(undici as any).ProxyAgent = patchedProxyAgent;
}

function getAgentOptions(systemCA: string[] | undefined, requestInit: RequestInit | undefined) {
let allowH2: boolean | undefined;
let requestCA: string | Buffer | Array<string | Buffer> | undefined = systemCA;
let proxyCA: string | Buffer | Array<string | Buffer> | undefined = systemCA;
const dispatcher: undiciType.Dispatcher = (requestInit as any)?.dispatcher;
const originalAgentOptions: undiciType.Agent.Options | undefined = dispatcher && (dispatcher as any)[agentOptions];
if (originalAgentOptions) {
allowH2 = originalAgentOptions.allowH2;
requestCA = originalAgentOptions.connect && typeof originalAgentOptions.connect === 'object' && 'ca' in originalAgentOptions.connect && originalAgentOptions.connect.ca || systemCA;
}
const originalProxyAgentOptions: undiciType.ProxyAgent.Options | string | undefined = dispatcher && (dispatcher as any)[proxyAgentOptions];
if (originalProxyAgentOptions && typeof originalProxyAgentOptions === 'object') {
allowH2 = originalProxyAgentOptions.allowH2;
requestCA = originalProxyAgentOptions.requestTls && 'ca' in originalProxyAgentOptions.requestTls && originalProxyAgentOptions.requestTls.ca || systemCA;
proxyCA = originalProxyAgentOptions.proxyTls && 'ca' in originalProxyAgentOptions.proxyTls && originalProxyAgentOptions.proxyTls.ca || systemCA;
}
return { allowH2, requestCA, proxyCA };
}

async function lookupProxyAuthorization(
extHostWorkspace: IExtHostWorkspaceProvider,
extHostLogService: ILogService,
Expand Down

0 comments on commit 016b89d

Please sign in to comment.