Add protocol to portsAttributes

Part of #123750
This commit is contained in:
Alex Ross 2021-05-18 12:55:17 +02:00
parent 45aafeb326
commit e4159c8f89
No known key found for this signature in database
GPG key ID: 89DDDBA66CBA7840
6 changed files with 194 additions and 34 deletions

View file

@ -59,6 +59,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"default": {
@ -85,7 +93,13 @@
"properties": {
"onAutoForward": {
"type": "string",
"enum": ["notify", "openBrowser", "openPreview", "silent", "ignore"],
"enum": [
"notify",
"openBrowser",
"openPreview",
"silent",
"ignore"
],
"enumDescriptions": [
"Shows a notification when a port is automatically forwarded.",
"Opens the browser when the port is automatically forwarded. Depending on your settings, this could open an embedded browser.",
@ -110,9 +124,23 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"defaultSnippets": [{ "body": { "onAutoForward": "ignore" } }],
"defaultSnippets": [
{
"body": {
"onAutoForward": "ignore"
}
}
],
"markdownDescription": "Set default properties that are applied to all ports that don't get properties from the setting `remote.portsAttributes`. For example:\n\n```\n{\n \"onAutoForward\": \"ignore\"\n}\n```",
"additionalProperties": false
},

View file

@ -167,6 +167,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"default": {
@ -225,6 +233,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"defaultSnippets": [
@ -476,6 +492,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"default": {
@ -534,6 +558,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"defaultSnippets": [
@ -761,6 +793,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"default": {
@ -819,6 +859,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"defaultSnippets": [
@ -1012,6 +1060,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"default": {
@ -1070,6 +1126,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"defaultSnippets": [
@ -1232,6 +1296,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"default": {
@ -1290,6 +1362,14 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": [
"http",
"https"
],
"description": "The protocol to use when forwarding this port."
}
},
"defaultSnippets": [
@ -1379,4 +1459,4 @@
"additionalProperties": false
}
]
}
}

View file

@ -73,6 +73,11 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": ["http", "https"],
"description": "The protocol to use when forwarding this port."
}
},
"default": {
@ -130,6 +135,11 @@
"type": "boolean",
"markdownDescription": "When true, a modal dialog will show if the chosen local port isn't used for forwarding.",
"default": false
},
"protocol": {
"type": "string",
"enum": ["http", "https"],
"description": "The protocol to use when forwarding this port."
}
},
"defaultSnippets": [

View file

@ -543,6 +543,7 @@ class TunnelItem implements ITunnelItem {
tunnel.source ?? (tunnel.userForwarded ? nls.localize('tunnel.user', "User Forwarded") :
(type === TunnelType.Detected ? nls.localize('tunnel.staticallyForwarded', "Statically Forwarded") : nls.localize('tunnel.automatic', "Auto Forwarded"))),
!!tunnel.hasRunningProcess,
tunnel.localUri,
tunnel.localAddress,
tunnel.localPort,
closeable === undefined ? tunnel.closeable : closeable,
@ -559,6 +560,7 @@ class TunnelItem implements ITunnelItem {
public remotePort: number,
public source: string,
public hasRunningProcess: boolean,
public localUri?: URI,
public localAddress?: string,
public localPort?: number,
public closeable?: boolean,
@ -1167,12 +1169,8 @@ export namespace OpenPortInBrowserAction {
export function run(model: TunnelModel, openerService: IOpenerService, key: string) {
const tunnel = model.forwarded.get(key) || model.detected.get(key);
let address: string | undefined;
if (tunnel && tunnel.localAddress && (address = model.address(tunnel.remoteHost, tunnel.remotePort))) {
if (!address.startsWith('http')) {
address = `http://${address}`;
}
return openerService.open(URI.parse(address), { allowContributedOpeners: false });
if (tunnel) {
return openerService.open(tunnel.localUri, { allowContributedOpeners: false });
}
return Promise.resolve();
}
@ -1201,18 +1199,13 @@ export namespace OpenPortInPreviewAction {
export async function run(model: TunnelModel, openerService: IOpenerService, externalOpenerService: IExternalUriOpenerService, key: string) {
const tunnel = model.forwarded.get(key) || model.detected.get(key);
let address: string | undefined;
if (tunnel && tunnel.localAddress && (address = model.address(tunnel.remoteHost, tunnel.remotePort))) {
if (!address.startsWith('http')) {
address = `http://${address}`;
}
const uri = URI.parse(address);
if (tunnel) {
const sourceUri = URI.parse(`http://${tunnel.remoteHost}:${tunnel.remotePort}`);
const opener = await externalOpenerService.getOpener(uri, { sourceUri }, new CancellationTokenSource().token);
const opener = await externalOpenerService.getOpener(tunnel.localUri, { sourceUri }, new CancellationTokenSource().token);
if (opener) {
return opener.openExternalUri(uri, { sourceUri }, new CancellationTokenSource().token);
return opener.openExternalUri(tunnel.localUri, { sourceUri }, new CancellationTokenSource().token);
}
return openerService.open(uri);
return openerService.open(tunnel.localUri);
}
return Promise.resolve();
}

View file

@ -183,6 +183,11 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
type: 'boolean',
markdownDescription: localize('remote.portsAttributes.requireLocalPort', "When true, a modal dialog will show if the chosen local port isn't used for forwarding."),
default: false
},
'protocol': {
type: 'string',
enum: ['http', 'https'],
description: localize('remote.portsAttributes.protocol', "The protocol to use when forwarding this port.")
}
},
default: {
@ -226,6 +231,11 @@ Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration)
type: 'boolean',
markdownDescription: localize('remote.portsAttributes.requireLocalPort', "When true, a modal dialog will show if the chosen local port isn't used for forwarding."),
default: false
},
'protocol': {
type: 'string',
enum: ['http', 'https'],
description: localize('remote.portsAttributes.protocol', "The protocol to use when forwarding this port.")
}
},
defaultSnippets: [{ body: { onAutoForward: 'ignore' } }],

View file

@ -24,6 +24,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { flatten } from 'vs/base/common/arrays';
import Severity from 'vs/base/common/severity';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { URI } from 'vs/base/common/uri';
export const IRemoteExplorerService = createDecorator<IRemoteExplorerService>('remoteExplorerService');
export const REMOTE_EXPLORER_TYPE_KEY: string = 'remote.explorerType';
@ -53,6 +54,7 @@ export interface ITunnelItem {
remoteHost: string;
remotePort: number;
localAddress?: string;
localUri?: URI;
localPort?: number;
name?: string;
closeable?: boolean;
@ -74,6 +76,7 @@ export interface Tunnel {
remoteHost: string;
remotePort: number;
localAddress: string;
localUri: URI;
localPort?: number;
name?: string;
closeable?: boolean;
@ -149,6 +152,7 @@ export interface Attributes {
onAutoForward: OnPortForward | undefined,
elevateIfNeeded: boolean | undefined;
requireLocalPort: boolean | undefined;
protocol: string | undefined;
}
interface PortRange { start: number, end: number }
@ -187,7 +191,8 @@ export class PortsAttributes extends Disposable {
label: undefined,
onAutoForward: undefined,
elevateIfNeeded: undefined,
requireLocalPort: undefined
requireLocalPort: undefined,
protocol: undefined
};
while (index >= 0) {
const found = this.portsAttributes[index];
@ -196,17 +201,20 @@ export class PortsAttributes extends Disposable {
attributes.elevateIfNeeded = (found.elevateIfNeeded !== undefined) ? found.elevateIfNeeded : attributes.elevateIfNeeded;
attributes.label = found.label ?? attributes.label;
attributes.requireLocalPort = found.requireLocalPort;
attributes.protocol = found.protocol;
} else {
// It's a range or regex, which means that if the attribute is already set, we keep it
attributes.onAutoForward = attributes.onAutoForward ?? found.onAutoForward;
attributes.elevateIfNeeded = (attributes.elevateIfNeeded !== undefined) ? attributes.elevateIfNeeded : found.elevateIfNeeded;
attributes.label = attributes.label ?? found.label;
attributes.requireLocalPort = (attributes.requireLocalPort !== undefined) ? attributes.requireLocalPort : undefined;
attributes.protocol = attributes.protocol ?? found.protocol;
}
index = this.findNextIndex(port, commandLine, this.portsAttributes, index + 1);
}
if (attributes.onAutoForward !== undefined || attributes.elevateIfNeeded !== undefined
|| attributes.label !== undefined || attributes.requireLocalPort !== undefined) {
|| attributes.label !== undefined || attributes.requireLocalPort !== undefined
|| attributes.protocol !== undefined) {
return attributes;
}
@ -274,7 +282,8 @@ export class PortsAttributes extends Disposable {
elevateIfNeeded: setting.elevateIfNeeded,
onAutoForward: setting.onAutoForward,
label: setting.label,
requireLocalPort: setting.requireLocalPort
requireLocalPort: setting.requireLocalPort,
protocol: setting.protocol
});
}
@ -284,7 +293,8 @@ export class PortsAttributes extends Disposable {
elevateIfNeeded: defaults.elevateIfNeeded,
label: defaults.label,
onAutoForward: defaults.onAutoForward,
requireLocalPort: defaults.requireLocalPort
requireLocalPort: defaults.requireLocalPort,
protocol: defaults.protocol
};
}
@ -365,8 +375,9 @@ export class TunnelModel extends Disposable {
this._register(this.configPortsAttributes.onDidChangeAttributes(this.updateAttributes, this));
this.forwarded = new Map();
this.remoteTunnels = new Map();
this.tunnelService.tunnels.then(tunnels => {
tunnels.forEach(tunnel => {
this.tunnelService.tunnels.then(async (tunnels) => {
const attributes = await this.getAttributes(tunnels.map(tunnel => tunnel.tunnelRemotePort));
for (const tunnel of tunnels) {
if (tunnel.localAddress) {
const key = makeAddress(tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
const matchingCandidate = mapHasAddressLocalhostOrAllInterfaces(this._candidates ?? new Map(), tunnel.tunnelRemoteHost, tunnel.tunnelRemotePort);
@ -374,6 +385,7 @@ export class TunnelModel extends Disposable {
remotePort: tunnel.tunnelRemotePort,
remoteHost: tunnel.tunnelRemoteHost,
localAddress: tunnel.localAddress,
localUri: await this.makeLocalUri(tunnel.localAddress, attributes?.get(tunnel.tunnelRemotePort)),
localPort: tunnel.tunnelLocalPort,
runningProcess: matchingCandidate?.detail,
hasRunningProcess: !!matchingCandidate,
@ -383,7 +395,7 @@ export class TunnelModel extends Disposable {
});
this.remoteTunnels.set(key, tunnel);
}
});
}
});
this.detected = new Map();
@ -395,6 +407,7 @@ export class TunnelModel extends Disposable {
remoteHost: tunnel.tunnelRemoteHost,
remotePort: tunnel.tunnelRemotePort,
localAddress: tunnel.localAddress,
localUri: await this.makeLocalUri(tunnel.localAddress, (await this.getAttributes([tunnel.tunnelRemotePort]))?.get(tunnel.tunnelRemotePort)),
localPort: tunnel.tunnelLocalPort,
closeable: true,
runningProcess: matchingCandidate?.detail,
@ -418,6 +431,14 @@ export class TunnelModel extends Disposable {
}));
}
private makeLocalUri(localAddress: string, attributes?: Attributes) {
if (localAddress.startsWith('http')) {
return URI.parse(localAddress);
}
const protocol = attributes?.protocol ?? 'http';
return URI.parse(`${protocol}://${localAddress}`);
}
private makeTunnelPrivacy(isPublic: boolean) {
return isPublic ? TunnelPrivacy.Public : this.tunnelService.canMakePublic ? TunnelPrivacy.Private : TunnelPrivacy.ConstantPrivate;
}
@ -490,9 +511,9 @@ export class TunnelModel extends Disposable {
return this.dialogService.show(Severity.Info, mismatchString, [nls.localize('remote.localPortMismatch.Ok', "Ok")]);
}
async forward(remote: { host: string, port: number }, local?: number, name?: string, source?: string, elevateIfNeeded?: boolean, isPublic?: boolean, restore: boolean = true): Promise<RemoteTunnel | void> {
async forward(remote: { host: string, port: number }, local?: number, name?: string, source?: string, elevateIfNeeded?: boolean, isPublic?: boolean, restore: boolean = true, attributes?: Attributes): Promise<RemoteTunnel | void> {
const existingTunnel = mapHasAddressLocalhostOrAllInterfaces(this.forwarded, remote.host, remote.port);
const attributes = (await this.getAttributes([remote.port]))?.get(remote.port);
attributes = attributes ?? (await this.getAttributes([remote.port]))?.get(remote.port);
const localPort = (local !== undefined) ? local : remote.port;
if (!existingTunnel) {
@ -511,6 +532,7 @@ export class TunnelModel extends Disposable {
name: attributes?.label ?? name,
closeable: true,
localAddress: tunnel.localAddress,
localUri: await this.makeLocalUri(tunnel.localAddress, attributes),
runningProcess: matchingCandidate?.detail,
hasRunningProcess: !!matchingCandidate,
pid: matchingCandidate?.pid,
@ -530,6 +552,9 @@ export class TunnelModel extends Disposable {
if (attributes?.label ?? name) {
existingTunnel.name = attributes?.label ?? name;
}
if (attributes?.protocol) {
existingTunnel.localUri = this.makeLocalUri(existingTunnel.localAddress, attributes);
}
this._onForwardPort.fire();
return mapHasAddressLocalhostOrAllInterfaces(this.remoteTunnels, remote.host, remote.port);
}
@ -564,12 +589,14 @@ export class TunnelModel extends Disposable {
addEnvironmentTunnels(tunnels: TunnelDescription[] | undefined): void {
if (tunnels) {
tunnels.forEach(tunnel => {
for (const tunnel of tunnels) {
const matchingCandidate = mapHasAddressLocalhostOrAllInterfaces(this._candidates ?? new Map(), tunnel.remoteAddress.host, tunnel.remoteAddress.port);
const localAddress = typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port);
this.detected.set(makeAddress(tunnel.remoteAddress.host, tunnel.remoteAddress.port), {
remoteHost: tunnel.remoteAddress.host,
remotePort: tunnel.remoteAddress.port,
localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port),
localAddress: localAddress,
localUri: this.makeLocalUri(localAddress),
closeable: false,
runningProcess: matchingCandidate?.detail,
hasRunningProcess: !!matchingCandidate,
@ -577,7 +604,7 @@ export class TunnelModel extends Disposable {
privacy: TunnelPrivacy.ConstantPrivate,
userForwarded: false
});
});
}
}
this._environmentTunnelsSet = true;
this._onEnvironmentTunnelsSet.fire();
@ -654,11 +681,22 @@ export class TunnelModel extends Disposable {
private async updateAttributes() {
// If the label changes in the attributes, we should update it.
for (let forwarded of this.forwarded.values()) {
const attributes = (await this.getAttributes([forwarded.remotePort], false))?.get(forwarded.remotePort);
if (attributes && attributes.label && attributes.label !== forwarded.name) {
const tunnels = Array.from(this.forwarded.values());
const allAttributes = await this.getAttributes(tunnels.map(tunnel => tunnel.remotePort), false);
if (!allAttributes) {
return;
}
for (const forwarded of tunnels) {
const attributes = allAttributes.get(forwarded.remotePort);
if (!attributes) {
continue;
}
if (attributes.label && attributes.label !== forwarded.name) {
await this.name(forwarded.remoteHost, forwarded.remotePort, attributes.label);
}
if (attributes.protocol && attributes.protocol !== forwarded.localUri.scheme) {
await this.forward({ host: forwarded.remoteHost, port: forwarded.remotePort }, forwarded.localPort, forwarded.name, forwarded.source, undefined, undefined, undefined, attributes);
}
}
}
@ -716,7 +754,8 @@ export class TunnelModel extends Disposable {
elevateIfNeeded: config?.elevateIfNeeded,
label: config?.label,
onAutoForward: config?.onAutoForward ?? PortsAttributes.providedActionToAction(provider?.autoForwardAction),
requireLocalPort: config?.requireLocalPort
requireLocalPort: config?.requireLocalPort,
protocol: config?.protocol
});
});