Merge from vscode 4d91d96e5e121b38d33508cdef17868bab255eae

This commit is contained in:
ADS Merger
2020-06-18 04:32:54 +00:00
committed by AzureDataStudio
parent a971aee5bd
commit 5e7071e466
1002 changed files with 24201 additions and 13193 deletions

View File

@@ -4,14 +4,21 @@
*--------------------------------------------------------------------------------------------*/
import { VSBuffer, VSBufferReadableStream } from 'vs/base/common/buffer';
import { CancellationToken } from 'vs/base/common/cancellation';
import { isUNC } from 'vs/base/common/extpath';
import { Schemas } from 'vs/base/common/network';
import { sep } from 'vs/base/common/path';
import { URI } from 'vs/base/common/uri';
import { IFileService } from 'vs/platform/files/common/files';
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { IRequestService } from 'vs/platform/request/common/request';
import { getWebviewContentMimeType } from 'vs/platform/webview/common/mimeTypes';
export const webviewPartitionId = 'webview';
export namespace WebviewResourceResponse {
export enum Type { Success, Failed, AccessDenied }
@@ -63,18 +70,38 @@ export async function loadLocalResource(
export async function loadLocalResourceStream(
requestUri: URI,
options: {
extensionLocation: URI | undefined;
roots: ReadonlyArray<URI>;
remoteConnectionData?: IRemoteConnectionData | null;
},
fileService: IFileService,
extensionLocation: URI | undefined,
roots: ReadonlyArray<URI>
requestService: IRequestService,
): Promise<WebviewResourceResponse.StreamResponse> {
const resourceToLoad = getResourceToLoad(requestUri, extensionLocation, roots);
const resourceToLoad = getResourceToLoad(requestUri, options.extensionLocation, options.roots);
if (!resourceToLoad) {
return WebviewResourceResponse.AccessDenied;
}
const mime = getWebviewContentMimeType(requestUri); // Use the original path for the mime
if (options.remoteConnectionData) {
// Remote uris must go to the resolved server.
if (resourceToLoad.scheme === Schemas.vscodeRemote || (options.extensionLocation?.scheme === REMOTE_HOST_SCHEME)) {
const uri = URI.parse(`http://${options.remoteConnectionData.host}:${options.remoteConnectionData.port}`).with({
path: '/vscode-remote-resource',
query: `tkn=${options.remoteConnectionData.connectionToken}&path=${encodeURIComponent(resourceToLoad.path)}`,
});
const response = await requestService.request({ url: uri.toString(true) }, CancellationToken.None);
if (response.res.statusCode === 200) {
return new WebviewResourceResponse.StreamSuccess(response.stream, mime);
}
return WebviewResourceResponse.Failed;
}
}
try {
const contents = await fileService.readFileStream(resourceToLoad);
const mime = getWebviewContentMimeType(requestUri); // Use the original path for the mime
return new WebviewResourceResponse.StreamSuccess(contents.value, mime);
} catch (err) {
console.log(err);
@@ -90,20 +117,7 @@ function getResourceToLoad(
const normalizedPath = normalizeRequestPath(requestUri);
for (const root of roots) {
if (!containsResource(root, normalizedPath)) {
continue;
}
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
return URI.from({
scheme: REMOTE_HOST_SCHEME,
authority: extensionLocation.authority,
path: '/vscode-resource',
query: JSON.stringify({
requestResourcePath: normalizedPath.path
})
});
} else {
if (containsResource(root, normalizedPath)) {
return normalizedPath;
}
}
@@ -112,20 +126,20 @@ function getResourceToLoad(
}
function normalizeRequestPath(requestUri: URI) {
if (requestUri.scheme !== Schemas.vscodeWebviewResource) {
if (requestUri.scheme === Schemas.vscodeWebviewResource) {
// The `vscode-webview-resource` scheme has the following format:
//
// vscode-webview-resource://id/scheme//authority?/path
//
const resourceUri = URI.parse(requestUri.path.replace(/^\/([a-z0-9\-]+)\/{1,2}/i, '$1://'));
return resourceUri.with({
query: requestUri.query,
fragment: requestUri.fragment
});
} else {
return requestUri;
}
// The `vscode-webview-resource` scheme has the following format:
//
// vscode-webview-resource://id/scheme//authority?/path
//
const resourceUri = URI.parse(requestUri.path.replace(/^\/([a-z0-9\-]+)\/{1,2}/i, '$1://'));
return resourceUri.with({
query: requestUri.query,
fragment: requestUri.fragment
});
}
function containsResource(root: URI, resource: URI): boolean {

View File

@@ -5,15 +5,17 @@
import { UriComponents } from 'vs/base/common/uri';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
import { IWebviewPortMapping } from 'vs/platform/webview/common/webviewPortMapping';
export const IWebviewManagerService = createDecorator<IWebviewManagerService>('webviewManagerService');
export interface IWebviewManagerService {
_serviceBrand: unknown;
registerWebview(id: string, metadata: RegisterWebviewMetadata): Promise<void>;
registerWebview(id: string, webContentsId: number, metadata: RegisterWebviewMetadata): Promise<void>;
unregisterWebview(id: string): Promise<void>;
updateLocalResourceRoots(id: string, roots: UriComponents[]): Promise<void>;
updateWebviewMetadata(id: string, metadataDelta: Partial<RegisterWebviewMetadata>): Promise<void>;
setIgnoreMenuShortcuts(webContentsId: number, enabled: boolean): Promise<void>;
}
@@ -21,4 +23,6 @@ export interface IWebviewManagerService {
export interface RegisterWebviewMetadata {
readonly extensionLocation: UriComponents | undefined;
readonly localResourceRoots: readonly UriComponents[];
readonly remoteConnectionData: IRemoteConnectionData | null;
readonly portMappings: readonly IWebviewPortMapping[];
}

View File

@@ -0,0 +1,81 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { IAddress } from 'vs/platform/remote/common/remoteAgentConnection';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { extractLocalHostUriMetaDataForPortMapping, ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel';
export interface IWebviewPortMapping {
webviewPort: number;
extensionHostPort: number;
}
/**
* Manages port mappings for a single webview.
*/
export class WebviewPortMappingManager implements IDisposable {
private readonly _tunnels = new Map<number, Promise<RemoteTunnel>>();
constructor(
private readonly _getExtensionLocation: () => URI | undefined,
private readonly _getMappings: () => readonly IWebviewPortMapping[],
private readonly tunnelService: ITunnelService
) { }
public async getRedirect(resolveAuthority: IAddress, url: string): Promise<string | undefined> {
const uri = URI.parse(url);
const requestLocalHostInfo = extractLocalHostUriMetaDataForPortMapping(uri);
if (!requestLocalHostInfo) {
return undefined;
}
for (const mapping of this._getMappings()) {
if (mapping.webviewPort === requestLocalHostInfo.port) {
const extensionLocation = this._getExtensionLocation();
if (extensionLocation && extensionLocation.scheme === REMOTE_HOST_SCHEME) {
const tunnel = await this.getOrCreateTunnel(resolveAuthority, mapping.extensionHostPort);
if (tunnel) {
if (tunnel.tunnelLocalPort === mapping.webviewPort) {
return undefined;
}
return encodeURI(uri.with({
authority: `127.0.0.1:${tunnel.tunnelLocalPort}`,
}).toString(true));
}
}
if (mapping.webviewPort !== mapping.extensionHostPort) {
return encodeURI(uri.with({
authority: `${requestLocalHostInfo.address}:${mapping.extensionHostPort}`
}).toString(true));
}
}
}
return undefined;
}
dispose() {
for (const tunnel of this._tunnels.values()) {
tunnel.then(tunnel => tunnel.dispose());
}
this._tunnels.clear();
}
private getOrCreateTunnel(remoteAuthority: IAddress, remotePort: number): Promise<RemoteTunnel> | undefined {
const existing = this._tunnels.get(remotePort);
if (existing) {
return existing;
}
const tunnel = this.tunnelService.openTunnel(remoteAuthority, undefined, remotePort);
if (tunnel) {
this._tunnels.set(remotePort, tunnel);
}
return tunnel;
}
}