From d1fb29e57318d8a20f3deb95496f4b7102de3f97 Mon Sep 17 00:00:00 2001 From: Jacques Erasmus Date: Mon, 22 Oct 2018 08:28:36 +0000 Subject: Remove base64 encoding from files that contain plain text --- .../ide/components/new_dropdown/upload.vue | 38 +++++++++++++------- .../unreleased/fix-base64-encoded-file-uploads.yml | 5 +++ .../ide/components/new_dropdown/upload_spec.js | 40 +++++++++------------- 3 files changed, 47 insertions(+), 36 deletions(-) create mode 100644 changelogs/unreleased/fix-base64-encoded-file-uploads.yml diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue index e2be805ed22..ec759043efc 100644 --- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue +++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue @@ -25,14 +25,32 @@ export default { }, }, methods: { - createFile(target, file, isText) { + isText(content, fileType) { + const knownBinaryFileTypes = ['image/']; + const knownTextFileTypes = ['text/']; + const isKnownBinaryFileType = knownBinaryFileTypes.find(type => fileType.includes(type)); + const isKnownTextFileType = knownTextFileTypes.find(type => fileType.includes(type)); + const asciiRegex = /^[ -~\t\n\r]+$/; // tests whether a string contains ascii characters only (ranges from space to tilde, tabs and new lines) + + if (isKnownBinaryFileType) { + return false; + } + + if (isKnownTextFileType) { + return true; + } + + // if it's not a known file type, determine the type by evaluating the file contents + return asciiRegex.test(content); + }, + createFile(target, file) { const { name } = file; let { result } = target; + const encodedContent = result.split('base64,')[1]; + const rawContent = encodedContent ? atob(encodedContent) : ''; + const isText = this.isText(rawContent, file.type); - if (!isText) { - // eslint-disable-next-line prefer-destructuring - result = result.split('base64,')[1]; - } + result = isText ? rawContent : encodedContent; this.$emit('create', { name: `${this.path ? `${this.path}/` : ''}${name}`, @@ -43,15 +61,9 @@ export default { }, readFile(file) { const reader = new FileReader(); - const isText = file.type.match(/text.*/) !== null; - reader.addEventListener('load', e => this.createFile(e.target, file, isText), { once: true }); - - if (isText) { - reader.readAsText(file); - } else { - reader.readAsDataURL(file); - } + reader.addEventListener('load', e => this.createFile(e.target, file), { once: true }); + reader.readAsDataURL(file); }, openFile() { Array.from(this.$refs.fileUpload.files).forEach(file => this.readFile(file)); diff --git a/changelogs/unreleased/fix-base64-encoded-file-uploads.yml b/changelogs/unreleased/fix-base64-encoded-file-uploads.yml new file mode 100644 index 00000000000..3dde2419fa1 --- /dev/null +++ b/changelogs/unreleased/fix-base64-encoded-file-uploads.yml @@ -0,0 +1,5 @@ +--- +title: Remove base64 encoding from files that contain plain text +merge_request: 22425 +author: +type: fixed diff --git a/spec/javascripts/ide/components/new_dropdown/upload_spec.js b/spec/javascripts/ide/components/new_dropdown/upload_spec.js index 70b885ede26..878e17ac805 100644 --- a/spec/javascripts/ide/components/new_dropdown/upload_spec.js +++ b/spec/javascripts/ide/components/new_dropdown/upload_spec.js @@ -40,21 +40,10 @@ describe('new dropdown upload', () => { describe('readFile', () => { beforeEach(() => { - spyOn(FileReader.prototype, 'readAsText'); spyOn(FileReader.prototype, 'readAsDataURL'); }); - it('calls readAsText for text files', () => { - const file = { - type: 'text/html', - }; - - vm.readFile(file); - - expect(FileReader.prototype.readAsText).toHaveBeenCalledWith(file); - }); - - it('calls readAsDataURL for non-text files', () => { + it('calls readAsDataURL for all files', () => { const file = { type: 'images/png', }; @@ -66,32 +55,37 @@ describe('new dropdown upload', () => { }); describe('createFile', () => { - const target = { - result: 'content', + const textTarget = { + result: 'base64,cGxhaW4gdGV4dA==', }; const binaryTarget = { - result: 'base64,base64content', + result: 'base64,w4I=', + }; + const textFile = { + name: 'textFile', + type: 'text/plain', }; - const file = { - name: 'file', + const binaryFile = { + name: 'binaryFile', + type: 'image/png', }; - it('creates new file', () => { - vm.createFile(target, file, true); + it('creates file in plain text (without encoding) if the file content is plain text', () => { + vm.createFile(textTarget, textFile); expect(vm.$emit).toHaveBeenCalledWith('create', { - name: file.name, + name: textFile.name, type: 'blob', - content: target.result, + content: 'plain text', base64: false, }); }); it('splits content on base64 if binary', () => { - vm.createFile(binaryTarget, file, false); + vm.createFile(binaryTarget, binaryFile); expect(vm.$emit).toHaveBeenCalledWith('create', { - name: file.name, + name: binaryFile.name, type: 'blob', content: binaryTarget.result.split('base64,')[1], base64: true, -- cgit v1.2.1