Path: blob/main/extensions/copilot/src/util/vs/base/common/network.ts
13405 views
//!!! DO NOT modify, this file was COPIED from 'microsoft/vscode'12/*---------------------------------------------------------------------------------------------3* Copyright (c) Microsoft Corporation. All rights reserved.4* Licensed under the MIT License. See License.txt in the project root for license information.5*--------------------------------------------------------------------------------------------*/67import * as errors from './errors';8import * as platform from './platform';9import { equalsIgnoreCase, startsWithIgnoreCase } from './strings';10import { URI } from './uri';11import * as paths from './path';1213export namespace Schemas {1415/**16* A schema that is used for models that exist in memory17* only and that have no correspondence on a server or such.18*/19export const inMemory = 'inmemory';2021/**22* A schema that is used for setting files23*/24export const vscode = 'vscode';2526/**27* A schema that is used for internal private files28*/29export const internal = 'private';3031/**32* A walk-through document.33*/34export const walkThrough = 'walkThrough';3536/**37* An embedded code snippet.38*/39export const walkThroughSnippet = 'walkThroughSnippet';4041export const http = 'http';4243export const https = 'https';4445export const file = 'file';4647export const mailto = 'mailto';4849export const untitled = 'untitled';5051export const data = 'data';5253export const command = 'command';5455export const vscodeRemote = 'vscode-remote';5657export const vscodeRemoteResource = 'vscode-remote-resource';5859export const vscodeManagedRemoteResource = 'vscode-managed-remote-resource';6061export const vscodeUserData = 'vscode-userdata';6263export const vscodeCustomEditor = 'vscode-custom-editor';6465export const vscodeNotebookCell = 'vscode-notebook-cell';66export const vscodeNotebookCellMetadata = 'vscode-notebook-cell-metadata';67export const vscodeNotebookCellMetadataDiff = 'vscode-notebook-cell-metadata-diff';68export const vscodeNotebookCellOutput = 'vscode-notebook-cell-output';69export const vscodeNotebookCellOutputDiff = 'vscode-notebook-cell-output-diff';70export const vscodeNotebookMetadata = 'vscode-notebook-metadata';71export const vscodeInteractiveInput = 'vscode-interactive-input';7273export const vscodeSettings = 'vscode-settings';7475export const vscodeWorkspaceTrust = 'vscode-workspace-trust';7677export const vscodeTerminal = 'vscode-terminal';7879/** Scheme used for code blocks in chat. */80export const vscodeChatCodeBlock = 'vscode-chat-code-block';8182/** Scheme used for LHS of code compare (aka diff) blocks in chat. */83export const vscodeChatCodeCompareBlock = 'vscode-chat-code-compare-block';8485/** Scheme used for the chat input editor. */86export const vscodeChatEditor = 'vscode-chat-editor';8788/** Scheme used for the chat input part */89export const vscodeChatInput = 'chatSessionInput';9091/** Scheme used for local chat session content */92export const vscodeLocalChatSession = 'vscode-chat-session';9394/**95* Scheme used internally for webviews that aren't linked to a resource (i.e. not custom editors)96*/97export const webviewPanel = 'webview-panel';9899/**100* Scheme used for loading the wrapper html and script in webviews.101*/102export const vscodeWebview = 'vscode-webview';103104/**105* Scheme used for integrated browser tabs using WebContentsView.106*/107export const vscodeBrowser = 'vscode-browser';108109/**110* Scheme used for extension pages111*/112export const extension = 'extension';113114/**115* Scheme used as a replacement of `file` scheme to load116* files with our custom protocol handler (desktop only).117*/118export const vscodeFileResource = 'vscode-file';119120/**121* Scheme used for temporary resources122*/123export const tmp = 'tmp';124125/**126* Scheme used vs live share127*/128export const vsls = 'vsls';129130/**131* Scheme used for the Source Control commit input's text document132*/133export const vscodeSourceControl = 'vscode-scm';134135/**136* Scheme used for input box for creating comments.137*/138export const commentsInput = 'comment';139140/**141* Scheme used for special rendering of settings in the release notes142*/143export const codeSetting = 'code-setting';144145/**146* Scheme used for output panel resources147*/148export const outputChannel = 'output';149150/**151* Scheme used for the accessible view152*/153export const accessibleView = 'accessible-view';154155/**156* Used for snapshots of chat edits157*/158export const chatEditingSnapshotScheme = 'chat-editing-snapshot-text-model';159export const chatEditingModel = 'chat-editing-text-model';160161/**162* Used for rendering multidiffs in copilot agent sessions163*/164export const copilotPr = 'copilot-pr';165}166167export function matchesScheme(target: URI | string, scheme: string): boolean {168if (URI.isUri(target)) {169return equalsIgnoreCase(target.scheme, scheme);170} else {171return startsWithIgnoreCase(target, scheme + ':');172}173}174175export function matchesSomeScheme(target: URI | string, ...schemes: string[]): boolean {176return schemes.some(scheme => matchesScheme(target, scheme));177}178179export const connectionTokenCookieName = 'vscode-tkn';180export const connectionTokenQueryName = 'tkn';181182class RemoteAuthoritiesImpl {183private readonly _hosts: { [authority: string]: string | undefined } = Object.create(null);184private readonly _ports: { [authority: string]: number | undefined } = Object.create(null);185private readonly _connectionTokens: { [authority: string]: string | undefined } = Object.create(null);186private _preferredWebSchema: 'http' | 'https' = 'http';187private _delegate: ((uri: URI) => URI) | null = null;188private _serverRootPath: string = '/';189190setPreferredWebSchema(schema: 'http' | 'https') {191this._preferredWebSchema = schema;192}193194setDelegate(delegate: (uri: URI) => URI): void {195this._delegate = delegate;196}197198setServerRootPath(product: { quality?: string; commit?: string }, serverBasePath: string | undefined): void {199this._serverRootPath = paths.posix.join(serverBasePath ?? '/', getServerProductSegment(product));200}201202getServerRootPath(): string {203return this._serverRootPath;204}205206private get _remoteResourcesPath(): string {207return paths.posix.join(this._serverRootPath, Schemas.vscodeRemoteResource);208}209210set(authority: string, host: string, port: number): void {211this._hosts[authority] = host;212this._ports[authority] = port;213}214215setConnectionToken(authority: string, connectionToken: string): void {216this._connectionTokens[authority] = connectionToken;217}218219getPreferredWebSchema(): 'http' | 'https' {220return this._preferredWebSchema;221}222223rewrite(uri: URI): URI {224if (this._delegate) {225try {226return this._delegate(uri);227} catch (err) {228errors.onUnexpectedError(err);229return uri;230}231}232const authority = uri.authority;233let host = this._hosts[authority];234if (host && host.indexOf(':') !== -1 && host.indexOf('[') === -1) {235host = `[${host}]`;236}237const port = this._ports[authority];238const connectionToken = this._connectionTokens[authority];239let query = `path=${encodeURIComponent(uri.path)}`;240if (typeof connectionToken === 'string') {241query += `&${connectionTokenQueryName}=${encodeURIComponent(connectionToken)}`;242}243return URI.from({244scheme: platform.isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource,245authority: `${host}:${port}`,246path: this._remoteResourcesPath,247query248});249}250}251252export const RemoteAuthorities = new RemoteAuthoritiesImpl();253254export function getServerProductSegment(product: { quality?: string; commit?: string }) {255return `${product.quality ?? 'oss'}-${product.commit ?? 'dev'}`;256}257258/**259* A string pointing to a path inside the app. It should not begin with ./ or ../260*/261export type AppResourcePath = (262`a${string}` | `b${string}` | `c${string}` | `d${string}` | `e${string}` | `f${string}`263| `g${string}` | `h${string}` | `i${string}` | `j${string}` | `k${string}` | `l${string}`264| `m${string}` | `n${string}` | `o${string}` | `p${string}` | `q${string}` | `r${string}`265| `s${string}` | `t${string}` | `u${string}` | `v${string}` | `w${string}` | `x${string}`266| `y${string}` | `z${string}`267);268269export const builtinExtensionsPath: AppResourcePath = 'vs/../../extensions';270export const nodeModulesPath: AppResourcePath = 'vs/../../node_modules';271export const nodeModulesAsarPath: AppResourcePath = 'vs/../../node_modules.asar';272export const nodeModulesAsarUnpackedPath: AppResourcePath = 'vs/../../node_modules.asar.unpacked';273274export const VSCODE_AUTHORITY = 'vscode-app';275276class FileAccessImpl {277278private static readonly FALLBACK_AUTHORITY = VSCODE_AUTHORITY;279280/**281* Returns a URI to use in contexts where the browser is responsible282* for loading (e.g. fetch()) or when used within the DOM.283*284* **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.285*/286asBrowserUri(resourcePath: AppResourcePath | ''): URI {287const uri = this.toUri(resourcePath);288return this.uriToBrowserUri(uri);289}290291/**292* Returns a URI to use in contexts where the browser is responsible293* for loading (e.g. fetch()) or when used within the DOM.294*295* **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context.296*/297uriToBrowserUri(uri: URI): URI {298// Handle remote URIs via `RemoteAuthorities`299if (uri.scheme === Schemas.vscodeRemote) {300return RemoteAuthorities.rewrite(uri);301}302303// Convert to `vscode-file` resource..304if (305// ...only ever for `file` resources306uri.scheme === Schemas.file &&307(308// ...and we run in native environments309platform.isNative ||310// ...or web worker extensions on desktop311(platform.webWorkerOrigin === `${Schemas.vscodeFileResource}://${FileAccessImpl.FALLBACK_AUTHORITY}`)312)313) {314return uri.with({315scheme: Schemas.vscodeFileResource,316// We need to provide an authority here so that it can serve317// as origin for network and loading matters in chromium.318// If the URI is not coming with an authority already, we319// add our own320authority: uri.authority || FileAccessImpl.FALLBACK_AUTHORITY,321query: null,322fragment: null323});324}325326return uri;327}328329/**330* Returns the `file` URI to use in contexts where node.js331* is responsible for loading.332*/333asFileUri(resourcePath: AppResourcePath | ''): URI {334const uri = this.toUri(resourcePath);335return this.uriToFileUri(uri);336}337338/**339* Returns the `file` URI to use in contexts where node.js340* is responsible for loading.341*/342uriToFileUri(uri: URI): URI {343// Only convert the URI if it is `vscode-file:` scheme344if (uri.scheme === Schemas.vscodeFileResource) {345return uri.with({346scheme: Schemas.file,347// Only preserve the `authority` if it is different from348// our fallback authority. This ensures we properly preserve349// Windows UNC paths that come with their own authority.350authority: uri.authority !== FileAccessImpl.FALLBACK_AUTHORITY ? uri.authority : null,351query: null,352fragment: null353});354}355356return uri;357}358359private toUri(uriOrModule: URI | string): URI {360if (URI.isUri(uriOrModule)) {361return uriOrModule;362}363364if (globalThis._VSCODE_FILE_ROOT) {365const rootUriOrPath = globalThis._VSCODE_FILE_ROOT;366367// File URL (with scheme)368if (/^\w[\w\d+.-]*:\/\//.test(rootUriOrPath)) {369return URI.joinPath(URI.parse(rootUriOrPath, true), uriOrModule);370}371372// File Path (no scheme)373const modulePath = paths.join(rootUriOrPath, uriOrModule);374return URI.file(modulePath);375}376377throw new Error('Cannot determine URI for module id!');378}379}380381export const FileAccess = new FileAccessImpl();382383export const CacheControlheaders: Record<string, string> = Object.freeze({384'Cache-Control': 'no-cache, no-store'385});386387export const DocumentPolicyheaders: Record<string, string> = Object.freeze({388'Document-Policy': 'include-js-call-stacks-in-crash-reports'389});390391export namespace COI {392393const coiHeaders = new Map<'3' | '2' | '1' | string, Record<string, string>>([394['1', { 'Cross-Origin-Opener-Policy': 'same-origin' }],395['2', { 'Cross-Origin-Embedder-Policy': 'require-corp' }],396['3', { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }],397]);398399export const CoopAndCoep = Object.freeze(coiHeaders.get('3'));400401const coiSearchParamName = 'vscode-coi';402403/**404* Extract desired headers from `vscode-coi` invocation405*/406export function getHeadersFromQuery(url: string | URI | URL): Record<string, string> | undefined {407let params: URLSearchParams | undefined;408if (typeof url === 'string') {409params = new URL(url).searchParams;410} else if (url instanceof URL) {411params = url.searchParams;412} else if (URI.isUri(url)) {413params = new URL(url.toString(true)).searchParams;414}415const value = params?.get(coiSearchParamName);416if (!value) {417return undefined;418}419return coiHeaders.get(value);420}421422/**423* Add the `vscode-coi` query attribute based on wanting `COOP` and `COEP`. Will be a noop when `crossOriginIsolated`424* isn't enabled the current context425*/426export function addSearchParam(urlOrSearch: URLSearchParams | Record<string, string>, coop: boolean, coep: boolean): void {427if (!(globalThis as typeof globalThis & { crossOriginIsolated?: boolean }).crossOriginIsolated) {428// depends on the current context being COI429return;430}431const value = coop && coep ? '3' : coep ? '2' : '1';432if (urlOrSearch instanceof URLSearchParams) {433urlOrSearch.set(coiSearchParamName, value);434} else {435urlOrSearch[coiSearchParamName] = value;436}437}438}439440441