Local and remote proxy settings (microsoft/vscode-copilot-release#3821)

This commit is contained in:
Christof Marti
2025-01-15 19:18:34 +01:00
parent 4d44668917
commit 118e6f5373
15 changed files with 237 additions and 124 deletions

View File

@@ -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();
}
});
});
}
});
});

View File

@@ -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);
});
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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));

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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,

View File

@@ -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);

View File

@@ -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));

View File

@@ -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));
}