diff options
author | Alexandru Dima <alexdima@microsoft.com> | 2022-06-08 15:22:06 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-06-08 15:22:06 +0300 |
commit | 793b0fd55003b731a344c32111d529fedff04eed (patch) | |
tree | 6f9b4608538c40054246767b28852d1f76fdaad5 | |
parent | d9f97a4e817399febfc82d03cf3c9051103d6663 (diff) |
Fix handling of remote authorities using ipv6 (#151500)
Fixes #151438: Fix handling of remote authorities using ipv6
4 files changed, 89 insertions, 11 deletions
diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index e9231a1df85..db9d8a87c0e 100644 --- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -9,7 +9,7 @@ import { RemoteAuthorities } from 'vs/base/common/network'; import { URI } from 'vs/base/common/uri'; import { IProductService } from 'vs/platform/product/common/productService'; import { IRemoteAuthorityResolverService, IRemoteConnectionData, ResolvedAuthority, ResolverResult } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { getRemoteServerRootPath } from 'vs/platform/remote/common/remoteHosts'; +import { getRemoteServerRootPath, parseAuthorityWithOptionalPort } from 'vs/platform/remote/common/remoteHosts'; export class RemoteAuthorityResolverService extends Disposable implements IRemoteAuthorityResolverService { @@ -62,12 +62,9 @@ export class RemoteAuthorityResolverService extends Disposable implements IRemot private _doResolveAuthority(authority: string): ResolverResult { const connectionToken = this._connectionTokens.get(authority) || this._connectionToken; - if (authority.indexOf(':') >= 0) { - const pieces = authority.split(':'); - return { authority: { authority, host: pieces[0], port: parseInt(pieces[1], 10), connectionToken } }; - } - const port = (/^https:/.test(window.location.href) ? 443 : 80); - return { authority: { authority, host: authority, port: port, connectionToken } }; + const defaultPort = (/^https:/.test(window.location.href) ? 443 : 80); + const { host, port } = parseAuthorityWithOptionalPort(authority, defaultPort); + return { authority: { authority, host: host, port: port, connectionToken } }; } _clearResolvedAuthority(authority: string): void { diff --git a/src/vs/platform/remote/common/remoteHosts.ts b/src/vs/platform/remote/common/remoteHosts.ts index 760033e5789..783ea2e0896 100644 --- a/src/vs/platform/remote/common/remoteHosts.ts +++ b/src/vs/platform/remote/common/remoteHosts.ts @@ -33,3 +33,46 @@ export function getRemoteName(authority: string | undefined): string | undefined export function getRemoteServerRootPath(product: { quality?: string; commit?: string }): string { return `/${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`; } + +export function parseAuthorityWithPort(authority: string): { host: string; port: number } { + const { host, port } = parseAuthority(authority); + if (typeof port === 'undefined') { + throw new Error(`Remote authority doesn't contain a port!`); + } + return { host, port }; +} + +export function parseAuthorityWithOptionalPort(authority: string, defaultPort: number): { host: string; port: number } { + let { host, port } = parseAuthority(authority); + if (typeof port === 'undefined') { + port = defaultPort; + } + return { host, port }; +} + +function parseAuthority(authority: string): { host: string; port: number | undefined } { + if (authority.indexOf('+') >= 0) { + throw new Error(`Remote authorities containing '+' need to be resolved!`); + } + + // check for ipv6 with port + const m1 = authority.match(/^(\[[0-9a-z:]+\]):(\d+)$/); + if (m1) { + return { host: m1[1], port: parseInt(m1[2], 10) }; + } + + // check for ipv6 without port + const m2 = authority.match(/^(\[[0-9a-z:]+\])$/); + if (m2) { + return { host: m2[1], port: undefined }; + } + + // anything with a trailing port + const m3 = authority.match(/(.*):(\d+)$/); + if (m3) { + return { host: m3[1], port: parseInt(m3[2], 10) }; + } + + // doesn't contain a port + return { host: authority, port: undefined }; +} diff --git a/src/vs/platform/remote/test/common/remoteHosts.test.ts b/src/vs/platform/remote/test/common/remoteHosts.test.ts new file mode 100644 index 00000000000..da7349774f6 --- /dev/null +++ b/src/vs/platform/remote/test/common/remoteHosts.test.ts @@ -0,0 +1,38 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; +import { parseAuthorityWithOptionalPort, parseAuthorityWithPort } from 'vs/platform/remote/common/remoteHosts'; + +suite('remoteHosts', () => { + + test('parseAuthority hostname', () => { + assert.deepStrictEqual(parseAuthorityWithPort('localhost:8080'), { host: 'localhost', port: 8080 }); + }); + + test('parseAuthority ipv4', () => { + assert.deepStrictEqual(parseAuthorityWithPort('127.0.0.1:8080'), { host: '127.0.0.1', port: 8080 }); + }); + + test('parseAuthority ipv6', () => { + assert.deepStrictEqual(parseAuthorityWithPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080'), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 8080 }); + }); + + test('parseAuthorityWithOptionalPort hostname', () => { + assert.deepStrictEqual(parseAuthorityWithOptionalPort('localhost:8080', 123), { host: 'localhost', port: 8080 }); + assert.deepStrictEqual(parseAuthorityWithOptionalPort('localhost', 123), { host: 'localhost', port: 123 }); + }); + + test('parseAuthorityWithOptionalPort ipv4', () => { + assert.deepStrictEqual(parseAuthorityWithOptionalPort('127.0.0.1:8080', 123), { host: '127.0.0.1', port: 8080 }); + assert.deepStrictEqual(parseAuthorityWithOptionalPort('127.0.0.1', 123), { host: '127.0.0.1', port: 123 }); + }); + + test('parseAuthorityWithOptionalPort ipv6', () => { + assert.deepStrictEqual(parseAuthorityWithOptionalPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080', 123), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 8080 }); + assert.deepStrictEqual(parseAuthorityWithOptionalPort('[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', 123), { host: '[2001:0db8:85a3:0000:0000:8a2e:0370:7334]', port: 123 }); + }); + +}); diff --git a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts index ea87ef0642a..7b25b8f9142 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/electronExtensionService.ts @@ -30,7 +30,7 @@ import { flatten } from 'vs/base/common/arrays'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { IRemoteExplorerService } from 'vs/workbench/services/remote/common/remoteExplorerService'; import { Action2, registerAction2 } from 'vs/platform/actions/common/actions'; -import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; +import { getRemoteName, parseAuthorityWithPort } from 'vs/platform/remote/common/remoteHosts'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IWebWorkerExtensionHostDataProvider, IWebWorkerExtensionHostInitData, WebWorkerExtensionHost } from 'vs/workbench/services/extensions/browser/webWorkerExtensionHost'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; @@ -349,12 +349,12 @@ export abstract class ElectronExtensionService extends AbstractExtensionService const authorityPlusIndex = remoteAuthority.indexOf('+'); if (authorityPlusIndex === -1) { // This authority does not need to be resolved, simply parse the port number - const lastColon = remoteAuthority.lastIndexOf(':'); + const { host, port } = parseAuthorityWithPort(remoteAuthority); return { authority: { authority: remoteAuthority, - host: remoteAuthority.substring(0, lastColon), - port: parseInt(remoteAuthority.substring(lastColon + 1), 10), + host, + port, connectionToken: undefined } }; |