diff --git a/product.json b/product.json index af393bf96cef5..15cc859dea8a0 100644 --- a/product.json +++ b/product.json @@ -509,7 +509,8 @@ "itemUrl": "https://open-vsx.org/vscode/item", "resourceUrlTemplate": "", "controlUrl": "", - "recommendationsUrl": "" + "recommendationsUrl": "", + "requestTimeout": 60000 }, "linkProtectionTrustedDomains": [ "https://open-vsx.org", diff --git a/src/vs/base/common/product.ts b/src/vs/base/common/product.ts index d47fc57bf84e5..286a3e2f31b19 100644 --- a/src/vs/base/common/product.ts +++ b/src/vs/base/common/product.ts @@ -72,6 +72,7 @@ export interface IProductConfiguration { readonly resourceUrlTemplate: string; readonly controlUrl: string; readonly recommendationsUrl: string; + readonly requestTimeout?: number; }; readonly extensionTips?: { [id: string]: string; }; diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index 471ca79aac500..a021e7600d732 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -368,6 +368,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { private extensionsGalleryUrl: string | undefined; private extensionsControlUrl: string | undefined; + private extensionsGalleryTimeout: number | undefined; private readonly commonHeadersPromise: Promise<{ [key: string]: string; }>; @@ -384,6 +385,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { this.extensionsGalleryUrl = config && config.serviceUrl; this.extensionsControlUrl = config && config.controlUrl; this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService, storageService); + this.extensionsGalleryTimeout = config?.requestTimeout ?? 60000; } private api(path = ''): string { @@ -556,6 +558,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { context = await this.requestService.request({ type: 'POST', url: this.api('/extensionquery'), + timeout: this.extensionsGalleryTimeout, data, headers }, token); @@ -605,6 +608,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { await this.requestService.request({ type: 'POST', url: this.api(`/publishers/${publisher}/extensions/${name}/${version}/stats?statType=${type}`), + timeout: this.extensionsGalleryTimeout, headers }, CancellationToken.None); } catch (error) { /* Ignore */ } @@ -706,7 +710,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { private async getAsset(asset: IGalleryExtensionAsset, options: IRequestOptions = {}, token: CancellationToken = CancellationToken.None): Promise { const commonHeaders = await this.commonHeadersPromise; - const baseOptions = { type: 'GET' }; + const baseOptions = { type: 'GET', timeout: this.extensionsGalleryTimeout }; const headers = { ...commonHeaders, ...(options.headers || {}) }; options = { ...options, ...baseOptions, headers }; @@ -810,7 +814,11 @@ export class ExtensionGalleryService implements IExtensionGalleryService { return []; } - const context = await this.requestService.request({ type: 'GET', url: this.extensionsControlUrl }, CancellationToken.None); + const context = await this.requestService.request({ + type: 'GET', + url: this.extensionsControlUrl, + timeout: this.extensionsGalleryTimeout + }, CancellationToken.None); if (context.res.statusCode !== 200) { throw new Error('Could not get extensions report.'); }