Merge branch 'pr/57955'

This commit is contained in:
Joao Moreno 2018-09-06 16:16:43 +02:00
commit 5c5877d686
15 changed files with 62 additions and 44 deletions

View file

@ -14,6 +14,8 @@ import { parse as parseUrl } from 'url';
import { createWriteStream } from 'fs';
import { assign } from 'vs/base/common/objects';
import { createGunzip } from 'zlib';
import { CancellationToken } from 'vs/base/common/cancellation';
import { canceled } from 'vs/base/common/errors';
export type Agent = any;
@ -46,7 +48,7 @@ export interface IRequestContext {
}
export interface IRequestFunction {
(options: IRequestOptions): TPromise<IRequestContext>;
(options: IRequestOptions, token: CancellationToken): TPromise<IRequestContext>;
}
async function getNodeRequest(options: IRequestOptions): Promise<IRawRequestFunction> {
@ -55,7 +57,7 @@ async function getNodeRequest(options: IRequestOptions): Promise<IRawRequestFunc
return module.request;
}
export function request(options: IRequestOptions): TPromise<IRequestContext> {
export function request(options: IRequestOptions, token: CancellationToken): TPromise<IRequestContext> {
let req: http.ClientRequest;
const rawRequestPromise = options.getRawRequest
@ -88,7 +90,7 @@ export function request(options: IRequestOptions): TPromise<IRequestContext> {
request(assign({}, options, {
url: res.headers['location'],
followRedirects: followRedirects - 1
})).then(c, e);
}), token).then(c, e);
} else {
let stream: Stream = res;
@ -116,7 +118,12 @@ export function request(options: IRequestOptions): TPromise<IRequestContext> {
}
req.end();
}, () => req && req.abort());
token.onCancellationRequested(() => {
req.abort();
e(canceled());
});
});
});
}

View file

