Skip to content

Commit 9505ca0

Browse files
Fix Viewer serving non-HTML content in web mode via positron proxy (#8802)
_Originally merged into prerelease/2025.08 in #8793 --- Addresses #8785 ### Before this fix, when running in web mode, the HtmlProxyServer was: - Reading ALL files (HTML, CSS, JS, images, etc.) as UTF-8 text - Using `res.send(content)` for all files, which doesn't set proper `Content-Type` headers - This caused CSS files to be served as `text/html` instead of `text/css`, JS files as `text/html` instead of `application/javascript`, etc. ### Now the code: - For HTML files: Continues to read them as text and inject HTML resources if needed (preserving the existing functionality) - For non-HTML files: Uses `res.sendFile()` with the `root` option, which automatically sets the correct `Content-Type` headers based on file extensions ### Why res.sendFile() with root option: - Built-in MIME type detection that properly maps file extensions to `Content-Type` headers - Built-in path traversal protection via the `root` option - Only HTML files need special processing (resource injection), so other files can use the standard secure file serving - Simpler and more secure than manual path validation or dynamic `express.static()` calls - This preserves the existing HTML processing while fixing the Content-Type issue for all other file types. This should resolve the issue where the proxy was sending back the wrong `Content-Type` header for non-HTML content like .js or .css files, which is important if the client is strictly enforcing the MIME type (such as when `nosniff` was enforced, which is the case in Workbench Positron Pro sessions). ## New Features N/A ## Bug Fixes - Fixed an issue with non-HTML content being served through Positron Proxy for the Viewer Pane in web mode. ## QA Notes Need to verify interactive plots in the Viewer function in Positron Pro in Workbench @:web Co-authored-by: Pete <[email protected]>
1 parent 9297100 commit 9505ca0

File tree

1 file changed

+12
-6
lines changed

1 file changed

+12
-6
lines changed

extensions/positron-proxy/src/htmlProxy.ts

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -93,16 +93,22 @@ export class HtmlProxyServer implements Disposable {
9393
this._app.use(`/${serverPath}`, async (req, res, next) => {
9494
const filePath = path.join(targetPath, req.path);
9595
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
96-
let content = fs.readFileSync(filePath, 'utf8');
9796
const fileExt = path.extname(filePath).toLowerCase();
9897
const isHtmlFile = ['.html', '.htm'].includes(fileExt);
9998

100-
// If the file is an HTML file and we have an HTML configuration, inject the
101-
// preview resources into the HTML content.
102-
if (isHtmlFile && htmlConfig) {
103-
content = injectPreviewResources(content, htmlConfig);
99+
if (isHtmlFile) {
100+
// For HTML files, read as text and potentially inject resources
101+
let content = fs.readFileSync(filePath, 'utf8');
102+
if (htmlConfig) {
103+
content = injectPreviewResources(content, htmlConfig);
104+
}
105+
res.send(content);
106+
} else {
107+
// For non-HTML files, use sendFile with root option for security and proper Content-Type.
108+
// The root option prevents path traversal attacks by restricting file access to within
109+
// targetPath.
110+
res.sendFile(req.path, { root: targetPath });
104111
}
105-
res.send(content);
106112
} else {
107113
next();
108114
}

0 commit comments

Comments
 (0)