Path: blob/main/src/vs/platform/agentHost/common/agentHostUri.ts
13395 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { encodeBase64, VSBuffer } from '../../../base/common/buffer.js';6import { Schemas } from '../../../base/common/network.js';7import { URI } from '../../../base/common/uri.js';8import type { ResourceLabelFormatter } from '../../label/common/label.js';910/**11* The URI scheme for accessing files on a remote agent host.12*13* URIs encode the original scheme, authority, and path so that any14* remote resource can be represented without assuming `file://`:15*16* ```17* vscode-agent-host://[connectionAuthority]/[originalScheme]/[originalAuthority]/[originalPath]18* ```19*20* For example, `file:///home/user/foo.ts` on remote `my-server` becomes:21* ```22* vscode-agent-host://my-server/file//home/user/foo.ts23* ```24*/25export const AGENT_HOST_SCHEME = 'vscode-agent-host';2627/**28* Wraps a remote URI into a {@link AGENT_HOST_SCHEME} URI that can be29* resolved through the agent host filesystem provider.30*31* @param originalUri The URI on the remote (e.g. `file:///path` or32* `agenthost-content:///sessionId/...`)33* @param connectionAuthority The sanitized connection identifier used as34* the URI authority (from {@link agentHostAuthority}).35*/36export function toAgentHostUri(originalUri: URI, connectionAuthority: string): URI {37if (connectionAuthority === 'local' && originalUri.scheme === Schemas.file) {38return originalUri;39}4041// Path format: /[originalScheme]/[originalAuthority]/[originalPath]42const originalAuthority = originalUri.authority || '';43return URI.from({44scheme: AGENT_HOST_SCHEME,45authority: connectionAuthority,46path: `/${originalUri.scheme}/${originalAuthority || '-'}${originalUri.path}`,47});48}4950/**51* Extracts the original URI from a {@link AGENT_HOST_SCHEME} URI.52*53* The inverse of {@link toAgentHostUri}.54*/55export function fromAgentHostUri(agentHostUri: URI): URI {56// Path: /[originalScheme]/[originalAuthority]/[rest of original path]57const path = agentHostUri.path;5859// Find first segment boundary after leading /60const schemeEnd = path.indexOf('/', 1);61if (schemeEnd === -1) {62// Malformed — treat whole path as file scheme63return URI.from({ scheme: 'file', path });64}6566const originalScheme = path.substring(1, schemeEnd);6768// Find second segment boundary (authority/path split)69const authorityEnd = path.indexOf('/', schemeEnd + 1);70if (authorityEnd === -1) {71// No path after authority72const originalAuthority = path.substring(schemeEnd + 1);73return URI.from({ scheme: originalScheme, authority: originalAuthority, path: '/' });74}7576let originalAuthority = path.substring(schemeEnd + 1, authorityEnd);77if (originalAuthority === '-') {78originalAuthority = '';79}8081const originalPath = path.substring(authorityEnd);8283return URI.from({84scheme: originalScheme,85authority: originalAuthority || undefined,86path: originalPath,87});88}8990/**91* Strips the redundant `ws://` scheme from an address. The transport layer92* already defaults to `ws://`, so only `wss://` needs to be preserved.93*/94export function normalizeRemoteAgentHostAddress(address: string): string {95if (address.startsWith('ws://')) {96return address.slice('ws://'.length);97}98return address;99}100101/**102* Encode a remote address into an identifier that is safe for use in103* both URI schemes and URI authorities, and is collision-free.104*105* Three tiers:106* 1. Purely alphanumeric addresses are returned as-is.107* 2. "Normal" addresses containing only `[a-zA-Z0-9.:-]` get colons108* replaced with `__` (double underscore) for human readability.109* Addresses containing `_` skip this tier to keep the encoding110* collision-free (`__` can only appear from colon replacement).111* 3. Everything else is url-safe base64-encoded with a `b64-` prefix.112*/113export function agentHostAuthority(address: string): string {114const normalized = normalizeRemoteAgentHostAddress(address);115if (/^[a-zA-Z0-9]+$/.test(normalized)) {116return normalized;117}118if (/^[a-zA-Z0-9.:\-]+$/.test(normalized)) {119return normalized.replaceAll(':', '__');120}121return 'b64-' + encodeBase64(VSBuffer.fromString(normalized), false, true);122}123124/**125* Label formatter for {@link AGENT_HOST_SCHEME} URIs. Strips the two126* leading path segments (`/scheme/authority`) to display the original127* file path.128*/129export const AGENT_HOST_LABEL_FORMATTER: ResourceLabelFormatter = {130scheme: AGENT_HOST_SCHEME,131formatting: {132label: '${path}',133separator: '/',134stripPathSegments: 2,135},136};137138139