@ -17,6 +17,7 @@ import product from 'vs/platform/node/product';
import { IRequestService } from 'vs/platform/request/node/request';
import { IRequestContext } from 'vs/base/node/request';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { CancellationToken } from 'vs/base/common/cancellation';
interface PostResult {
readonly blob_id: string;
@ -86,7 +87,7 @@ async function postLogs(
headers: {
'Content-Type': 'application/zip'
}
});
}, CancellationToken.None);
} catch (e) {
clearInterval(dotter);
console.log(localize('postError', 'Error posting logs: {0}', e));

View file

@ -24,7 +24,6 @@ import { writeFileAndFlushSync } from 'vs/base/node/extfs';
import { generateUuid, isUUID } from 'vs/base/common/uuid';
import { values } from 'vs/base/common/map';
import { CancellationToken } from 'vs/base/common/cancellation';
import { wireCancellationToken } from 'vs/base/common/async';
interface IRawGalleryExtensionFile {
assetType: string;
@ -375,7 +374,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
query = query.withFilter(FilterType.ExtensionName, id);
}
return this.queryGallery(query).then(({ galleryExtensions }) => {
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => {
if (galleryExtensions.length) {
const galleryExtension = galleryExtensions[0];
const versionAsset = version ? galleryExtension.versions.filter(v => v.version === version)[0] : galleryExtension.versions[0];
@ -447,7 +446,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
query = query.withSortOrder(options.sortOrder);
}
return this.queryGallery(query).then(({ galleryExtensions, total }) => {
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions, total }) => {
const extensions = galleryExtensions.map((e, index) => toExtension(e, e.versions[0], index, query, options.source));
const pageSize = query.pageSize;
const getPage = (pageIndex: number, ct: CancellationToken) => {
@ -456,17 +455,15 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
}
const nextPageQuery = query.withPage(pageIndex + 1);
const promise = this.queryGallery(nextPageQuery)
return this.queryGallery(nextPageQuery, ct)
.then(({ galleryExtensions }) => galleryExtensions.map((e, index) => toExtension(e, e.versions[0], index, nextPageQuery, options.source)));
return wireCancellationToken(ct, promise);
};
return { firstPage: extensions, total, pageSize, getPage } as IPager<IGalleryExtension>;
});
}
private queryGallery(query: Query): TPromise<{ galleryExtensions: IRawGalleryExtension[], total: number; }> {
private queryGallery(query: Query, token: CancellationToken): TPromise<{ galleryExtensions: IRawGalleryExtension[], total: number; }> {
return this.commonHeadersPromise.then(commonHeaders => {
const data = JSON.stringify(query.raw);
const headers = assign({}, commonHeaders, {
@ -481,7 +478,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
url: this.api('/extensionquery'),
data,
headers
}).then(context => {
}, token).then(context => {
if (context.res.statusCode >= 400 && context.res.statusCode < 500) {
return { galleryExtensions: [], total: 0 };
@ -511,7 +508,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
type: 'POST',
url: this.api(`/publishers/${publisher}/extensions/${name}/${version}/stats?statType=${type}`),
headers
}).then(null, () => null);
}, CancellationToken.None).then(null, () => null);
});
}
@ -584,7 +581,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
.withAssetTypes(AssetType.Manifest, AssetType.VSIX)
.withFilter(FilterType.ExtensionId, extension.identifier.uuid);
return this.queryGallery(query)
return this.queryGallery(query, CancellationToken.None)
.then(({ galleryExtensions }) => {
const [rawExtension] = galleryExtensions;
@ -619,7 +616,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
.withAssetTypes(AssetType.Icon, AssetType.License, AssetType.Details, AssetType.Manifest, AssetType.VSIX)
.withFilter(FilterType.ExtensionName, ...extensionNames);
return this.queryGallery(query).then(result => {
return this.queryGallery(query, CancellationToken.None).then(result => {
const dependencies = [];
const ids = [];
@ -658,7 +655,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
});
}
private getAsset(asset: IGalleryExtensionAsset, options: IRequestOptions = {}): TPromise<IRequestContext> {
private getAsset(asset: IGalleryExtensionAsset, options: IRequestOptions = {}, token: CancellationToken = CancellationToken.None): TPromise<IRequestContext> {
return this.commonHeadersPromise.then(commonHeaders => {
const baseOptions = { type: 'GET' };
const headers = assign({}, commonHeaders, options.headers || {});
@ -668,7 +665,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
const fallbackUrl = asset.fallbackUri;
const firstOptions = assign({}, options, { url });
return this.requestService.request(firstOptions)
return this.requestService.request(firstOptions, token)
.then(context => {
if (context.res.statusCode === 200) {
return TPromise.as(context);
@ -700,7 +697,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
this.telemetryService.publicLog('galleryService:cdnFallback', { url, message });
const fallbackOptions = assign({}, options, { url: fallbackUrl });
return this.requestService.request(fallbackOptions).then(null, err => {
return this.requestService.request(fallbackOptions, token).then(null, err => {
if (isPromiseCanceledError(err)) {
return TPromise.wrapError<IRequestContext>(err);
}
@ -783,7 +780,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
return TPromise.as([]);
}
return this.requestService.request({ type: 'GET', url: this.extensionsControlUrl }).then(context => {
return this.requestService.request({ type: 'GET', url: this.extensionsControlUrl }, CancellationToken.None).then(context => {
if (context.res.statusCode !== 200) {
return TPromise.wrapError(new Error('Could not get extensions report.'));
}
@ -831,4 +828,4 @@ export function resolveMarketplaceHeaders(environmentService: IEnvironmentServic
'X-Market-User-Id': uuid
};
});
}
}

View file

@ -8,18 +8,20 @@ import { TPromise } from 'vs/base/common/winjs.base';
import { IRequestOptions, IRequestContext, IRequestFunction } from 'vs/base/node/request';
import { Readable } from 'stream';
import { RequestService as NodeRequestService } from 'vs/platform/request/node/requestService';
import { CancellationToken } from 'vscode';
import { canceled } from 'vs/base/common/errors';
/**
* This service exposes the `request` API, while using the global
* or configured proxy settings.
*/
export class RequestService extends NodeRequestService {
request(options: IRequestOptions): TPromise<IRequestContext> {
return super.request(options, xhrRequest);
request(options: IRequestOptions, token: CancellationToken): TPromise<IRequestContext> {
return super.request(options, token, xhrRequest);
}
}
export const xhrRequest: IRequestFunction = (options: IRequestOptions): TPromise<IRequestContext> => {
export const xhrRequest: IRequestFunction = (options: IRequestOptions, token: CancellationToken): TPromise<IRequestContext> => {
const xhr = new XMLHttpRequest();
return new TPromise<IRequestContext>((resolve, reject) => {
@ -68,11 +70,12 @@ export const xhrRequest: IRequestFunction = (options: IRequestOptions): TPromise
// TODO: remove any
xhr.send(options.data as any);
return null;
}, () => {
// cancel
xhr.abort();
token.onCancellationRequested(() => {
xhr.abort();
reject(canceled());
});
});
};

View file

@ -9,6 +9,7 @@ import { IRequestOptions, IRequestContext, request, IRawRequestFunction } from '
import { RequestService as NodeRequestService } from 'vs/platform/request/node/requestService';
import { assign } from 'vs/base/common/objects';
import { net } from 'electron';
import { CancellationToken } from 'vs/base/common/cancellation';
function getRawRequest(options: IRequestOptions): IRawRequestFunction {
return net.request as any as IRawRequestFunction;
@ -16,7 +17,7 @@ function getRawRequest(options: IRequestOptions): IRawRequestFunction {
export class RequestService extends NodeRequestService {
request(options: IRequestOptions): TPromise<IRequestContext> {
return super.request(options, options => request(assign({}, options || {}, { getRawRequest })));
request(options: IRequestOptions, token: CancellationToken): TPromise<IRequestContext> {
return super.request(options, token, options => request(assign({}, options || {}, { getRawRequest }), token));
}
}
}

View file

@ -10,13 +10,14 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IRequestOptions, IRequestContext } from 'vs/base/node/request';
import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry';
import { Registry } from 'vs/platform/registry/common/platform';
import { CancellationToken } from 'vs/base/common/cancellation';
export const IRequestService = createDecorator<IRequestService>('requestService2');
export interface IRequestService {
_serviceBrand: any;
request(options: IRequestOptions): TPromise<IRequestContext>;
request(options: IRequestOptions, token: CancellationToken): TPromise<IRequestContext>;
}
export interface IHTTPConfiguration {
@ -50,4 +51,4 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration)
description: localize('proxyAuthorization', "The value to send as the 'Proxy-Authorization' header for every network request.")
}
}
});
});

View file

@ -12,6 +12,7 @@ import { getProxyAgent } from 'vs/base/node/proxy';
import { IRequestService, IHTTPConfiguration } from 'vs/platform/request/node/request';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation';
/**
* This service exposes the `request` API, while using the global
@ -40,7 +41,7 @@ export class RequestService implements IRequestService {
this.authorization = config.http && config.http.proxyAuthorization;
}
request(options: IRequestOptions, requestFn: IRequestFunction = request): TPromise<IRequestContext> {
request(options: IRequestOptions, token: CancellationToken, requestFn: IRequestFunction = request): TPromise<IRequestContext> {
this.logService.trace('RequestService#request', options.url);
const { proxyUrl, strictSSL } = this;
@ -54,7 +55,7 @@ export class RequestService implements IRequestService {
options.headers = assign(options.headers || {}, { 'Proxy-Authorization': this.authorization });
}
return requestFn(options);
return requestFn(options, token);
});
}
}

View file

@ -19,6 +19,7 @@ import * as pfs from 'vs/base/node/pfs';
import * as path from 'path';
import * as assert from 'assert';
import { getPathFromAmdModule } from 'vs/base/common/amd';
import { CancellationToken } from 'vs/base/common/cancellation';
interface ColorInfo {
@ -41,7 +42,7 @@ export const experimental = []; // 'settings.modifiedItemForeground', 'editorUnn
suite('Color Registry', function () {
test('all colors documented', async function () {
const reqContext = await request({ url: 'https://raw.githubusercontent.com/Microsoft/vscode-docs/vnext/docs/getstarted/theme-color-reference.md' });
const reqContext = await request({ url: 'https://raw.githubusercontent.com/Microsoft/vscode-docs/vnext/docs/getstarted/theme-color-reference.md' }, CancellationToken.None);
const content = await asText(reqContext);
const expression = /\-\s*\`([\w\.]+)\`: (.*)/g;

View file

@ -15,6 +15,7 @@ import { IUpdateService, State, StateType, AvailableForDownload, UpdateType } fr
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ILogService } from 'vs/platform/log/common/log';
import { IRequestService } from 'vs/platform/request/node/request';
import { CancellationToken } from 'vs/base/common/cancellation';
export function createUpdateURL(platform: string, quality: string): string {
return `${product.updateUrl}/api/update/${platform}/${quality}/${product.commit}`;
@ -161,7 +162,7 @@ export abstract class AbstractUpdateService implements IUpdateService {
if (!this.url) {
return TPromise.as(undefined);
}
return this.requestService.request({ url: this.url }).then(context => {
return this.requestService.request({ url: this.url }, CancellationToken.None).then(context => {
// The update server replies with 204 (No Content) when no
// update is available - that's all we want to know.
if (context.res.statusCode === 204) {

View file

@ -17,6 +17,7 @@ import { createUpdateURL, AbstractUpdateService } from 'vs/platform/update/elect
import { asJson } from 'vs/base/node/request';
import { TPromise } from 'vs/base/common/winjs.base';
import { shell } from 'electron';
import { CancellationToken } from 'vs/base/common/cancellation';
export class LinuxUpdateService extends AbstractUpdateService {
@ -44,7 +45,7 @@ export class LinuxUpdateService extends AbstractUpdateService {
this.setState(State.CheckingForUpdates(context));
this.requestService.request({ url: this.url })
this.requestService.request({ url: this.url }, CancellationToken.None)
.then<IUpdate>(asJson)
.then(update => {
if (!update || !update.url || !update.version || !update.productVersion) {

View file

@ -24,6 +24,7 @@ import { checksum } from 'vs/base/node/crypto';
import { tmpdir } from 'os';
import { spawn } from 'child_process';
import { shell } from 'electron';
import { CancellationToken } from 'vs/base/common/cancellation';
function pollUntil(fn: () => boolean, timeout = 1000): TPromise<void> {
return new TPromise<void>(c => {
@ -115,7 +116,7 @@ export class Win32UpdateService extends AbstractUpdateService {
this.setState(State.CheckingForUpdates(context));
this.requestService.request({ url: this.url })
this.requestService.request({ url: this.url }, CancellationToken.None)
.then<IUpdate>(asJson)
.then(update => {
const updateType = getUpdateType();
@ -150,7 +151,7 @@ export class Win32UpdateService extends AbstractUpdateService {
const hash = update.hash;
const downloadPath = `${updatePackagePath}.tmp`;
return this.requestService.request({ url })
return this.requestService.request({ url }, CancellationToken.None)
.then(context => download(downloadPath, context))
.then(hash ? () => checksum(downloadPath, update.hash) : () => null)
.then(() => pfs.rename(downloadPath, updatePackagePath))

View file

@ -21,6 +21,7 @@ import { asJson } from 'vs/base/node/request';
import { Emitter, Event } from 'vs/base/common/event';
import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/common/textfiles';
import { WorkspaceStats } from 'vs/workbench/parts/stats/node/workspaceStats';
import { CancellationToken } from 'vs/base/common/cancellation';
interface IExperimentStorageState {
enabled: boolean;
@ -168,7 +169,7 @@ export class ExperimentService extends Disposable implements IExperimentService
if (!product.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
return TPromise.as([]);
}
return this.requestService.request({ type: 'GET', url: product.experimentsUrl }).then(context => {
return this.requestService.request({ type: 'GET', url: product.experimentsUrl }, CancellationToken.None).then(context => {
if (context.res.statusCode !== 200) {
return TPromise.as(null);
}
@ -431,4 +432,4 @@ function safeParse(text: string, defaultObject: any) {
catch (e) {
return defaultObject;
}
}
}

View file

@ -43,6 +43,7 @@ import { assign } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import { areSameExtensions, getGalleryExtensionIdFromLocal } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IExperimentService, ExperimentActionType, ExperimentState } from 'vs/workbench/parts/experiments/node/experimentService';
import { CancellationToken } from 'vs/base/common/cancellation';
const milliSecondsInADay = 1000 * 60 * 60 * 24;
const choiceNever = localize('neverShowAgain', "Don't Show Again");
@ -898,7 +899,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe
return null;
}
return this.requestService.request({ type: 'GET', url: this._extensionsRecommendationsUrl }).then(context => {
return this.requestService.request({ type: 'GET', url: this._extensionsRecommendationsUrl }, CancellationToken.None).then(context => {
if (context.res.statusCode !== 200) {
return TPromise.as(null);
}

View file

@ -271,7 +271,7 @@ class RemoteSearchProvider implements ISearchProvider {
'api-key': this.options.endpoint.key
},
timeout: 5000
}).then(context => {
}, CancellationToken.None).then(context => {
if (context.res.statusCode >= 300) {
throw new Error(`${details} returned status code: ${context.res.statusCode}`);
}

View file

@ -27,6 +27,7 @@ import { IWebviewEditorService } from 'vs/workbench/parts/webview/electron-brows
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { WebviewEditorInput } from 'vs/workbench/parts/webview/electron-browser/webviewEditorInput';
import { KeybindingParser } from 'vs/base/common/keybindingParser';
import { CancellationToken } from 'vs/base/common/cancellation';
function renderBody(
body: string,
@ -156,7 +157,7 @@ export class ReleaseNotesManager {
};
if (!this._releaseNotesCache[version]) {
this._releaseNotesCache[version] = this._requestService.request({ url })
this._releaseNotesCache[version] = this._requestService.request({ url }, CancellationToken.None)
.then(asText)
.then(text => {
if (!/^#\s/.test(text)) { // release notes always starts with `#` followed by whitespace