From ea6373c577a95aeb249867280a738519a28a8e0b Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 8 Jul 2016 11:26:00 +0200 Subject: [PATCH] block large images from loading embedded --- .../ui/resourceviewer/resourceViewer.ts | 26 ++++++++++++------- .../browser/parts/editor/binaryDiffEditor.ts | 8 +++--- .../browser/parts/editor/binaryEditor.ts | 4 +-- .../common/editor/binaryEditorModel.ts | 24 ++++++++++++++++- .../files/common/editors/fileEditorInput.ts | 3 +-- 5 files changed, 47 insertions(+), 18 deletions(-) diff --git a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts b/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts index 571c6760386..d4340ec2c4b 100644 --- a/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts +++ b/src/vs/base/browser/ui/resourceviewer/resourceViewer.ts @@ -63,20 +63,28 @@ const mapExtToMediaMimes = { '.movie': 'video/x-sgi-movie' }; +export interface IResourceDescriptor { + resource: URI; + name: string; + size: number; +} + /** * Helper to actually render the given resource into the provided container. Will adjust scrollbar (if provided) automatically based on loading * progress of the binary resource. */ export class ResourceViewer { - public static show(name: string, resource: URI, container: Builder, scrollbar: DomScrollableElement): void { + private static MAX_IMAGE_SIZE = 1024 * 1024; // showing images inline is memory intense, so we have a limit + + public static show(descriptor: IResourceDescriptor, container: Builder, scrollbar: DomScrollableElement): void { // Ensure CSS class $(container).setClass('monaco-resource-viewer'); // Lookup media mime if any let mime: string; - const ext = paths.extname(resource.toString()); + const ext = paths.extname(descriptor.resource.toString()); if (ext) { mime = mapExtToMediaMimes[ext.toLowerCase()]; } @@ -86,12 +94,12 @@ export class ResourceViewer { } // Show Image inline - if (mime.indexOf('image/') >= 0) { + if (mime.indexOf('image/') >= 0 && descriptor.size <= ResourceViewer.MAX_IMAGE_SIZE) { $(container) .empty() .addClass('image') .img({ - src: resource.toString() // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now() // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique + src: descriptor.resource.toString() // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now() // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique }).on(DOM.EventType.LOAD, (e, img) => { const imgElement = img.getHTMLElement(); if (imgElement.naturalWidth > imgElement.width || imgElement.naturalHeight > imgElement.height) { @@ -105,7 +113,7 @@ export class ResourceViewer { } // Update title when we know the image bounds - img.title(nls.localize('imgTitle', "{0} ({1}x{2})", paths.basename(resource.fsPath), imgElement.naturalWidth, imgElement.naturalHeight)); + img.title(nls.localize('imgTitle', "{0} ({1}x{2})", paths.basename(descriptor.resource.fsPath), imgElement.naturalWidth, imgElement.naturalHeight)); scrollbar.scanDomNode(); }); @@ -117,7 +125,7 @@ export class ResourceViewer { .empty() .element('object') .attr({ - data: resource.toString(), // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now(), // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique + data: descriptor.resource.toString(), // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now(), // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique width: '100%', height: '100%', type: mime @@ -130,7 +138,7 @@ export class ResourceViewer { .empty() .element('audio') .attr({ - src: resource.toString(), // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now(), // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique + src: descriptor.resource.toString(), // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now(), // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique text: nls.localize('missingAudioSupport', "Sorry but playback of audio files is not supported."), controls: 'controls' }).on(DOM.EventType.LOAD, () => { @@ -144,7 +152,7 @@ export class ResourceViewer { .empty() .element('video') .attr({ - src: resource.toString(), // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now(), // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique + src: descriptor.resource.toString(), // disabled due to https://github.com/electron/electron/issues/6275 + '?' + Date.now(), // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique text: nls.localize('missingVideoSupport', "Sorry but playback of video files is not supported."), controls: 'controls' }).on(DOM.EventType.LOAD, () => { @@ -157,7 +165,7 @@ export class ResourceViewer { $(container) .empty() .span({ - text: nls.localize('nativeBinaryError', "The file cannot be displayed in the editor because it is either binary, very large or uses an unsupported text encoding.") + text: nls.localize('nativeBinaryError', "The file will not be displayed in the editor because it is either binary, very large or uses an unsupported text encoding.") }); scrollbar.scanDomNode(); diff --git a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts index afe662f9788..fb414b5d727 100644 --- a/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts @@ -109,15 +109,15 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas // Render original let original = resolvedModel.originalModel; - this.renderInput(original.getName(), original.getResource(), true); + this.renderInput(original.getName(), original.getResource(), original.getSize(), true); // Render modified let modified = resolvedModel.modifiedModel; - this.renderInput(modified.getName(), modified.getResource(), false); + this.renderInput(modified.getName(), modified.getResource(), modified.getSize(), false); }); } - private renderInput(name: string, resource: URI, isOriginal: boolean): void { + private renderInput(name: string, resource: URI, size: number, isOriginal: boolean): void { // Reset Sash to default 50/50 ratio if needed if (this.leftContainerWidth && this.dimension && this.leftContainerWidth !== this.dimension.width / 2) { @@ -130,7 +130,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas let container = isOriginal ? this.leftBinaryContainer : this.rightBinaryContainer; let scrollbar = isOriginal ? this.leftScrollbar : this.rightScrollbar; - ResourceViewer.show(name, resource, container, scrollbar); + ResourceViewer.show({ name, resource, size }, container, scrollbar); } public clearInput(): void { diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index c094e3f8c64..a561fa124a6 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -75,8 +75,8 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { } // Render Input - let binaryResourceModel = resolvedModel; - ResourceViewer.show(binaryResourceModel.getName(), binaryResourceModel.getResource(), this.binaryContainer, this.scrollbar); + let model = resolvedModel; + ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize() }, this.binaryContainer, this.scrollbar); return TPromise.as(null); }); diff --git a/src/vs/workbench/common/editor/binaryEditorModel.ts b/src/vs/workbench/common/editor/binaryEditorModel.ts index 92dd238c337..4e52f089c91 100644 --- a/src/vs/workbench/common/editor/binaryEditorModel.ts +++ b/src/vs/workbench/common/editor/binaryEditorModel.ts @@ -4,8 +4,10 @@ *--------------------------------------------------------------------------------------------*/ 'use strict'; +import {TPromise} from 'vs/base/common/winjs.base'; import {EditorModel} from 'vs/workbench/common/editor'; import URI from 'vs/base/common/uri'; +import {IFileService} from 'vs/platform/files/common/files'; /** * An editor model that just represents a resource and mime for a resource that can be loaded. @@ -13,8 +15,13 @@ import URI from 'vs/base/common/uri'; export class BinaryEditorModel extends EditorModel { private name: string; private resource: URI; + private size: number; - constructor(resource: URI, name: string) { + constructor( + resource: URI, + name: string, + @IFileService protected fileService: IFileService + ) { super(); this.name = name; @@ -34,4 +41,19 @@ export class BinaryEditorModel extends EditorModel { public getResource(): URI { return this.resource; } + + /** + * The size of the binary file if known. + */ + public getSize(): number { + return this.size; + } + + public load(): TPromise { + return this.fileService.resolveFile(this.resource).then(stat => { + this.size = stat.size; + + return this; + }); + } } \ No newline at end of file diff --git a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts index c4da10c80a3..d283f19f5c0 100644 --- a/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts +++ b/src/vs/workbench/parts/files/common/editors/fileEditorInput.ts @@ -301,8 +301,7 @@ export class FileEditorInput extends CommonFileEditorInput { if ((error).fileOperationResult === FileOperationResult.FILE_IS_BINARY || (error).fileOperationResult === FileOperationResult.FILE_TOO_LARGE) { textModel.dispose(); - let binaryModel = new BinaryEditorModel(this.resource, this.getName()); - return binaryModel.load(); + return this.instantiationService.createInstance(BinaryEditorModel, this.resource, this.getName()).load(); } // Bubble any other error up -- GitLab