diff --git a/src/vs/base/node/request.ts b/src/vs/base/node/request.ts index b71ed417ddeb60322cf3e722943d50eab1b0c9e9..cc9e228b4a2eb2e47a16302adccdc210d8083d68 100644 --- a/src/vs/base/node/request.ts +++ b/src/vs/base/node/request.ts @@ -31,11 +31,19 @@ export interface IRequestOptions { } export interface IRequestContext { - req: http.ClientRequest; - res: http.ClientResponse; + // req: http.ClientRequest; + // res: http.ClientResponse; + res: { + headers: { [n: string]: string }; + statusCode?: number; + }; stream: Stream; } +export interface IRequestFunction { + (options: IRequestOptions): TPromise; +} + export function request(options: IRequestOptions): TPromise { let req: http.ClientRequest; @@ -71,7 +79,7 @@ export function request(options: IRequestOptions): TPromise { stream = stream.pipe(createGunzip()); } - c({ req, res, stream }); + c({ res, stream }); } }); @@ -144,4 +152,4 @@ export function asJson(context: IRequestContext): TPromise { context.stream.on('end', () => c(JSON.parse(buffer.join('')))); context.stream.on('error', e); }); -} \ No newline at end of file +} diff --git a/src/vs/platform/request/electron-browser/requestService.ts b/src/vs/platform/request/electron-browser/requestService.ts new file mode 100644 index 0000000000000000000000000000000000000000..188ad8a755f43687ceb451d90ee200f8d900574d --- /dev/null +++ b/src/vs/platform/request/electron-browser/requestService.ts @@ -0,0 +1,95 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +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'; + +/** + * This service exposes the `request` API, while using the global + * or configured proxy settings. + */ +export class RequestService extends NodeRequestService { + request(options: IRequestOptions): TPromise { + return super.request(options, xhrRequest); + } +} + +class ArryBufferStream extends Readable { + + private _buffer: Buffer; + private _offset: number; + private _length: number; + + constructor(arraybuffer: ArrayBuffer) { + super(); + this._buffer = new Buffer(new Uint8Array(arraybuffer)); + this._offset = 0; + this._length = this._buffer.length; + } + + _read(size: number) { + if (this._offset < this._length) { + this.push(this._buffer.slice(this._offset, (this._offset + size))); + this._offset += size; + } else { + this.push(null); + } + } +} + +export const xhrRequest: IRequestFunction = (options: IRequestOptions): TPromise => { + + const xhr = new XMLHttpRequest(); + return new TPromise((resolve, reject) => { + + xhr.open(options.type, options.url, true, options.user, options.password); + setRequestHeaders(xhr, options); + + xhr.responseType = 'arraybuffer'; + xhr.onerror = reject; + xhr.onload = (e) => { + resolve({ + res: { + statusCode: xhr.status, + headers: getResponseHeaders(xhr) + }, + stream: new ArryBufferStream(xhr.response) + }); + }; + + xhr.send(options.data); + return null; + + }, () => { + // cancel + xhr.abort(); + }); +}; + +function setRequestHeaders(xhr: XMLHttpRequest, options: IRequestOptions): void { + if (options.headers) { + for (let k in options.headers) { + try { + xhr.setRequestHeader(k, options.headers[k]); + } catch (e) { + console.warn(e); + } + } + } +} + +function getResponseHeaders(xhr: XMLHttpRequest): { [name: string]: string } { + const headers: { [name: string]: string } = Object.create(null); + for (const line of xhr.getAllResponseHeaders().split(/\r\n|\n|\r/g)) { + if (line) { + const idx = line.indexOf(':'); + headers[line.substr(0, idx).trim().toLowerCase()] = line.substr(idx + 1).trim(); + } + } + return headers; +} diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index de2af740b3de811b67727d1bb859cd0de509f7e8..ac91d258b24d625585818f24a33f89bf601cbe26 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -7,7 +7,7 @@ import { TPromise } from 'vs/base/common/winjs.base'; import { IDisposable } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; -import { IRequestOptions, IRequestContext, request } from 'vs/base/node/request'; +import { IRequestOptions, IRequestContext, IRequestFunction, request } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; import { IRequestService, IHTTPConfiguration } from 'vs/platform/request/node/request'; import { IConfigurationService, IConfigurationServiceEvent } from 'vs/platform/configuration/common/configuration'; @@ -42,7 +42,7 @@ export class RequestService implements IRequestService { this.authorization = config.http && config.http.proxyAuthorization; } - request(options: IRequestOptions): TPromise { + request(options: IRequestOptions, requestFn: IRequestFunction = request): TPromise { const { proxyUrl, strictSSL } = this; options.agent = options.agent || getProxyAgent(options.url, { proxyUrl, strictSSL }); @@ -52,6 +52,6 @@ export class RequestService implements IRequestService { options.headers = assign(options.headers || {}, { 'Proxy-Authorization': this.authorization }); } - return request(options); + return requestFn(options); } } diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 5f79e8039f5e469f3e54e87c6c38e08c4b91d613..19762e9363d6d05e9b9820ea08be1274f20c6147 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -37,7 +37,7 @@ import { WindowsChannelClient } from 'vs/platform/windows/common/windowsIpc'; import { WindowService } from 'vs/platform/windows/electron-browser/windowService'; import { MessageService } from 'vs/workbench/services/message/electron-browser/messageService'; import { IRequestService } from 'vs/platform/request/node/request'; -import { RequestService } from 'vs/platform/request/node/requestService'; +import { RequestService } from 'vs/platform/request/electron-browser/requestService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { SearchService } from 'vs/workbench/services/search/node/searchService'; import { LifecycleService } from 'vs/workbench/services/lifecycle/electron-browser/lifecycleService'; @@ -560,4 +560,4 @@ export class WorkbenchShell { // Container $(this.container).empty(); } -} \ No newline at end of file +}