From e4e48b1a05e4e4f208048b0ef68cdc6d99e2c5bf Mon Sep 17 00:00:00 2001 From: James Yu Date: Fri, 16 Feb 2024 09:25:21 +0000 Subject: [PATCH] Snippet and math preview panels use networked resource --- resources/snippetview/snippetview.html | 14 ++++++------- src/extras/math-preview-panel.ts | 22 +++++++++++++------- src/extras/snippet-view.ts | 18 +++++++++++++---- src/preview/server.ts | 28 +++++++++++++++++++------- src/utils/webview.ts | 21 ------------------- 5 files changed, 57 insertions(+), 46 deletions(-) diff --git a/resources/snippetview/snippetview.html b/resources/snippetview/snippetview.html index a3416499b..4e2531f28 100644 --- a/resources/snippetview/snippetview.html +++ b/resources/snippetview/snippetview.html @@ -3,17 +3,17 @@ - + - + - - - + + +
diff --git a/src/extras/math-preview-panel.ts b/src/extras/math-preview-panel.ts index 6e9e6dde0..5180fd571 100644 --- a/src/extras/math-preview-panel.ts +++ b/src/extras/math-preview-panel.ts @@ -31,7 +31,7 @@ class MathPreviewPanelSerializer implements vscode.WebviewPanelSerializer { enableScripts: true, localResourceRoots: [resourcesFolder(lw.extensionRoot)] } - panel.webview.html = getHtml(panel.webview) + panel.webview.html = getHtml() logger.log('Math preview panel: restored') return Promise.resolve() } @@ -66,7 +66,7 @@ function open() { } ) initializePanel(panel) - panel.webview.html = getHtml(panel.webview) + panel.webview.html = getHtml() const configuration = vscode.workspace.getConfiguration('latex-workshop') const editorGroup = configuration.get('mathpreviewpanel.editorGroup') as string if (activeDocument) { @@ -130,13 +130,21 @@ function clearCache() { state.prevMacros = undefined } -function getHtml(webview: vscode.Webview) { - const jsPath = vscode.Uri.file(path.join(lw.extensionRoot, './resources/mathpreviewpanel/mathpreview.js')) - const jsPathSrc = webview.asWebviewUri(jsPath) +let serverHandlerInserted = false +function getHtml() { + if (serverHandlerInserted === false) { + lw.server.setHandler((url: string) => { + if (url.startsWith('/mathpreviewpanel/')) { + return path.resolve(lw.extensionRoot, 'resources') + } + return undefined + }) + serverHandlerInserted = true + } return ` - + - +
diff --git a/src/extras/snippet-view.ts b/src/extras/snippet-view.ts index d258a1473..c4128abf0 100644 --- a/src/extras/snippet-view.ts +++ b/src/extras/snippet-view.ts @@ -2,7 +2,6 @@ import * as vscode from 'vscode' import { readFileSync } from 'fs' import * as path from 'path' import { lw } from '../lw' -import { replaceWebviewPlaceholders } from '../utils/webview' export { state, @@ -81,7 +80,19 @@ function receive(message: SnippetViewResult) { } class SnippetViewProvider implements vscode.WebviewViewProvider { + private serverHandlerInserted = false + public resolveWebviewView(webviewView: vscode.WebviewView) { + if (this.serverHandlerInserted === false) { + lw.server.setHandler((url: string) => { + if (url.startsWith('/snippetview/')) { + return path.resolve(lw.extensionRoot, 'resources') + } + return undefined + }) + this.serverHandlerInserted = true + } + state.view = webviewView webviewView.webview.options = { @@ -93,9 +104,8 @@ class SnippetViewProvider implements vscode.WebviewViewProvider { }) const webviewSourcePath = path.join(lw.extensionRoot, 'resources', 'snippetview', 'snippetview.html') - let webviewHtml = readFileSync(webviewSourcePath, { encoding: 'utf8' }) - webviewHtml = replaceWebviewPlaceholders(webviewHtml, state.view.webview) - webviewView.webview.html = webviewHtml + webviewView.webview.html = readFileSync(webviewSourcePath, { encoding: 'utf8' }) + .replaceAll('%PORT%', lw.server.getPort().toString()) webviewView.webview.onDidReceiveMessage((e: SnippetViewResult) => { state.callbacks.forEach((cb) => void cb(e)) diff --git a/src/preview/server.ts b/src/preview/server.ts index 62c4563fc..d28f203bd 100644 --- a/src/preview/server.ts +++ b/src/preview/server.ts @@ -11,6 +11,7 @@ const logger = lw.log('Server') export { getPort, getUrl, + setHandler, initialize, // initialized } @@ -52,9 +53,11 @@ const state: { httpServer: http.Server, wsServer?: WsServer, address?: AddressInfo, - validOriginUri?: vscode.Uri + validOriginUri?: vscode.Uri, + handlers: ((url: string) => string | undefined)[] } = { httpServer: initialize(), + handlers: [] // initialized } @@ -76,6 +79,10 @@ async function getUrl(pdfUri: vscode.Uri): Promise<{url: string, uri: vscode.Uri return { url, uri: vscode.Uri.parse(url, true) } } +function setHandler(newHandler: (url: string) => string | undefined) { + state.handlers.push(newHandler) +} + function getValidOrigin(): string { if (state.validOriginUri) { return `${state.validOriginUri.scheme}://${state.validOriginUri.authority}` @@ -144,7 +151,7 @@ function checkHttpOrigin(req: http.IncomingMessage, response: http.ServerRespons return true } const reqOrigin = req.headers['origin'] - if (reqOrigin !== undefined && reqOrigin !== validOrigin) { + if (reqOrigin !== undefined && !reqOrigin.startsWith('vscode-webview:') && reqOrigin !== validOrigin) { logger.log(`Origin in http request is invalid: ${JSON.stringify(req.headers)}`) logger.log(`Valid origin: ${validOrigin}`) response.writeHead(403) @@ -155,7 +162,7 @@ function checkHttpOrigin(req: http.IncomingMessage, response: http.ServerRespons } } -function sendOkResponse(response: http.ServerResponse, content: Buffer, contentType: string) { +function sendOkResponse(response: http.ServerResponse, content: Buffer, contentType: string, cors: boolean = true) { // // Headers to enable site isolation. // - https://fetch.spec.whatwg.org/#cross-origin-resource-policy-header @@ -170,7 +177,7 @@ function sendOkResponse(response: http.ServerResponse, content: Buffer, contentT response.writeHead(200, { 'Content-Type': contentType, 'Content-Length': content.length, - ...sameOriginPolicyHeaders + ...(cors ? sameOriginPolicyHeaders : {'Access-Control-Allow-Origin': '*'}) }) response.end(content) } @@ -209,13 +216,20 @@ async function handler(request: http.IncomingMessage, response: http.ServerRespo } let root: string if (request.url.startsWith('/build/') || request.url.startsWith('/cmaps/') || request.url.startsWith('/standard_fonts/')) { - root = path.resolve(`${lw.extensionRoot}/node_modules/pdfjs-dist`) + root = path.resolve(lw.extensionRoot, 'node_modules', 'pdfjs-dist') } else if (request.url.startsWith('/out/viewer/') || request.url.startsWith('/viewer/')) { // For requests to /out/viewer/*.js and requests to /viewer/*.ts. // The latter is for debugging with sourcemap. root = path.resolve(lw.extensionRoot) } else { - root = path.resolve(`${lw.extensionRoot}/viewer`) + root = path.resolve(lw.extensionRoot, 'viewer') + } + for (const overrideHandler of state.handlers) { + const overrideRoot = overrideHandler(request.url) + if (overrideRoot !== undefined) { + root = overrideRoot + break + } } // // Prevent directory traversal attack. @@ -276,7 +290,7 @@ async function handler(request: http.IncomingMessage, response: http.ServerRespo } response.end() } else { - sendOkResponse(response, content, contentType) + sendOkResponse(response, content, contentType, false) } }) } diff --git a/src/utils/webview.ts b/src/utils/webview.ts index 3ed82f3a9..4b2a0377e 100644 --- a/src/utils/webview.ts +++ b/src/utils/webview.ts @@ -1,25 +1,4 @@ import * as vscode from 'vscode' -import { lw } from '../lw' - -const logger = lw.log('Util', 'Webview') - -let pathLogged = false -export function replaceWebviewPlaceholders(content: string, webview: vscode.Webview): string { - const extensionRootUri = vscode.Uri.file(lw.extensionRoot) - const resourcesFolderUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionRootUri, 'resources')) - const resourcesFolderLink = resourcesFolderUri.toString() - const pdfjsDistUri = webview.asWebviewUri(vscode.Uri.joinPath(extensionRootUri, 'node_modules', 'pdfjs-dist')) - const pdfjsDistLink = pdfjsDistUri.toString() - if (!pathLogged) { - pathLogged = true - logger.log(`%VSCODE_RES% = ${resourcesFolderLink} .`) - logger.log(`%VSCODE_PDFJS_DIST% = ${pdfjsDistLink} .`) - logger.log(`%VSCODE_CSP% = ${webview.cspSource} .`) - } - return content.replace(/%VSCODE_RES%/g, resourcesFolderLink) - .replace(/%VSCODE_PDFJS_DIST%/g, pdfjsDistLink) - .replace(/%VSCODE_CSP%/g, webview.cspSource) -} function getMoveCommands(tabEditorGroup: string) { if (tabEditorGroup === 'left') {