Skip to content

Commit ca4dfa3

Browse files
committed
Validate checksum for requests
1 parent 61e010f commit ca4dfa3

File tree

6 files changed

+90
-71
lines changed

6 files changed

+90
-71
lines changed

src/lsptoolshost/razor/htmlDocument.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@ import { getUriPath } from '../../razor/src/uriPaths';
99
export class HtmlDocument {
1010
public readonly path: string;
1111
private content = '';
12+
private checksum = '';
1213

13-
public constructor(public readonly uri: vscode.Uri) {
14+
public constructor(public readonly uri: vscode.Uri, checksum: string) {
1415
this.path = getUriPath(uri);
16+
this.checksum = checksum;
1517
}
1618

1719
public getContent() {
1820
return this.content;
1921
}
2022

21-
public setContent(content: string) {
23+
public getChecksum() {
24+
return this.checksum;
25+
}
26+
27+
public setContent(checksum: string, content: string) {
28+
this.checksum = checksum;
2229
this.content = content;
2330
}
2431
}

src/lsptoolshost/razor/htmlDocumentManager.ts

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,22 @@ export class HtmlDocumentManager {
6565
return vscode.Disposable.from(didCloseRegistration, providerRegistration);
6666
}
6767

68-
public async updateDocumentText(uri: vscode.Uri, text: string) {
69-
const document = await this.getDocument(uri);
68+
public async updateDocumentText(uri: vscode.Uri, checksum: string, text: string) {
69+
// We don't pass the checksum in here, because we'd be comparing the new one against the old one.
70+
let document = await this.findDocument(uri);
7071

71-
this.logger.logTrace(`New content for '${uri}', updating '${document.path}'.`);
72+
if (!document) {
73+
this.logger.logTrace(
74+
`File '${uri}' didn't exist in the Razor document list, so adding it with checksum '${checksum}'.`
75+
);
76+
document = this.addDocument(uri, checksum);
77+
}
78+
79+
this.logger.logTrace(`New content for '${uri}', updating '${document.path}', checksum '${checksum}'.`);
80+
81+
await vscode.workspace.openTextDocument(document.uri);
7282

73-
document.setContent(text);
83+
document.setContent(checksum, text);
7484

7585
this.contentProvider.fireDidChange(document.uri);
7686
}
@@ -85,30 +95,36 @@ export class HtmlDocumentManager {
8595
}
8696
}
8797

88-
public async getDocument(uri: vscode.Uri): Promise<HtmlDocument> {
89-
let document = this.findDocument(uri);
98+
public async getDocument(uri: vscode.Uri, checksum?: string): Promise<HtmlDocument | undefined> {
99+
const document = this.findDocument(uri);
90100

91-
// This might happen in the case that a file is opened outside the workspace
92101
if (!document) {
102+
this.logger.logTrace(`File '${uri}' didn't exist in the Razor document list. Doing nothing.`);
103+
return undefined;
104+
}
105+
106+
if (checksum && document.getChecksum() !== checksum) {
93107
this.logger.logInfo(
94-
`File '${uri}' didn't exist in the Razor document list. This is likely because it's from outside the workspace.`
108+
`Found '${uri}' in the Razor document list, but the checksum '${document.getChecksum()}' doesn't match '${checksum}'.`
95109
);
96-
document = this.addDocument(uri);
110+
return undefined;
97111
}
98112

113+
// No checksum, just give them the latest document and hope they know what to do with it.
114+
99115
await vscode.workspace.openTextDocument(document.uri);
100116

101-
return document!;
117+
return document;
102118
}
103119

104-
private addDocument(uri: vscode.Uri): HtmlDocument {
120+
private addDocument(uri: vscode.Uri, checksum: string): HtmlDocument {
105121
let document = this.findDocument(uri);
106122
if (document) {
107123
this.logger.logInfo(`Skipping document creation for '${document.path}' because it already exists.`);
108124
return document;
109125
}
110126

111-
document = this.createDocument(uri);
127+
document = this.createDocument(uri, checksum);
112128
this.htmlDocuments[document.path] = document;
113129

114130
return document;
@@ -131,12 +147,12 @@ export class HtmlDocumentManager {
131147
);
132148
}
133149

134-
private createDocument(uri: vscode.Uri) {
150+
private createDocument(uri: vscode.Uri, checksum: string) {
135151
uri = uri.with({
136152
scheme: HtmlDocumentContentProvider.scheme,
137153
path: `${uri.path}${virtualHtmlSuffix}`,
138154
});
139-
const projectedDocument = new HtmlDocument(uri);
155+
const projectedDocument = new HtmlDocument(uri, checksum);
140156

141157
return projectedDocument;
142158
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
import { TextDocumentIdentifier } from 'vscode-languageserver-types';
6+
7+
export class HtmlForwardedRequest<Params> {
8+
constructor(
9+
public readonly textDocument: TextDocumentIdentifier,
10+
public readonly checksum: string,
11+
public readonly request: Params
12+
) {}
13+
}

src/lsptoolshost/razor/htmlUpdateParameters.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,9 @@
66
import { TextDocumentIdentifier } from 'vscode-languageserver-protocol';
77

88
export class HtmlUpdateParameters {
9-
constructor(public readonly textDocument: TextDocumentIdentifier, public readonly text: string) {}
9+
constructor(
10+
public readonly textDocument: TextDocumentIdentifier,
11+
public readonly checksum: string,
12+
public readonly text: string
13+
) {}
1014
}

src/lsptoolshost/razor/razorEndpoints.ts

Lines changed: 28 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ import { RazorMapTextChangesParams } from '../../razor/src/mapping/razorMapTextC
5050
import { RazorMapTextChangesResponse } from '../../razor/src/mapping/razorMapTextChangesResponse';
5151
import { FormattingHandler } from '../../razor/src/formatting/formattingHandler';
5252
import { ReportIssueCommand } from '../../razor/src/diagnostics/reportIssueCommand';
53+
import { HtmlDocument } from './htmlDocument';
54+
import { HtmlForwardedRequest } from './htmlForwardedRequest';
5355

5456
export function registerRazorEndpoints(
5557
context: vscode.ExtensionContext,
@@ -83,27 +85,18 @@ export function registerRazorEndpoints(
8385

8486
registerMethodHandler<HtmlUpdateParameters, void>('razor/updateHtml', async (params) => {
8587
const uri = UriConverter.deserialize(params.textDocument.uri);
86-
await documentManager.updateDocumentText(uri, params.text);
88+
await documentManager.updateDocumentText(uri, params.checksum, params.text);
8789
});
8890

89-
registerRequestHandler(DocumentColorRequest.type, async (params) => {
90-
const uri = UriConverter.deserialize(params.textDocument.uri);
91-
const document = await documentManager.getDocument(uri);
92-
91+
registerCohostHandler(DocumentColorRequest.type, documentManager, async (document) => {
9392
return await DocumentColorHandler.doDocumentColorRequest(document.uri);
9493
});
9594

96-
registerRequestHandler(ColorPresentationRequest.type, async (params) => {
97-
const uri = UriConverter.deserialize(params.textDocument.uri);
98-
const document = await documentManager.getDocument(uri);
99-
95+
registerCohostHandler(ColorPresentationRequest.type, documentManager, async (document, params) => {
10096
return await ColorPresentationHandler.doColorPresentationRequest(document.uri, params);
10197
});
10298

103-
registerRequestHandler(FoldingRangeRequest.type, async (params) => {
104-
const uri = UriConverter.deserialize(params.textDocument.uri);
105-
const document = await documentManager.getDocument(uri);
106-
99+
registerCohostHandler(FoldingRangeRequest.type, documentManager, async (document) => {
107100
const results = await vscode.commands.executeCommand<vscode.FoldingRange[]>(
108101
'vscode.executeFoldingRangeProvider',
109102
document.uri
@@ -112,10 +105,7 @@ export function registerRazorEndpoints(
112105
return FoldingRangeHandler.convertFoldingRanges(results, razorLogger);
113106
});
114107

115-
registerRequestHandler(HoverRequest.type, async (params) => {
116-
const uri = UriConverter.deserialize(params.textDocument.uri);
117-
const document = await documentManager.getDocument(uri);
118-
108+
registerCohostHandler(HoverRequest.type, documentManager, async (document, params) => {
119109
const results = await vscode.commands.executeCommand<vscode.Hover[]>(
120110
'vscode.executeHoverProvider',
121111
document.uri,
@@ -126,10 +116,7 @@ export function registerRazorEndpoints(
126116
return rewriteHover(applicableHover);
127117
});
128118

129-
registerRequestHandler(DocumentHighlightRequest.type, async (params) => {
130-
const uri = UriConverter.deserialize(params.textDocument.uri);
131-
const document = await documentManager.getDocument(uri);
132-
119+
registerCohostHandler(DocumentHighlightRequest.type, documentManager, async (document, params) => {
133120
const results = await vscode.commands.executeCommand<vscode.DocumentHighlight[]>(
134121
'vscode.executeDocumentHighlights',
135122
document.uri,
@@ -139,21 +126,15 @@ export function registerRazorEndpoints(
139126
return rewriteHighlight(results);
140127
});
141128

142-
registerRequestHandler(CompletionRequest.type, async (params) => {
143-
const uri = UriConverter.deserialize(params.textDocument.uri);
144-
const document = await documentManager.getDocument(uri);
145-
129+
registerCohostHandler(CompletionRequest.type, documentManager, async (document, params) => {
146130
return CompletionHandler.provideVscodeCompletions(
147131
document.uri,
148132
params.position,
149133
params.context?.triggerCharacter
150134
);
151135
});
152136

153-
registerRequestHandler(ReferencesRequest.type, async (params) => {
154-
const uri = UriConverter.deserialize(params.textDocument.uri);
155-
const document = await documentManager.getDocument(uri);
156-
137+
registerCohostHandler(ReferencesRequest.type, documentManager, async (document, params) => {
157138
const results = await vscode.commands.executeCommand<vscode.Location[]>(
158139
'vscode.executeReferenceProvider',
159140
document.uri,
@@ -163,10 +144,7 @@ export function registerRazorEndpoints(
163144
return rewriteLocations(results);
164145
});
165146

166-
registerRequestHandler(ImplementationRequest.type, async (params) => {
167-
const uri = UriConverter.deserialize(params.textDocument.uri);
168-
const document = await documentManager.getDocument(uri);
169-
147+
registerCohostHandler(ImplementationRequest.type, documentManager, async (document, params) => {
170148
const results = await vscode.commands.executeCommand<vscode.Location[]>(
171149
'vscode.executeImplementationProvider',
172150
document.uri,
@@ -176,10 +154,7 @@ export function registerRazorEndpoints(
176154
return rewriteLocations(results);
177155
});
178156

179-
registerRequestHandler(DefinitionRequest.type, async (params) => {
180-
const uri = UriConverter.deserialize(params.textDocument.uri);
181-
const document = await documentManager.getDocument(uri);
182-
157+
registerCohostHandler(DefinitionRequest.type, documentManager, async (document, params) => {
183158
const results = await vscode.commands.executeCommand<vscode.Location[]>(
184159
'vscode.executeDefinitionProvider',
185160
document.uri,
@@ -189,10 +164,7 @@ export function registerRazorEndpoints(
189164
return rewriteLocations(results);
190165
});
191166

192-
registerRequestHandler(SignatureHelpRequest.type, async (params) => {
193-
const uri = UriConverter.deserialize(params.textDocument.uri);
194-
const document = await documentManager.getDocument(uri);
195-
167+
registerCohostHandler(SignatureHelpRequest.type, documentManager, async (document, params) => {
196168
const results = await vscode.commands.executeCommand<vscode.SignatureHelp>(
197169
'vscode.executeSignatureHelpProvider',
198170
document.uri,
@@ -206,21 +178,15 @@ export function registerRazorEndpoints(
206178
return rewriteSignatureHelp(results);
207179
});
208180

209-
registerRequestHandler(DocumentFormattingRequest.type, async (params) => {
210-
const uri = UriConverter.deserialize(params.textDocument.uri);
211-
const document = await documentManager.getDocument(uri);
212-
181+
registerCohostHandler(DocumentFormattingRequest.type, documentManager, async (document, params) => {
213182
const content = document.getContent();
214183
const options = <vscode.FormattingOptions>params.options;
215184

216185
const response = await FormattingHandler.getHtmlFormattingResult(document.uri, content, options);
217186
return response?.edits;
218187
});
219188

220-
registerRequestHandler(DocumentOnTypeFormattingRequest.type, async (params) => {
221-
const uri = UriConverter.deserialize(params.textDocument.uri);
222-
const document = await documentManager.getDocument(uri);
223-
189+
registerCohostHandler(DocumentOnTypeFormattingRequest.type, documentManager, async (document, params) => {
224190
const content = document.getContent();
225191
const options = <vscode.FormattingOptions>params.options;
226192

@@ -262,11 +228,21 @@ export function registerRazorEndpoints(
262228
}
263229

264230
// Helper method that registers a request handler, and logs errors to the Razor logger.
265-
function registerRequestHandler<Params, Result, Error>(
231+
function registerCohostHandler<Params, Result, Error>(
266232
type: RequestType<Params, Result, Error>,
267-
invocation: (params: Params) => Promise<Result>
233+
documentManager: HtmlDocumentManager,
234+
invocation: (document: HtmlDocument, request: Params) => Promise<Result>
268235
) {
269-
return registerMethodHandler<Params, Result>(type.method, invocation);
236+
return registerMethodHandler<HtmlForwardedRequest<Params>, Result | undefined>(type.method, async (params) => {
237+
const uri = UriConverter.deserialize(params.textDocument.uri);
238+
const document = await documentManager.getDocument(uri, params.checksum);
239+
240+
if (!document) {
241+
return undefined;
242+
}
243+
244+
return invocation(document, params.request);
245+
});
270246
}
271247

272248
function registerMethodHandler<Params, Result>(method: string, invocation: (params: Params) => Promise<Result>) {

src/razor/src/diagnostics/reportIssueCreator.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,12 @@ export class ReportIssueCreator {
3737
csharpContent = await this.getProjectedCSharp(razorDocument);
3838
htmlContent = await this.getProjectedHtml(razorDocument);
3939
} else if (this.cohostingDocumentManager) {
40-
const htmlDocument = await this.cohostingDocumentManager.getDocument(collectionResult.document.uri);
4140
csharpContent = vscode.l10n.t('Cohosting is on, client has no access to CSharp content');
42-
htmlContent = htmlDocument.getContent();
41+
42+
const htmlDocument = await this.cohostingDocumentManager.getDocument(collectionResult.document.uri);
43+
if (htmlDocument) {
44+
htmlContent = htmlDocument.getContent();
45+
}
4346
}
4447
}
4548

0 commit comments

Comments
 (0)