diff --git a/src/vs/server/node/server.cli.ts b/src/vs/server/node/server.cli.ts index c3b8f6e8ea4..290287dee59 100644 --- a/src/vs/server/node/server.cli.ts +++ b/src/vs/server/node/server.cli.ts @@ -105,7 +105,7 @@ export function main(desc: ProductDescription, args: string[]): void { options['openExternal'] = { type: 'boolean' }; } - const errorReporter : ErrorReporter = { + const errorReporter: ErrorReporter = { onMultipleValues: (id: string, usedValue: string) => { console.error(`Option ${id} can only be defined once. Using value ${usedValue}.`); }, @@ -261,6 +261,8 @@ export function main(desc: ProductDescription, args: string[]): void { type: 'status' }, verbose).then((res: string) => { console.log(res); + }).catch(e => { + console.error('Error when requesting status:', e); }); return; } @@ -274,6 +276,8 @@ export function main(desc: ProductDescription, args: string[]): void { force: parsedArgs['force'] }, verbose).then((res: string) => { console.log(res); + }).catch(e => { + console.error('Error when invoking the extension management command:', e); }); return; } @@ -298,7 +302,9 @@ export function main(desc: ProductDescription, args: string[]): void { forceNewWindow: parsedArgs['new-window'], waitMarkerFilePath, remoteAuthority: remote - }, verbose); + }, verbose).catch(e => { + console.error('Error when invoking the open command:', e); + }); if (waitMarkerFilePath) { waitForFileDeleted(waitMarkerFilePath); @@ -329,7 +335,9 @@ function openInBrowser(args: string[], verbose: boolean) { sendToPipe({ type: 'openExternal', uris - }, verbose); + }, verbose).catch(e => { + console.error('Error when invoking the open external command:', e); + }); } } @@ -337,7 +345,7 @@ function sendToPipe(args: PipeCommand, verbose: boolean): Promise { if (verbose) { console.log(JSON.stringify(args, null, ' ')); } - return new Promise(resolve => { + return new Promise((resolve, reject) => { const message = JSON.stringify(args); if (!cliPipe) { console.log('Message ' + message); @@ -348,10 +356,19 @@ function sendToPipe(args: PipeCommand, verbose: boolean): Promise { const opts: _http.RequestOptions = { socketPath: cliPipe, path: '/', - method: 'POST' + method: 'POST', + headers: { + 'content-type': 'application/json', + 'accept': 'application/json' + } }; const req = _http.request(opts, res => { + if (res.headers['content-type'] !== 'application/json') { + reject('Error in response: Invalid content type: Expected \'application/json\', is: ' + res.headers['content-type']); + return; + } + const chunks: string[] = []; res.setEncoding('utf8'); res.on('data', chunk => { @@ -359,7 +376,17 @@ function sendToPipe(args: PipeCommand, verbose: boolean): Promise { }); res.on('error', (err) => fatal('Error in response.', err)); res.on('end', () => { - resolve(chunks.join('')); + const content = chunks.join(''); + try { + const obj = JSON.parse(content); + if (res.statusCode === 200) { + resolve(obj); + } else { + reject(obj); + } + } catch (e) { + reject('Error in response: Unable to parse response as JSON: ' + content); + } }); }); diff --git a/src/vs/workbench/api/node/extHostCLIServer.ts b/src/vs/workbench/api/node/extHostCLIServer.ts index 2a03770b37e..715d56fe616 100644 --- a/src/vs/workbench/api/node/extHostCLIServer.ts +++ b/src/vs/workbench/api/node/extHostCLIServer.ts @@ -79,39 +79,45 @@ export class CLIServerBase { } private onRequest(req: http.IncomingMessage, res: http.ServerResponse): void { + const sendResponse = (statusCode: number, returnObj: any) => { + res.writeHead(statusCode, { 'content-type': 'application/json' }); + res.end(JSON.stringify(returnObj), (err?: any) => err && this.logService.error(err)); + }; + const chunks: string[] = []; req.setEncoding('utf8'); req.on('data', (d: string) => chunks.push(d)); - req.on('end', () => { - const data: PipeCommand | any = JSON.parse(chunks.join('')); - switch (data.type) { - case 'open': - this.open(data, res); - break; - case 'openExternal': - this.openExternal(data, res); - break; - case 'status': - this.getStatus(data, res); - break; - case 'extensionManagement': - this.manageExtensions(data, res) - .catch(this.logService.error); - break; - default: - res.writeHead(404); - res.write(`Unknown message type: ${data.type}`, err => { - if (err) { - this.logService.error(err); - } - }); - res.end(); - break; + req.on('end', async () => { + try { + const data: PipeCommand | any = JSON.parse(chunks.join('')); + let returnObj; + switch (data.type) { + case 'open': + returnObj = await this.open(data); + break; + case 'openExternal': + returnObj = await this.openExternal(data); + break; + case 'status': + returnObj = await this.getStatus(data); + break; + case 'extensionManagement': + returnObj = await this.manageExtensions(data); + break; + default: + sendResponse(404, `Unknown message type: ${data.type}`); + break; + } + sendResponse(200, returnObj); + } catch (e) { + const message = e instanceof Error ? e.message : JSON.stringify(e); + sendResponse(500, message); + this.logService.error('Error while processing pipe request', e); } }); } - private open(data: OpenCommandPipeArgs, res: http.ServerResponse) { + private async open(data: OpenCommandPipeArgs): Promise { const { fileURIs, folderURIs, forceNewWindow, diffMode, addMode, forceReuseWindow, gotoLineMode, waitMarkerFilePath, remoteAuthority } = data; const urisToOpen: IWindowOpenable[] = []; if (Array.isArray(folderURIs)) { @@ -141,58 +147,30 @@ export class CLIServerBase { const windowOpenArgs: IOpenWindowOptions = { forceNewWindow, diffMode, addMode, gotoLineMode, forceReuseWindow, preferNewWindow, waitMarkerFileURI, remoteAuthority }; this._commands.executeCommand('_remoteCLI.windowOpen', urisToOpen, windowOpenArgs); - res.writeHead(200); - res.end(); + return ''; } - private async openExternal(data: OpenExternalCommandPipeArgs, res: http.ServerResponse) { + private async openExternal(data: OpenExternalCommandPipeArgs): Promise { for (const uriString of data.uris) { const uri = URI.parse(uriString); const urioOpen = uri.scheme === 'file' ? uri : uriString; // workaround for #112577 await this._commands.executeCommand('_remoteCLI.openExternal', urioOpen); } - res.writeHead(200); - res.end(); } - private async manageExtensions(data: ExtensionManagementPipeArgs, res: http.ServerResponse) { - try { - const toExtOrVSIX = (inputs: string[] | undefined) => inputs?.map(input => /\.vsix$/i.test(input) ? URI.parse(input) : input); - const commandArgs = { - list: data.list, - install: toExtOrVSIX(data.install), - uninstall: toExtOrVSIX(data.uninstall), - force: data.force - }; - const output = await this._commands.executeCommand('_remoteCLI.manageExtensions', commandArgs); - res.writeHead(200); - res.write(output); - } catch (err) { - res.writeHead(500); - res.write(String(err), err => { - if (err) { - this.logService.error(err); - } - }); - } - res.end(); + private async manageExtensions(data: ExtensionManagementPipeArgs): Promise { + const toExtOrVSIX = (inputs: string[] | undefined) => inputs?.map(input => /\.vsix$/i.test(input) ? URI.parse(input) : input); + const commandArgs = { + list: data.list, + install: toExtOrVSIX(data.install), + uninstall: toExtOrVSIX(data.uninstall), + force: data.force + }; + return await this._commands.executeCommand('_remoteCLI.manageExtensions', commandArgs); } - private async getStatus(data: StatusPipeArgs, res: http.ServerResponse) { - try { - const status = await this._commands.executeCommand('_remoteCLI.getSystemStatus'); - res.writeHead(200); - res.write(status); - res.end(); - } catch (err) { - res.writeHead(500); - res.write(String(err), err => { - if (err) { - this.logService.error(err); - } - }); - res.end(); - } + private async getStatus(data: StatusPipeArgs) { + return await this._commands.executeCommand('_remoteCLI.getSystemStatus'); } dispose(): void {