Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/platform/extensionResourceLoader/common/extensionResourceLoader.ts
3294 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { isWeb } from '../../../base/common/platform.js';
7
import { format2 } from '../../../base/common/strings.js';
8
import { URI } from '../../../base/common/uri.js';
9
import { IConfigurationService } from '../../configuration/common/configuration.js';
10
import { IEnvironmentService } from '../../environment/common/environment.js';
11
import { IFileService } from '../../files/common/files.js';
12
import { createDecorator } from '../../instantiation/common/instantiation.js';
13
import { IProductService } from '../../product/common/productService.js';
14
import { getServiceMachineId } from '../../externalServices/common/serviceMachineId.js';
15
import { IStorageService } from '../../storage/common/storage.js';
16
import { TelemetryLevel } from '../../telemetry/common/telemetry.js';
17
import { getTelemetryLevel, supportsTelemetry } from '../../telemetry/common/telemetryUtils.js';
18
import { RemoteAuthorities } from '../../../base/common/network.js';
19
import { TargetPlatform } from '../../extensions/common/extensions.js';
20
import { ExtensionGalleryResourceType, getExtensionGalleryManifestResourceUri, IExtensionGalleryManifest, IExtensionGalleryManifestService } from '../../extensionManagement/common/extensionGalleryManifest.js';
21
import { ILogService } from '../../log/common/log.js';
22
import { Disposable } from '../../../base/common/lifecycle.js';
23
24
const WEB_EXTENSION_RESOURCE_END_POINT_SEGMENT = '/web-extension-resource/';
25
26
export const IExtensionResourceLoaderService = createDecorator<IExtensionResourceLoaderService>('extensionResourceLoaderService');
27
28
/**
29
* A service useful for reading resources from within extensions.
30
*/
31
export interface IExtensionResourceLoaderService {
32
readonly _serviceBrand: undefined;
33
34
/**
35
* Read a certain resource within an extension.
36
*/
37
readExtensionResource(uri: URI): Promise<string>;
38
39
/**
40
* Returns whether the gallery provides extension resources.
41
*/
42
supportsExtensionGalleryResources(): Promise<boolean>;
43
44
/**
45
* Return true if the given URI is a extension gallery resource.
46
*/
47
isExtensionGalleryResource(uri: URI): Promise<boolean>;
48
49
/**
50
* Computes the URL of a extension gallery resource. Returns `undefined` if gallery does not provide extension resources.
51
*/
52
getExtensionGalleryResourceURL(galleryExtension: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): Promise<URI | undefined>;
53
}
54
55
export function migratePlatformSpecificExtensionGalleryResourceURL(resource: URI, targetPlatform: TargetPlatform): URI | undefined {
56
if (resource.query !== `target=${targetPlatform}`) {
57
return undefined;
58
}
59
const paths = resource.path.split('/');
60
if (!paths[3]) {
61
return undefined;
62
}
63
paths[3] = `${paths[3]}+${targetPlatform}`;
64
return resource.with({ query: null, path: paths.join('/') });
65
}
66
67
export abstract class AbstractExtensionResourceLoaderService extends Disposable implements IExtensionResourceLoaderService {
68
69
readonly _serviceBrand: undefined;
70
71
private readonly _initPromise: Promise<void>;
72
73
private _extensionGalleryResourceUrlTemplate: string | undefined;
74
private _extensionGalleryAuthority: string | undefined;
75
76
constructor(
77
protected readonly _fileService: IFileService,
78
private readonly _storageService: IStorageService,
79
private readonly _productService: IProductService,
80
private readonly _environmentService: IEnvironmentService,
81
private readonly _configurationService: IConfigurationService,
82
private readonly _extensionGalleryManifestService: IExtensionGalleryManifestService,
83
protected readonly _logService: ILogService,
84
) {
85
super();
86
this._initPromise = this._init();
87
}
88
89
private async _init(): Promise<void> {
90
try {
91
const manifest = await this._extensionGalleryManifestService.getExtensionGalleryManifest();
92
this.resolve(manifest);
93
this._register(this._extensionGalleryManifestService.onDidChangeExtensionGalleryManifest(() => this.resolve(manifest)));
94
} catch (error) {
95
this._logService.error(error);
96
}
97
}
98
99
private resolve(manifest: IExtensionGalleryManifest | null): void {
100
this._extensionGalleryResourceUrlTemplate = manifest ? getExtensionGalleryManifestResourceUri(manifest, ExtensionGalleryResourceType.ExtensionResourceUri) : undefined;
101
this._extensionGalleryAuthority = this._extensionGalleryResourceUrlTemplate ? this._getExtensionGalleryAuthority(URI.parse(this._extensionGalleryResourceUrlTemplate)) : undefined;
102
}
103
104
public async supportsExtensionGalleryResources(): Promise<boolean> {
105
await this._initPromise;
106
return this._extensionGalleryResourceUrlTemplate !== undefined;
107
}
108
109
public async getExtensionGalleryResourceURL({ publisher, name, version, targetPlatform }: { publisher: string; name: string; version: string; targetPlatform?: TargetPlatform }, path?: string): Promise<URI | undefined> {
110
await this._initPromise;
111
if (this._extensionGalleryResourceUrlTemplate) {
112
const uri = URI.parse(format2(this._extensionGalleryResourceUrlTemplate, {
113
publisher,
114
name,
115
version: targetPlatform !== undefined
116
&& targetPlatform !== TargetPlatform.UNDEFINED
117
&& targetPlatform !== TargetPlatform.UNKNOWN
118
&& targetPlatform !== TargetPlatform.UNIVERSAL
119
? `${version}+${targetPlatform}`
120
: version,
121
path: 'extension'
122
}));
123
return this._isWebExtensionResourceEndPoint(uri) ? uri.with({ scheme: RemoteAuthorities.getPreferredWebSchema() }) : uri;
124
}
125
return undefined;
126
}
127
128
public abstract readExtensionResource(uri: URI): Promise<string>;
129
130
async isExtensionGalleryResource(uri: URI): Promise<boolean> {
131
await this._initPromise;
132
return !!this._extensionGalleryAuthority && this._extensionGalleryAuthority === this._getExtensionGalleryAuthority(uri);
133
}
134
135
protected async getExtensionGalleryRequestHeaders(): Promise<Record<string, string>> {
136
const headers: Record<string, string> = {
137
'X-Client-Name': `${this._productService.applicationName}${isWeb ? '-web' : ''}`,
138
'X-Client-Version': this._productService.version
139
};
140
if (supportsTelemetry(this._productService, this._environmentService) && getTelemetryLevel(this._configurationService) === TelemetryLevel.USAGE) {
141
headers['X-Machine-Id'] = await this._getServiceMachineId();
142
}
143
if (this._productService.commit) {
144
headers['X-Client-Commit'] = this._productService.commit;
145
}
146
return headers;
147
}
148
149
private _serviceMachineIdPromise: Promise<string> | undefined;
150
private _getServiceMachineId(): Promise<string> {
151
if (!this._serviceMachineIdPromise) {
152
this._serviceMachineIdPromise = getServiceMachineId(this._environmentService, this._fileService, this._storageService);
153
}
154
return this._serviceMachineIdPromise;
155
}
156
157
private _getExtensionGalleryAuthority(uri: URI): string | undefined {
158
if (this._isWebExtensionResourceEndPoint(uri)) {
159
return uri.authority;
160
}
161
const index = uri.authority.indexOf('.');
162
return index !== -1 ? uri.authority.substring(index + 1) : undefined;
163
}
164
165
protected _isWebExtensionResourceEndPoint(uri: URI): boolean {
166
const uriPath = uri.path, serverRootPath = RemoteAuthorities.getServerRootPath();
167
// test if the path starts with the server root path followed by the web extension resource end point segment
168
return uriPath.startsWith(serverRootPath) && uriPath.startsWith(WEB_EXTENSION_RESOURCE_END_POINT_SEGMENT, serverRootPath.length);
169
}
170
171
}
172
173