Skip to content

Commit 643e8d1

Browse files
committed
Register a non standard LSP request used specifically for VSCode. This LSP request
gets triggered when an HTTP/HTTPS request to a schema is being made. Instead of the server resolving the schema the language server will send the URI to the client side to be resolved. This has to be done in order to circumvent signed certificate errors that happen when you are trying to fetch the schemas outside of VSCode. Signed-off-by: Josh Pinkney <joshpinkney@gmail.com>
1 parent 2bae915 commit 643e8d1

4 files changed

Lines changed: 52 additions & 8 deletions

File tree

src/languageservice/services/schemaRequestHandler.ts

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,30 @@
11
import { URI } from 'vscode-uri';
2-
import { IConnection } from 'vscode-languageserver';
2+
import { IConnection, WorkspaceFolder } from 'vscode-languageserver';
33
import { xhr, XHRResponse, getErrorStatusDescription } from 'request-light';
44
import * as fs from 'fs';
55

6-
import { CustomSchemaContentRequest } from '../../requestTypes';
6+
import { CustomSchemaContentRequest, VSCodeContentRequest } from '../../requestTypes';
77
import { isRelativePath, relativeToAbsolutePath } from '../utils/paths';
88

99
/**
1010
* Handles schema content requests given the schema URI
1111
* @param uri can be a local file, vscode request, http(s) request or a custom request
1212
*/
13-
export const schemaRequestHandler = (connection: IConnection, uri: string): Promise<string> => {
13+
export const schemaRequestHandler = (
14+
connection: IConnection,
15+
uri: string,
16+
workspaceFolders: WorkspaceFolder[],
17+
workspaceRoot: URI,
18+
useVSCodeContentRequest: boolean
19+
): Promise<string> => {
1420
if (!uri) {
1521
return Promise.reject('No schema specified');
1622
}
1723

1824
// If the requested schema URI is a relative file path
1925
// Convert it into a proper absolute path URI
2026
if (isRelativePath(uri)) {
21-
uri = relativeToAbsolutePath(this.workspaceFolders, this.workspaceRoot, uri);
27+
uri = relativeToAbsolutePath(workspaceFolders, workspaceRoot, uri);
2228
}
2329

2430
let scheme = URI.parse(uri).scheme.toLowerCase();
@@ -47,6 +53,19 @@ export const schemaRequestHandler = (connection: IConnection, uri: string): Prom
4753

4854
// HTTP(S) requests are sent and the response result is either the schema content or an error
4955
if (scheme === 'http' || scheme === 'https') {
56+
// If we running inside of VSCode we need to make a content request. This content request
57+
// will make it so that schemas behind VPN's will resolve correctly
58+
if (useVSCodeContentRequest) {
59+
return connection.sendRequest(VSCodeContentRequest.type, uri).then(
60+
(responseText) => {
61+
return responseText;
62+
},
63+
(error) => {
64+
return Promise.reject(error.message);
65+
}
66+
) as Promise<string>;
67+
}
68+
5069
// Send the HTTP(S) schema content request and return the result
5170
const headers = { 'Accept-Encoding': 'gzip, deflate' };
5271
return xhr({ url: uri, followRedirects: 5, headers }).then(

src/requestTypes.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ export namespace DynamicCustomSchemaRequestRegistration {
1717
export const type: NotificationType<{}, {}> = new NotificationType('yaml/registerCustomSchemaRequest');
1818
}
1919

20+
export namespace VSCodeContentRequestRegistration {
21+
export const type: NotificationType<{}, {}> = new NotificationType('yaml/registerContentRequest');
22+
}
23+
2024
export namespace VSCodeContentRequest {
2125
export const type: RequestType<{}, {}, {}, {}> = new RequestType('vscode/content');
2226
}

src/server.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,13 @@ import {
4646
CustomSchemaRequest,
4747
SchemaModificationNotification,
4848
ISchemaAssociations,
49+
VSCodeContentRequestRegistration,
4950
} from './requestTypes';
50-
import { schemaRequestHandler } from './languageservice/services/schemaRequestHandler';
5151
import { isRelativePath, relativeToAbsolutePath, workspaceFoldersChanged } from './languageservice/utils/paths';
5252
import { URI } from 'vscode-uri';
5353
import { KUBERNETES_SCHEMA_URL, JSON_SCHEMASTORE_URL } from './languageservice/utils/schemaUrls';
54+
import { schemaRequestHandler } from './languageservice/services/schemaRequestHandler';
55+
5456
// eslint-disable-next-line @typescript-eslint/no-explicit-any
5557
nls.config(process.env['VSCODE_NLS_CONFIG'] as any);
5658

@@ -136,6 +138,7 @@ let workspaceFolders: WorkspaceFolder[] = [];
136138
let clientDynamicRegisterSupport = false;
137139
let hierarchicalDocumentSymbolSupport = false;
138140
let hasWorkspaceFolderCapability = false;
141+
let useVSCodeContentRequest = false;
139142

140143
/****************************
141144
* Reusable helper functions
@@ -373,7 +376,15 @@ console.error = connection.console.error.bind(connection.console);
373376
// for open, change and close text document events
374377
documents.listen(connection);
375378

376-
const schemaRequestService = schemaRequestHandler.bind(this, connection);
379+
/**
380+
* Handles schema content requests given the schema URI
381+
* @param uri can be a local file, vscode request, http(s) request or a custom request
382+
*/
383+
const schemaRequestHandlerWrapper = (connection: IConnection, uri: string): Promise<string> => {
384+
return schemaRequestHandler(connection, uri, workspaceFolders, workspaceRoot, useVSCodeContentRequest);
385+
};
386+
387+
const schemaRequestService = schemaRequestHandlerWrapper.bind(this, connection);
377388

378389
export const customLanguageService = getCustomLanguageService(schemaRequestService, workspaceContext);
379390

@@ -456,6 +467,15 @@ connection.onNotification(DynamicCustomSchemaRequestRegistration.type, () => {
456467
customLanguageService.registerCustomSchemaProvider(schemaProvider);
457468
});
458469

470+
/**
471+
* Received a notification from the client that it can accept content requests
472+
* This means that the server sends schemas back to the client side to get resolved rather
473+
* than resolving them on the extension side
474+
*/
475+
connection.onNotification(VSCodeContentRequestRegistration.type, () => {
476+
useVSCodeContentRequest = true;
477+
});
478+
459479
/**
460480
* Run when the editor configuration is changed
461481
* The client syncs the 'yaml', 'http.proxy', 'http.proxyStrictSSL' settings sections
Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import * as sinon from 'sinon';
88
import * as fs from 'fs';
99
import { IConnection } from 'vscode-languageserver';
1010
import * as assert from 'assert';
11+
import { URI } from 'vscode-uri';
1112

1213
suite('Schema Request Handler Tests', () => {
1314
suite('schemaRequestHandler', () => {
@@ -23,7 +24,7 @@ suite('Schema Request Handler Tests', () => {
2324
});
2425
test('Should care Win URI', async () => {
2526
const connection = <IConnection>{};
26-
const resultPromise = schemaRequestHandler(connection, 'c:\\some\\window\\path\\scheme.json');
27+
const resultPromise = schemaRequestHandler(connection, 'c:\\some\\window\\path\\scheme.json', [], URI.parse(''), false);
2728
assert.ok(readFileStub.calledOnceWith('c:\\some\\window\\path\\scheme.json'));
2829
readFileStub.callArgWith(2, undefined, '{some: "json"}');
2930
const result = await resultPromise;
@@ -32,7 +33,7 @@ suite('Schema Request Handler Tests', () => {
3233

3334
test('UNIX URI should works', async () => {
3435
const connection = <IConnection>{};
35-
const resultPromise = schemaRequestHandler(connection, '/some/unix/path/');
36+
const resultPromise = schemaRequestHandler(connection, '/some/unix/path/', [], URI.parse(''), false);
3637
readFileStub.callArgWith(2, undefined, '{some: "json"}');
3738
const result = await resultPromise;
3839
assert.equal(result, '{some: "json"}');

0 commit comments

Comments
 (0)