mirror of
https://github.com/microsoft/vscode.git
synced 2025-12-24 20:26:08 +00:00
Local and remote proxy settings (microsoft/vscode-copilot-release#3821)
This commit is contained in:
@@ -11,6 +11,7 @@ import { AddressInfo } from 'net';
|
||||
import { resetCaches } from '@vscode/proxy-agent';
|
||||
import * as vscode from 'vscode';
|
||||
import { middleware, Straightforward } from 'straightforward';
|
||||
import assert from 'assert';
|
||||
|
||||
(vscode.env.uiKind === vscode.UIKind.Web ? suite.skip : suite)('vscode API - network proxy support', () => {
|
||||
|
||||
@@ -166,4 +167,61 @@ import { middleware, Straightforward } from 'straightforward';
|
||||
await vscode.workspace.getConfiguration().update('integration-test.http.proxyAuth', undefined, vscode.ConfigurationTarget.Global);
|
||||
}
|
||||
});
|
||||
|
||||
(vscode.env.remoteName ? test : test.skip)('separate local / remote proxy settings', async () => {
|
||||
// Assumes test resolver runs with `--use-host-proxy`.
|
||||
const localProxy = 'http://localhost:1234';
|
||||
const remoteProxy = 'http://localhost:4321';
|
||||
|
||||
const actualLocalProxy1 = vscode.workspace.getConfiguration().get('http.proxy');
|
||||
|
||||
const p1 = waitForConfigChange('http.proxy');
|
||||
await vscode.workspace.getConfiguration().update('http.proxy', localProxy, vscode.ConfigurationTarget.Global);
|
||||
await p1;
|
||||
const actualLocalProxy2 = vscode.workspace.getConfiguration().get('http.proxy');
|
||||
|
||||
const p2 = waitForConfigChange('http.useLocalProxyConfiguration');
|
||||
await vscode.workspace.getConfiguration().update('http.useLocalProxyConfiguration', false, vscode.ConfigurationTarget.Global);
|
||||
await p2;
|
||||
const actualRemoteProxy1 = vscode.workspace.getConfiguration().get('http.proxy');
|
||||
|
||||
const p3 = waitForConfigChange('http.proxy');
|
||||
await vscode.workspace.getConfiguration().update('http.proxy', remoteProxy, vscode.ConfigurationTarget.Global);
|
||||
await p3;
|
||||
const actualRemoteProxy2 = vscode.workspace.getConfiguration().get('http.proxy');
|
||||
|
||||
const p4 = waitForConfigChange('http.proxy');
|
||||
await vscode.workspace.getConfiguration().update('http.proxy', undefined, vscode.ConfigurationTarget.Global);
|
||||
await p4;
|
||||
const actualRemoteProxy3 = vscode.workspace.getConfiguration().get('http.proxy');
|
||||
|
||||
const p5 = waitForConfigChange('http.proxy');
|
||||
await vscode.workspace.getConfiguration().update('http.useLocalProxyConfiguration', true, vscode.ConfigurationTarget.Global);
|
||||
await p5;
|
||||
const actualLocalProxy3 = vscode.workspace.getConfiguration().get('http.proxy');
|
||||
|
||||
const p6 = waitForConfigChange('http.proxy');
|
||||
await vscode.workspace.getConfiguration().update('http.proxy', undefined, vscode.ConfigurationTarget.Global);
|
||||
await p6;
|
||||
const actualLocalProxy4 = vscode.workspace.getConfiguration().get('http.proxy');
|
||||
|
||||
assert.strictEqual(actualLocalProxy1, '');
|
||||
assert.strictEqual(actualLocalProxy2, localProxy);
|
||||
assert.strictEqual(actualRemoteProxy1, '');
|
||||
assert.strictEqual(actualRemoteProxy2, remoteProxy);
|
||||
assert.strictEqual(actualRemoteProxy3, '');
|
||||
assert.strictEqual(actualLocalProxy3, localProxy);
|
||||
assert.strictEqual(actualLocalProxy4, '');
|
||||
|
||||
function waitForConfigChange(key: string) {
|
||||
return new Promise<void>(resolve => {
|
||||
const s = vscode.workspace.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(key)) {
|
||||
s.dispose();
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -649,7 +649,7 @@ export class ChannelClient implements IChannelClient, IDisposable {
|
||||
});
|
||||
|
||||
return result.finally(() => {
|
||||
disposable.dispose();
|
||||
disposable?.dispose(); // Seen as undefined in tests.
|
||||
this.activeRequests.delete(disposableWithRequestCancel);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ class CliMain extends Disposable {
|
||||
services.set(IUriIdentityService, new UriIdentityService(fileService));
|
||||
|
||||
// Request
|
||||
const requestService = new RequestService(configurationService, environmentService, logService);
|
||||
const requestService = new RequestService('local', configurationService, environmentService, logService);
|
||||
services.set(IRequestService, requestService);
|
||||
|
||||
// Download Service
|
||||
|
||||
@@ -134,91 +134,117 @@ export async function asJson<T = {}>(context: IRequestContext): Promise<T | null
|
||||
}
|
||||
}
|
||||
|
||||
export function updateProxyConfigurationsScope(scope: ConfigurationScope): void {
|
||||
registerProxyConfigurations(scope);
|
||||
export function updateProxyConfigurationsScope(useHostProxy: boolean, useHostProxyDefault: boolean): void {
|
||||
registerProxyConfigurations(useHostProxy, useHostProxyDefault);
|
||||
}
|
||||
|
||||
let proxyConfiguration: IConfigurationNode | undefined;
|
||||
function registerProxyConfigurations(scope: ConfigurationScope): void {
|
||||
let proxyConfiguration: IConfigurationNode[] = [];
|
||||
function registerProxyConfigurations(useHostProxy = true, useHostProxyDefault = true): void {
|
||||
const configurationRegistry = Registry.as<IConfigurationRegistry>(Extensions.Configuration);
|
||||
const oldProxyConfiguration = proxyConfiguration;
|
||||
proxyConfiguration = {
|
||||
id: 'http',
|
||||
order: 15,
|
||||
title: localize('httpConfigurationTitle', "HTTP"),
|
||||
type: 'object',
|
||||
scope,
|
||||
properties: {
|
||||
'http.proxy': {
|
||||
type: 'string',
|
||||
pattern: '^(https?|socks|socks4a?|socks5h?)://([^:]*(:[^@]*)?@)?([^:]+|\\[[:0-9a-fA-F]+\\])(:\\d+)?/?$|^$',
|
||||
markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables."),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxyStrictSSL': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: localize('strictSSL', "Controls whether the proxy server certificate should be verified against the list of supplied CAs."),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxyKerberosServicePrincipal': {
|
||||
type: 'string',
|
||||
markdownDescription: localize('proxyKerberosServicePrincipal', "Overrides the principal service name for Kerberos authentication with the HTTP proxy. A default based on the proxy hostname is used when this is not set."),
|
||||
restricted: true
|
||||
},
|
||||
'http.noProxy': {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
markdownDescription: localize('noProxy', "Specifies domain names for which proxy settings should be ignored for HTTP/HTTPS requests."),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxyAuthorization': {
|
||||
type: ['null', 'string'],
|
||||
default: null,
|
||||
markdownDescription: localize('proxyAuthorization', "The value to send as the `Proxy-Authorization` header for every network request."),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxySupport': {
|
||||
type: 'string',
|
||||
enum: ['off', 'on', 'fallback', 'override'],
|
||||
enumDescriptions: [
|
||||
localize('proxySupportOff', "Disable proxy support for extensions."),
|
||||
localize('proxySupportOn', "Enable proxy support for extensions."),
|
||||
localize('proxySupportFallback', "Enable proxy support for extensions, fall back to request options, when no proxy found."),
|
||||
localize('proxySupportOverride', "Enable proxy support for extensions, override request options."),
|
||||
],
|
||||
default: 'override',
|
||||
description: localize('proxySupport', "Use the proxy support for extensions."),
|
||||
restricted: true
|
||||
},
|
||||
'http.systemCertificates': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description: localize('systemCertificates', "Controls whether CA certificates should be loaded from the OS. (On Windows and macOS, a reload of the window is required after turning this off.)"),
|
||||
restricted: true
|
||||
},
|
||||
'http.experimental.systemCertificatesV2': {
|
||||
type: 'boolean',
|
||||
tags: ['experimental'],
|
||||
default: false,
|
||||
description: localize('systemCertificatesV2', "Controls whether experimental loading of CA certificates from the OS should be enabled. This uses a more general approach than the default implementation."),
|
||||
restricted: true
|
||||
},
|
||||
'http.electronFetch': {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: localize('electronFetch', "Controls whether use of Electron's fetch implementation instead of Node.js' should be enabled. All local extensions will get Electron's fetch implementation for the global fetch API."),
|
||||
restricted: true
|
||||
},
|
||||
'http.fetchAdditionalSupport': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
markdownDescription: localize('fetchAdditionalSupport', "Controls whether Node.js' fetch implementation should be extended with additional support. Currently proxy support ({0}) and system certificates ({1}) are added when the corresponding settings are enabled.", '`#http.proxySupport#`', '`#http.systemCertificates#`'),
|
||||
restricted: true
|
||||
proxyConfiguration = [
|
||||
{
|
||||
id: 'http',
|
||||
order: 15,
|
||||
title: localize('httpConfigurationTitle', "HTTP"),
|
||||
type: 'object',
|
||||
scope: ConfigurationScope.MACHINE,
|
||||
properties: {
|
||||
'http.useLocalProxyConfiguration': {
|
||||
type: 'boolean',
|
||||
default: useHostProxyDefault,
|
||||
markdownDescription: localize('useLocalProxy', "Controls whether in the remote extension host the local proxy configuration should be used. This setting only applies as a remote setting during [remote development](https://aka.ms/vscode-remote)."),
|
||||
restricted: true
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'http',
|
||||
order: 15,
|
||||
title: localize('httpConfigurationTitle', "HTTP"),
|
||||
type: 'object',
|
||||
scope: ConfigurationScope.APPLICATION,
|
||||
properties: {
|
||||
'http.electronFetch': {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
description: localize('electronFetch', "Controls whether use of Electron's fetch implementation instead of Node.js' should be enabled. All local extensions will get Electron's fetch implementation for the global fetch API."),
|
||||
restricted: true
|
||||
},
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'http',
|
||||
order: 15,
|
||||
title: localize('httpConfigurationTitle', "HTTP"),
|
||||
type: 'object',
|
||||
scope: useHostProxy ? ConfigurationScope.APPLICATION : ConfigurationScope.MACHINE,
|
||||
properties: {
|
||||
'http.proxy': {
|
||||
type: 'string',
|
||||
pattern: '^(https?|socks|socks4a?|socks5h?)://([^:]*(:[^@]*)?@)?([^:]+|\\[[:0-9a-fA-F]+\\])(:\\d+)?/?$|^$',
|
||||
markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxyStrictSSL': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
markdownDescription: localize('strictSSL', "Controls whether the proxy server certificate should be verified against the list of supplied CAs. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxyKerberosServicePrincipal': {
|
||||
type: 'string',
|
||||
markdownDescription: localize('proxyKerberosServicePrincipal', "Overrides the principal service name for Kerberos authentication with the HTTP proxy. A default based on the proxy hostname is used when this is not set. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.noProxy': {
|
||||
type: 'array',
|
||||
items: { type: 'string' },
|
||||
markdownDescription: localize('noProxy', "Specifies domain names for which proxy settings should be ignored for HTTP/HTTPS requests. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxyAuthorization': {
|
||||
type: ['null', 'string'],
|
||||
default: null,
|
||||
markdownDescription: localize('proxyAuthorization', "The value to send as the `Proxy-Authorization` header for every network request. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.proxySupport': {
|
||||
type: 'string',
|
||||
enum: ['off', 'on', 'fallback', 'override'],
|
||||
enumDescriptions: [
|
||||
localize('proxySupportOff', "Disable proxy support for extensions."),
|
||||
localize('proxySupportOn', "Enable proxy support for extensions."),
|
||||
localize('proxySupportFallback', "Enable proxy support for extensions, fall back to request options, when no proxy found."),
|
||||
localize('proxySupportOverride', "Enable proxy support for extensions, override request options."),
|
||||
],
|
||||
default: 'override',
|
||||
markdownDescription: localize('proxySupport', "Use the proxy support for extensions. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.systemCertificates': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
markdownDescription: localize('systemCertificates', "Controls whether CA certificates should be loaded from the OS. On Windows and macOS, a reload of the window is required after turning this off. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.experimental.systemCertificatesV2': {
|
||||
type: 'boolean',
|
||||
tags: ['experimental'],
|
||||
default: false,
|
||||
markdownDescription: localize('systemCertificatesV2', "Controls whether experimental loading of CA certificates from the OS should be enabled. This uses a more general approach than the default implementation. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`'),
|
||||
restricted: true
|
||||
},
|
||||
'http.fetchAdditionalSupport': {
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
markdownDescription: localize('fetchAdditionalSupport', "Controls whether Node.js' fetch implementation should be extended with additional support. Currently proxy support ({1}) and system certificates ({2}) are added when the corresponding settings are enabled. When during [remote development](https://aka.ms/vscode-remote) the {0} setting is disabled this setting can be configured in the local and the remote settings separately.", '`#http.useLocalProxyConfiguration#`', '`#http.proxySupport#`', '`#http.systemCertificates#`'),
|
||||
restricted: true
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
configurationRegistry.updateConfigurations({ add: [proxyConfiguration], remove: oldProxyConfiguration ? [oldProxyConfiguration] : [] });
|
||||
];
|
||||
configurationRegistry.updateConfigurations({ add: proxyConfiguration, remove: oldProxyConfiguration });
|
||||
}
|
||||
|
||||
registerProxyConfigurations(ConfigurationScope.APPLICATION);
|
||||
registerProxyConfigurations();
|
||||
|
||||
@@ -7,6 +7,9 @@ import { net } from 'electron';
|
||||
import { CancellationToken } from '../../../base/common/cancellation.js';
|
||||
import { IRequestContext, IRequestOptions } from '../../../base/parts/request/common/request.js';
|
||||
import { IRawRequestFunction, RequestService as NodeRequestService } from '../node/requestService.js';
|
||||
import { IConfigurationService } from '../../configuration/common/configuration.js';
|
||||
import { INativeEnvironmentService } from '../../environment/common/environment.js';
|
||||
import { ILogService } from '../../log/common/log.js';
|
||||
|
||||
function getRawRequest(options: IRequestOptions): IRawRequestFunction {
|
||||
return net.request as any as IRawRequestFunction;
|
||||
@@ -14,6 +17,14 @@ function getRawRequest(options: IRequestOptions): IRawRequestFunction {
|
||||
|
||||
export class RequestService extends NodeRequestService {
|
||||
|
||||
constructor(
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@INativeEnvironmentService environmentService: INativeEnvironmentService,
|
||||
@ILogService logService: ILogService,
|
||||
) {
|
||||
super('local', configurationService, environmentService, logService);
|
||||
}
|
||||
|
||||
override request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext> {
|
||||
return super.request({ ...(options || {}), getRawRequest, isChromiumNetwork: true }, token);
|
||||
}
|
||||
|
||||
@@ -21,12 +21,6 @@ import { AbstractRequestService, AuthInfo, Credentials, IRequestService } from '
|
||||
import { Agent, getProxyAgent } from './proxy.js';
|
||||
import { createGunzip } from 'zlib';
|
||||
|
||||
interface IHTTPConfiguration {
|
||||
proxy?: string;
|
||||
proxyStrictSSL?: boolean;
|
||||
proxyAuthorization?: string;
|
||||
}
|
||||
|
||||
export interface IRawRequestFunction {
|
||||
(options: http.RequestOptions, callback?: (res: http.IncomingMessage) => void): http.ClientRequest;
|
||||
}
|
||||
@@ -52,6 +46,7 @@ export class RequestService extends AbstractRequestService implements IRequestSe
|
||||
private shellEnvErrorLogged?: boolean;
|
||||
|
||||
constructor(
|
||||
private readonly machine: 'local' | 'remote',
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@INativeEnvironmentService private readonly environmentService: INativeEnvironmentService,
|
||||
@ILogService logService: ILogService,
|
||||
@@ -66,11 +61,9 @@ export class RequestService extends AbstractRequestService implements IRequestSe
|
||||
}
|
||||
|
||||
private configure() {
|
||||
const config = this.configurationService.getValue<IHTTPConfiguration | undefined>('http');
|
||||
|
||||
this.proxyUrl = config?.proxy;
|
||||
this.strictSSL = !!config?.proxyStrictSSL;
|
||||
this.authorization = config?.proxyAuthorization;
|
||||
this.proxyUrl = this.getConfigValue<string>('http.proxy');
|
||||
this.strictSSL = !!this.getConfigValue<boolean>('http.proxyStrictSSL');
|
||||
this.authorization = this.getConfigValue<string>('http.proxyAuthorization');
|
||||
}
|
||||
|
||||
async request(options: NodeRequestOptions, token: CancellationToken): Promise<IRequestContext> {
|
||||
@@ -115,7 +108,7 @@ export class RequestService extends AbstractRequestService implements IRequestSe
|
||||
|
||||
async lookupKerberosAuthorization(urlStr: string): Promise<string | undefined> {
|
||||
try {
|
||||
const spnConfig = this.configurationService.getValue<string>('http.proxyKerberosServicePrincipal');
|
||||
const spnConfig = this.getConfigValue<string>('http.proxyKerberosServicePrincipal');
|
||||
const response = await lookupKerberosAuthorization(urlStr, spnConfig, this.logService, 'RequestService#lookupKerberosAuthorization');
|
||||
return 'Negotiate ' + response;
|
||||
} catch (err) {
|
||||
@@ -128,6 +121,14 @@ export class RequestService extends AbstractRequestService implements IRequestSe
|
||||
const proxyAgent = await import('@vscode/proxy-agent');
|
||||
return proxyAgent.loadSystemCertificates({ log: this.logService });
|
||||
}
|
||||
|
||||
private getConfigValue<T>(key: string): T | undefined {
|
||||
if (this.machine === 'remote') {
|
||||
return this.configurationService.getValue<T>(key);
|
||||
}
|
||||
const values = this.configurationService.inspect<T>(key);
|
||||
return values.userLocalValue || values.defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
export async function lookupKerberosAuthorization(urlStr: string, spnConfig: string | undefined, logService: ILogService, logPrefix: string) {
|
||||
|
||||
@@ -923,7 +923,8 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
|
||||
|
||||
// Proxy
|
||||
if (!e || e.affectsConfiguration('http.proxy') || e.affectsConfiguration('http.noProxy')) {
|
||||
let newHttpProxy = (this.configurationService.getValue<string>('http.proxy') || '').trim()
|
||||
const inspect = this.configurationService.inspect<string>('http.proxy');
|
||||
let newHttpProxy = (inspect.userLocalValue || '').trim()
|
||||
|| (process.env['https_proxy'] || process.env['HTTPS_PROXY'] || process.env['http_proxy'] || process.env['HTTP_PROXY'] || '').trim() // Not standardized.
|
||||
|| undefined;
|
||||
|
||||
|
||||
@@ -129,7 +129,7 @@ class CliMain extends Disposable {
|
||||
userDataProfilesService.init()
|
||||
]);
|
||||
|
||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||
services.set(IRequestService, new SyncDescriptor(RequestService, ['remote']));
|
||||
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
||||
services.set(ITelemetryService, NullTelemetryService);
|
||||
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryServiceWithNoStorageService));
|
||||
|
||||
@@ -149,7 +149,7 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
|
||||
services.set(IExtensionHostStatusService, extensionHostStatusService);
|
||||
|
||||
// Request
|
||||
const requestService = new RequestService(configurationService, environmentService, logService);
|
||||
const requestService = new RequestService('remote', configurationService, environmentService, logService);
|
||||
services.set(IRequestService, requestService);
|
||||
|
||||
let oneDsAppender: ITelemetryAppender = NullAppender;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IExtHostWorkspaceProvider } from '../common/extHostWorkspace.js';
|
||||
import { ExtHostConfigProvider } from '../common/extHostConfiguration.js';
|
||||
import { ConfigurationInspect, ExtHostConfigProvider } from '../common/extHostConfiguration.js';
|
||||
import { MainThreadTelemetryShape } from '../common/extHost.protocol.js';
|
||||
import { IExtensionHostInitData } from '../../services/extensions/common/extensionHostProtocol.js';
|
||||
import { ExtHostExtensionService } from './extHostExtensionService.js';
|
||||
@@ -39,17 +39,20 @@ export function connectProxyResolver(
|
||||
disposables: DisposableStore,
|
||||
) {
|
||||
|
||||
const useHostProxy = initData.environment.useHostProxy;
|
||||
const doUseHostProxy = typeof useHostProxy === 'boolean' ? useHostProxy : !initData.remote.isRemote;
|
||||
const isRemote = initData.remote.isRemote;
|
||||
const useHostProxyDefault = initData.environment.useHostProxy ?? !isRemote;
|
||||
const fallbackToLocalKerberos = useHostProxyDefault;
|
||||
const loadLocalCertificates = useHostProxyDefault;
|
||||
const isUseHostProxyEnabled = () => configProvider.getConfiguration('http').get<boolean>('useLocalProxyConfiguration', useHostProxyDefault);
|
||||
const params: ProxyAgentParams = {
|
||||
resolveProxy: url => extHostWorkspace.resolveProxy(url),
|
||||
lookupProxyAuthorization: lookupProxyAuthorization.bind(undefined, extHostWorkspace, extHostLogService, mainThreadTelemetry, configProvider, {}, {}, initData.remote.isRemote, doUseHostProxy),
|
||||
getProxyURL: () => configProvider.getConfiguration('http').get('proxy'),
|
||||
getProxySupport: () => configProvider.getConfiguration('http').get<ProxySupportSetting>('proxySupport') || 'off',
|
||||
getNoProxyConfig: () => configProvider.getConfiguration('http').get<string[]>('noProxy') || [],
|
||||
isAdditionalFetchSupportEnabled: () => configProvider.getConfiguration('http').get<boolean>('fetchAdditionalSupport', true),
|
||||
addCertificatesV1: () => certSettingV1(configProvider),
|
||||
addCertificatesV2: () => certSettingV2(configProvider),
|
||||
lookupProxyAuthorization: lookupProxyAuthorization.bind(undefined, extHostWorkspace, extHostLogService, mainThreadTelemetry, configProvider, {}, {}, initData.remote.isRemote, fallbackToLocalKerberos),
|
||||
getProxyURL: () => getExtHostConfigValue<string>(configProvider, isRemote, 'http.proxy'),
|
||||
getProxySupport: () => getExtHostConfigValue<ProxySupportSetting>(configProvider, isRemote, 'http.proxySupport') || 'off',
|
||||
getNoProxyConfig: () => getExtHostConfigValue<string[]>(configProvider, isRemote, 'http.noProxy') || [],
|
||||
isAdditionalFetchSupportEnabled: () => getExtHostConfigValue<boolean>(configProvider, isRemote, 'http.fetchAdditionalSupport', true),
|
||||
addCertificatesV1: () => certSettingV1(configProvider, isRemote),
|
||||
addCertificatesV2: () => certSettingV2(configProvider, isRemote),
|
||||
log: extHostLogService,
|
||||
getLogLevel: () => {
|
||||
const level = extHostLogService.getLevel();
|
||||
@@ -68,13 +71,13 @@ export function connectProxyResolver(
|
||||
}
|
||||
},
|
||||
proxyResolveTelemetry: () => { },
|
||||
useHostProxy: doUseHostProxy,
|
||||
useHostProxy: isUseHostProxyEnabled(), // TODO: can change at runtime now
|
||||
loadAdditionalCertificates: async () => {
|
||||
const promises: Promise<string[]>[] = [];
|
||||
if (initData.remote.isRemote) {
|
||||
promises.push(loadSystemCertificates({ log: extHostLogService }));
|
||||
}
|
||||
if (doUseHostProxy) {
|
||||
if (loadLocalCertificates) {
|
||||
extHostLogService.trace('ProxyResolver#loadAdditionalCertificates: Loading certificates from main process');
|
||||
const certs = extHostWorkspace.loadCertificates(); // Loading from main process to share cache.
|
||||
certs.then(certs => extHostLogService.trace('ProxyResolver#loadAdditionalCertificates: Loaded certificates from main process', certs.length));
|
||||
@@ -249,14 +252,12 @@ function createPatchedModules(params: ProxyAgentParams, resolveProxy: ResolvePro
|
||||
};
|
||||
}
|
||||
|
||||
function certSettingV1(configProvider: ExtHostConfigProvider) {
|
||||
const http = configProvider.getConfiguration('http');
|
||||
return !http.get<boolean>('experimental.systemCertificatesV2', systemCertificatesV2Default) && !!http.get<boolean>('systemCertificates');
|
||||
function certSettingV1(configProvider: ExtHostConfigProvider, isRemote: boolean) {
|
||||
return !getExtHostConfigValue<boolean>(configProvider, isRemote, 'http.experimental.systemCertificatesV2', systemCertificatesV2Default) && !!getExtHostConfigValue<boolean>(configProvider, isRemote, 'http.systemCertificates');
|
||||
}
|
||||
|
||||
function certSettingV2(configProvider: ExtHostConfigProvider) {
|
||||
const http = configProvider.getConfiguration('http');
|
||||
return !!http.get<boolean>('experimental.systemCertificatesV2', systemCertificatesV2Default) && !!http.get<boolean>('systemCertificates');
|
||||
function certSettingV2(configProvider: ExtHostConfigProvider, isRemote: boolean) {
|
||||
return !!getExtHostConfigValue<boolean>(configProvider, isRemote, 'http.experimental.systemCertificatesV2', systemCertificatesV2Default) && !!getExtHostConfigValue<boolean>(configProvider, isRemote, 'http.systemCertificates');
|
||||
}
|
||||
|
||||
const modulesCache = new Map<IExtensionDescription | undefined, { http?: typeof http; https?: typeof https; undici?: typeof undiciType }>();
|
||||
@@ -306,7 +307,7 @@ async function lookupProxyAuthorization(
|
||||
proxyAuthenticateCache: Record<string, string | string[] | undefined>,
|
||||
basicAuthCache: Record<string, string | undefined>,
|
||||
isRemote: boolean,
|
||||
useHostProxy: boolean,
|
||||
fallbackToLocalKerberos: boolean,
|
||||
proxyURL: string,
|
||||
proxyAuthenticate: string | string[] | undefined,
|
||||
state: { kerberosRequested?: boolean; basicAuthCacheUsed?: boolean; basicAuthAttempt?: number }
|
||||
@@ -323,14 +324,14 @@ async function lookupProxyAuthorization(
|
||||
state.kerberosRequested = true;
|
||||
|
||||
try {
|
||||
const spnConfig = configProvider.getConfiguration('http').get<string>('proxyKerberosServicePrincipal');
|
||||
const spnConfig = getExtHostConfigValue<string>(configProvider, isRemote, 'http.proxyKerberosServicePrincipal');
|
||||
const response = await lookupKerberosAuthorization(proxyURL, spnConfig, extHostLogService, 'ProxyResolver#lookupProxyAuthorization');
|
||||
return 'Negotiate ' + response;
|
||||
} catch (err) {
|
||||
extHostLogService.debug('ProxyResolver#lookupProxyAuthorization Kerberos authentication failed', err);
|
||||
}
|
||||
|
||||
if (isRemote && useHostProxy) {
|
||||
if (isRemote && fallbackToLocalKerberos) {
|
||||
extHostLogService.debug('ProxyResolver#lookupProxyAuthorization Kerberos authentication lookup on host', `proxyURL:${proxyURL}`);
|
||||
const auth = await extHostWorkspace.lookupKerberosAuthorization(proxyURL);
|
||||
if (auth) {
|
||||
@@ -405,3 +406,13 @@ function sendTelemetry(mainThreadTelemetry: MainThreadTelemetryShape, authentica
|
||||
extensionHostType: isRemote ? 'remote' : 'local',
|
||||
});
|
||||
}
|
||||
|
||||
function getExtHostConfigValue<T>(configProvider: ExtHostConfigProvider, isRemote: boolean, key: string, fallback: T): T;
|
||||
function getExtHostConfigValue<T>(configProvider: ExtHostConfigProvider, isRemote: boolean, key: string): T | undefined;
|
||||
function getExtHostConfigValue<T>(configProvider: ExtHostConfigProvider, isRemote: boolean, key: string, fallback?: T): T | undefined {
|
||||
if (isRemote) {
|
||||
return configProvider.getConfiguration().get<T>(key) ?? fallback;
|
||||
}
|
||||
const values: ConfigurationInspect<T> | undefined = configProvider.getConfiguration().inspect<T>(key);
|
||||
return values?.globalLocalValue ?? values?.defaultValue ?? fallback;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ suite('Color Registry', function () {
|
||||
|
||||
const docUrl = 'https://raw.githubusercontent.com/microsoft/vscode-docs/main/api/references/theme-color.md';
|
||||
|
||||
const reqContext = await new RequestService(new TestConfigurationService(), environmentService, new NullLogService()).request({ url: docUrl }, CancellationToken.None);
|
||||
const reqContext = await new RequestService('local', new TestConfigurationService(), environmentService, new NullLogService()).request({ url: docUrl }, CancellationToken.None);
|
||||
const content = (await asTextOrError(reqContext))!;
|
||||
|
||||
const expression = /-\s*\`([\w\.]+)\`: (.*)/g;
|
||||
|
||||
@@ -111,7 +111,7 @@ export abstract class AbstractExtensionService extends Disposable implements IEx
|
||||
@IProductService protected readonly _productService: IProductService,
|
||||
@IWorkbenchExtensionManagementService protected readonly _extensionManagementService: IWorkbenchExtensionManagementService,
|
||||
@IWorkspaceContextService private readonly _contextService: IWorkspaceContextService,
|
||||
@IConfigurationService private readonly _configurationService: IConfigurationService,
|
||||
@IConfigurationService protected readonly _configurationService: IConfigurationService,
|
||||
@IExtensionManifestPropertiesService private readonly _extensionManifestPropertiesService: IExtensionManifestPropertiesService,
|
||||
@ILogService protected readonly _logService: ILogService,
|
||||
@IRemoteAgentService protected readonly _remoteAgentService: IRemoteAgentService,
|
||||
|
||||
@@ -15,7 +15,6 @@ import { Categories } from '../../../../platform/action/common/actionCommonCateg
|
||||
import { Action2, registerAction2 } from '../../../../platform/actions/common/actions.js';
|
||||
import { ICommandService } from '../../../../platform/commands/common/commands.js';
|
||||
import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js';
|
||||
import { ConfigurationScope } from '../../../../platform/configuration/common/configurationRegistry.js';
|
||||
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
|
||||
import { ExtensionKind } from '../../../../platform/environment/common/environment.js';
|
||||
import { IExtensionGalleryService } from '../../../../platform/extensionManagement/common/extensionManagement.js';
|
||||
@@ -414,7 +413,13 @@ export class NativeExtensionService extends AbstractExtensionService implements
|
||||
return this._startLocalExtensionHost(emitter);
|
||||
}
|
||||
|
||||
updateProxyConfigurationsScope(remoteEnv.useHostProxy ? ConfigurationScope.APPLICATION : ConfigurationScope.MACHINE);
|
||||
const useHostProxyDefault = remoteEnv.useHostProxy;
|
||||
this._register(this._configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('http.useLocalProxyConfiguration')) {
|
||||
updateProxyConfigurationsScope(this._configurationService.getValue('http.useLocalProxyConfiguration'), useHostProxyDefault);
|
||||
}
|
||||
}));
|
||||
updateProxyConfigurationsScope(this._configurationService.getValue('http.useLocalProxyConfiguration'), useHostProxyDefault);
|
||||
} else {
|
||||
|
||||
this._remoteAuthorityResolverService._setCanonicalURIProvider(async (uri) => uri);
|
||||
|
||||
@@ -29,7 +29,7 @@ export class BrowserRequestService extends AbstractRequestService implements IRe
|
||||
async request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext> {
|
||||
try {
|
||||
if (!options.proxyAuthorization) {
|
||||
options.proxyAuthorization = this.configurationService.getValue<string>('http.proxyAuthorization');
|
||||
options.proxyAuthorization = this.configurationService.inspect<string>('http.proxyAuthorization').userLocalValue;
|
||||
}
|
||||
const context = await this.logAndRequest(options, () => request(options, token, () => navigator.onLine));
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export class NativeRequestService extends AbstractRequestService implements IReq
|
||||
|
||||
async request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext> {
|
||||
if (!options.proxyAuthorization) {
|
||||
options.proxyAuthorization = this.configurationService.getValue<string>('http.proxyAuthorization');
|
||||
options.proxyAuthorization = this.configurationService.inspect<string>('http.proxyAuthorization').userLocalValue;
|
||||
}
|
||||
return this.logAndRequest(options, () => request(options, token, () => navigator.onLine));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user